Spring Cloud for Azure starter App Configuration client library for Java

This package helps Spring Application to load properties from Azure Configuration Store.

Package (Maven) | Samples | Reference Documentation

Getting started

Prerequisites

Include the package

There are two libraries that can be used azure-spring-cloud-appconfiguration-config and azure-spring-cloud-appconfiguration-config-web. There are two differences between them the first being the web version takes on spring-web as a dependency, and the web version has various methods for refreshing configurations on a watch interval when the application is active. For more information on refresh see the Configuration Refresh section.

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>azure-spring-cloud-appconfiguration-config</artifactId>
    <version>2.7.0</version>
</dependency>

or

<dependency>
    <groupId>com.azure.spring</groupId>
    <artifactId>azure-spring-cloud-appconfiguration-config-web</artifactId>
    <version>2.7.0</version>
</dependency>

Key concepts

Azure App Configuration provides a service to centrally manage application settings and feature flags. Modern programs, especially programs running in a cloud, generally have many components that are distributed in nature. Spreading configuration settings across these components can lead to hard-to-troubleshoot errors during an application deployment. Use App Configuration to store all the settings for your application and secure their accesses in one place.

Examples

Please use this sample as a reference for how to use this starter.

Supported properties

Name Description Required Default
spring.cloud.azure.appconfiguration.stores List of configuration stores from which to load configuration properties Yes true
spring.cloud.azure.appconfiguration.enabled Whether enable spring-cloud-azure-appconfiguration-config or not No true
spring.cloud.azure.appconfiguration.refresh-interval Amount of time, of type Duration, configurations are stored before a check can occur. No null

spring.cloud.azure.appconfiguration.stores is a list of stores, where each store follows the following format:

Name Description Required Default
spring.cloud.azure.appconfiguration.stores[0].enabled Whether the store will be loaded. No true
spring.cloud.azure.appconfiguration.stores[0].fail-fast Whether to throw a RuntimeException or not when failing to read from App Configuration during application start-up. If an exception does occur during startup when set to false the store is skipped. No true
spring.cloud.azure.appconfiguration.stores[0].selects[0].key-filter The key pattern used to indicate which configuration(s) will be loaded. No /application/*
spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter The label used to indicate which configuration(s) will be loaded. No ${spring.profiles.active} or if null \0

Configuration Store Authentication

Name Description Required Default
spring.cloud.azure.appconfiguration.stores[0].endpoint When the endpoint of an App Configuration store is specified, a managed identity or a token credential provided using AppConfigCredentialProvider will be used to connect to the App Configuration service. An IllegalArgumentException will be thrown if the endpoint and connection-string are specified at the same time. Conditional null
spring.cloud.azure.appconfiguration.stores[0].connection-string When the connection-string of an App Configuration store is specified, HMAC authentication will be used to connect to the App Configuration service. An IllegalArgumentException will be thrown if the endpoint and connection-string are specified at the same time. Conditional null
spring.cloud.azure.appconfiguration.stores[0].managed-identity.client-id Client id of the user assigned managed identity, only required when choosing to use user assigned managed identity on Azure No null

spring.cloud.azure.appconfiguration.stores[0].monitoring is a set of configurations dealing with refresh of configurations:

Name Description Required Default
spring.cloud.azure.appconfiguration.stores[0].monitoring.enabled Whether the configurations and feature flags will be re-loaded if a change is detected. No false
spring.cloud.azure.appconfiguration.stores[0].monitoring.refresh-interval Amount of time, of type Duration, configurations are stored before a check can occur. No 30s
spring.cloud.azure.appconfiguration.stores[0].monitoring.feature-flag-refresh-interval Amount of time, of type Duration, feature flags are stored before a check can occur. No 30s
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key A key that is watched for change via etag. If a change is detected on the key then a refresh of all configurations will be triggered. Yes (If monitoring enabled) null
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].label The label of the key that is being watched for etag changes. No \0
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.primary-token.name The name of a token used with Event Hub to trigger push based refresh. No null
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.primary-token.secret The secret value of a token used with Event Hub to trigger push based refresh. No null
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.secondary-token.name The name of a token used with Event Hub to trigger push based refresh. No null
spring.cloud.azure.appconfiguration.stores[0].monitoring.push-notification.secondary-token.secret The secret value of a token used with Event Hub to trigger push based refresh. No null

spring.cloud.azure.appconfiguration.stores[x].feature-flags is a set of configurations for the feature flags of the store:

Name Description Required Default
spring.cloud.azure.appconfiguration.stores[0].feature-flags.enabled Whether feature flags are loaded from the config store. No false
spring.cloud.azure.appconfiguration.stores[0].feature-flags.label-filter The label used to indicate which feature flags will be loaded. No \0

Advanced usage

Load from multiple configuration stores

If the application needs to load configuration properties from multiple stores, following configuration sample describes how the bootstrap.properties(or .yaml) can be configured.

spring.cloud.azure.appconfiguration.stores[0].connection-string=[first-store-connection-string]
spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=[my-label]
spring.cloud.azure.appconfiguration.stores[1].connection-string=[second-store-connection-string]

If duplicate keys exists for multiple stores, the last configuration store has the highest priority.

Load from multiple labels

If the application needs to load property values from multiple labels in the same configuration store, following configuration can be used:

spring.cloud.azure.appconfiguration.stores[0].connection-string=[first-store-connection-string]
spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=[my-label1]
spring.cloud.azure.appconfiguration.stores[0].selects[1].label-filter=[my-label2]

Multiple labels can be separated with comma, if duplicate keys exists for multiple labels, the last label has highest priority.

Spring Profiles

Spring Profiles are supported by automatically by being set as App Configuration Labels. Using the label filter configuration overrides profile use. To include Spring Profiles and labels:

spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=${spring.profiles.active},v1

If you need to use (No Label) you need to do the following:

spring.cloud.azure.appconfiguration.stores[0].selects[0].label-filter=,${spring.profiles.active}

where the empty value before the comma equals the \0 value.

and for yaml

spring:
  cloud:
    azure:
      appconfiguration:
        stores:
         -
           selects:
             -
              label-filter: ',${spring.profiles.active}'

Configuration Refresh

Configuration Refresh feature allows the application to load the latest property value from configuration store automatically, without restarting the application.

Changing a property key in the configuration store on Azure Portal, e.g., /application/config.message, log similar with below will be printed on the console.

INFO 17496 --- [TaskScheduler-1] o.s.c.e.event.RefreshEventListener       : Refresh keys changed: [config.message]

The application now will be using the updated properties. By default, @ConfigurationProperties annotated beans will be automatically refreshed. Use @RefreshScope on beans which are required to be refreshed when properties are changed.

By default, all the keys following the pattern /application/* with the label ${spring.profiles.active} or when no Spring Profile is set (No Label) is used. At least one watch key is required when monitoring is enabled.

spring.cloud.azure.appconfiguration.stores[0].monitoring.enabled=true
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key=[my-watched-key]
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].label=[my-watched-label]

When using the web library, applications will attempt a refresh whenever a servlet request occurs after the watch interval time when monitoring is enabled.

In the console library calling refreshConfiguration on AppConfigurationRefresh will result in a refresh if the watch interval has passed. The web library can also use this method along with servlet request method.

Push Based Refresh

The Web Provider can be connect to your Azure App Configuration store via an Azure Event Grid Web Hook to trigger a refresh event. By adding the Spring Actuator as a dependency you can add App Configuration Refresh as an exposed endpoint. There are two options appconfiguration-refresh and appconfiguration-refresh-bus. These endpoints work just like there counterparts refresh and refresh-bus, but have the required web hook authorization to work with Azure Event Grid. When needing to refresh multiple application instances azure-servicebus-jms-spring-boot-starter needs to be setup to have the refresh triggered in all instances.

management.endpoints.web.exposure.include= appconfiguration-refresh, appconfiguration-refresh-bus

In addition a required query parameter has been added for security. No token name or value is set by default, but setting one is required in order to use the endpoints. It is suggested you set up your token value in Key Vault and add it to your store through a key vault reference. The values should be:

/application/spring.cloud.appconfiguration.stores[0].monitoring.push-notification.primary-token.name=[primary-token-name]
/application/spring.cloud.appconfiguration.stores[0].monitoring.push-notification.primary-token.secret=[primary-token-secret]
/application/spring.cloud.appconfiguration.stores[0].monitoring.push-notification.secondary-token.name=[secondary-token-name]
/application/spring.cloud.appconfiguration.stores[0].monitoring.push-notification.secondary-token.secret=[secondary-token-secret]

To setup the webhook open your app store and open the events tab. Select "+ Event Subscription". Set the name of your Event and select the Endpoint type of Web Hook. Select "Select an endpoint". You endpoint will be your look as following:

http://myApplication.azurewebsites.net/actuator/appconfiguration-refresh?myTokenName=mySecret

Your application will need to be up and running with token-name and token-secret set as Selecting Confirm Selection will validate the endpoint.

Note: This validation only happens on the creation/modification of the endpoint.

It is also highly recommended that filters are setup as otherwise a refresh will be triggered after every key creation and modification.

Failfast

Failfast feature decides whether throw RuntimeException or not when exception happens. If an exception does occur when false the store is skipped. Any store skipped on startup will be automatically skipped on Refresh. By default, failfast is enabled, it can be disabled with below configuration:

spring.cloud.azure.appconfiguration.stores[0].fail-fast=false

Placeholders in App Configuration

The values in App Configuration are filtered through the existing Environment when they are used. Placeholders can be used just like in application.properties, but with the added benefit of support for key vault references. Example with kafka:

/application/app.name=MyApp
/application/app.description=${app.name} is configured with Azure App Configuration

Use Managed Identity to access App Configuration

Managed identity allows application to access Azure Active Directory protected resource on Azure.

In this library, Azure Identity SDK is used to access Azure App Configuration and optionally Azure Key Vault, for secrets. Only one method of authentication can be set at one time. When not using the AppConfigCredentialProvider and/or KeyVaultCredentialProvider the same authentication method is used for both App Configuration and Key Vault.

Follow the below steps to enable accessing App Configuration with managed identity:

  1. Enable managed identities for the supported Azure services, for example, virtual machine or App Service, on which the application will be deployed.

  2. Configure the Azure RBAC of your App Configuration store to grant access to the Azure service where your application is running. Select the App Configuration Data Reader. The App Configuration Data Owner role is not required but can be used if needed.

  3. Configure bootstrap.properties(or .yaml) in the Spring Boot application.

The configuration store endpoint must be configured when connection-string is empty. When using a User Assigned Id the value spring.cloud.azure.appconfiguration.managed-identity.client-id=[client-id] must be set.

bootstrap.application
spring.cloud.azure.appconfiguration.stores[0].endpoint=[config-store-endpoint]

#If Using User Assigned Identity
spring.cloud.azure.appconfiguration.managed-identity.client-id=[client-id]

Token Credential Provider

Another method of authentication is using AppConfigCredentialProvider and/or KeyVaultCredentialProvider. By implementing either of these classes and providing and generating a @Bean of them will enable authentication through any method defined by the Java Azure SDK. The uri value is the endpoint/dns name of the connection service, so if needed different credentials can be used per config store/key vault.

public class MyCredentials implements AppConfigCredentialProvider, KeyVaultCredentialProvider {

    @Override
    public TokenCredential getAppConfigCredential(String uri) {
            return buildCredential();
    }

    @Override
    public TokenCredential getKeyVaultCredential(String uri) {
            return buildCredential();
    }

    TokenCredential buildCredential() {
            return new DefaultAzureCredentialBuilder().build();
    }

}

Client Builder Customization

The service client builders used for connecting to App Configuration and Key Vault can be customized by implementing interfaces ConfigurationClientBuilderSetup and SecretClientBuilderSetup respectively. Generating and providing a @Bean of them will update the default service client builders used in App Configuration SDK and Key Vault SDK. If necessary, the customization can be done per App Configuration store or Key Vault instance.

public interface ConfigurationClientBuilderSetup {
    public void setup(ConfigurationClientBuilder builder, String endpoint);
}

public interface SecretClientBuilderSetup {
    public void setup(SecretClientBuilder builder, String uri);
}

For example, the following implementation of MyClient replaces the default HttpClient with one using a proxy for all traffic to App Configuration and Key Vault.

public class MyClient implements ConfigurationClientBuilderSetup, SecretClientBuilderSetup {

    @Override
    public void setup(ConfigurationClientBuilder builder, String endpoint) {
        builder.httpClient(buildHttpClient());
    }

    @Override
    public void setup(SecretClientBuilder builder, String uri) {
        builder.httpClient(buildHttpClient());
    }

    private HttpClient buildHttpClient() {
        String hostname = System.getProperty("https.proxyHosts");
        String portString = System.getProperty("https.proxyPort");
        int port = Integer.valueOf(portString);

        ProxyOptions proxyOptions = new ProxyOptions(ProxyOptions.Type.HTTP,
                new InetSocketAddress(hostname, port));
        return new NettyAsyncHttpClientBuilder()
                .proxy(proxyOptions)
                .build();
    }

}

Troubleshooting

Logging setting

Please refer to spring logging document to get more information about logging.

Logging setting examples

  • Example: Setting logging level of hibernate
logging.level.root=WARN
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR

Next steps

The following section provide a sample project illustrating how to use the starter.

More sample code

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.

Please follow instructions here to build from source or contribute.