Terraform Azure Key Vault访问策略创建/销毁循环问题求助
Terraform Azure Key Vault 访问策略循环问题及解决方案
问题描述
通过Terraform模块创建Key Vault并配置默认访问策略后,为Synapse系统分配身份添加独立azurerm_key_vault_access_policy资源时,首次apply操作可正常执行,但后续每次执行plan时,Key Vault模块与独立访问策略资源会陷入创建/销毁循环。移除模块内默认策略会导致Terraform权限不足报错,添加服务主体策略又会回到循环状态。
相关代码
synapse.tf
# Key vault Policy import { to = azurerm_key_vault_access_policy.synapse-identity-policy id = module.app3-kv.vault_id } resource "azurerm_key_vault_access_policy" "synapse-identity-policy" { key_vault_id = module.app3-kv.vault_id tenant_id = azurerm_synapse_workspace.synapse.identity[0].tenant_id object_id = azurerm_synapse_workspace.synapse.identity[0].principal_id key_permissions = [ "Get", "WrapKey", "UnwrapKey" ] }
Key Vault模块 (main.tf)
resource "azurerm_key_vault" "key_vault" { name = var.kv_name location = var.location resource_group_name = var.resource_group_name tenant_id = data.azurerm_client_config.current.tenant_id sku_name = var.kv_sku_name enabled_for_disk_encryption = var.enabled_for_disk_encryption enabled_for_deployment = var.enabled_for_deployment enabled_for_template_deployment = var.enabled_for_template_deployment soft_delete_retention_days = 7 purge_protection_enabled = true tags = var.tags access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = var.kv_access_group_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions } access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions } //public_network_access_enabled = var.public_network_access_enabled network_acls { bypass = var.kv_bypass default_action = var.kv_default_action ip_rules = var.kv_ip_address } } output "vault_id" { value = azurerm_key_vault.key_vault.id } output "vault_name" { value = azurerm_key_vault.key_vault.name } output "vault_resource_group_name" { value = azurerm_key_vault.key_vault.resource_group_name }
key_vault.tf
module "app3-kv" { source = "../modules/key_vault" kv_name = var.kv_name resource_group_name = data.azurerm_resource_group.kv-rg.name location = var.location enabled_for_deployment = true enabled_for_disk_encryption = true enabled_for_template_deployment = true tags = var.kv_tags depends_on = [data.azurerm_resource_group.kv-rg] }
Plan输出示例
# module.spexs-app3-kv.azurerm_key_vault.key_vault will be updated in-place ~ resource "azurerm_key_vault" "key_vault" { ~ access_policy = [ # (1 unchanged element hidden) { application_id = "" certificate_permissions = [ "Get", "List", "GetIssuers", "ListIssuers", ] key_permissions = [ "Get", "Create", "Delete", "List", "Recover", "Restore", "UnwrapKey", "WrapKey", "List", "GetRotationPolicy", "SetRotationPolicy", ] object_id = "964c5f8c-c077-44b0-8be4-60c775720e5e" secret_permissions = [ "Get", "List", "Set", "Delete", "Recover", "Restore", ] storage_permissions = [] tenant_id = "" }, - { - application_id = "" - certificate_permissions = [] - key_permissions = [ - "Get", - "WrapKey", - "UnwrapKey", ] - object_id = "b5957f89-c575-42f5-8fe1-c4ba8265eaa6" - secret_permissions = [] - storage_permissions = [] - tenant_id = "" }, ] id = "/subscriptions/subid/resourceGroups/AGV-C-AKV-RGP-04-001/providers/Microsoft.KeyVault/vaults/AGV-C-AKV-04-003-SYNAPSE" name = "AGV-C-AKV-04-003-SYNAPSE" tags = { "Billing Project" = "" "Component" = "Azure Key Vault" "Environment" = "" "System" = "" "Terraform" = "" } # (12 unchanged attributes hidden) # (1 unchanged block hidden) }
问题原因与解决方案
原因
这是Terraform Azure Provider的已知行为:当同时使用azurerm_key_vault资源内的access_policy块和独立的azurerm_key_vault_access_policy资源时,两者会互相覆盖对方的策略。因为azurerm_key_vault的access_policy块管理的是所有访问策略,而独立资源会尝试添加自己的策略,导致Terraform在plan时检测到不一致,触发循环。
解决方案
方案1:统一用独立azurerm_key_vault_access_policy资源管理所有策略
完全移除azurerm_key_vault模块内的access_policy块,改用独立资源管理所有访问策略,包括Terraform服务主体和默认组的权限:
- 在Key Vault模块中删除所有
access_policy块 - 为Terraform服务主体和默认组创建独立访问策略:
resource "azurerm_key_vault_access_policy" "terraform-sp" { key_vault_id = azurerm_key_vault.key_vault.id tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions } resource "azurerm_key_vault_access_policy" "default-group" { key_vault_id = azurerm_key_vault.key_vault.id tenant_id = data.azurerm_client_config.current.tenant_id object_id = var.kv_access_group_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions }
- 保留Synapse身份的独立访问策略资源
这样所有策略都由独立资源管理,不会出现互相覆盖的情况。
方案2:在Key Vault模块中包含所有访问策略(包括Synapse身份)
如果不想拆分策略,可以将Synapse的访问策略整合到Key Vault模块中,通过变量传入需要授权的身份信息:
- 在Key Vault模块中添加变量:
variable "additional_access_policies" { type = list(object({ tenant_id = string object_id = string key_permissions = list(string) secret_permissions = list(string) certificate_permissions = list(string) })) default = [] }
- 在
azurerm_key_vault资源中动态生成访问策略:
resource "azurerm_key_vault" "key_vault" { // 其他属性不变 access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = var.kv_access_group_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions } access_policy { tenant_id = data.azurerm_client_config.current.tenant_id object_id = data.azurerm_client_config.current.object_id key_permissions = var.key_permissions secret_permissions = var.secret_permissions certificate_permissions = var.certificate_permissions } dynamic "access_policy" { for_each = var.additional_access_policies content { tenant_id = access_policy.value.tenant_id object_id = access_policy.value.object_id key_permissions = access_policy.value.key_permissions secret_permissions = access_policy.value.secret_permissions certificate_permissions = access_policy.value.certificate_permissions } } // 其他属性不变 }
- 在调用模块时传入Synapse身份的策略:
module "app3-kv" { source = "../modules/key_vault" // 其他变量不变 additional_access_policies = [ { tenant_id = azurerm_synapse_workspace.synapse.identity[0].tenant_id object_id = azurerm_synapse_workspace.synapse.identity[0].principal_id key_permissions = ["Get", "WrapKey", "UnwrapKey"] secret_permissions = [] certificate_permissions = [] } ] }
这种方式将所有策略集中管理,避免独立资源和模块内策略的冲突。
内容的提问来源于stack exchange,提问作者NickP
相关产品推荐
相关产品推荐

