为啥 ssh 从 crontab 失败但从命令行执行时成功?
Posted
技术标签:
【中文标题】为啥 ssh 从 crontab 失败但从命令行执行时成功?【英文标题】:Why ssh fails from crontab but succedes when executed from a command line?为什么 ssh 从 crontab 失败但从命令行执行时成功? 【发布时间】:2010-10-26 13:21:52 【问题描述】:我有一个 bash 脚本,它对远程机器执行 ssh 并在那里执行命令,例如:
ssh -nxv user@remotehost echo "hello world"
当我从命令行执行命令时,它工作正常,但在作为 crontab 的一部分执行时失败(错误代码=255 - 无法建立 SSH 连接)。详情:
...
Waiting for server public key.
Received server public key and host key.
Host 'remotehost' is known and matches the XXX host key.
...
Remote: Your host key cannot be verified: unknown or invalid host key.
Server refused our host key.
Trying XXX authentication with key '...'
Server refused our key.
...
在本地执行时,我以 root 身份运行,crontab 也以 root 身份运行。 从 crontab 和命令行执行 'id' 得到完全相同的结果:
$ id
> uid=0(root) gid=0(root) groups=0(root),...
我从一些本地机器 ssh 到运行 crond 的机器。我有 ssh 密钥和凭据,可以 ssh 到 crond 机器和脚本连接到的任何其他机器。
PS。请不要问/抱怨/评论以 root 身份执行任何操作是错误的/错误的/等等 - 这不是这个问题的目的。
【问题讨论】:
尝试使用 -v 而不是 -q --- 它仍然不起作用,但它会为您提供可能帮助您解决问题的诊断。 谢谢戴夫! - 使用 -v 执行时,我在输出中包含了有趣的部分 由于事实/问题的改变,我删除了我的答案。 【参考方案1】:所以我遇到了类似的问题。我来到这里并看到了各种答案,但通过一些实验,我可以通过密码短语、ssh-agent 和 cron 使用 sshkey。
首先,我的 ssh 设置在我的 bash 初始化脚本中使用以下脚本。
# JFD Added this for ssh
SSH_ENV=$HOME/.ssh/environment
# start the ssh-agent
function start_agent
echo "Initializing new SSH agent..."
# spawn ssh-agent
/usr/bin/ssh-agent | sed 's/^echo/#echo/' > "$SSH_ENV"
echo succeeded
chmod 600 "$SSH_ENV"
. "$SSH_ENV" > /dev/null
/usr/bin/ssh-add
if [ -f "$SSH_ENV" ]; then
. "$SSH_ENV" > /dev/null
ps -ef | grep $SSH_AGENT_PID | grep ssh-agent$ > /dev/null ||
start_agent;
else
start_agent;
fi
当我登录时,我输入我的密码一次,然后它会使用 ssh-agent 自动对我进行身份验证。
ssh-agent 详细信息保存在 .ssh/environment 中。以下是该脚本的外观:
SSH_AUTH_SOCK=/tmp/ssh-v3Tbd2Hjw3n9/agent.2089; export SSH_AUTH_SOCK;
SSH_AGENT_PID=2091; export SSH_AGENT_PID;
#echo Agent pid 2091;
关于 cron,您可以通过多种方式将作业设置为普通用户。 如果您以 root 用户身份运行 crontab -e,它将设置一个 root 用户 cron。如果您以 crontab -u davis -e 运行,它将添加一个 cron 作业作为用户 ID davis。同样,如果您以用户 davis 运行并执行 crontab -e,它将创建一个以用户 davis 运行的 cron 作业。这可以通过以下条目进行验证:
30 * * * * /usr/bin/whoami
这将每 30 分钟将 whoami 的结果邮寄给用户 davis。 (我以用户 davis 的身份执行了 crontabe -e。)
如果您尝试查看哪些键被用作用户 davis,请执行以下操作:
36 * * * * /usr/bin/ssh-add -l
会失败,邮件发送的日志会说
To: davis@xxxx.net
Subject: Cron <davis@hostyyy> /usr/bin/ssh-add -l
Could not open a connection to your authentication agent.
解决方案是获取上述 ssh-agent 的 env 脚本。这是生成的 cron 条目:
55 10 * * * . /home/davis/.ssh/environment; /home/davis/bin/domythingwhichusesgit.sh
这将在 10:55 运行脚本。注意领先。在脚本中。它说要在我的环境中运行此脚本,类似于 .bash 初始化脚本中的内容。
【讨论】:
【参考方案2】:不要在没有密码的情况下公开您的 SSH 密钥。请改用ssh-cron,它允许您使用 SSH 代理安排任务。
【讨论】:
这与上面关于keychain 的答案有何不同?还是 netskink 下面的hard-coded answer? 它只是开箱即用,但在底层,它们的作用基本相同。【参考方案3】:昨天我遇到了类似的问题...
我在一台服务器上有 cron 作业,它使用 ssh 在另一台服务器上启动一些操作...问题是用户权限和密钥...
在我的 crontab 中
* * * * * php /path/to/script/doSomeJob.php
而且它根本不起作用(没有权限)。 我尝试以特定用户身份运行 cron,该用户已连接到其他服务器
* * * * * user php /path/to/script/doSomeJob.php
但是没有效果。
最后,我导航到脚本,然后执行 php 文件,它工作了..
* * * * * cd /path/to/script/; php doSomeJob.php
【讨论】:
【参考方案4】:keychain
以一种无痛的方式解决这个问题。它在 Debian/Ubuntu 的存储库中:
sudo apt-get install keychain
也许对于许多其他发行版(看起来它起源于 Gentoo)。
如果没有运行ssh-agent
,该程序将启动一个ssh-agent
,并提供可以是source
d 的shell 脚本并将当前shell 连接到这个特定的ssh-agent
。
对于bash
,使用名为id_rsa
的私钥,将以下内容添加到您的.profile
:
keychain --nogui id_rsa
这将启动ssh-agent
并在重新启动后首次登录时添加id_rsa
密钥。如果密钥受密码保护,它也会要求输入密码。 不再需要使用不受保护的密钥!对于后续登录,它会识别代理并且不再要求输入密码。
另外,在.bashrc
的最后一行添加以下内容:
. ~/.keychain/$HOSTNAME-sh
这将使 shell 知道到哪里可以访问由keychain
管理的 SSH 代理。确保.bashrc
来自.profile
。
但是,cron
的工作似乎仍然没有看到这一点。作为补救措施,在crontab
中包含上面的行,就在您的实际命令之前:
* * * * * . ~/.keychain/$HOSTNAME-sh; your-actual-command
【讨论】:
我不认为涉及钥匙链可以以任何可靠的方式使这更容易。 @Dan-Kegel - 实际上,keychain 所做的正是下面的netskink's answer。除了这里,您不必自己编写代码。【参考方案5】:我猜通常当您从本地机器 ssh 到运行 crond 的机器时,您的私钥会加载到 ssh-agent 中并通过连接转发。所以当你从命令行执行命令时,它会在 ssh-agent 中找到你的私钥,并用它来登录远程机器。
crond 执行命令时,它没有 ssh-agent 的访问权限,所以不能使用你的私钥。
您必须在运行 crond 的计算机上为 root 创建一个新的私钥,并将其公共部分复制到您希望 crond 登录的远程计算机上的相应 authorized_keys
文件中。
【讨论】:
Dave,如何列出在 ssh-agent 中注册的密钥?这将有助于实际检查该案例。 尝试运行 ssh-add -l(即破折号小写-L)。 嗯,很奇怪,这似乎不是真的。在我的 cron 脚本中,我在底部添加了一个简单的:ssh-agent,它似乎返回了一个有效的代理。 BUT 即使这样,我也无法使用奇怪的 crontab 进行 ssh 身份验证!我尝试了您的解决方案,但它也不起作用 顺便说一句,当我在脚本中执行whoami
时,我的用户名不是 root。
@apouche ssh-agent
不会返回现有代理,它会尝试设置一个新代理。以上是关于为啥 ssh 从 crontab 失败但从命令行执行时成功?的主要内容,如果未能解决你的问题,请参考以下文章
从测试视图运行时测试成功,但从测试列表编辑器或命令行运行时失败
Jenkins Maven Build Step失败但从命令行运行
Crontab could not create directory .ssh