Proposed Pull Request Change

title description services author ms.service ms.topic ms.date ms.author ms.custom
Manage secrets in Azure Container Apps Learn to store and consume sensitive configuration values in Azure Container Apps. container-apps craigshoemaker azure-container-apps how-to 09/04/2026 cshoe ['devx-track-azurecli', 'devx-track-azurepowershell', 'build-2023', 'sfi-ropc-nochange']
📄 Document Links
GitHub View on GitHub Microsoft Learn View on Microsoft Learn
⚠ Content Truncation Detected
The generated rewrite appears to be incomplete.
Original lines: -
Output lines: -
Ratio: -
Raw New Markdown
Generating updated version of doc...
Rendered New Markdown
Generating updated version of doc...
+0 -0
+0 -0
--- title: Manage secrets in Azure Container Apps description: Learn to store and consume sensitive configuration values in Azure Container Apps. services: container-apps author: craigshoemaker ms.service: azure-container-apps ms.topic: how-to ms.date: 09/04/2026 ms.author: cshoe ms.custom: - devx-track-azurecli - devx-track-azurepowershell - build-2023 - sfi-ropc-nochange --- # Manage secrets in Azure Container Apps Azure Container Apps allows your application to securely store sensitive configuration values. Once secrets are defined at the application level, secured values are available to revisions in your container apps. Additionally, you can reference secured values inside scale rules. For information on using secrets with Dapr, refer to [Dapr integration](./dapr-overview.md). - Secrets are scoped to an application, outside of any specific revision of an application. - New revisions don't get generated through adding, removing, or changing secrets. - Each application revision can reference one or more secrets. - Multiple revisions can reference the same secrets. An updated or deleted secret doesn't automatically affect existing revisions in your app. When a secret is updated or deleted, you can respond to changes in one of two ways: 1. Deploy a new revision. 2. Restart an existing revision. Before you delete a secret, deploy a new revision that no longer references the old secret. Then deactivate all revisions that reference the secret. ## Permissions for managing secrets Azure Container Apps exposes separate `listSecrets` operations for container apps, jobs, and Dapr components. These operations return secret values in plain text. Grant these permissions only to identities that need to read secret values. Several Azure built-in roles for Container Apps define permissions using wildcard patterns as a convenience. The following examples grant the ability to read secret values through a wildcard or explicit `listSecrets` permission, even when the role name or description suggests narrower access. This list isn't exhaustive; review the current [Azure built-in roles for containers](/azure/role-based-access-control/built-in-roles/containers) before assigning a role. The following roles grant access to container app or job secret values: | Built-in role | Relevant permissions in the role definition | Matching secrets operation | | --- | --- | --- | | Container Apps Contributor | `Microsoft.App/containerApps/*/action` | `Microsoft.App/containerApps/listSecrets/action` | | Container Apps Operator | `Microsoft.App/containerApps/*/action` | `Microsoft.App/containerApps/listSecrets/action` | | Container Apps Jobs Contributor | `Microsoft.App/jobs/*/action` | `Microsoft.App/jobs/listSecrets/action` | | Container Apps Jobs Operator | `Microsoft.App/jobs/*/action` | `Microsoft.App/jobs/listSecrets/action` | The following roles grant access to secret values configured for Dapr components: | Built-in role | Relevant permissions in the role definition | Matching secrets operation | | --- | --- | --- | | Container Apps ManagedEnvironments Contributor | `Microsoft.App/managedEnvironments/*/action` | `Microsoft.App/managedEnvironments/daprComponents/listSecrets/action` | | Container Apps ConnectedEnvironments Contributor | `Microsoft.App/connectedEnvironments/*`, `Microsoft.App/connectedEnvironments/daprComponents/listSecrets/action` | `Microsoft.App/connectedEnvironments/daprComponents/listSecrets/action` | The effective access depends on the role assignment scope. For example, an assignment at the resource group scope grants the matching permission for every applicable resource in that resource group. > [!IMPORTANT] > The descriptions of the **Container Apps Operator** and **Container Apps Jobs Operator** roles emphasize operational tasks. However, their wildcard actions also grant permission to list secrets. Review the full permission list of a role before you assign it. ### Create a custom role with narrower permissions Built-in roles are a convenience, not a limitation. If no built-in role matches the level of access you want to grant, define an [Azure custom role](/azure/role-based-access-control/custom-roles) that lists only the operations you need and omits the `listSecrets` action. For example, the following custom role allows a user to view jobs and executions and stop running executions, without granting the `listSecrets` action: ```json { "Name": "Container Apps Jobs Execution Stopper", "IsCustom": true, "Description": "View Container Apps jobs and stop running executions.", "Actions": [ "Microsoft.App/jobs/read", "Microsoft.App/jobs/executions/read", "Microsoft.App/jobs/execution/read", "Microsoft.App/jobs/stop/action", "Microsoft.App/jobs/stop/execution/action", "Microsoft.App/managedEnvironments/read" ], "NotActions": [], "AssignableScopes": [ "/subscriptions/<SUBSCRIPTION_ID>" ] } ``` Avoid wildcard patterns such as `Microsoft.App/jobs/*/action` in a custom role definition. This wildcard grants every current and future operation that matches the pattern, including `listSecrets`. > [!WARNING] > For Container Apps jobs, omitting the `listSecrets` action from a custom role isn't enough to protect secret values if the role also grants `Microsoft.App/jobs/start/action`. The [Jobs - Start REST API](/rest/api/resource-manager/containerapps/jobs/start) accepts an optional execution template that can override the main and init container images, commands, and environment variables. A user who can start a job and knows a secret's name can reference that secret from a container of their choosing and read its value inside the container. The container can also use any managed identity [configured to be available to it](managed-identity.md#control-managed-identity-availability). Treat permission to start a job as permission to use the job's secrets and available managed identities. For more information, see [Azure custom roles](/azure/role-based-access-control/custom-roles). ## Defining secrets Secrets are defined as a set of name/value pairs. The value of each secret is specified directly or as a reference to a secret stored in Azure Key Vault. > [!NOTE] > Avoid specifying the value of a secret directly in a production environment. Instead, use a reference to a secret stored in Azure Key Vault, as described in the [Store secret value in Container Apps section](#reference-secret-from-key-vault). ### Store secret value in Container Apps The following is used when you define secrets through the portal, or via different command line options. # [Azure portal](#tab/azure-portal) 1. Go to your container app in the [Azure portal](https://portal.azure.com). 1. Under the *Security* section, select **Secrets**. 1. Select **Add**. 1. In the *Add secret* context pane, enter the following information: - **Name**: The name of the secret. - **Type**: Select **Container Apps Secret**. - **Value**: The value of the secret. 1. Select **Add**. # [ARM template](#tab/arm-template) Secrets are defined at the application level in the `resources.properties.configuration.secrets` section. ```json "resources": [ { ... "properties": { "configuration": { "secrets": [ { "name": "queue-connection-string", "value": "<MY-CONNECTION-STRING-VALUE>" }], } } } ``` Here, a connection string to a queue storage account is declared in the `secrets` array. In this example, you would replace `<MY-CONNECTION-STRING-VALUE>` with the value of your connection string. # [Azure CLI](#tab/azure-cli) When you create a container app, secrets are defined using the `--secrets` parameter. - The parameter accepts a space-delimited set of name/value pairs. - An equals sign (`=`) delimits each pair. ```azurecli az containerapp create \ --resource-group "my-resource-group" \ --name queuereader \ --environment "my-environment-name" \ --image demos/queuereader:v1 \ --secrets "queue-connection-string=<CONNECTION_STRING>" ``` Here, a connection string to a queue storage account is declared in the `--secrets` parameter. Replace `<CONNECTION_STRING>` with the value of your connection string. # [PowerShell](#tab/powershell) When you create a container app, secrets are defined as one or more Secret objects that are passed through the `ConfigurationSecrets` parameter. ```azurepowershell $EnvId = (Get-AzContainerAppManagedEnv -ResourceGroupName my-resource-group -EnvName my-environment-name).Id $TemplateObj = New-AzContainerAppTemplateObject -Name queuereader -Image demos/queuereader:v1 $SecretObj = New-AzContainerAppSecretObject -Name queue-connection-string -Value $QueueConnectionString $ContainerAppArgs = @{ Name = 'my-resource-group' Location = '<location>' ResourceGroupName = 'my-resource-group' ManagedEnvironmentId = $EnvId TemplateContainer = $TemplateObj ConfigurationSecret = $SecretObj } New-AzContainerApp @ContainerAppArgs ``` Here, a connection string to a queue storage account is declared. The value for `queue-connection-string` comes from an environment variable named `$QueueConnectionString`. --- ## <a name="reference-secret-from-key-vault"></a>Reference secret from Key Vault When you define a secret, you create a reference to a secret stored in Azure Key Vault. Container Apps automatically retrieves the secret value from Key Vault and makes it available as a secret in your container app. To reference a secret from Key Vault, you must first enable managed identity in your container app and grant the identity access to the Key Vault secrets. To enable managed identity in your container app, see [Managed identities](managed-identity.md). To grant access to Key Vault secrets, grant the Azure RBAC role [Key Vault Secrets User](/azure/role-based-access-control/built-in-roles/security#key-vault-secrets-user) to the managed identity. # [Azure portal](#tab/azure-portal) 1. Go to your container app in the [Azure portal](https://portal.azure.com). 1. Under the *Security* section, select **Identity**. 1. In the *System assigned* tab, set the *Status* to **On**. > [!NOTE] > You can also use a user-assigned managed identity, which can be reused across multiple resources and persists independently of the app lifecycle. To use it, select the *User assigned* tab and choose an existing identity. 1. Select **Save** to enable system assigned managed identity. 1. A popup appears to confirm that you want to enable system assigned managed identity and register your container app with Microsoft Entra ID. Select **Yes**. 1. Under the *Security* section, select **Secrets**. 1. Select **Add**. 1. In the *Add secret* context pane, enter the following information: - **Name**: The name of the secret. - **Type**: Select **Key Vault reference**. - **Key Vault secret URL**: The URI of your secret in Key Vault. This URI has the following form: `https://<YOUR_KEY_VAULT_NAME>.vault.azure.net/secrets/<YOUR_SECRET_NAME>/<32_DIGIT_HEX_ID>` - **Identity**: Select **System assigned**. 1. Select **Add**. # [ARM template](#tab/arm-template) Secrets are defined at the application level in the `resources.properties.configuration.secrets` section. ```json "resources": [ { ... "properties": { "configuration": { "secrets": [ { "name": "queue-connection-string", "keyVaultUrl": "<KEY_VAULT_SECRET_URI>", "identity": "system" }], } } } ``` Here, a connection string to a queue storage account is declared in the `secrets` array. Its value is automatically retrieved from Key Vault using the specified identity. To use a user managed identity, replace `system` with the identity's resource ID. Replace `<KEY_VAULT_SECRET_URI>` with the URI of your secret in Key Vault. # [Azure CLI](#tab/azure-cli) When you create a container app, secrets are defined using the `--secrets` parameter. - The parameter accepts a space-delimited set of name/value pairs. - An equals sign (`=`) delimits each pair. - To specify a Key Vault reference, use the format `<SECRET_NAME>=keyvaultref:<KEY_VAULT_SECRET_URI>,identityref:<MANAGED_IDENTITY_ID>`. For example, `queue-connection-string=keyvaultref:https://mykeyvault.vault.azure.net/secrets/queuereader,identityref:/subscriptions/ffffffff-eeee-dddd-cccc-bbbbbbbbbbb0/resourcegroups/my-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-identity`. ```azurecli az containerapp create \ --resource-group "my-resource-group" \ --name queuereader \ --environment "my-environment-name" \ --image demos/queuereader:v1 \ --user-assigned "<USER_ASSIGNED_IDENTITY_ID>" \ --secrets "queue-connection-string=keyvaultref:<KEY_VAULT_SECRET_URI>,identityref:<USER_ASSIGNED_IDENTITY_ID>" ``` Here, a connection string to a queue storage account is declared in the `--secrets` parameter. Replace `<KEY_VAULT_SECRET_URI>` with the URI of your secret in Key Vault. Replace `<USER_ASSIGNED_IDENTITY_ID>` with the resource ID of the user assigned identity. > [!NOTE] > The user assigned identity must have access to read the secret in Key Vault. System assigned identity can't be used with the create command because it's not available until after the container app is created. # [PowerShell](#tab/powershell) Secrets Key Vault references aren't supported in PowerShell. --- > [!NOTE] > If you're using [UDR With Azure Firewall](user-defined-routes.md), you'll need to add the `AzureKeyVault` service tag and the *login.microsoft.com* FQDN to the allow list for your firewall. Refer to [configuring UDR with Azure Firewall](use-azure-firewall.md) to decide which additional service tags you need. #### Key Vault secret URI and secret rotation The Key Vault secret URI must be in one of the following formats: - `https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931`: Reference a specific version of a secret. - `https://myvault.vault.azure.net/secrets/mysecret`: Reference the latest version of a secret. If a version isn't specified in the URI, then the app uses the latest version that exists in the key vault. When newer versions become available, the app automatically retrieves the latest version within 30 minutes. Any active revisions that reference the secret in an environment variable is automatically restarted to pick up the new value. For full control of which version of a secret is used, specify the version in the URI. ## <a name="using-secrets"></a>Referencing secrets in environment variables After declaring secrets at the application level as described in the [defining secrets](#defining-secrets) section, you can reference them in environment variables when you create a new revision in your container app. When an environment variable references a secret, its value is populated with the value defined in the secret. ### Example The following example shows an application that declares a connection string at the application level. This connection is referenced in a container environment variable and in a scale rule. # [Azure portal](#tab/azure-portal) After you've [defined a secret](#defining-secrets) in your container app, you can reference it in an environment variable when you create a new revision. 1. Go to your container app in the [Azure portal](https://portal.azure.com). 1. Under the *Application* section, select **Revisions and replicas**. 1. In the *Revisions and replicas* page, select **Create new revision**. 1. In the *Create and deploy new revision* page, in the *Container* tab, under the *Container image* section, select a container. 1. Select **Edit**. 1. In the *Edit a container* context pane, select the **Environment variables** tab. 1. Select **Add**. 1. Enter the following information: - **Name**: The name of the environment variable. - **Source**: Select **Reference a secret**. - **Value**: Select the secret you defined previously. 1. Select **Save**. 1. In the *Create and deploy new revision* page, select **Create** to create the new revision. # [ARM template](#tab/arm-template) In this example, the application connection string is declared as `queue-connection-string` and becomes available elsewhere in the configuration sections. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "String" }, "environment_id": { "type": "String" }, "key_vault_secret_uri": { ⬅️ "type": "String" ⬅️ } ⬅️ }, "variables": {}, "resources": [ { "name": "queuereader", "type": "Microsoft.App/containerApps", "apiVersion": "2022-03-01", "kind": "containerapp", "location": "[parameters('location')]", "properties": { "managedEnvironmentId": "[parameters('environment_id')]", "configuration": { "activeRevisionsMode": "single", "secrets": [ ⬅️ { ⬅️ "name": "queue-connection-string", ⬅️ "keyVaultUrl": "[parameters('key_vault_secret_uri')", ⬅️ "identity": "system" ⬅️ }] ⬅️ }, "template": { "containers": [ { "image": "myregistry/myQueueApp:v1", "name": "myQueueApp", "env": [ { "name": "QueueName", "value": "myqueue" }, { "name": "ConnectionString", ⬅️ "secretRef": "queue-connection-string" ⬅️ } ] } ], "scale": { "minReplicas": 0, "maxReplicas": 10, "rules": [ { "name": "myqueuerule", "azureQueue": { "queueName": "demoqueue", "queueLength": 100, "auth": [ { "secretRef": "queue-connection-string", ⬅️ "triggerParameter": "connection" ⬅️ } ] } } ] } } } }] } ``` Here, the environment variable named `connection-string` gets its value from the application-level `queue-connection-string` secret. Also, the Azure Queue Storage scale rule's authentication configuration uses the `queue-connection-string` secret as to define its connection. To avoid committing secret values to source control with your ARM template, pass secret values as ARM template parameters. # [Azure CLI](#tab/azure-cli) In this example, you create a container app using the Azure CLI with a secret that's referenced in an environment variable. To reference a secret in an environment variable in the Azure CLI, set its value to `secretref:`, followed by the name of the secret. ```azurecli az containerapp create \ --resource-group "my-resource-group" \ --name myQueueApp \ --environment "my-environment-name" \ --image demos/myQueueApp:v1 \ --user-assigned "<USER_ASSIGNED_IDENTITY_ID>" \ --secrets "queue-connection-string=keyvaultref:<KEY_VAULT_SECRET_URI>,identityref:<USER_ASSIGNED_IDENTITY_ID>" \ --env-vars "QueueName=myqueue" "ConnectionString=secretref:queue-connection-string" ``` Here, the environment variable named `connection-string` gets its value from the application-level `queue-connection-string` secret. # [PowerShell](#tab/powershell) Secrets Key Vault references aren't supported in PowerShell. In this example, you create a container using Azure PowerShell with a secret that referenced in an environment variable. To reference the secret in an environment variable in PowerShell, set its value to `secretref:`, followed by the name of the secret. ```azurepowershell $EnvId = (Get-AzContainerAppManagedEnv -ResourceGroupName my-resource-group -EnvName my-environment-name).Id $SecretObj = New-AzContainerAppSecretObject -Name queue-connection-string -Value $QueueConnectionString $EnvVarObjQueue = New-AzContainerAppEnvironmentVarObject -Name QueueName -Value myqueue $EnvVarObjConn = New-AzContainerAppEnvironmentVarObject -Name ConnectionString -SecretRef queue-connection-string -Value secretref $TemplateObj = New-AzContainerAppTemplateObject -Name myQueueApp -Image demos/myQueueApp:v1 -Env $EnvVarObjQueue, $EnvVarObjConn $ContainerAppArgs = @{ Name = 'myQueueApp' Location = '<location>' ResourceGroupName = 'my-resource-group' ManagedEnvironmentId = $EnvId TemplateContainer = $TemplateObj ConfigurationSecret = $SecretObj } New-AzContainerApp @ContainerAppArgs ``` Here, the environment variable named `ConnectionString` gets its value from the application-level `$QueueConnectionString` secret. --- ## <a name="secrets-volume-mounts"></a>Mounting secrets in a volume After declaring secrets at the application level as described in the [defining secrets](#defining-secrets) section, you can reference them in volume mounts when you create a new revision in your container app. When you mount secrets in a volume, each secret is mounted as a file in the volume. The file name is the name of the secret, and the file contents are the value of the secret. You can load all secrets in a volume mount, or you can load specific secrets. ### Example # [Azure portal](#tab/azure-portal) After you've [defined a secret](#defining-secrets) in your container app, you can reference it in a volume mount when you create a new revision. 1. Go to your container app in the [Azure portal](https://portal.azure.com). 1. Under the *Application* section, select **Revisions and replicas**. 1. In the *Revisions and replicas* page, select **Create new revision**. 1. In the *Create and deploy new revision* page, in the *Container* tab, under the *Container image* section, select a container. 1. Select **Edit**. 1. In the *Edit a container* context pane, select the **Volume mounts** tab. 1. Select **Create new volume**. 1. In the *Add volume* context pane, enter the following information: - **Volume type**: Select `Secret`. - **Name**: `mysecrets` - **Mount all secrets**: enabled > [!NOTE] > If you want to load specific secrets, disable **Mount all secrets** and select the secrets you want to load. 1. Select **Add**. 1. In the *Edit a container* context pane, under *Volume name*, select **mysecrets**. 1. Under *Mount path*, enter `/mnt/secrets`. 1. Select **Save**. 1. In the *Create and deploy new revision* page, select **Create** to create the new revision with the volume mount. # [ARM template](#tab/arm-template) In this example, two secrets are declared at the application level. These secrets are mounted in a volume named `mysecrets` of type `Secret`. The volume is mounted at the path `/mnt/secrets`. The application can then reference the secrets in the volume mount. ```json { "$schema": "https://schema.management.azure.com/schemas/2019-08-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "location": { "type": "String" }, "environment_id": { "type": "String" }, "key_vault_secret_uri": { "type": "Securestring" }, "api-key": { "type": "Securestring" } }, "variables": {}, "resources": [ { "name": "queuereader", "type": "Microsoft.App/containerApps", "apiVersion": "2022-11-01-preview", "kind": "containerapp", "location": "[parameters('location')]", "properties": { "managedEnvironmentId": "[parameters('environment_id')]", "configuration": { "activeRevisionsMode": "single", "secrets": [ { "name": "queue-connection-string", "keyVaultUrl": "[parameters('key_vault_secret_uri')", "identity": "system" }, { "name": "api-key", "value": "[parameters('api-key')]" } ] }, "template": { "containers": [ { "image": "myregistry/myQueueApp:v1", "name": "myQueueApp", "volumeMounts": [ { "name": "mysecrets", "mountPath": "/mnt/secrets" } ] } ], "volumes": [ { "name": "mysecrets", "storageType": "Secret" } ] } } }] } ``` To load specific secrets and specify their paths within the mounted volume, you define the secrets in the `secrets` array of the volume object. The following example shows how to load only the `queue-connection-string` secret in the `mysecrets` volume mount with a file name of `connection-string.txt`. ```json { "properties": { ... "configuration": { ... "secrets": [ { "name": "queue-connection-string", "keyVaultUrl": "[parameters('key_vault_secret_uri')", "identity": "system" }, { "name": "api-key", "value": "[parameters('api-key')]" } ] }, "template": { "containers": [ { "image": "myregistry/myQueueApp:v1", "name": "myQueueApp", "volumeMounts": [ { "name": "mysecrets", "mountPath": "/mnt/secrets" } ] } ], "volumes": [ { "name": "mysecrets", "storageType": "Secret", "secrets": [ { "secretRef": "queue-connection-string", "path": "connection-string.txt" } ] } ] } ... } ... } ``` In your app, you can read the secret from a file located at `/mnt/secrets/connection-string.txt`. # [Azure CLI](#tab/azure-cli) In this example, two secrets are declared at the application level. These secrets are mounted in a volume named `mysecrets` of type `Secret`. The volume is mounted at the path `/mnt/secrets`. The application can then read the secrets as files in the volume mount. ```azurecli az containerapp create \ --resource-group "my-resource-group" \ --name myQueueApp \ --environment "my-environment-name" \ --image demos/myQueueApp:v1 \ --user-assigned "<USER_ASSIGNED_IDENTITY_ID>" \ --secrets "queue-connection-string=keyvaultref:<KEY_VAULT_SECRET_URI>,identityref:<USER_ASSIGNED_IDENTITY_ID>" "api-key=$API_KEY" \ --secret-volume-mount "/mnt/secrets" ``` To load specific secrets and specify their paths within the mounted volume, define your app using [YAML](azure-resource-manager-api-spec.md?tabs=yaml#container-app-examples). # [PowerShell](#tab/powershell) Mounting secrets as a volume isn't supported in PowerShell. --- ## Troubleshoot Key Vault references When you reference secrets from Azure Key Vault, you might encounter issues during secret retrieval or synchronization. Here are common errors and resolutions: | Error | Cause | Resolution | |-------|-------|-----------| | Managed identity not enabled | The container app doesn't have a managed identity assigned. | Enable system-assigned or user-assigned managed identity on your container app. See [Managed identities](managed-identity.md). | | Identity not found | The specified managed identity doesn't exist or isn't assigned to the container app. | Verify the identity is created and assigned to the container app in the **Identity** section. | | Secret disabled in Key Vault | The secret is disabled in the Key Vault resource. | Go to your Key Vault in the Azure portal and enable the secret. | | Authentication failed | The managed identity lacks the required permissions to read the secret. | Grant the **Key Vault Secrets User** role to the managed identity on your Key Vault. See [Key Vault Secrets User](/azure/role-based-access-control/built-in-roles/security#key-vault-secrets-user). | | RBAC permission denied | The managed identity has insufficient permissions to access the Key Vault. | Verify the RBAC role assignment on the Key Vault and ensure it includes read permissions for secrets. | ## Next steps > [!div class="nextstepaction"] > [Containers](containers.md)
Success! Branch created successfully. Create Pull Request on GitHub
Error: