众所周知,cron 和 ssh-agent 不通信,因此 ssh 命令不能在 cron 下轻松运行。有一些涉及钥匙串等的解决方案可以做到这一点。但是,在我的情况下,我需要在远程服务器上运行一个 cron 作业(我通过代理转发通过 ssh 登录),它将使用 ssh 在第二个远程服务器上执行。所以我的密钥不存在于 ssh 命令发起的第一个远程服务器中。在 cron 下运行 ssh 的所有解决方案都假定源服务器上存在 ssh 密钥。没有 ssh 密钥时如何使用 cron 运行 ssh 命令?我认为需要让 cron 了解 ssh-agent 变量。但我不知道该怎么做。知道怎么做吗?
这是我在远程服务器 1 上的 crontab:
*/1 * * * * ssh root@remote2 "some command" >> /home/output.log
edit1:remote2 只是一个例子。这必须为大约 100 台服务器重复。
edit2:SSH_AUTH_SOCK 解决方案尝试
~/.ssh 文件夹的内容:
$ ls -lt /home/centos/.ssh
lrwxrwxrwx. 1 centos centos 31 24. Mär 15:13 ssh_auth_sock -> /tmp/ssh-59Ay2ronRN/agent.24129
crontab的内容:
*/1 * * * * SSH_AUTH_SOCK=/home/centos/.ssh/ssh_auth_sock;/bin/bash /home/test.sh
/home/test.sh 的内容:
#!/bin/bash
echo "`date +%FT%T` $0: test cronjob from centos .. $SSH_AUTH_SOCK" >> ${runlog}
/usr/bin/ssh remote2 "sudo less /var/log/program.log | grep 'NOT ENDING'" >>${runlog} 2>&1
${runlog} 的内容:
2022-03-24T15:22:01 /home/test.sh: test cronjob from centos ..
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
edit3:SSH_AUTH_SOCK 解决方案更新(已解决)
如下声明 SSH_AUTH_SOCK 有效:
…
SSH_AUTH_SOCK=/…
*/1 * * * * ssh …
…
解决方案
SSH_AUTH_SOCK
是相关变量。由远程服务器 1 上的 cron 生成的变量看到的变量
ssh
不必与您在ssh
远程服务器 1 上看到的变量保持相同的值。它最终应该导致相同的套接字。像这样进行:登录到远程服务器 1(使用代理转发)后,在某个私有位置创建一个具有固定名称的符号链接。该链接应指向当前使用的套接字。由于这与 SSH 密切相关,因此您
~/.ssh
的位置很好;我认为它是私有的(权限700
)。在远程服务器 1 ( ) 上的 crontab 中,将以下行置于
crontab -e
以下行之前ssh
:注意 cron 既不扩展
~/
也不扩展$HOME
,因此您需要/your/homedir/
明确指定。使用远程服务器上主目录的实际路径 1. 您的 crontab 将如下所示:在注销远程服务器1之前(即终止代理的转发之前),删除链接:
再次登录时,重复步骤1;退出前,重复步骤3;这些步骤可以自动化。crontab 中的变量是静态的,无需重复步骤 2。
请注意,可靠地自动化这些步骤通常不是一项简单的任务。通常,您可以多次连接到远程服务器 1 并以任意顺序断开连接。手动处理符号链接非常简单:代码是静态的(变量部分位于变量后面),您只需要考虑是否、何时以及在哪个会话中使用它。
怀疑
如果没有
~/.ssh/ssh_auth_sock
或者链接断开,或者代理的转发没有了,那么ssh
crontab中的命令就会失败。您将指定约 100 个命令。在命令打印到其标准错误后,cron 是否会向您发送电子邮件?您重定向了标准输出,但没有重定向标准错误。这些命令将异步运行。来自
some command
s 的结果可能会在output.log
. 除非您使用单独的日志;但随后(而且不仅如此)……如果
some command
超过 1 分钟怎么办?考虑一个检查代理是否响应的脚本(检查退出状态
ssh-add -l >/dev/null 2>&1
应该足够了)。考虑 GNUparallel
(比较这个答案)。问问自己 cron 是否真的适合这项任务。漏洞?
在您将我们的符号链接断开之前忽略
rm ~/.ssh/ssh_auth_sock
或断开与远程服务器 1的连接(套接字已移除,链接仍然存在)。rm
想象一个攻击者(服务器 1 的另一个合法用户)设法预测或猜测你的悬空链接仍然指向的路径。想象一下他们在这个确切的路径上创建他们的套接字并授予您的用户权限。在我在 Kubuntu 中使用 OpenSSH 的测试中,路径类似于
/tmp/ssh-GjYJe19sjiAb/agent.372911
. 攻击者可以ls /tmp
观察那里ssh-GjYJe19sjiAb/
,我是所有者。他们无法知道下一个组件 (agent.372911
)。当目录消失时,他们仍然可以注意到,他们可以将其重新创建为他们的。接下来,他们种植通向代理的套接字,并创建数百万个具有不同可能名称的符号链接。他们确保我的用户可以访问目录和套接字。最终
ssh
from crontab 遵循我们的符号链接和攻击者的符号链接,它使用攻击者的代理。它有多糟糕?如果
ssh
crontab 中的某些(可能ssh
与所讨论的任务无关)使用存储在远程服务器 1 上的密钥文件,成功登录到某个地方及其配置状态AddKeysToAgent=yes
,那么该密钥将被添加到攻击者的代理中,他们将能够用它进行身份验证。攻击者可以将他们的密钥添加到代理。您
ssh
来自 crontab 的 (s) 将很乐意尝试使用它们。似乎无害。如果root@remote2
通过他们的密钥有效地识别用户(例如 AFAIK[email protected]
这样做)并且攻击者也是其密钥被识别的合法用户,则不会remote2
。通过让您ssh
使用他们的密钥,攻击者some command
在他们的环境中执行remote2
,他们可以轻松地将任何内容打印到您的output.log
. 也许在这种特殊情况下,它只是一个日志;但是一般来说,您可能希望根据您得到的结果做出一些重要的决定。希望这两种情况都不适用于您的情况。如果是这样,悬空的符号链接不是问题。而不是
rm
在您从远程服务器 1 注销之前,您可以rm
在您登录之后,就在您之前ln
。