Managing Secrets and Configuration in IaC with Azure Key Vault

If you've seen this error trying to handle secrets in Bicep deployments, this is your guide to resolve it:

Warning outputs-should-not-contain-secrets: Outputs should not contain secrets. Found possible secret: function 'listConnectionStrings' [https://aka.ms/bicep/linter/outputs-should-not-contain-secrets]

Managing secrets and configuration in your Infrastructure as Code (IaC) projects is crucial for maintaining security and compliance. In this post, we'll explore how to use Azure Key Vault to securely handle secrets and configuration settings in your Bicep deployments. We'll walk through the steps to avoid exposing secrets in your outputs and ensure your deployment remains secure.

Why Secrets Shouldn't Be in Outputs

The warning message you're seeing is a critical reminder that secrets, such as connection strings or API keys, should never be exposed in outputs. Outputs are often logged, displayed, or used in other resources, potentially leading to unintentional exposure of sensitive information. Instead, secrets should be securely stored and accessed using dedicated secret management tools like Azure Key Vault.

Key Vault Creation

Creating a Key Vault is a critical step in securely managing your secrets. In our Bicep module, we define a Key Vault resource with the necessary properties and access policies. Here’s an example:

resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: 'kv${resNameCleaned}'
  location: location
  properties: {
    enabledForTemplateDeployment: true
    sku: {
      family: 'A'
      name: 'standard'
    }
    tenantId: subscription().tenantId
    accessPolicies: [
      {
        objectId: objectId
        tenantId: subscription().tenantId
        permissions: {
          keys: [
            'list'
          ]
          secrets: [
            'list'
          ]
        }
      }
    ]
  }
}

This snippet creates a Key Vault with a standard SKU and sets up access policies to allow getting, listing, and setting secrets.

Key Vault Reference in Main Bicep File

Referencing the Key Vault in your main Bicep file is crucial for integrating it with other resources, such as retrieving secrets for your applications. Here’s how you can reference an existing Key Vault:

resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  name: modulexy.outputs.kvName
}

In this snippet, we reference the existing Key Vault using its name output from another module.

getSecret-Function

The getSecret function is used to securely retrieve secrets stored in the Key Vault. This is an essential function for passing secrets to other resources without exposing them. Here’s an example:

resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
  name: modulexy.outputs.kvName
}

module functions 'functions.bicep' = {
  name: 'functions-deployment'
  params: {
    COSMOS_TABLEAPI_CONNECTION_STRING: keyvault.getSecret(cosmosdb.outputs.secretName)
    resName: resName
  }
}

In this snippet, the COSMOS_TABLEAPI_CONNECTION_STRING parameter for the Function App module is retrieved using the getSecret function, ensuring the secret is securely accessed.

Secure Parameter

For the getSecret function to work correctly, the parameter that receives the secret must be marked as secure. This ensures the parameter is handled securely throughout the deployment process. Here’s how to define a secure parameter:

@secure()
param COSMOS_TABLEAPI_CONNECTION_STRING string

Marking the parameter as secure prevents it from being exposed in logs or outputs.

By using Azure Key Vault in your Bicep deployments, you can securely manage secrets and configuration settings, avoiding the risks associated with exposing sensitive information. Following the steps outlined above will help you maintain a secure and compliant IaC environment.

Stay secure and happy coding!