Managing Secrets in Azure Container Apps
Will Velida
Posted on March 26, 2024
Azure Container Apps allows your apps to secure sensitive configuration values as secrets. Once you define your secrets, you can pass them as configuration to revisions of your Container Apps, and as secured values to your scale rules.
In this article, I'll discuss what secrets are, where we can define secrets, and how we can reference them in our application's environment variables.
If you want to watch a video that talks about these concepts, check out the video below!
What are Secrets in Azure Container Apps?
Secrets are sensitive configuration values in our Container App applications. The secrets we defined are scoped at the application level, meaning that they aren't tied to a specific revision of our application.
Adding, removing and changing secrets don't generate new revisions of our application, and each app revision can reference one or more secrets. You can also have multiple revisions reference the same secret.
You will inevitably change the values of your secrets, but since changing secrets don't generate new revisions of your application, you can either deploy a new revision with the new secret value, or restart an existing revision.
If you need to delete secrets from your Container App, deploy a new revision that doesn't reference the secret, then deactivate all revision that reference the old secret.
How can we define our secrets in Azure Container Apps?
Secrets are defined as a set of name/value pairs. We can either specify the secret in our Container App directly, or as a reference to a secret stored in Azure Key Vault.
Storing the secret value in Container Apps
Using Bicep, we can store our secret value directly in our Container App like so:
resource containerApp 'Microsoft.App/containerApps@2023-08-01-preview' = {
name: containerAppName
tags: tags
location: location
properties: {
managedEnvironmentId: env.id
configuration: {
// Omitted Code
secrets: [
{
name: 'cosmos-db-connection-string'
value: cosmosDbAccount.listConnectionStrings().connectionStrings[0].connectionString
}
{
name: 'app-insights-key'
value: appInsights.properties.InstrumentationKey
}
{
name: 'app-insights-connection-string'
value: appInsights.properties.ConnectionString
}
]
activeRevisionsMode: 'Multiple'
}
// Omitted Code
}
Secrets are defined at the application level in the resources.properties.configuration.secrets
section. So in this block, I've set the connection string to a Cosmos DB account directly in the secrets
array.
Referencing a secret from Azure Key Vault
We can also reference secrets that are stored in Azure Key Vault. Azure Container Apps will retrieve that secret from Key Vault, and then make it available to your Container App.
There's a couple of things that we need to do before we can retrieve secrets from Key Vault:
- Enable Managed Identity in your Container App.
- Grant the identity the role to read secrets from Azure Key Vault.
We need to grant our Container App the Key Vault Secret User Role. To do this in Bicep, we can do the following:
var keyVaultSecretUserRoleId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
resource keyVaultSecretUserRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(containerApp.id, keyVaultSecretUserRoleId)
scope: keyVault
properties: {
principalId: containerApp.identity.principalId
roleDefinitionId: keyVaultSecretUserRoleId
principalType: 'ServicePrincipal'
}
}
In this block, we are giving our Container App the Key Vault Secret User Role using the role definition id (as a guid), over the scope of our Key Vault.
Once this is done, we can reference the secret in Key Vault like so:
resource containerApp 'Microsoft.App/containerApps@2023-08-01-preview' = {
name: containerAppName
tags: tags
location: location
properties: {
// Omitted Code
secrets: [
{
name: 'cosmos-db-connection-string-kv'
keyVaultUrl: 'https://${keyVault.name}.vault.azure.net/secrets/CosmosDbConnectionString'
identity: 'system'
}
]
activeRevisionsMode: 'Multiple'
}
// Omitted Code
}
In this code block, we are referencing a secret for our Cosmos DB connection string in our Key Vault. We use system
for our identity
property. If we were to use a user managed identity, we can replace system
with the identity's resource ID.
For our Key Vault secret URI, we can either reference a specific version of the secret, or the latest version of a secret.
If we don't specify the version of the secret in the URI, then the app will use the latest version that exists in the key vault. As newer versions of the secret are published, your application will retrieve the latest version within 30 minutes.
If you want more control over which version of the secret is used, specify the version in the URL.
How can we reference secrets in our environment variables?
Once we have defined our secrets, we can reference them in our Container Apps environment variables. When our environment variables reference a secret, its value will be the value defined in the secret.
To do this in our Bicep code, we can write the following:
resource containerApp 'Microsoft.App/containerApps@2023-08-01-preview' = {
name: containerAppName
tags: tags
location: location
properties: {
// Omitted code
secrets: [
{
name: 'cosmos-db-connection-string'
value: cosmosDbAccount.listConnectionStrings().connectionStrings[0].connectionString
}
{
name: 'app-insights-key'
value: appInsights.properties.InstrumentationKey
}
{
name: 'app-insights-connection-string'
value: appInsights.properties.ConnectionString
}
{
name: 'cosmos-db-connection-string-kv'
keyVaultUrl: 'https://${keyVault.name}.vault.azure.net/secrets/CosmosDbConnectionString'
identity: 'system'
}
]
activeRevisionsMode: 'Multiple'
}
template: {
containers: [
{
name: containerAppName
image: 'mcr.microsoft.com/k8se/quickstart:latest'
env: [
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
secretRef: 'app-insights-key'
}
{
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
secretRef: 'app-insights-connection-string'
}
{
name: 'COSMOS_DB_CONNECTION_STRING'
secretRef: 'cosmos-db-connection-string'
}
{
name: 'COSMOS_DB_CONNECTION_KV'
secretRef: 'cosmos-db-connection-string-kv'
}
]
}
]
// Omitted code
}
}
}
So in this block, we define environment variables that use secrets in the secretRef
property. For example, the COSMOS_DB_CONNECTION_KV
environment variable using the secret value of the cosmos-db-connection-string-kv
secret.
When we look at our Container App in the portal, we can see that our secrets are defined under Secrets:
And then these secrets are referenced in our Container Apps environment variables:
Conclusion
In this post, we talked about secrets in Azure Container Apps. Using Bicep, we can reference secrets directly in our Container App, and we can reference secrets that are stored in Azure Key Vault.
I'm building a sample application that uses Azure Container Apps for a video series on my YouTube, so here are a couple of resources that you can use to learn more about secrets:
If you want to learn more about secrets in Azure Container Apps, check out the following documentation.
If you have any questions, feel free to reach out to me on twitter @willvelida
Until next time, Happy coding! 🤓🖥️
Posted on March 26, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.