如何通过环境变量传递 ssh 密钥密码

Posted

技术标签:

【中文标题】如何通过环境变量传递 ssh 密钥密码【英文标题】:How to pass an ssh key passphrase via environment variable 【发布时间】:2016-11-16 05:22:30 【问题描述】:

我在我的应用程序中使用ssh 命令运行shell 脚本。使用的私钥是通过密码加密的,问题是 - 当被问到时我无法交互地传递它。ssh-agent 中没有添加密钥。我无法执行ssh-add my_key,因为假设密码是交互式传递的。它对终端通信有好处,但在应用程序内部使用不太好。

man page 说:

DISPLAY 和 SSH_ASKPASS

如果 ssh-add 需要密码,如果它是从终端运行的,它将从当前终端读取密码。 如果 ssh-add 没有与之关联的终端,但设置了 DISPLAY 和 SSH_ASKPASS,它将执行 SSH_ASKPASS 指定的程序并打开 X11 窗口以读取密码。这在以下情况下特别有用 从 .xsession 或相关脚本调用 ssh-add。 (请注意,在某些机器上可能需要重定向 来自 /dev/null 的输入来完成这项工作。)

当我执行SSH_ASKPASS=file_with_passphrase ssh-add my_key 时,我仍然要求输入密码,看起来 env var 在这种情况下被忽略了。我试图执行ssh -o BatchMode=yes 并且服务器只是拒绝了编码的密钥,因为没有人能够对其进行解码。

ssh-agent 中使用它之前,我绝对可以手动解码 ssh 密钥,但看起来我即将从 SSH_ASKPASS 变量中获得我需要的东西,但我不知道如何让它工作。很高兴获得社区帮助。

【问题讨论】:

你说When I execute SSH_ASKPASS=file_with_passphrase ssh-add my_key I still asked to type a passphrase - 但这并不是手册页所说的 - 该文件必须是可执行的并在标准输出上输出密码 - 所以它应该类似于echo "echo 'your_password'" > /tmp/unsafe; chmod +x /tmp/unsafe; SSH_ASKPASS=/tmp/unsafe ssh-add my_key。作为可以在SSH_ASKPASS 中使用的示例,请参阅x11-ssh-askpass 命令 - 您可以查看其手册页并运行它以查看其行为方式。 @IwanAucamp 哦,谢谢,误会了,制作了一个脚本而不是文件。顺便说一句,它没有帮助 【参考方案1】:

因此,实际上有几件事情对你正在尝试做的事情很重要:

    必须设置显示 它不能有与之关联的终端 在某些机器上,可能需要从 /dev/null 重定向输入(我的就是其中之一)。 SSH_ASKPASS 必须包含在stdout 上输出密码的可执行文件。

所以举一个让它工作的例子(对我来说,我猜应该也可以在其他 linux 上工作):

创建虚拟密钥:

ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'

创建 askpass 脚本以回显密码文件:

cat > /tmp/se-so-38354773-askpass <<EOF
#!/usr/bin/env bash
echo "$0:$@ : this is for debugging to see if the echo script runs" 1>&2
echo "se-so-38354773-pp"
EOF
chmod +x /tmp/se-so-38354773-askpass

我将此文件放在 /tmp/ 中 - 但这对安全性不利,除非您在写入文件之前更改文件的权限以确保其他人无法读取它(或设置 umask)。

然后你可以按如下方式进行 ssh-add:

DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null

setsid 将它与您的终端(如果有)分离 - 虽然我的计算机上不需要它 - 但是是的 - 我认为在其他一些情况下可能需要它。

当你完成测试后做清理:

ssh-add -d /tmp/se-so-38354773.key
rm /tmp/se-so-38354773*

我的电脑上的示例输出:

iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ ssh-keygen -t rsa -C se-so-38354773 -f /tmp/se-so-38354773.key -N 'se-so-38354773-pp'
Generating public/private rsa key pair.
Your identification has been saved in /tmp/se-so-38354773.key.
Your public key has been saved in /tmp/se-so-38354773.key.pub.
The key fingerprint is:
SHA256:s+jVUPEyb2DzRM5y+Hm3XDzVRREKn5yU2d0hk61hIQ0 se-so-38354773
The key's randomart image is:
+---[RSA 2048]----+
|          .E+=B=O|
|           B*B*o=|
|          X B*o o|
|         o % o ..|
|        S   * ..+|
|       . = . ...+|
|      . o .    o |
|     . .         |
|      .          |
+----[SHA256]-----+
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ 
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ cat > /tmp/se-so-38354773-askpass <<EOF
> #!/usr/bin/env bash
> echo "$0:$@ : this is for debugging to see if the echo script runs" 1>&2
> echo "se-so-38354773-pp"
> EOF
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ chmod +x /tmp/se-so-38354773-askpass
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ 
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ DISPLAY=":0.0" SSH_ASKPASS="/tmp/se-so-38354773-askpass" setsid ssh-add /tmp/se-so-38354773.key </dev/null
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ 
bash: : this is for debugging to see if the echo script runs
Identity added: /tmp/se-so-38354773.key (/tmp/se-so-38354773.key)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ ssh-add -d /tmp/se-so-38354773.key
Identity removed: /tmp/se-so-38354773.key (se-so-38354773)
iwana@iwana-nb.concurrent.co.za:~/projects/gitlab.com/aucampia/stackexchange/***/38354773
$ rm /tmp/se-so-38354773*

【讨论】:

user@imnc:~/Code/Sandbox$ chmod +x passphrase.sh user@imnc:~/Code/Sandbox$ DISPLAY=":0.0" SSH_ASKPASS=./passphrase.sh setsid ssh-add encrypted_key Enter passphrase for encrypted_key: 不知道为什么,但我仍然被要求输入密码。也没有用 哦,再次抱歉,错过了 dev/null 重定向,它实际上正在工作。非常感谢 实现如此简单的要求似乎太棘手了,而且不安全。想知道人们是如何解决这样的问题的。 @SergeyVoitovich 你能详细说明一下你的用例吗?我只需要使用一次,这实际上不是用于添加密钥,而是用于将密码传递给 ssh,因为端点正在运行一些自定义 ssh 解决方案,但不支持我可用的基于密钥的身份验证。如果您有自动化用例,在大多数情况下,正确的方法是不使用密码,只限制对密钥的访问,并限制对授权密钥文件的访问。请参阅serverfault.com/questions/142959 进行一些讨论。 确定:分布式 Java Web 应用程序,一个实例通过 ssh 使用 git 从另一个实例获取 repo。通常ssh key 不知道ssh agent``. Inside I call native git and pass key with GIT_SSH` 环境变量。 GIT_SSH 设置为 bash 脚本,它调用本机 ssh。为了支持 Windows,除了git bash 支持之外,我不能使用其他东西(遗憾的是,我对此知之甚少)。密钥可能已加密,我的应用程序要求提供密码短语,我正在搜索以满足此需求:)【参考方案2】:

编辑:我正在为这个答案添加更多细节。如果你有一个 PEM 编码的私钥和密码,你可以先使用 openssl 来解密密钥,因为 openssl 将接受标准输入上的密码。

要生成一个适用于此的新密钥,请使用以下命令:

ssh-keygen -t rsa -m pem -b 4096

它不能是“OPENSSH”键。看起来像这样的现有密钥的开头应该可以工作。

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,8032BCA01FB25FCCD89AFDED8DB52079

然后,您可以在将密钥发送到 ssh-add 之前使用 openssl 解密密钥。 Openssl 接受带有 -passin stdin 选项的 stdin 上的密码,默认情况下会输出到 stdout,然后 ssh-add 可以通过添加 - 作为第一个参数来接受 stdin 上的未加密密钥。

echo "$MY_PASSPHRASE" | openssl rsa -in my_encrypted_key -passin stdin | ssh-add -

【讨论】:

回答更具体。

以上是关于如何通过环境变量传递 ssh 密钥密码的主要内容,如果未能解决你的问题,请参考以下文章

如何不通过 ssh 连接命令传递语言环境

SSH 从本地文件运行命令并传递本地环境变量

在远程 ssh 命令中传递变量

我需要通过 gitlab-ci 中的 ssh 将 env 变量传递给 docker

ssh时传递环境变量

SSH 连接过程设置环境变量