With Key Vault references for App Service and Azure Functions you can keep secrets not only out of your code but also out of your Application Settings in the Azure Portal. Here is how to configure that with Terraform ensuring that the latest version will be used.

After following the official Key Vault references for App Service and Azure Functions documentation, you will end with a reference like @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931) instead of the actual value in your Application Settings. To achieve this with Terraform, we need to add the Azure Key Vault and the Secret both to our Terraform definition.

data "azurerm_client_config" "current" {}

# Azure Key Vault
resource "azurerm_key_vault" "default" {
  name                = "myvault"
  location            = "westeurope"
  resource_group_name = "demo"
  tenant_id           = "${data.azurerm_client_config.current.tenant_id}"

  sku {
    name = "standard"
  }
}

# Access Policy
resource "azurerm_key_vault_access_policy" "myapp" {
  key_vault_id = "${azurerm_key_vault.default.id}"
  tenant_id    = "${data.azurerm_client_config.current.tenant_id}"

  object_id = "${azurerm_app_service.myapp.identity.0.principal_id}"

  secret_permissions = [
    "get",
  ]
}

# Secret
resource "azurerm_key_vault_secret" "mysecret" {
  name         = "MySecret"
  value        = "XXXXXXXXXXXX"
  key_vault_id = "${azurerm_key_vault.default.id}"
}

According to the Terraform documentation for Key Vault Secrets, we can now access the Secret URI with the azurerm_key_vault_secret.mysecret.id attribute. So we can go and set an App Services App Settings Value t0 @Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.mysecret.id}).

Azure Key Vault Secret with multiple versions

The problem is, that this approach only works fine, while there is a single version of the secret available. Once there are multiple versions as shown in the screenshot above, azurerm_key_vault_secret.mysecret.id still returns the URI to the first, not the latest version. So we need to build our own URI. The azurerm_key_vault_secret.mysecret.version attribute, gives us the latest version of a secret, so we could build a custom Key Vault reference with the following combination.

@Microsoft.KeyVault(SecretUri=${azurerm_key_vault.default.vault_uri}secrets/${azurerm_key_vault_secret.mysecret.name}/${azurerm_key_vault_secret.mysecret.version})

Embedded in a full Terraform definiton for an Azure App Service, the Key Vault reference would look like the following example.

resource "azurerm_app_service" "myapp" {
  name                = "myapp"
  location            = "westeurope"
  resource_group_name = "demo"
  app_service_plan_id = "..."

  app_settings {    
    MySecretValue = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault.default.vault_uri}secrets/${azurerm_key_vault_secret.mysecret.name}/${azurerm_key_vault_secret.mysecret.version})"    
  }

  identity {
    type = "SystemAssigned"
  }
}

I hope that helped or saved you time. I was debugging my Azure Setup for hours recently, until I found out that my Terraform script is not injecting the latest version of a Secret.


☝️ Advertisement Block: I will buy myself a pizza every time I make enough money with these ads to do so. So please feed a hungry developer and consider disabling your Ad Blocker.