Azure Key Vault Naming Conventions: CAF Rules and Soft-Delete Gotchas
CAF-compliant naming for Azure Key Vault — including the 24-character limit, globally unique names, soft-delete name reservation, and Terraform/Bicep examples.
Azure Key Vault has two naming quirks that catch teams out: the 24-character maximum, and soft-delete name reservation. A Key Vault you delete stays reserved under that name for 90 days — even across subscriptions. Get the naming right upfront, because recovering from a collision on a deleted vault is surprisingly painful.
The constraints
| Rule | Detail |
|---|---|
| CAF prefix | kv |
| Min length | 3 characters |
| Max length | 24 characters |
| Allowed characters | Alphanumerics and hyphens |
| Must start with | A letter |
| Must end with | A letter or digit |
| Scope of uniqueness | Global (within Azure public cloud) |
| Soft-delete reservation | 90 days after deletion |
CAF naming pattern
kv-{workload}-{environment}-{region}-{instance}
Examples:
| Workload | Environment | Region | Key Vault name |
|---|---|---|---|
| payments | prod | eus | kv-payments-prod-eus |
| hrportal | dev | weu | kv-hrportal-dev-weu |
| shared | prod | eus | kv-shared-prod-eus-001 |
| infra | stg | uks | kv-infra-stg-uks-001 |
Note that kv-payments-prod-eus is already 20 characters — you have 4 characters left for an instance number before hitting the 24-character ceiling. For longer workload names, abbreviate:
kv-pmts-prod-eus-001 ← "pmts" for payments (22 chars)
kv-hrp-prod-eus-001 ← "hrp" for hrportal (19 chars)
The soft-delete gotcha
Since Azure Key Vault 2020, soft-delete is mandatory and cannot be disabled. When you delete a Key Vault, its name is reserved for 90 days in a “soft-deleted” state — even if you move to a different subscription or even a different Azure AD tenant in the same cloud.
This creates a problem in CI/CD pipelines and Terraform workflows that create and destroy environments frequently. If a Key Vault named kv-payments-dev-eus-001 is destroyed in a teardown, you can’t create a new one with the same name for 90 days.
Solutions
Option 1 — Purge on delete (Terraform):
resource "azurerm_key_vault" "main" {
name = "kv-payments-dev-eus-001"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
soft_delete_retention_days = 7 # minimum allowed
purge_protection_enabled = false # allow hard delete
}
With purge_protection_enabled = false and a short retention, you can manually purge the vault after deletion and immediately reuse the name. Never disable purge protection in production.
Option 2 — Include a timestamp or build ID in the name:
variable "instance" { default = "001" } # bump this for each teardown cycle
resource "azurerm_key_vault" "main" {
name = "kv-payments-dev-eus-${var.instance}"
}
Option 3 — Don’t destroy dev Key Vaults; rotate secrets instead. If the vault is cheap to keep running (it is — ~$0/month at low usage), leave it and rotate the secrets rather than deleting the vault.
Purging a soft-deleted Key Vault
If you’re blocked by a soft-deleted vault name, purge it from the CLI:
# List soft-deleted vaults
az keyvault list-deleted --resource-type vault
# Purge a specific vault (irreversible)
az keyvault purge --name kv-payments-dev-eus-001 --location eastus
Or from PowerShell:
Get-AzKeyVault -InRemovedState
Remove-AzKeyVault -VaultName "kv-payments-dev-eus-001" -Location "eastus" -InRemovedState -Force
Managed HSM naming
Azure Dedicated HSM and Managed HSM have their own resource type:
| Resource | CAF prefix | Max length | Hyphens |
|---|---|---|---|
| Key Vault (standard/premium) | kv | 24 | Yes |
| Managed HSM | kvmhsm | 24 | Yes |
kvmhsm-payments-prod-eus-001
Naming in Terraform
variable "workload" { default = "payments" }
variable "environment" { default = "prod" }
variable "region" { default = "eus" }
resource "azurerm_resource_group" "main" {
name = "rg-${var.workload}-${var.environment}-${var.region}-001"
location = "eastus"
}
data "azurerm_client_config" "current" {}
resource "azurerm_key_vault" "main" {
name = "kv-${var.workload}-${var.environment}-${var.region}-001"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
soft_delete_retention_days = 90
purge_protection_enabled = true # required for production
tags = {
environment = var.environment
workload = var.workload
}
}
Naming in Bicep
param workload string = 'payments'
param environment string = 'prod'
param region string = 'eus'
var kvName = take('kv-${workload}-${environment}-${region}-001', 24)
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
name: kvName
location: resourceGroup().location
properties: {
sku: {
family: 'A'
name: 'standard'
}
tenantId: subscription().tenantId
enableSoftDelete: true
softDeleteRetentionInDays: 90
enablePurgeProtection: true
}
}
The take() function truncates to 24 characters if the name would exceed the limit — safer than letting the deployment fail at runtime.
Enforcing Key Vault naming with Azure Policy
Require the kv- prefix and deny any Key Vault with purge protection disabled in production:
{
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.KeyVault/vaults" },
{ "field": "name", "notMatch": "kv-*" }
]
},
"then": { "effect": "Deny" }
}
Summary
- Pattern:
kv-{workload}-{environment}-{region}-{instance}— 24-character max, hyphens allowed - Names are globally unique across all of Azure; plan accordingly
- Soft-delete reserves your vault name for 90 days after deletion — critical for ephemeral environments
- Disable purge protection only in dev/test; always enable it in production
- Use
take()in Bicep orsubstr()in Terraform to guard against truncation at the 24-char limit
Use AzureNamer to generate Key Vault names and the corresponding Azure Policy in seconds.
Try AzureNamer
Generate CAF-compliant names for all 203 Azure resource types — free, no login required.
Open the Generator →