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

时间:2021-09-16 01:07:47

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的一部分执行时它失败(errorcode = 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.

PS。请不要问/抱怨/评论以root身份执行任何错误/错误/等等 - 这不是这个问题的目的。

5 个解决方案

#1


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_keys file on the remote machine that you want crond to log in to.

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

#2


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-agent if none is running, and provide shell scripts that can be sourced and connect the current shell to this particular ssh-agent.

如果没有运行,该程序将启动ssh-agent,并提供可以获取的shell脚本并将当前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-agent and add the id_rsa key 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-agent并在重新启动后首次登录时添加id_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 .bashrc is sourced from .profile.

这将让shell知道从keychain管理的SSH代理的到达位置。确保.bashrc来自.profile。

However, it seems that cron jobs 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

#3


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

不要使用密码短语暴露您的SSH密钥。请改用ssh-cron,它允许您使用SSH代理安排任务。

#4


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,它将创建一个以userid 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。 (我做了一个crontabe -e作为用户davis。)

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: davis@xxxx.net
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脚本中的脚本。

#5


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

#1


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_keys file on the remote machine that you want crond to log in to.

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

#2


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-agent if none is running, and provide shell scripts that can be sourced and connect the current shell to this particular ssh-agent.

如果没有运行,该程序将启动ssh-agent,并提供可以获取的shell脚本并将当前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-agent and add the id_rsa key 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-agent并在重新启动后首次登录时添加id_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 .bashrc is sourced from .profile.

这将让shell知道从keychain管理的SSH代理的到达位置。确保.bashrc来自.profile。

However, it seems that cron jobs 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

#3


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

不要使用密码短语暴露您的SSH密钥。请改用ssh-cron,它允许您使用SSH代理安排任务。

#4


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,它将创建一个以userid 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。 (我做了一个crontabe -e作为用户davis。)

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: davis@xxxx.net
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脚本中的脚本。

#5


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