Skip to main content

Terraform must not read Key Vault secrets via data source

FieldValue
IDDX-TF-0001
AVD IDAVD-DX-0001
SeverityHIGH
SourceDX

Ensure Key Vault secret values are not read through Terraform data sources

Reading Key Vault secrets through the data.azurerm_key_vault_secret data source exposes the plaintext secret value during Terraform evaluation. The resolved value is written to the Terraform plan and to the state file, where it remains in clear text regardless of how it is consumed afterwards.

State and plan artifacts should always be treated as sensitive, so secret values must never be materialized into them.

Impact

Plaintext secret values become accessible to anyone who can read the Terraform plan or state, widening the blast radius of a credential leak.

Do not read secret values with data.azurerm_key_vault_secret. Instead, use runtime secret references or the write-only secret pattern (value_wo) so that the value never enters the Terraform plan or state. Follow the appropriate remediation steps below to resolve the issue.

Problematic Code

data "azurerm_key_vault_secret" "bad_example" {
name = "my-secret"
key_vault_id = azurerm_key_vault.this.id
}

resource "azurerm_app_service" "this" {
# ...
app_settings = {
"SECRET" = data.azurerm_key_vault_secret.bad_example.value
}
}
# Reference the secret at runtime via Key Vault references.
resource "azurerm_app_service" "this" {
# ...
app_settings = {
"SECRET" = "@Microsoft.KeyVault(VaultName=${azurerm_key_vault.this.name};SecretName=my-secret)"
}
}

When you need to write a secret, prefer the ephemeral resources and write-only value_wo argument so the value is kept out of state:

# Key Vault
resource "azurerm_key_vault_secret" "this" {
name = "my-secret"
key_vault_id = azurerm_key_vault.this.id
value_wo = var.secret_value
value_wo_version = 1
}

# PostgreSQL server
ephemeral "random_password" "db" {
length = 32
special = true
}

resource "azurerm_postgresql_flexible_server" "this" {
# ...
administrator_login = "pgadmin"
administrator_password = ephemeral.random_password.db.result
}

resource "azurerm_key_vault_secret" "db_password" {
name = "postgres-admin-password"
key_vault_id = azurerm_key_vault.this.id
content_type = "text/plain"
value_wo = ephemeral.random_password.db.result
value_wo_version = 1 # increment this on every rotation
}