I have created a simple Spring Boot App Service in Azure to learn about the Azure App Configuration capabilities. This app uses both the "MessageProperties" approach that is used in the Azure Documentation (see code below) and also uses a com.azure.data.appconfiguration.ConfigurationClient implementation to get settings from my App Configuration resource using a client.
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties
public class MessageProperties {
private String message;
private String myKeyVaultSecret;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getMyKeyVaultSecret() {
return myKeyVaultSecret;
}
public void setMyKeyVaultSecret(String myKeyVaultSecret) {
this.myKeyVaultSecret = myKeyVaultSecret;
}
}
For now, I am only use App Configuration to store two settings. One is just a simple name/value pair and the other is KeyVault reference (see below):
I have done all the other related things that need to be done in order for my App Service to be able to get Key Vault secrets. I created a System Managed Identity for my App Service and created an Access Policy in Key Vault for this Managed Identity to get/list secrets. I also create a Role Assignment in my App Configuration Resource that grants the "App Configuration Data Reader" role to my App Service.
I then created a basic RestController that returns the two settings I created in App Configuration. However, the thing to note is that this controller returns the KeyVault referenced setting in two different ways. One using the "MessageProperties" based implementation and the other using the Java SDK ClientConfiguration based implementation. I have provided the code for my Controller below, which also includes the App Configuration Client code:
import com.azure.data.appconfiguration.ConfigurationClient;
import com.azure.data.appconfiguration.ConfigurationClientBuilder;
import com.azure.data.appconfiguration.models.ConfigurationSetting;
import com.azure.identity.DefaultAzureCredential;
import com.azure.identity.DefaultAzureCredentialBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class HelloController {
private final MessageProperties properties;
public HelloController(MessageProperties properties) {
this.properties = properties;
}
@GetMapping
public Response getMessage() {
Response response = new Response();
response.setMessage((properties.getMessage()));
response.setSecretFromProps(properties.getMyKeyVaultSecret());
response.setSecretFromClient(getPropertyFromClient());
return response;
}
private String getPropertyFromClient() {
DefaultAzureCredential tokenCredential = new DefaultAzureCredentialBuilder().build();
final ConfigurationClient client = new ConfigurationClientBuilder()
.credential(tokenCredential) // use Managed Identity
.endpoint("https://my-dev-app-configuration.azconfig.io")
.buildClient();
try {
ConfigurationSetting setting = client.getConfigurationSetting("/application/myKeyVaultSecret", null);
return setting.getValue();
} catch(Exception e) {
return "default";
}
}
}
When I deploy the code to my App Service in Azure and make a request to my API, the response I get is as follows (with some alteration to mask secrets):
{
"message": "Hello World!",
"secretFromProps": "Endpoint=sb://my-dev-eventhub.servicebus.windows.net...",
"secretFromClient": "{\"uri\":\"https://my-dev-key-vault.vault.azure.net/secrets/event-hub-connection\"}"
}
As you can see, my MessageProperties instance provided the actual value for the KeyVault secret reference I created in App Configuration. However, my App Configuration Client simply returns the KeyVault secret URI that I selected when I created the KeyVault reference in App Configuration. It's as though the client cannot distinguish between simple name/value pairs in App Configuration and KeyVault referenced settings. Is this the expected behavior or am I missing something? I have also provided the key dependencies I am using, as well as a copy of my bootstrap.properties file:
Dependencies
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>spring-cloud-azure-appconfiguration-config-web</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-data-appconfiguration</artifactId>
<version>1.1.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
bootstrap.properties
spring.cloud.azure.appconfiguration.stores[0].endpoint=${APP_CONFIGURATION_ENDPOINT}
spring.cloud.azure.appconfiguration.cache-expiration=10s
Thanks for any help you can provide!