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

Docker镜像构建时Azure Key Vault凭据传递异常排查

问题

Python脚本使用azure.identity库的DefaultAzureCredential()函数,本地登录有权限的Azure账号时运行正常。但通过Azure Key Vault存储的凭据作为环境变量,在Docker容器内运行时触发以下错误:

default_credential = DefaultAzureCredential()
                         ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/azure/identity/_credentials/default.py", line 149, in __init__
    credentials.append(EnvironmentCredential(authority=authority, _within_dac=True, **kwargs))
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/azure/identity/_credentials/environment.py", line 70, in __init__
    self._credential = ClientSecretCredential(
                       ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/azure/identity/_credentials/client_secret.py", line 45, in __init__
    raise ValueError("client_id should be the id of a Microsoft Entra application")
ValueError: client_id should be the id of a Microsoft Entra application

当前使用的Azure DevOps YAML配置如下:

parameters:
- name: KVConnection
  type: string
  default: 'read-keyvault'
- name: keyVault
  type: string
  default: 'bi-pv-kv'
- name: containerRegistry
  type: string
  default: 'dcr'
- name: CRconnection
  type: string
  default: 'buildandpushdocker'

steps:
- task: AzureKeyVault@2
  displayName: "Get KV secrets"
  inputs:
    azureSubscription: ${{ parameters.KVConnection }}
    KeyVaultName: ${{ parameters.keyVault }}
    SecretsFilter: '*'
    RunAsPreJob: true
  
- bash: |
    echo "##vso[task.setvariable variable=clientid]$(sp-client-id)"
    echo "##vso[task.setvariable variable=clientcred]$(sp-az-secret)"
    echo "##vso[task.setvariable variable=tenantid]$(sp-tenant-id)"
  displayName: Set environment variables

- task: Docker@2
  displayName: Build Planview image 
  inputs: 
    command: build
    repository: planview
    containerRegistry: ${{ parameters.containerRegistry }}
    identity: ${{ parameters.CRconnection }}
    arguments: '--build-arg AZURE_CLIENT_ID=$(clientid) --build-arg AZURE_TENANT_ID=$(tenantid)
      --build-arg AZURE_CLIENT_SECRET=$(clientcred)'
    tags: | 
      planview

- task: Docker@2
  displayName: Push Planview image 
  inputs: 
    command: push
    repository: planview
    containerRegistry: ${{ parameters.containerRegistry }}
    identity: ${{ parameters.CRconnection }}
    tags: |
      planview

已知服务连接配置正确,本地硬编码Key Vault凭据到Dockerfile运行正常,问题出在凭据传递环节,需排查配置错误并给出改进方案。

排查与改进方案

1. 核心问题定位

错误提示说明容器内的AZURE_CLIENT_ID环境变量为空或无效,结合配置分析,可能的原因:

  • Azure Key Vault中sp-client-id的secret名称不匹配、值为空或格式错误
  • Bash步骤设置变量时,$(sp-client-id)未正确解析为Key Vault的secret值
  • Docker build参数传递时,变量未正确注入镜像

2. 针对性修复步骤

步骤1:验证Key Vault Secret的有效性

确认Key Vault中存在sp-client-id、sp-az-secret、sp-tenant-id三个secret,且sp-client-id的值是有效的Microsoft Entra应用UUID。

步骤2:简化凭据传递流程(推荐)

去掉中间的Bash变量转换步骤,直接在Docker任务中引用Key Vault拉取的secret,减少变量传递环节的出错概率:

- task: AzureKeyVault@2
  displayName: "Get KV secrets"
  inputs:
    azureSubscription: ${{ parameters.KVConnection }}
    KeyVaultName: ${{ parameters.keyVault }}
    SecretsFilter: 'sp-client-id,sp-az-secret,sp-tenant-id' # 明确指定需要的secret,避免冗余
    RunAsPreJob: true

- task: Docker@2
  displayName: Build Planview image 
  inputs: 
    command: build
    repository: planview
    containerRegistry: ${{ parameters.containerRegistry }}
    identity: ${{ parameters.CRconnection }}
    arguments: '--build-arg AZURE_CLIENT_ID=$(sp-client-id) --build-arg AZURE_TENANT_ID=$(sp-tenant-id) --build-arg AZURE_CLIENT_SECRET=$(sp-az-secret)'
    tags: | 
      planview

步骤3:修正Bash变量的可见性(若需保留Bash步骤)

默认情况下,##vso[task.setvariable]设置的变量仅对系统环境可见,Docker任务无法直接读取,需设置为输出变量并显式引用:

- bash: |
    echo "##vso[task.setvariable variable=clientid;isOutput=true]$(sp-client-id)"
    echo "##vso[task.setvariable variable=clientcred;isOutput=true]$(sp-az-secret)"
    echo "##vso[task.setvariable variable=tenantid;isOutput=true]$(sp-tenant-id)"
  displayName: Set environment variables
  name: setVars # 给步骤命名,用于后续引用

- task: Docker@2
  displayName: Build Planview image 
  inputs: 
    command: build
    repository: planview
    containerRegistry: ${{ parameters.containerRegistry }}
    identity: ${{ parameters.CRconnection }}
    arguments: '--build-arg AZURE_CLIENT_ID=$(setVars.clientid) --build-arg AZURE_TENANT_ID=$(setVars.tenantid) --build-arg AZURE_CLIENT_SECRET=$(setVars.clientcred)'
    tags: | 
      planview

步骤4:确保Dockerfile正确接收参数

检查Dockerfile中是否包含以下指令,将build-arg转换为容器内的环境变量:

ARG AZURE_CLIENT_ID
ARG AZURE_TENANT_ID
ARG AZURE_CLIENT_SECRET

ENV AZURE_CLIENT_ID=$AZURE_CLIENT_ID
ENV AZURE_TENANT_ID=$AZURE_TENANT_ID
ENV AZURE_CLIENT_SECRET=$AZURE_CLIENT_SECRET

步骤5:优化安全方案(可选)

将客户端密钥通过build-arg嵌入镜像存在安全风险,建议改为:

  • 容器部署时启用系统/用户分配的托管身份,赋予其访问目标资源的权限,此时DefaultAzureCredential()会自动使用托管身份认证,无需设置环境变量
  • 容器运行时动态从Key Vault拉取凭据,而非构建时嵌入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:45:02