Eduard Keilholz

Hi, my name is Eduard Keilholz. I'm a Microsoft developer working at 4DotNet in The Netherlands. I like to speak at conferences about all and nothing, mostly Azure (or other cloud) related topics.
LinkedIn | Twitter | Mastodon | Bsky


I received the Microsoft MVP Award for Azure

Eduard Keilholz
HexMaster's Blog
Some thoughts about software development, cloud, azure, ASP.NET Core and maybe a little bit more...

Secrets Made Easy - for Container Apps

Given my previous posts, it is clear that I’m trying to learn doing container stuff. Especially Azure Container Apps, because it is just an awesome service. This post, covers how to deal with secrets when working with Container Apps, because yes… These may need secrets too.

The Key Vault

Let me first drop a little disclaimer here. Although you can manage secrets in your Container App, it doesn’t mean you should. For larger environment I think I would still recommend using the Azure Key Vault. It is sophisticated, has some clever features and allows for more fine-grained control over who can access what secret (or key, or certificate). For straight forward secret management without any special demands, working with secrets inside Container Apps is just fine.

Secrets in Container Apps

Once you have deployed a Container App (ACA), and navigate to it using the Azure Portal, you will see a blade called Secrets. This is where ACA stores its secrets using Key/value pairs. Secrets are tied to a revision and will be valid across all of that revision. Changing secrets will not create a new revision.

Alternatively, you can create secrets on creation of your ACA with Bicep. If you don’t know what Bicep (or Infrastructure as Code) is, consider this book containing all the ins and out you must know about Infrastructure as Code and especially for Azure. The following snippet of Bicep creates a Storage Account and a Container App resource. This Container App resource will have one secret, the secret key that can be used to connect to the storage account:

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-09-01' = {
  name: uniqueString(defaultResourceName)
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
}

resource apiContainerApp 'Microsoft.App/containerApps@2022-03-01' = {
  name: '${defaultResourceName}-cnt-api'
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    managedEnvironmentId: containerAppEnvironments.id
    configuration: {
      activeRevisionsMode: 'Single'
      secrets: [
        {
          name: 'storage-account-secret'
          value: listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value
        }
      ]
      ingress: {
        external: true
        ...
      }
    }
    template: {
     ...
    }
  }
}

I left some stuff out to keep the template shorter and better readable

Configuring a container with secrets

To configure a container, you can use Environment Variables as you can read in a post I wrote earlier. Environment Variables in Container Apps can also reference a secret. The following snippet of Bicep container the same Container App resource description as above, but now it also describes a container:

resource apiContainerApp 'Microsoft.App/containerApps@2022-03-01' = {
  name: '${defaultResourceName}-cnt-api'
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    managedEnvironmentId: containerAppEnvironments.id
    configuration: {
      activeRevisionsMode: 'Single'
      secrets: [
        {
          name: 'storage-account-secret'
          value: listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value
        }
      ]
      ingress: {
        ...
      }
    }
    template: {
      containers: [
        {
          image: 'path-to-container-image'
          name: 'container-name'
          resources: {
            cpu: json('0.25')
            memory: '0.5Gi'
          }
          env: [
            {
              name: 'Azure_StorageAccount'
              value: storageAccount.name
            }
            {
              name: 'Azure_StorageKey'
              secretRef: 'storage-account-secret'
            }
          ]
        }
      ]
      scale: {
        minReplicas: 0
        maxReplicas: 10
      }
    }
  }
}

You can see that two Environment Variables are added. One is the name of the storage account, which is not a secret. It containes a name, the name of the Environment Variable, and a value. The second Environment Variable represents the secret Key of the Storage Account. Instead of the name and value properties, this Environment Variable contains a name and secretRef property. The value of the secretRef property must be the name of the secret you want to refer to. And the fun thing is, that’s it. You have now dealt with secrets in Container Apps.

This is how easy dealing with secrets can be. Again, I think this is a really straight-forward way of handling secrets. But… There is no sophisticated way of setting permissions and controlling access to secrets like in the Key Vault. Nor does it support certificates and all the goodness that comes with the Key Vault. For compact, easy to monitor systems it’s absolutely simple and easy to use.