bash 为什么 ssh 从 crontab 失败,但从命令行执行时成功?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/869589/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:11:04  来源:igfitidea点击:

Why ssh fails from crontab but succedes when executed from a command line?

bashunixsshcrontab

提问by tkokoszka

I have a bash script that does ssh to a remote machine and executes a command there, like:

我有一个 bash 脚本,它对远程机器执行 ssh 并在那里执行命令,例如:

ssh -nxv user@remotehost echo "hello world"

When I execute the command from a command line it works fine, but it fails when is being executed as a part of crontab (errorcode=255 - cannot establish SSH connection). Details:

当我从命令行执行命令时,它工作正常,但作为 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.
...

When executing locally I'm acting as a root, crontab works as root as well. Executing 'id' from crontab and command line gives exactly the same result:

在本地执行时,我以 root 身份运行,crontab 也以 root 身份运行。从 crontab 和命令行执行 'id' 给出完全相同的结果:

$ id
> uid=0(root) gid=0(root) groups=0(root),...

I do ssh from some local machine to the machine running crond. I have ssh key and credentials to ssh to crond machine and any other machine that the scripts connects to.

我从一些本地机器 ssh 到运行 crond 的机器。我有 ssh 密钥和凭据,可以通过 ssh 连接到 crond 机器和脚本连接到的任何其他机器。

PS. Please do not ask/complain/comment that executing anything as root is bad/wrong/etc - it is not the purpose of this question.

附注。请不要问/抱怨/评论以 root 身份执行任何事情是坏的/错误的/等等——这不是这个问题的目的。

采纳答案by dave4420

I am guessing that normally when you ssh from your local machine to the machine running crond, your private key is loaded in ssh-agent and forwarded over the connection. So when you execute the command from the command line, it finds your private key in ssh-agent and uses it to log in to the remote machine.

我猜通常当您从本地机器 ssh 到运行 crond 的机器时,您的私钥会加载到 ssh-agent 中并通过连接转发。因此,当您从命令行执行命令时,它会在 ssh-agent 中找到您的私钥并使用它来登录远程机器。

When crond executes the command, it does not have access to ssh-agent, so cannot use your private key.

当 crond 执行命令时,它无权访问 ssh-agent,因此无法使用您的私钥。

You will have to create a new private key for root on the machine running crond, and copy the public part of it to the appropriate authorized_keysfile on the remote machine that you want crond to log in to.

您必须在运行 crond 的机器上为 root 创建一个新的私钥,并将其公共部分复制到authorized_keys您希望 crond 登录的远程机器上的相应文件中。

回答by krlmlr

keychain

keychain

solves this in a painless way. It's in the repos for Debian/Ubuntu:

以一种无痛的方式解决这个问题。它位于 Debian/Ubuntu 的存储库中:

sudo apt-get install keychain

and perhaps for many other distros (it looks like it originated from Gentoo).

也许对于许多其他发行版(看起来它起源于 Gentoo)。

This program will start an ssh-agentif none is running, and provide shell scripts that can be sourced and connect the current shell to this particular ssh-agent.

该程序将启动一个ssh-agentif none is running,并提供可以将source当前 shell 连接到此特定ssh-agent.

For bash, with a private key named id_rsa, add the following to your .profile:

对于bash,使用名为 的私钥id_rsa,将以下内容添加到您的.profile

keychain --nogui id_rsa

This will start an ssh-agentand add the id_rsakey on the first login after reboot. If the key is passphrase-protected, it will also ask for the passphrase. No need to use unprotected keys anymore!For subsequent logins, it will recognize the agent and not ask for a passphrase again.

这将启动ssh-agentid_rsa在重新启动后第一次登录时添加密钥。如果密钥受密码保护,它还会询问密码。不再需要使用不受保护的密钥!对于后续登录,它将识别代理并且不再要求输入密码。

Also, add the following as a last line of your .bashrc:

另外,将以下内容添加为您的最后一行.bashrc

. ~/.keychain/$HOSTNAME-sh

This will let the shell know where to reach the SSH agent managed by keychain. Make sure that .bashrcis sourced from .profile.

这将让 shell 知道从哪里到达由keychain. 确保它.bashrc来自.profile.

However, it seems that cronjobs still don't see this. As a remedy, include the line above in the crontab, just before your actual command:

然而,cron工作似乎仍然没有看到这一点。作为补救措施,将上面的行包含在 中crontab,就在您的实际命令之前:

* * * * * . ~/.keychain/$HOSTNAME-sh; your-actual-command

回答by Luchostein

Don't expose your SSH keys without passphrase. Use ssh-croninstead, which allows you to schedule tasks using SSH agents.

不要在没有密码的情况下公开您的 SSH 密钥。请改用ssh-cron,它允许您使用 SSH 代理安排任务。

回答by netskink

So I had a similar problem. I came here and saw various answers but with some experimentation here is how I got it work with sshkeys with passphrase, ssh-agent and cron.

所以我遇到了类似的问题。我来到这里并看到了各种答案,但在这里进行了一些实验,这是我如何使用带有密码、ssh-agent 和 cron 的 sshkeys 使其工作的方法。

First off, my ssh setup uses the following script in my bash init script.

首先,我的 ssh 设置在我的 bash init 脚本中使用以下脚本。

# 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

When I login, I enter my passphrase once and then from then on it will use ssh-agent to authenticate me automatically.

当我登录时,我输入我的密码一次,然后它会使用 ssh-agent 自动验证我的身份。

The ssh-agent details are kept in .ssh/environment. Here is what that script will look like:

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;

Regarding cron, you can setup a job as a regular user in various ways. If you run crontab -e as root user it will setup a root user cron. If you run as crontab -u davis -e it will add a cron job as userid davis. Likewise, if you run as user davis and do crontab -e it will create a cron job which runs as userid davis. This can be verified with the following entry:

关于 cron,您可以通过各种方式将作业设置为普通用户。如果您以 root 用户身份运行 crontab -e,它将设置一个 root 用户 cron。如果您以 crontab -u davis -e 的身份运行,它将添加一个 cron 作业作为 userid davis。同样,如果您以用户 davis 身份运行并执行 crontab -e,它将创建一个以用户 ID davis 身份运行的 cron 作业。这可以通过以下条目进行验证:

30 *  *   *   *     /usr/bin/whoami

This will mail the result of whoami every 30 minutes to user davis. (I did a crontabe -e as user davis.)

这将每 30 分钟将 whoami 的结果邮寄给用户 davis。(我作为用户 davis 做了一个 crontabe -e。)

If you try to see what keys are used as user davis, do this:

如果您尝试查看哪些键用作用户 davis,请执行以下操作:

36 *  *   *   *     /usr/bin/ssh-add -l

It will fail, the log sent by mail will say

会失败,邮件发送的日志会说

To: [email protected]
Subject: Cron <davis@hostyyy> /usr/bin/ssh-add -l

Could not open a connection to your authentication agent.

The solution is to source the env script for ssh-agent above. Here is the resulting cron entry:

解决方案是为上面的 ssh-agent 提供 env 脚本。这是生成的 cron 条目:

55 10  *   *   *     . /home/davis/.ssh/environment; /home/davis/bin/domythingwhichusesgit.sh

This will run the script at 10:55. Notice the leading . in the script. It says to run this script in my environment similar to what is in the .bash init script.

这将在 10:55 运行脚本。注意领先的 . 在脚本中。它说在我的环境中运行这个脚本,类似于 .bash init 脚本中的内容。

回答by Djomla

Yesterday I had similar problem...

昨天我也遇到了类似的问题...

I have cron job on one server, which start some action on other server, using ssh... Problem was user permissions, and keys...

我在一台服务器上有 cron 作业,它使用 ssh 在另一台服务器上启动一些操作......问题是用户权限和密钥......

in crontab I had

在 crontab 我有

* * * * * php /path/to/script/doSomeJob.php

And it simply didn't work ( didnt have permissions ). I tryed to run cron as specific user, which is connected to other server

它根本不起作用(没有权限)。我尝试以连接到其他服务器的特定用户身份运行 cron

* * * * * user php /path/to/script/doSomeJob.php

But with no effect.

但是没有效果。

Finally, i navicate to script and then execute php file, and it worked..

最后,我导航到脚本然后执行 php 文件,它工作了..

* * * * * cd /path/to/script/; php doSomeJob.php