web-dev-qa-db-ja.com

sshがcrontabで失敗するのに、コマンドラインから実行すると成功するのはなぜですか?

リモートマシンにsshを実行し、そこで次のようなコマンドを実行するbashスクリプトがあります。

ssh -nxv user@remotehost echo "hello world"

コマンドラインからコマンドを実行すると正常に動作しますが、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.
...

ローカルで実行する場合、私はrootとして機能し、crontabはrootとしても機能します。 crontabとコマンドラインから「id」を実行すると、まったく同じ結果が得られます。

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

ローカルマシンからcrondを実行しているマシンにsshを実行します。 crondマシンおよびスクリプトが接続するその他のマシンにsshするためのsshキーと資格情報があります。

PS。ルートとして何かを実行するのは悪い/間違っているなどと尋ねたり、不平を言ったり、コメントしたりしないでください。これはこの質問の目的ではありません。

24
tkokoszka

通常、ローカルマシンからcrondを実行しているマシンにsshを実行すると、秘密鍵がssh-agentに読み込まれ、接続を介して転送されると思います。したがって、コマンドラインからコマンドを実行すると、ssh-agentで秘密鍵が検出され、それを使用してリモートマシンにログインします。

Crondがコマンドを実行すると、ssh-agentにアクセスできないため、秘密鍵を使用できません。

Crondを実行しているマシンでrootの新しい秘密鍵を作成し、その公開部分をcrondにログインさせたいリモートマシンの適切なauthorized_keysファイルにコピーする必要があります。

11
dave4420

keychain

痛みのない方法でこれを解決します。これはDebian/Ubuntuのリポジトリにあります:

Sudo apt-get install keychain

そしておそらく他の多くのディストリビューション(Gentooから発信されたように見えます)。

このプログラムは、何も実行されていない場合はssh-agentを開始し、sourcedのシェルスクリプトを提供して、現在のシェルをこの特定のssh-agentに接続します。

bashの場合、id_rsaという名前の秘密鍵を使用して、.profileに以下を追加します。

keychain --nogui id_rsa

これにより、ssh-agentが開始され、再起動後の最初のログイン時にid_rsaキーが追加されます。キーがパスフレーズで保護されている場合は、パスフレーズも要求されます。 保護されていないキーを使用する必要はもうありません!以降のログインでは、エージェントがエージェントを認識し、パスフレーズを再度要求することはありません。

また、.bashrcの最後の行として次を追加します。

. ~/.keychain/$HOSTNAME-sh

これにより、シェルはkeychainによって管理されているSSHエージェントに到達する場所を知ることができます。 .bashrc.profileから供給されていることを確認してください。

ただし、cronジョブはまだこれを認識していないようです。解決策として、実際のコマンドの直前のcrontabに上記の行を含めます。

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

パスフレーズなしでSSHキーを公開しないでください。代わりに ssh-cron を使用してください。これにより、SSHエージェントを使用してタスクをスケジュールできます。

4
Luchostein

だから私も同様の問題を抱えていました。私はここに来てさまざまな答えを見ましたが、ここでいくつかの実験を行って、パスフレーズ、ssh-agent、およびcronを使用してsshkeyで動作させる方法を説明します。

まず、私のsshセットアップでは、bashinitスクリプトで次のスクリプトを使用します。

# 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

ログインするときにパスフレーズを1回入力すると、それ以降、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として実行すると、ユーザーIDdavisとしてcronジョブが追加されます。同様に、ユーザーdavisとして実行し、crontab -eを実行すると、ユーザーIDdavisとして実行されるcronジョブが作成されます。これは、次のエントリで確認できます。

30 *  *   *   *     /usr/bin/whoami

これにより、whoamiの結果が30分ごとにユーザーdavisにメールで送信されます。 (私はユーザーdavisとしてcrontabe -eを実行しました。)

ユーザーdavisとして使用されているキーを確認しようとする場合は、次のようにします。

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

それは失敗します、メールで送られたログは言うでしょう

To: [email protected]
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 initスクリプトと同様に、このスクリプトを私の環境で実行するように指示されています。

1
netskink