【发布时间】:2022-03-06 11:41:23
【问题描述】:
我创建了一个包含 Git 客户端的 Windows 容器,并且我能够使用 HTTP 从我们的 Bitbucket 服务器克隆和结帐。这意味着我需要为与 Git 的每笔交易提供用户名和密码。 我现在更想使用 SSH。因此,我使用 ssh-keygen 生成了一个 SSH 密钥,并将公钥添加到我在 Bitbucket 中的用户帐户中,在我的本地 PC 上,当我使用 Pageant 加载我的密钥时,我能够成功地与 Bitbucket 进行交易。
在容器中,我正在努力让它发挥作用。
我找到了一些信息here,这些信息包含在我的 Dockerfile 中——特别是命令 Set-Service、Start-Service 和 Get-Service。
这在一定程度上有效,这条线 RUN printf "${SSH_KEY_PASSPHRASE}" | ssh-add C:\Users\Jenkins\.ssh\id_rsa 无法构建 - 它无法识别 printf。我尝试用echo 替换它,但也失败了。
如果我从我的 Dockerfile 中删除这一行,我可以构建和运行这个容器;然后我尝试使用 powershell 会话进入它并尝试手动运行ssh-add C:\Users\Jenkins\.ssh\id_rsa,但我得到了响应Could not open a connection to your authentication agent.
如果我运行Get-Service ssh-agent,它会报告 ssh-agent 正在运行。
所以我的问题如下:
- 为什么
ssh-add命令不起作用? - 如何在这个容器中添加我的 ssh 密钥?
- 当我让
ssh-add命令工作时,如何在 Dockerfile 中指定密码?
这是我的 Dockerfile:
# escape=`
FROM mcr.microsoft.com/windows/servercore
ARG SSH_KEY_PASSPHRASE
COPY .\files\Git-2.18.0-64-bit.exe C:\installers\git-installer.exe
COPY .\files\Git-2.18.0-64-bit.inf C:\installers\git-installer-script.inf
RUN powershell -Command `
# Install Git ; `
Start-Process -filepath C:\installers\git-installer.exe -passthru -wait -argumentlist "/LOADINF=C:\installers\git-installer-script.inf","/VERYSILENT","/NORESTART" ; `
Remove-Item C:\installers\ -Force -Recurse;
RUN powershell -Command `
net user /add Jenkins; `
net localgroup Administrators Jenkins /add;
USER Jenkins
RUN powershell -Command `
mkdir ~\.ssh;
COPY .\id_rsa C:\Users\Jenkins\.ssh\id_rsa
RUN powershell -Command `
# Make sure you're running as an Administrator `
Set-Service ssh-agent -StartupType Automatic; `
Start-Service ssh-agent; `
Get-Service ssh-agent;
# This doesn't work and I don't know how to do this
RUN printf "${SSH_KEY_PASSPHRASE}" | ssh-add C:\Users\Jenkins\.ssh\id_rsa
编辑 1
我现在发现,如果运行这个容器(在 dockerfile 中没有ssh-add 命令)然后使用 ssh URL 运行 git clone,它会指出无法建立 bitbucket 主机的真实性,执行你想继续连接吗?我输入“是”,然后它“将我的位存储桶主机永久添加到已知主机列表中”,然后询问密钥“c/Users/Jenkins/.ssh/id_rsa”的密码。
一旦我输入密码,它就会成功克隆回购。 这个结果让我很吃惊,并引出了一个新问题:
- 如果我还没有添加它,它如何知道 c/Users/Jenkins/.ssh 中的 ssh 密钥?我显然在某处缺少一些理解。
编辑 2
我玩过我的 Dockerfile 并发现该行
RUN powershell -Command mkdir ~\.ssh 在某种程度上似乎很重要。
如果我删除此行并运行容器,我可以看到我的密钥存在于C:\Users\Jenkins\.ssh\ 但如果我运行ssh-add .\Users\Jenkins\.ssh\id_rsa 它会失败并显示Permissions for id_rsa are too open。
如果我包含mkdir 行,对我来说没有明显区别,但ssh-add 命令似乎工作并报告Identity added: .\Users\Jenkins\.ssh\id_rsa (<my company domain>+<my windows username@PC name>)。
如果我不手动创建 .ssh 文件夹,它似乎仍然是在 COPY 命令期间隐式创建的,但 ssh-add 失败。这是怎么回事?
接下来,我将 ssh-add 命令包含到我的 Dockerfile 中并重新构建它,可以看到密钥已添加 - 它报告 Identity added: .\Users\Jenkins\.ssh\id_rsa。
在这个阶段我无法与 Git 交互,因为路径没有设置,所以我修改了我的 Dockerfile 以通过在我安装 Git 的命令中添加以下行来设置路径;
${env:PATH} = 'C:\Git\bin;C:\Git\usr\bin;C:\Git\mingw64\bin;' + $env:PATH;
[Environment]::SetEnvironmentVariable('PATH', ${env:PATH}, [EnvironmentVariableTarget]::Machine);
现在,当我构建映像时,ssh-add 命令失败并显示“无法打开与您的身份验证代理的连接”。
我跑了Get-Service ssh-agent,它报告它正在运行。
所以不知何故,将 Git 包含在路径中导致了关于 ssh-add 命令的差异。
这里发生了什么?
我该如何解决这个问题?
我还重新创建了没有密码短语的密钥,因此在 docker 构建期间无需输入密码短语,并且我指定了 windows 的版本。
这是我更新的 Dockerfile:
# escape=`
FROM mcr.microsoft.com/windows/servercore:1903
# Install Git
COPY .\files\Git-2.18.0-64-bit.exe C:\installers\git-installer.exe
COPY .\files\Git-2.18.0-64-bit.inf C:\installers\git-installer-script.inf
RUN powershell -Command `
Start-Process -filepath C:\installers\git-installer.exe -passthru -wait -argumentlist "/LOADINF=C:\installers\git-installer-script.inf","/VERYSILENT","/NORESTART" ; `
Remove-Item C:\installers\ -Force -Recurse; `
# Set the path to include Git folders - not listed in my original post `
${env:PATH} = 'C:\Git\bin;C:\Git\usr\bin;C:\Git\mingw64\bin;' + $env:PATH; `
[Environment]::SetEnvironmentVariable('PATH', ${env:PATH}, [EnvironmentVariableTarget]::Machine);
# Create a Jenkins user with admin permissions
RUN powershell -Command `
net user /add Jenkins; `
net localgroup Administrators Jenkins /add;
USER Jenkins
# The presence or absence of this mkdir command affects ssh-add for some reason
RUN powershell -Command `
mkdir ~\.ssh;
# This key was created without a passphrase
COPY .\id_rsa C:\Users\Jenkins\.ssh\id_rsa
RUN powershell -Command `
# Make sure you're running as an Administrator `
Set-Service ssh-agent -StartupType Automatic; `
Start-Service ssh-agent; `
Get-Service ssh-agent; `
ssh-add .\Users\Jenkins\.ssh\id_rsa;
编辑 3
感谢我找到here 的信息,我似乎无法成功运行ssh-add 是由于未设置SSH_AUTH_SOCK 环境变量。
运行ssh-agent 提供设置此环境变量所需的数据,在Linux 中您可以运行eval $(ssh-agent),但Windows 中的powershell 无法识别eval 命令。在这个阶段,我尝试从我的最后一个 dockerfile 中注释掉 ssh-add 命令,然后在容器中我手动运行 ssh-agent 命令并使用成功的 $Env:SSH_AUTH_SOCK = "<value returned from ssh-agent>" 设置环境变量,如果我运行 Get-ChildItem Env: 我看到了列出了新的环境变量。
然后我尝试运行git clone ssh://git@mybitbucketurl/myrepo.git 报告“无法确定主机 mybitbucketurl (xx.yy.zz.aa:port) 的真实性。您确定要继续吗(是/否) ?”
我输入“是”,它“将 mybitbucketurl:port,[xx.yy.zz.aa]:port (RSA) 永久添加到已知主机列表中”,然后克隆了我的存储库。
我认为我现在已经破解了这个问题,并认为我只需要弄清楚如何在 powershell 中执行 eval 等效命令。当我在寻找有关如何执行此操作的线索时,我发现了这个link,其中的答案列出了这个命令:
ssh-agent ssh-add C:\Users\<username>\.ssh\id_rsa。
我尝试在我的容器中手动运行它,它报告说添加了身份,但是当我尝试运行git clone 时,它首先将 URL 添加到已知主机列表中,然后失败并显示“致命:无法从远程读取存储库”。
运行 Get-ChildItem Env: 表明未设置 SSH_AUTH_SOCK 环境变量,所以我猜想像这样运行它是一种孤立的会话,尽管我真的不知道这个命令发生了什么。
因此,从这里看来,我需要弄清楚如何运行 ssh-agent 命令并在 powershell 中使用其结果来永久设置环境变量。
完成这项工作后,我需要弄清楚如何将我的 Git 主机 URL 添加到已知主机列表中。
编辑 4
我的问题的症结似乎是我的 docker 映像的构建时间和运行时间之间的差异,特别是我希望通过 ssh-agent 和 ssh-add 实现的目标。
如果我将图像设置为包含 ssh 密钥然后运行它,我可以手动执行以下操作(请注意,我已从 powershell 切换到 bash):
$ echo $SSH_AUTH_SOCK
$ eval $(ssh-agent)
Agent pid 2036
$ sh-add Users/Jenkins/.ssh/id_rsa
Identity added: Users/Jenkins/.ssh/id_rsa
$ echo $SSH_AUTH_SOCK
/tmp/ssh-qCM264wFqpqq/agent.1748
所以从这里我可以看到,在容器中运行时它会做我想做的事。
但是,如果我尝试在构建时从 Dockerfile 运行这些命令,事情就不会像我希望的那样工作。
经过一番思考,我怀疑eval $(ssh-agent) 命令可能会运行,但SSH_AUTH_SOCK 环境变量未保留在映像层中,并且当容器运行时,ssh-agent 将不会运行,可能需要启动它。
这样做的正确方法是什么:
- 我是否尝试通过启动脚本在容器启动期间运行这些命令?
- 有没有办法在构建时仍然执行此操作(即从 Dockerfile) - 为了实现这一点,我需要手动设置
SSH_AUTH_SOCK环境变量,但这似乎每次运行ssh-agent时都不同 -这值得追求吗?
【问题讨论】: