Skip to content

Key Vault References

Use Azure App Service Key Vault References to inject secrets into configuration without embedding secret values in code or pipeline variables.

sequenceDiagram
    participant APP as App Service App
    participant MI as Managed Identity
    participant KV as Azure Key Vault
    participant CFG as IConfiguration
    APP->>KV: Resolve @Microsoft.KeyVault reference via MI
    KV-->>APP: Secret value
    APP->>CFG: Expose as App Setting
    CFG-->>APP: Read ConnectionStrings:MainDb

Prerequisites

  • Azure Key Vault with at least one secret
  • App Service managed identity enabled
  • Managed identity granted Key Vault Secrets User on vault

Main content

1) Create and verify secret

az keyvault secret set \
  --vault-name "$KEY_VAULT_NAME" \
  --name "sql-connection" \
  --value "Server=tcp:<sql-server>.database.windows.net,1433;Database=<db>;Authentication=Active Directory Managed Identity;Encrypt=True;" \
  --output json
| Flag | Description | |---|---| | az keyvault secret set | Creates a new secret or a new secret version in the Key Vault. | | --vault-name "$KEY_VAULT_NAME" | Targets the Key Vault that will store the secret. | | --name "sql-connection" | Stores the value under the sql-connection secret name. | | --value "..." | Writes the managed-identity SQL connection string as the secret value. | | --output json | Returns the created secret metadata as JSON. |

2) Set Key Vault reference in App Settings

az webapp config appsettings set \
  --resource-group "$RESOURCE_GROUP_NAME" \
  --name "$WEB_APP_NAME" \
  --settings ConnectionStrings__MainDb="@Microsoft.KeyVault(SecretUri=https://$KEY_VAULT_NAME.vault.azure.net/secrets/sql-connection/)" \
  --output json
| Flag | Description | |---|---| | az webapp config appsettings set | Creates or updates app settings on the web app. | | --resource-group "$RESOURCE_GROUP_NAME" | Targets the resource group that contains the web app. | | --name "$WEB_APP_NAME" | Selects the web app that will resolve the Key Vault reference. | | --settings ConnectionStrings__MainDb="@Microsoft.KeyVault(...)" | Stores a Key Vault reference expression instead of a plaintext connection string. | | --output json | Returns the updated app-settings payload as JSON. |

Reference format:

@Microsoft.KeyVault(SecretUri=https://<vault-name>.vault.azure.net/secrets/<secret-name>/<optional-version>)

3) Read secret value through normal IConfiguration

var mainDb = builder.Configuration["ConnectionStrings:MainDb"]
    ?? throw new InvalidOperationException("Connection string missing.");

No Key Vault SDK code is required for this pattern.

4) Optional SDK-based configuration provider alternative

If you need richer behavior (labels, filtering, explicit reload logic), use configuration provider:

<ItemGroup>
  <PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.4.0" />
  <PackageReference Include="Azure.Identity" Version="1.12.0" />
</ItemGroup>
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;

builder.Configuration.AddAzureKeyVault(
    new Uri("https://<vault-name>.vault.azure.net/"),
    new DefaultAzureCredential(),
    new KeyVaultSecretManager());

5) Secret rotation behavior

Key Vault references refresh automatically, but not instantly. For urgent secret rollovers, restart app after setting a new secret version.

az webapp restart --resource-group "$RESOURCE_GROUP_NAME" --name "$WEB_APP_NAME" --output none
| Flag | Description | |---|---| | az webapp restart | Restarts the web app so it re-reads configuration and refreshes Key Vault references sooner. | | --resource-group "$RESOURCE_GROUP_NAME" | Targets the resource group that contains the app. | | --name "$WEB_APP_NAME" | Selects the web app to restart. | | --output none | Suppresses command output after the restart request is sent. |

6) Slot-safe secret references

Use slot settings to prevent staging secrets from swapping into production:

az webapp config appsettings set \
  --resource-group "$RESOURCE_GROUP_NAME" \
  --name "$WEB_APP_NAME" \
  --slot "staging" \
  --slot-settings PaymentApi__Key="@Microsoft.KeyVault(SecretUri=https://$KEY_VAULT_NAME.vault.azure.net/secrets/payment-api-key/)" \
  --output json
| Flag | Description | |---|---| | az webapp config appsettings set | Creates or updates app settings on the selected slot. | | --resource-group "$RESOURCE_GROUP_NAME" | Targets the resource group that contains the web app. | | --name "$WEB_APP_NAME" | Selects the web app whose staging slot will be updated. | | --slot "staging" | Applies the change to the staging slot instead of production. | | --slot-settings PaymentApi__Key="@Microsoft.KeyVault(...)" | Creates a slot-sticky Key Vault reference so the staging secret does not swap into production. | | --output json | Returns the updated slot settings as JSON. |

7) Azure DevOps snippet with reference values

- task: AzureAppServiceSettings@1
  inputs:
    azureSubscription: $(azureSubscription)
    appName: $(webAppName)
    resourceGroupName: $(resourceGroupName)
    appSettings: |
      [
        {
          "name": "ConnectionStrings__MainDb",
          "value": "@Microsoft.KeyVault(SecretUri=https://<vault-name>.vault.azure.net/secrets/sql-connection/)",
          "slotSetting": true
        }
      ]

Do not log resolved secret values

Key Vault references reduce secret sprawl only if you avoid printing resolved values in logs, errors, and debugging output.

Verification

  1. Confirm App Setting value is reference expression (not plaintext).
  2. Hit an endpoint that uses the secret-backed setting.
  3. Validate successful dependency call.

az webapp config appsettings list --resource-group "$RESOURCE_GROUP_NAME" --name "$WEB_APP_NAME" --output table
| Flag | Description | |---|---| | az webapp config appsettings list | Lists the current app settings configured on the web app. | | --resource-group "$RESOURCE_GROUP_NAME" | Targets the resource group that contains the app. | | --name "$WEB_APP_NAME" | Selects the web app whose settings will be listed. | | --output table | Formats the settings list as a readable table. |

Troubleshooting

Secret resolution fails

  • Ensure managed identity has vault access role.
  • Ensure secret URI is correct.
  • Check vault firewall/network restrictions.

Value remains stale after rotation

  • Use versioned URI for deterministic rollout.
  • Restart app after rotation if immediate effect is required.

Works in production but not staging

Validate slot-specific identity and slot-specific app settings configuration.

See Also

Sources