如何在Terraform中动态获取Azure DevOps默认SPN用于Key Vault变量组扩展
核心问题解答
1. 是否必须使用默认SPN?
是。Azure DevOps变量组与Key Vault的集成扩展仅支持项目自动创建的默认SPN,自定义SPN无法实现变量组自动拉取Key Vault机密的功能,这是官方设计的限制。
2. 能否通过模糊匹配获取默认SPN?
可以。利用Terraform的AzureAD数据源,通过项目名称前缀模糊匹配,再过滤出带随机UID后缀的SPN(项目会生成两个SPN,其中用于Key Vault的那个名称格式为<项目名>-<随机UID>)。
3. 处理这类默认应用注册的经验
- 必须确保Azure DevOps项目创建完成后再查询SPN,避免因SPN未同步到AzureAD导致查询失败;
- 必要时添加延迟等待,应对AzureAD与Azure DevOps之间的同步延迟;
- 变量组资源需依赖Key Vault访问策略,确保权限配置完成后再创建变量组。
具体Terraform实现步骤
1. 创建Azure DevOps项目
resource "azuredevops_project" "my_project" { name = "my-devops-project" description = "项目描述" visibility = "private" version_control = "Git" work_item_template = "Agile" }
2. 等待SPN同步并查询OID
由于Azure DevOps创建SPN后同步到AzureAD存在延迟,添加30秒等待:
resource "time_sleep" "wait_for_spn_sync" { create_duration = "30s" depends_on = [azuredevops_project.my_project] } data "azuread_service_principals" "ado_project_spns" { display_name_contains = azuredevops_project.my_project.name depends_on = [time_sleep.wait_for_spn_sync] } # 过滤出用于Key Vault的SPN(名称带随机后缀) locals { keyvault_spn = [ for spn in data.azuread_service_principals.ado_project_spns.service_principals : spn if length(regexall("${azuredevops_project.my_project.name}-[a-f0-9]{8,}", spn.display_name)) > 0 ][0] }
3. 配置Key Vault访问策略
resource "azurerm_key_vault_access_policy" "ado_spn_access" { key_vault_id = azurerm_key_vault.my_kv.id tenant_id = data.azuread_client_config.current.tenant_id object_id = local.keyvault_spn.object_id # 变量组需要的机密权限 secret_permissions = [ "Get", "List", ] }
4. 创建关联Key Vault的变量组
resource "azuredevops_variable_group" "kv_secrets" { name = "KeyVaultSecrets" project_id = azuredevops_project.my_project.id description = "从Key Vault拉取的机密变量" allow_access = true variable { name = "DB_PASSWORD" is_secret = true key_vault_id = azurerm_key_vault.my_kv.id secret_name = "db-password" } depends_on = [azurerm_key_vault_access_policy.ado_spn_access] }
错误原因回顾
│ Error: Expanding variable group resource data: Failed to get the Azure Key valut. Erroe: ( code: forbidden, messge: Failed to query service connection API: 'https://mykv.vault.azure.net/secrets?api-version=2016-10-01'. Status Code: 'Forbidden', Response from server: '{"error":{"code":"Forbidden","message":"The user, group or application 'appid=xxxxxxxx;oid=xxxxxxxx;iss=https://sts.windows.net/
/' does not have secrets list permission on key vault 'mykv;location=uksouth'. For help resolving this issue, please see https://go.microsoft.com/fwlink/?linkid=2125287","innererror":{"code":"AccessDenied"}}}' )
该错误是因为Azure DevOps项目创建的默认SPN未被添加到Key Vault访问策略中,导致变量组无法拉取机密。通过上述动态获取SPN OID并配置权限的方式,可避免手动提取OID重复执行apply的问题。
内容的提问来源于stack exchange,提问作者b0bu

