使用 crontab 自动建立 ssh 连接

使用 crontab 自动建立 ssh 连接

我一直在努力使用 crontab 自动执行使用 ssh 的 git push 过程,事实证明使用 ssh 代理设置密钥非常棘手。从测试代理的基本脚本开始:

# set paths (all examples)
source /etc/profile
export PATH=$PATH:/Users/myusername/.ssh

eval "$(ssh-agent)" > ssh_agent.txt
/usr/bin/ssh-add -l >> ssh_agent.txt

..输出以下内容:

Agent pid 16062
The agent has no identities.

因此代理处于活动状态。现在添加密钥并检查它是否已在代理中注册。在 iTerm2 中手动执行此操作即可:

/usr/bin/ssh-add /Users/myusername/.ssh/id_rsa
2048 [key fingerprint] /Users/myusername/.ssh/id_rsa (RSA)

我尝试使用以下脚本在 crontab 作业中复制此操作:

/usr/bin/ssh-add /Users/myusername/.ssh/id_rsa
/usr/bin/ssh-add -l >> ssh_agent.txt

..报告The agent has no identities给文件,并通过以下内容"You have mail in /var/mail/myusername"

[email metadata]
Enter passphrase for /Users/myusername/.ssh/id_rsa: 

因此密钥正在尝试加载,但在密码提示符处卡住了。在这里我想使用来expect给它设置密码,如下所述unix.stackexchange 答案(看起来它应该可以在 OSX 上运行):

#!/usr/bin/expect -f
/usr/bin/ssh-add /Users/myusername/.ssh/id_rsa
expect "Enter passphrase for /Users/myusername/.ssh/id_rsa:"
send "mypassphrase\n";
interact

邮件错误响应是:

Enter passphrase for /Users/myusername/.ssh/id_rsa: 
couldn't read file "Enter passphrase for /Users/myusername/.ssh/id_rsa:": no such file or directory
/Users/myusername/test/crontest.sh: line 17: send: command not found
/Users/myusername/test/crontest.sh: line 18: interact: command not found

所以我尝试了基于此的替代配置所以回答

#!/usr/bin/expect -f
expect -c "
/usr/bin/ssh-add /Users/myusername/.ssh/id_rsa
expect \"Enter passphrase for /Users/myusername/.ssh/id_rsa: \"
send \"mypassphrase\n\";
interact
"

..并收到以下邮件错误报告:

invalid command name "/usr/bin/ssh-add"
    while executing
"/usr/bin/ssh-add /Users/myusername/.ssh/id_rsa"
Could not open a connection to your authentication agent.

我不明白这里的问题 - ssh 代理可以工作,密钥似乎可以访问,那么这个“连接”问题是什么?我尝试了其他配置,但expect没有成功。非常感谢您的帮助。

答案1

我不建议在 cron 作业中运行ssh-add它,expect因为在 cron 用于执行其作业的有限环境中运行它过于复杂,并且我不想在 crontab 中存储密码。

我不会使用常规 SSH 密钥,而是创建一个新密钥,该密钥仅用于运行您希望由 cron 运行的命令。我会配置没有密码短语的密钥,并更改其所有权/权限 (0600),以便只有 cron 作业运行时的有效用户 ID(即正在处理其 crontab 的用户的 ID)才能访问它。

在您的特定情况下,特定命令是git push将新密钥上传到您的 git 服务器。大多数 git 服务器应该能够接受多个公共 SSH 密钥。

一般来说,对于自动化流程,最好创建没有密码短语的特定密钥。然后通过在文件中的行前面添加选项对,在远程 SSH 服务器上配置一组受限制的允许命令 authorized_keys,例如,

command="automated-task.sh",client=my.local.host,no-pty,no-agent-forwarding,no-port-forwarding ssh-rsa AAA…public…part…of…specific…keypair automated_user@server

免责声明:我对 GNU/Linux 的经验比 OS X 丰富,但据我所知,上述信息应该适用于所有 *nix 系统。

答案2

这个答案有另一个可行的解决方案

如果您正在ssh-add将密钥添加到 ssh 代理,则可以将SSH_AUTH_SOCK环境变量添加到 crontab,然后 ssh 命令将能够使用已加载和解锁的密钥。

  1. 在常规终端会话中,加载您的 ssh-agent(这留给读者练习;我认为在 macOS 上它默认运行,或者您可以运行ssh-add -t 24h ~/path/to/your.key)。
  2. 使用以下命令获取 SSH_AUTH_SOCK 位置env | grep SSH_AUTH_SOCK
  3. 将其添加到你的 crontab 的顶部,例如SSH_AUTH_SOCK=/Users/USER/.ssh/ssh_auth_sock

如果您尚未加载或验证密钥,crontab ssh 命令仍将失败,但对我来说没问题,因为 99% 的时间我都已加载密钥。

答案3

替代答案

我只是想仔细看看你的expect脚本,我发现它们缺少spawn命令:

#!/usr/bin/expect -f
spawn /usr/bin/ssh-add /Users/myusername/.ssh/id_rsa
expect "Enter passphrase for /Users/myusername/.ssh/id_rsa:"
send "mypassphrase\n";
interact

来自expect手册:

生成 [参数] 程序 [参数]

创建运行程序 args 的新进程。其 stdin、stdout 和 stderr 连接到 Expect,以便其他 Expect 命令可以读取和写入它们。如果 close 或进程本身关闭任何文件标识符,则连接将被中断。

相关内容