How to properly manage secrets in Azure App Service with Terraform

Laurent Bel
Pernod Ricard Tech
Published in
3 min readJun 8, 2021

--

In this tutorial we are going to discuss how to properly manage secrets in Azure App Service using Terraform.

Application Settings in Azure App Service

If you are familiar with Azure App Service, you surely know that a common pattern to store secrets is to use Application Settings.

Applications settings in Azure App Service

Even though it is not a security best practice, you can store secrets directly in Application Settings. It works well, and I guess we all used it once at least.

But this comes two main concerns:

  1. Secrets are not really secured in Application Settings
    It would be best to use a Key Vault to properly store the secret so that it is only accessible to relevant people and services.
  2. It does not articulate well with Terraform
    When using Terraform, you probably want to store your Applications Settings in tfvars files that you will ultimately put in a Git repo. This would cause your secrets to end up in your Git repo. And you certainly don’t want that.

Key vault at rescue

One solution is to store your secrets in an Azure Key Vault and reference that Key Vault in App Service’s applications settings.

You can very easily point any application setting to a secret in a Key Vault by simply using:

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)

or

@Microsoft.KeyVault(VaultName=myvault;SecretName=mysecret)

This would make your app settings look like this (note the “Key Vault Reference” flag):

How to properly Terraform this ?

The first step is to create a “System Identity” or the App Service. This System Identity will be used by the App Service to access the Key Vault. It takes a single instruction to create this:

resource "azurerm_app_service" "app" {  ...  identity {
type = "SystemAssigned"
}

}

Then you need to create a Key Vault:

resource "azurerm_key_vault" "keyvault" {
name = "mykeyvault"
tenant_id = var.azure_ad_tenant_id
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku_name = "standard"
}

Then you need to create an access policy so that your App Service can “read” (get) data from that Key Vault. This step is important otherwise your App Service will not be able to access the Key Vault and will not be able to read the secret:

resource "azurerm_key_vault_access_policy" "keyvault_policy" {
key_vault_id = azurerm_key_vault.keyvault.id
tenant_id = var.azure_ad_tenant_id
object_id = azurerm_app_service.app.identity[0].principal_id
secret_permissions = [
"Get"
]
}

Then you can add one or more secret to the Key Vault:

resource "azurerm_key_vault_secret" "keyvault_secret" {
name = "my-secret"
value = ""
key_vault_id = azurerm_key_vault.keyvault.id
lifecycle {
ignore_changes = [value, version]
}
}

Note two things here :

  • The value of the secret is empty. It will be defined manually in Azure so that we do not store it in our Terraform file. We create an empty secret.
  • The lifecycle policy will ignore changes if the value and the version, allowing us to change that directly in Azure without causing a drift of the infrastructure.

We can now properly reference the secret from the Key Vault in our App Service:

resource "azurerm_app_service" "app" {

...

app_settings = {
"NORMAL = "This is not a secret",
"MY-SECRET-SETTING" = "@Microsoft.KeyVault(SecretUri=${azurerm_key_vault_secret.keyvault_secret.versionless_id})"
}
}

Conclusion

That’s it, nothing rocket science. You can now safely store your secrets (and update them if needed) in your key vault. Your Terraform file will not contain any of your secrets, everything will be in the Key Vault.

--

--

Laurent Bel
Pernod Ricard Tech

Leading the IT Architecture & Innovation team at Pernod Ricard. Interested in IT technology in general.