Use Bicep to manage secrets
Deployments often require secrets to be stored and propagated securely throughout your Azure environment. Bicep and Azure provide many features to assist you with managing secrets in your deployments.
Avoid secrets where you can
It is possible to avoid using secrets altogether in many situations. Many Azure resources enable managed identities to authenticate and be authorized to access other resources within Azure and without you needing to handle or manage any credentials. Additionally, some Azure services can generate HTTPS certificates for you automatically, sparing you from handling certificates and private keys. Use managed identities and service-managed certificates wherever possible.
Use secure parameters
When you need to provide secrets to your Bicep deployments as parameters, use the @secure()
decorator. When you mark a parameter as secure, Azure Resource Manager avoids logging the value or displaying it in the Azure portal, the Azure CLI, or Azure PowerShell.
Avoid outputs for secrets
Don't use Bicep outputs for secure data. Outputs are logged to the deployment history, and anyone with access to the deployment can view the values of a deployment's outputs.
If you need to generate a secret within a Bicep deployment and make it available to the caller or to other resources, consider one of the following approaches.
Look up secrets dynamically
Sometimes, you need to access a secret from one resource to configure another one. For example, you might have created a storage account in another deployment and need to access its primary key to configure an Azure Functions app. You can use the existing
keyword to obtain a strongly typed reference to the pre-created storage account, and then use the storage account's listKeys()
method to create a connection string with the primary key.
The following example is part of a larger example. For a Bicep file that you can deploy, see the complete file.
param location string = resourceGroup().location
param storageAccountName string
param functionAppName string = 'fn-${uniqueString(resourceGroup().id)}'
var appServicePlanName = 'MyPlan'
var applicationInsightsName = 'MyApplicationInsights'
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' existing = {
name: storageAccountName
}
var storageAccountConnectionString = 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}'
resource functionApp 'Microsoft.Web/sites@2023-12-01' = {
name: functionAppName
location: location
kind: 'functionapp'
properties: {
httpsOnly: true
serverFarmId: appServicePlan.id
siteConfig: {
appSettings: [
{
name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
value: applicationInsights.properties.InstrumentationKey
}
{
name: 'AzureWebJobsStorage'
value: storageAccountConnectionString
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~3'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: storageAccountConnectionString
}
]
}
}
}
resource appServicePlan 'Microsoft.Web/serverfarms@2023-12-01' = {
name: appServicePlanName
location: location
sku: {
name: 'Y1'
tier: 'Dynamic'
}
}
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
name: applicationInsightsName
location: location
kind: 'web'
properties: {
Application_Type: 'web'
publicNetworkAccessForIngestion: 'Enabled'
publicNetworkAccessForQuery: 'Enabled'
}
}
Taking this approach can help you to avoid passing secrets into or out of your Bicep file and also to store secrets in a key vault.
Use Key Vault
Azure Key Vault is designed to store and manage secure data. Use a key vault to manage your secrets, certificates, keys, and other data that needs to be protected and shared.
You can use Bicep to create and manage vaults and secrets. Define your vaults by creating a resource with the type Microsoft.KeyVault/vaults
.
When you create a vault, you need to determine who and what can access its data. If you plan to read the vault's secrets from within a Bicep file, set the enabledForTemplateDeployment
property to true
.
Add secrets to a key vault
Secrets are a child resource and can be created by using the type Microsoft.KeyVault/vaults/secrets
. The following example demonstrates how to create a vault and a secret.
The following example is part of a larger example. For a Bicep file that you can deploy, see the complete file.
param location string = resourceGroup().location
param keyVaultName string = 'mykv${uniqueString(resourceGroup().id)}'
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: keyVaultName
location: location
properties: {
enabledForTemplateDeployment: true
tenantId: tenant().tenantId
accessPolicies: [
]
sku: {
name: 'standard'
family: 'A'
}
}
}
resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
parent: keyVault
name: 'MySecretName'
properties: {
value: 'MyVerySecretValue'
}
}
Tip
When you use automated deployment pipelines, it can sometimes be challenging to determine how to bootstrap key vault secrets for your deployments. For example, if you've been provided with an API key to use when communicating with an external API, then the secret needs to be added to a vault before it can be used in your deployments.
When you work with secrets that come from a third party, you might need to manually add them to your vault before you can reference them for all subsequent uses.
Use a key vault with modules
When you use Bicep modules, you can provide secure parameters by using the getSecret
function.
You can also reference a key vault defined in another resource group by using the existing
and scope
keywords together. In the following example, the Bicep file is deployed to a resource group named Networking. The value for the module's parameter mySecret is defined in a key vault named contosonetworkingsecrets, which is located in the Secrets resource group:
resource networkingSecretsKeyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
scope: resourceGroup('Secrets')
name: 'contosonetworkingsecrets'
}
module exampleModule 'module.bicep' = {
name: 'exampleModule'
params: {
mySecret: networkingSecretsKeyVault.getSecret('mySecret')
}
}
Use a key vault in a .bicepparam file
When you use .bicepparam
file format, you can provide secure values to parameters by using the getSecret
function.
Reference the key vault by providing the subscription ID, resource group name, and key vault name. You can get the value of the secret by providing the secret name. You can optionally provide the secret version; the latest version is used if you don't.
using './main.bicep'
param secureUserName = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>', '<secretVersion>')
param securePassword = az.getSecret('<subscriptionId>', '<resourceGroupName>', '<keyVaultName>', '<secretName>')
Work with secrets in pipelines
The following best practices can help you to handle your secrets with caution when you use a pipeline to deploy your Azure resources:
- Avoid storing secrets in your code repository. For example, don't add secrets to parameters files or to pipeline definition YAML files.
- In GitHub Actions, use encrypted secrets to store secure data. Use secret scanning to detect any accidental commits of secrets.
- In Azure Pipelines, use secret variables to store secure data.
Related resources
- Resource documentation:
- Azure features:
- Bicep features:
- Quickstart templates:
- Azure Pipelines:
- GitHub Actions: