有一个非常奇怪的问题。我创建了一个小型 bash 脚本,它通过 ssh(使用公钥身份验证)在远程主机上运行命令。
当我从命令行手动运行该脚本时,它运行良好,但当放置在 /etc/cron.hourly 中时,它会失败并出现Permission denied, please try again.
错误。
- 我使用以下脚本明确设置了密钥
ssh -i /root/.ssh/id_rsa user@remote "command"
; - 该脚本以 root 身份运行(我添加了一个
echo `id` > /tmp/whoami.log
以进行仔细检查);并且 - ssh 密钥没有密码保护......
该系统是 Ubuntu 12.04 服务器,我没有太多远程访问权限来进行故障排除,但正如我所说的,手动运行 ssh 或从命令行运行相同的 bash 脚本就可以了。
知道为什么会发生这种情况或如何解决它吗?
更新
事实证明我错了,ssh 密钥曾是密码保护(使用钥匙串加载 ssh-agent),这就是为什么它在脚本中失败,但在从 bash 会话运行时却不会失败的原因。添加. ~/.keychain/$HOSTNAME-sh
到我的脚本解决了这个问题(感谢 @grawity 为我指明了正确的方向并提供了全面的答案)。
答案1
交互式命令和 cron 任务在不同的环境中运行 - 特别是,交互式会话可能正在运行 SSH 代理,或者存储 Kerberos TGT。由于ssh
订单验证方式,您不能确保您的密钥能够被使用,因为您添加了该-i
选项。
如果 SSH 代理正在运行,
ssh
客户端将始终尝试代理密钥前使用任何明确指定的键。如果网络使用 Kerberos 并且存在 Kerberos TGT,则 OpenSSH 将使用它前尝试公钥认证。
我对您的环境一无所知,但这两种可能性都很容易检查:
在命令前添加
unset SSH_AUTH_SOCK
and ,unset KRB5CCNAME
ssh
然后手动运行修改后的脚本。这将阻止脚本看到代理或 Kerberos 票证,并且只会使用明确指定的密钥。
添加
-v
选项到ssh
。这将显示有关身份验证如何发生的更多详细信息。
您还可以添加-oIdentitiesOnly=yes
到ssh
命令;这将强制它使用指定的键。
如果你添加从 cron 访问代理的提示 - 那就更好了
通常不建议这样做,因为代理通常与您的交互式登录会话紧密相关。特别是,它仅在您登录时启动,并在您注销时终止 - 并且它需要您的密码才能真正解锁 SSH 密钥(假设它们受密码保护)。
你提到了“Keychain”——这是 OS X 程序,还是 Linux 脚本?(我不太了解 Mac OS X 的架构,但据我所知,它使它很多从 cronjob 访问用户的 ssh-agent 更加困难……)
答案2
解决此问题的另一个方法是将 cron 设置为 ssh 到本地框,从而运行 ssh 命令,而不是通过其本地绝对路径运行文件或命令。这会缓存 KRB5CCNAME 并可在 /path/command 不起作用的情况下工作。
# Fails:
0 * * * * /home/user/sshscript.sh
# Works:
0 * * * * /usr/bin/ssh user@localhost /home/user/sshscript.sh
#!/bin/bash
# Works:
unset SSH_AUTH_SOCK
unset KRB5CCNAME
/usr/bin/ssh user@localhost /home/user/sshscript.sh
答案3
您可以使用ssh-cron设置计划的 SSH 连接以保护服务器,而无需暴露您的 SSH 密钥,而是使用 SSH 代理。
答案4
您可以在 crontab 中运行脚本或命令,例如:
0 * * * * bash -c -l “/home/user/sshscript.sh”
或者
0 * * * * bash -c -l “ssh root@yourhost‘echo $HOSTNAME’”