Saturday, 31 January 2026

Use Terraform to Switch Azure Key Vault to Use RBAC Permisions from Access Policies Without a Downtime for Applications/Users

 For Azure Key Vaults access policies based permision setup is now legacy and all key vaults will have to use Azure RBAC permisions eventually for data access permisions according to offcial Microsft documentation here. Using terraform we can setup the changes. However, we have to be carefull about the switching to RBAC from access policies in production scenarios to avoid interptions to applications. Taking two step approach, first set RBAC permisions and in a next release performing switch to RBAC for key vault will help the transtion to be smooth. Let's look at how to setup this requirement with terraform.

The expectation is to have a keyvault setup with RBAC permisions as shown below.


 Let's first look at terrraform code used to setup a key vault with access policies based permission.

resource "azurerm_key_vault" "instancekeyvault" {
  name                        = "ch-demo-kv"
  location                    = azurerm_resource_group.instancerg.location
  resource_group_name         = azurerm_resource_group.instancerg.name
  tenant_id                   = data.azurerm_client_config.current.tenant_id
  sku_name                    = "standard"
  enabled_for_deployment      = false
  enabled_for_disk_encryption = false
  purge_protection_enabled    = true

  network_acls {
    bypass                     = "AzureServices"
    default_action             = "Deny"
    ip_rules                   = split(",", local.kv_allowed_ips)
    virtual_network_subnet_ids = local.kv_allowed_subnets
  }

  # Developers
  access_policy {
    tenant_id          = var.TENANTID
    object_id          = data.azuread_group.devs.object_id
    secret_permissions = var.ENV == local.dev_environment ? ["Get", "List"] : []
  }

  access_policy {
    tenant_id               = data.azurerm_client_config.current.tenant_id
    object_id               = local.tenant_appservice_spn_objectid
    secret_permissions      = ["Get", ]
    certificate_permissions = ["Get", ]
  }

  # IaC service principal
  access_policy {
    tenant_id               = data.azurerm_client_config.current.tenant_id
    object_id               = data.azurerm_client_config.current.object_id
    key_permissions         = ["Get", "Purge", "Recover"]
    secret_permissions      = ["Get", "List", "Set", "Delete", "Purge", "Recover"]
    certificate_permissions = ["Create", "Get", "List", "Delete", "Purge", "Recover"]
  }

  # Containers in AKS via user assigned identity
  access_policy {
    tenant_id          = var.TENANTID
    object_id          = azurerm_user_assigned_identity.aks.principal_id
    secret_permissions = ["Get", "List", ]
  }
}

In above setup the keyvault will be using access policies to grant permisions to data pane objects keys. secrets and certificates.




Step1/Release1

While keeping above access policies based keyvault permisions, now we can as the first step/release add RBAC permisions equivalent to existing access policy based permisions. Note that we have to add roles sperately for same spn or user to match with the access policy permission setup. List of roles available can be found here in the documentation.

# Developers as secrets users in dev
resource "azurerm_role_assignment" "kv_devs_secret_user" {
  count = var.ENV == local.dev_environment ? 1 : 0

  scope                = azurerm_key_vault.instancekeyvault.id
  role_definition_name = "Key Vault Secrets User"
  principal_id         = data.azuread_group.devs.object_id
}

resource "azurerm_role_assignment" "kv_webapp_spn_secret_user" {
  scope                = azurerm_key_vault.instancekeyvault.id
  role_definition_name = "Key Vault Secrets User"
  principal_id         = local.tenant_appservice_spn_objectid
}

resource "azurerm_role_assignment" "kv_webapp_spn_cert_user" {
  scope                = azurerm_key_vault.instancekeyvault.id
  role_definition_name = "Key Vault Certificate User"
  principal_id         = local.tenant_appservice_spn_objectid
}

# Service principal for IaC as Key Vault Administrator - all data plane operations
resource "azurerm_role_assignment" "kv_iac_spn_admin" {
  scope                = azurerm_key_vault.instancekeyvault.id
  role_definition_name = "Key Vault Administrator"
  principal_id         = data.azurerm_client_config.current.object_id
}

# Containers in AKS via user assigned identity
resource "azurerm_role_assignment" "kv_aks_uai_secret_user" {
  scope                = azurerm_key_vault.instancekeyvault.id
  role_definition_name = "Key Vault Secrets User"
  principal_id         = azurerm_user_assigned_identity.aks.principal_id
}

With above when we deploy the key vault without any other change  it will just add the RBAC permissions to key vault. But still the keyvault is using access policies to grant data pane operation permissions.


Once this is deployed to production we can move on with step 2.

Step2/Release2

In the step 2 we can set the keyvault to use the RBAC permisions and remove access policies as shown below. Now when the switch to RBAC for KV happens in the system in production, the RBAC permisions equivalent to previous access policy based permisions are already there in place. So there will be no down time for the applications due to the permission model of the keyvault is changed from access policies to RBAC. Key change is setting the rbac_authorization_enabled  = true and removing access policies.

resource "azurerm_key_vault" "instancekeyvault" {
  name                        = "ch-demo-kv"
  location                    = azurerm_resource_group.instancerg.location
  resource_group_name         = azurerm_resource_group.instancerg.name
  tenant_id                   = data.azurerm_client_config.current.tenant_id
  sku_name                    = "standard"
  enabled_for_deployment      = false
  enabled_for_disk_encryption = false
  purge_protection_enabled    = true
  rbac_authorization_enabled  = true

  network_acls {
    bypass                     = "AzureServices"
    default_action             = "Deny"
    ip_rules                   = split(",", local.kv_allowed_ips)
    virtual_network_subnet_ids = local.kv_allowed_subnets
  }
}

After the deployment the key vault will be using RBAC permisions as shown below.



No comments:

Popular Posts