You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Terraform部署Azure Key Vault时403权限错误问题排查

Azure Key Vault Terraform 403权限错误排查

问题描述

我作为DevOps人员,计划通过Terraform创建Azure Key Vault,为开发者配置Get权限,自身拥有该Vault的完整管理权限。执行terraform validate命令未报错,但执行terraform apply时出现403权限错误,错误信息如下:

│ Error: checking for presence of existing Secret "ConnectionStrings--DBContext" (Key Vault "https://deneme-beta.vault.azure.net/"): keyvault.BaseClient#GetSecret: Failure responding to request: StatusCode=403 -- Original Error: autorest/azure: Service returned an error. Status=403 Code="Forbidden" Message="The user, group or application 'appid=04b071-811ddb-461a-bbee-02f9e1bf7b46;oid=b78911-511d7b-4968-a654-4389ef10196d;numgroups=1;iss=https://sts.windows.net/d07101-51110d-4151-abf2-d14d0729ada3/' does not have secrets get permission on key vault 'deneme-beta;location=germanywestcentral'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287" InnerError={"code":"AccessDenied"}
│ 
│   with azurerm_key_vault_secret.vault_secrets["deneme-beta-ConnectionStrings--DBContext"],
│   on main.tf line 59, in resource "azurerm_key_vault_secret" "vault_secrets":
│   59: resource "azurerm_key_vault_secret" "vault_secrets" {

配置文件

locals.tf

locals {
  contexts = [
    {
      "name" : "deneme-beta",
      "vars" : [
        {
          "variable" : "ConnectionStrings--DBContext",
          "value" : "data source=192.168.10.1:1521/beta;password=deneme-test;user id=PRJ"
        },
        {
          "variable" : "MinioSettings--SecretKey",
          "value" : "flkjdwfkljdkfjdjkfjdkfjkdjf"
        },
        {
          "variable" : "RabbitMQConfiguration--Password",
          "value" : "94j9j9j9j"
        }
      ]
    },
    {
      "name" : "deneme-stage",
      "vars" : [
        {
          "variable" : "ConnectionStrings--DBContext",
          "value" : "data source=192.168.10.1:1521/stage;password=deneme-stage;user id=PRJ"
        },
        {
          "variable" : "MinioSettings--SecretKey",
          "value" : "dkmkdemmdcmdkmckmdkcmddcdcdcdc"
        },
        {
          "variable" : "RabbitMQConfiguration--Password",
          "value" : "223232323"
        }
      ]
    }
  ]

  variables = merge([for context in local.contexts : {
    for vars in context.vars :
    "${context.name}-${vars.variable}" => {
      name     = context.name
      variable = vars.variable
      value    = vars.value
    }
  }]...)

}

provider.tf

terraform {
  required_version = ">=1.0"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
      version = "~>2.48"
    }
  }

}
provider "azurerm" {
  features {}
}

main.tf

resource "azurerm_resource_group" "rg" {
  name     = "rg_vault_deneme"
  location = "germanywestcentral"
}

data "azurerm_client_config" "current" {}

resource "azurerm_key_vault" "ygm_vaults" {
  for_each                   = toset([for context in local.contexts : context.name])
  name                       = each.key
  location                   = azurerm_resource_group.rg.location
  resource_group_name        = azurerm_resource_group.rg.name
  tenant_id                  = data.azurerm_client_config.current.tenant_id
  sku_name                   = "standard"
  soft_delete_retention_days = 7
  purge_protection_enabled   = false

}

resource "azurerm_key_vault_access_policy" "ygm_vault_access_policy-devops" {
  for_each     = azurerm_key_vault.ygm_vaults
  key_vault_id = azurerm_key_vault.ygm_vaults[each.value.name].id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id

  key_permissions = [
    "Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore",
  ]

  secret_permissions = [
    "Get", "List", "Set", "Delete", "Recover", "Backup", "Restore",
  ]

}

data "azuread_client_config" "current" {}

data "azuread_user" "developer" {
  user_principal_name = "deneme@live.com"
}

resource "azurerm_key_vault_access_policy" "ygm_vault_access_policy-developer" {
  for_each     = azurerm_key_vault.ygm_vaults
  key_vault_id = azurerm_key_vault.ygm_vaults[each.value.name].id
  tenant_id    = data.azuread_client_config.current.tenant_id
  object_id    = data.azuread_user.developer.object_id

  key_permissions = [
    "Get",
    "List"
  ]

  secret_permissions = [
    "Get",
    "List"
  ]
}

resource "azurerm_key_vault_secret" "vault_secrets" {
  for_each     = local.variables
  key_vault_id = azurerm_key_vault.ygm_vaults[each.value.name].id

  name  = each.value.variable
  value = each.value.value
}

问题排查与修复

问题根源

  1. 资源并行创建导致权限未生效:Terraform默认并行执行资源创建,azurerm_key_vault_secret可能在azurerm_key_vault_access_policy(给DevOps用户配置权限)完全生效前就尝试访问Key Vault,触发403错误。
  2. 访问策略引用冗余:azurerm_key_vault_access_policy中key_vault_id使用azurerm_key_vault.ygm_vaults[each.value.name].id的写法冗余,且未明确依赖关系,可能导致策略应用延迟。

修复步骤

1. 添加资源依赖关系

在azurerm_key_vault_secret资源中添加depends_on,确保访问策略完全应用后再创建密钥:

resource "azurerm_key_vault_secret" "vault_secrets" {
  for_each     = local.variables
  key_vault_id = azurerm_key_vault.ygm_vaults[each.value.name].id

  name  = each.value.variable
  value = each.value.value

  # 明确依赖两个访问策略,确保权限生效后再创建密钥
  depends_on = [
    azurerm_key_vault_access_policy.ygm_vault_access_policy-devops,
    azurerm_key_vault_access_policy.ygm_vault_access_policy-developer
  ]
}

2. 简化访问策略的Key Vault引用

azurerm_key_vault_access_policy的for_each已遍历azurerm_key_vault.ygm_vaults,直接用each.value.id引用Key Vault ID即可:

# DevOps访问策略
resource "azurerm_key_vault_access_policy" "ygm_vault_access_policy-devops" {
  for_each     = azurerm_key_vault.ygm_vaults
  key_vault_id = each.value.id
  tenant_id    = data.azurerm_client_config.current.tenant_id
  object_id    = data.azurerm_client_config.current.object_id

  key_permissions = [
    "Get", "List", "Update", "Create", "Import", "Delete", "Recover", "Backup", "Restore",
  ]

  secret_permissions = [
    "Get", "List", "Set", "Delete", "Recover", "Backup", "Restore",
  ]
}

# 开发者访问策略
resource "azurerm_key_vault_access_policy" "ygm_vault_access_policy-developer" {
  for_each     = azurerm_key_vault.ygm_vaults
  key_vault_id = each.value.id
  tenant_id    = data.azuread_client_config.current.tenant_id
  object_id    = data.azuread_user.developer.object_id

  key_permissions = [
    "Get",
    "List"
  ]

  secret_permissions = [
    "Get",
    "List"
  ]
}

3. 验证订阅级权限(可选)

确认执行Terraform的用户在Azure订阅中拥有Key Vault Contributor或更高权限,避免因订阅级权限不足导致访问策略无法正常应用。

内容的提问来源于stack exchange,提问作者Serkan 2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:30:54