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

Azure DevOps管道Docker容器Libcrypto密钥加载错误求助

Terragrunt + Azure DevOps 管道模块下载权限问题排查与解决

问题背景

使用Azure DevOps管道实现Terragrunt持续集成,Terraform模块存储在独立代码仓库,执行terragrunt plan需要通过SSH密钥访问该仓库。所有Terragrunt命令在Docker容器中运行,构建容器时已注入SSH密钥,但执行terragrunt plan时出现模块下载失败,核心错误如下:

Load key "/root/.ssh/id_rsa": error in libcrypto
git@ssh.dev.azure.com: Permission denied (password,publickey).

现有配置

Dockerfile

FROM devopsinfra/docker-terragrunt:azure-tf-1.5.5-tg-0.50.1

RUN apt-get update
RUN apt-get install -y git

ARG SSH_PRIVATE_KEY

RUN mkdir /root/.ssh/
RUN echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa

RUN touch /root/.ssh/known_hosts
RUN touch /root/.ssh/config
RUN ssh-keyscan -t rsa ssh.dev.azure.com >> /root/.ssh/known_hosts
RUN echo $'Host ssh.dev.azure.com vs-ssh.visualstudio.com \n\
           HostkeyAlgorithms +ssh-rsa \n\
           IdentityFile ~/.ssh/id_rsa \n\
           IdentitiesOnly yes' >> /root/.ssh/config

RUN chmod -R 600 ~/.ssh

Azure DevOps 管道配置

- task: Docker@1
  displayName: 'Building image'
  inputs:
    command: 'Build an image'
    imageName: 'tg-azure-img'
    arguments: '--build-arg SSH_PRIVATE_KEY="$(ado-privatekey)"'
- task: Docker@1
  displayName: 'Terragrunt Plan'
  inputs:
     command: 'Run an image'
     imageName: 'tg-azure-img'
     qualifyImageName: false
     volumes: '$(Pipeline.Workspace)/drop:/code'
     envVars: |
       ARM_CLIENT_SECRET=$(edsp-terraform-ci-credential)
       ARM_CLIENT_ID=$(arm-client-id)
       ARM_TENANT_ID=$(arm-tenant-id)
       ARM_SUBSCRIPTION_ID=$(arm-subscription-id)
     workingDirectory: '/code/subscriptions/${{ parameters.workingDirectory }}'
     containerCommand: '/bin/bash run-plan.sh'
     runInBackground: false

解决思路

1. 修复SSH密钥写入时的格式损坏问题

使用echo命令写入SSH密钥会丢失换行符,导致密钥文件损坏。替换为printf命令保留完整格式:

# 替换原echo "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa
RUN printf "%s" "${SSH_PRIVATE_KEY}" > ~/.ssh/id_rsa

2. 规范SSH目录与文件权限

chmod -R 600 ~/.ssh会将known_hosts和config也设为600权限(应为644),调整为:

RUN chmod 700 ~/.ssh          # 目录仅所有者可读写执行
RUN chmod 600 ~/.ssh/id_rsa   # 密钥文件仅所有者可读
RUN chmod 644 ~/.ssh/known_hosts ~/.ssh/config  # 配置文件可读

3. 容器运行时注入密钥(更安全)

避免在镜像中硬编码敏感密钥,改为管道运行时挂载临时密钥文件:

  • 步骤1:添加管道准备SSH密钥任务
- task: Bash@3
  displayName: 'Prepare SSH Key'
  inputs:
    targetType: 'inline'
    script: |
      mkdir -p $(Pipeline.Workspace)/ssh
      echo "$(ado-privatekey)" > $(Pipeline.Workspace)/ssh/id_rsa
      echo $'Host ssh.dev.azure.com vs-ssh.visualstudio.com \n\
             HostkeyAlgorithms +ssh-rsa \n\
             IdentityFile ~/.ssh/id_rsa \n\
             IdentitiesOnly yes' > $(Pipeline.Workspace)/ssh/config
      ssh-keyscan -t rsa ssh.dev.azure.com >> $(Pipeline.Workspace)/ssh/known_hosts
      chmod 700 $(Pipeline.Workspace)/ssh
      chmod 600 $(Pipeline.Workspace)/ssh/id_rsa
      chmod 644 $(Pipeline.Workspace)/ssh/config $(Pipeline.Workspace)/ssh/known_hosts
  • 步骤2:修改Dockerfile移除密钥相关构建步骤
    删除Dockerfile中所有ARG SSH_PRIVATE_KEY及后续密钥写入、权限配置的代码。
  • 步骤3:更新容器运行任务
- task: Docker@1
  displayName: 'Terragrunt Plan'
  inputs:
     command: 'Run an image'
     imageName: 'tg-azure-img'
     qualifyImageName: false
     volumes: |
       $(Pipeline.Workspace)/drop:/code
       $(Pipeline.Workspace)/ssh:/root/.ssh
     envVars: |
       ARM_CLIENT_SECRET=$(edsp-terraform-ci-credential)
       ARM_CLIENT_ID=$(arm-client-id)
       ARM_TENANT_ID=$(arm-tenant-id)
       ARM_SUBSCRIPTION_ID=$(arm-subscription-id)
     workingDirectory: '/code/subscriptions/${{ parameters.workingDirectory }}'
     containerCommand: '/bin/bash run-plan.sh'
     runInBackground: false

4. 验证SSH连接有效性

在容器运行命令前添加调试步骤,测试SSH连通性:

containerCommand: '/bin/bash -c "ssh -T git@ssh.dev.azure.com && run-plan.sh"'

若仍失败,需确认:

  • 公钥已正确添加到Azure DevOps服务账号的SSH密钥列表中
  • 密钥为无密码的PEM格式(Azure DevOps不支持带密码的SSH密钥)
  • ssh.config中的Host配置覆盖了所有需要的域名

5. 改用HTTPS + PAT认证替代SSH

放弃SSH密钥,改用Azure DevOps个人访问令牌(PAT)通过HTTPS访问模块仓库:

  • 将Terraform模块源改为HTTPS格式:git::https://dev.azure.com/myorg/modules.git//path/to/module
  • 在管道中添加环境变量:
envVars: |
  # ... 其他ARM变量
  GIT_USERNAME=any_username
  GIT_PASSWORD=$(ado-pat)
  • 在Terragrunt配置中添加Git凭证配置:
generate "git_credentials" {
  path      = "git_credentials.tf"
  if_exists = "overwrite_terragrunt"
  contents = <<EOF
terraform {
  git_credentials {
    username = "${get_env("GIT_USERNAME")}"
    password = "${get_env("GIT_PASSWORD")}"
  }
}
EOF
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:43:16