ssh-agent 和 crontab - 有没有让这些满足的好方法?
Posted
技术标签:
【中文标题】ssh-agent 和 crontab - 有没有让这些满足的好方法?【英文标题】:ssh-agent and crontab -- is there a good way to get these to meet? 【发布时间】:2011-01-13 09:35:46 【问题描述】:我编写了一个简单的脚本,它每晚将 svn 活动日志邮寄给我们的开发人员。到现在为止,我和svn仓库在同一台机器上运行它,所以我不必担心身份验证,我可以使用svn的file:///地址样式。
现在我在家用计算机上运行脚本,访问远程存储库,所以我不得不更改为 svn+ssh:// 路径。 ssh-key 设置好后,在正常情况下,我无需输入密码即可访问 svn 存储库。
但是,crontab 无法访问我的 ssh-keys / ssh-agent。我在网上的几个地方读到过这个问题,这里也提到了这个问题,但没有解决:
Why ssh fails from crontab but succedes when executed from a command line?
我的解决方案是将其添加到脚本的顶部:
### TOTAL HACK TO MAKE SSH-KEYS WORK ###
eval `ssh-agent -s`
这似乎在 MacOSX 10.6 下工作。
我的问题是,这有多可怕,有没有更好的方法?
【问题讨论】:
【参考方案1】:另外...
如果您的密钥有密码,钥匙串会询问您一次(在您重新启动机器或终止 ssh-agent 之前有效)。
钥匙串是你需要的!只需安装它并在您的 .bash_profile 中添加以下代码:
keychain ~/.ssh/id_dsa
所以在你的脚本中使用下面的代码来加载 ssh-agent 环境变量:
. ~/.keychain/$HOSTNAME-sh
注意:keychain 也会生成 csh 和 fish shell 的代码。
从https://serverfault.com/questions/92683/execute-rsync-command-over-ssh-with-an-ssh-agent-via-crontab复制的答案
【讨论】:
钥匙串的主页告诉我在对我有用的 cron 脚本中使用keychain --noask --eval id_dsa
- 不太确定什么是最可取的。见funtoo.org/Keychain
我不得不使用 _ eval keychain --noask --eval id_dsa
_【参考方案2】:
当您运行 ssh-agent -s 时,它会启动一个您稍后需要终止的后台进程。因此,最低限度是将您的 hack 更改为:
eval `ssh-agent -s`
svn stuff
kill $SSH_AGENT_PID
但是,我不明白这个 hack 是如何工作的。简单地运行代理而不运行 ssh-add 将不会加载任何密钥。也许 MacOS 的 ssh-agent 的行为与其 manual page 所说的不同。
【讨论】:
我也很惊讶,但我认为答案就在这里:serverfault.com/questions/108798/…我猜这是存储在系统钥匙串中的密码的组合,并且在系统之前添加了 ssh-keys登出。但这只是一个猜测。感谢您提供有关终止 cron ssh-agent 进程的提示! 在昨晚进行测试后,我在后台运行了大约十几个 ssh-agent 进程,因此投票支持您。谢谢!【参考方案3】:我遇到了类似的问题。我的脚本(依赖于 ssh 密钥)在我手动运行时有效,但在使用 crontab 运行时失败。
使用手动定义适当的键
ssh -i /path/to/key
没用。
但最终我发现 crontab 运行 SSH 时 SSH_AUTH_SOCK 是空的。我不完全确定为什么,但我只是
env | grep SSH
复制返回的值并将此定义添加到我的 crontab 的头部。
SSH_AUTH_SOCK="/tmp/value-you-get-from-above-command"
我对这里发生的事情没有深入了解,但它解决了我的问题。现在 crontab 运行顺利。
【讨论】:
/path/to/key 是不是密码为空?如果不需要密码,我认为您不需要使用授权套接字。 请注意上面的/tmp
。这是指一个临时文件,当ssh-agent
退出或计算机关闭时将被删除。
@DaveX, ssh-agent
如果您使用的是agent forwarding,也很有用。
@Mikkel,是的,如果您有可用于验证密钥的代理,无论是通过转发还是通过 cron 外部的某些其他进程,您都可以参考该代理。 Bryan Kennedy 在手动操作和 crontab 操作之间的区别可能是由于无法访问自动 cron 作业的代理。如果您没有可用的可访问代理,则可以使用不需要密码的私钥。可以通过在 authorized_keys 中使用“from”前缀来限制将接受密钥的客户端主机来提高无密码密钥的安全性【参考方案4】:
我的解决方案 - 基于 pra 的 - 略微改进,即使脚本失败也能终止进程:
eval `ssh-agent`
function cleanup
/bin/kill $SSH_AGENT_PID
trap cleanup EXIT
ssh-add
svn-stuff
请注意,我必须在我的机器上调用 ssh-add (scientific linux 6)。
【讨论】:
错误处理!疯狂的想法。 ;-) 这看起来不错,谢谢!【参考方案5】:恢复运行 ssh-agent 的 pid 和套接字的一种方法是。
SSH_AGENT_PID=`pgrep -U $USER ssh-agent`
for PID in $SSH_AGENT_PID; do
let "FPID = $PID - 1"
FILE=`find /tmp -path "*ssh*" -type s -iname "agent.$FPID"`
export SSH_AGENT_PID="$PID"
export SSH_AUTH_SOCK="$FILE"
done
这当然假设您在系统中安装了 pgrep,并且只有一个 ssh-agent 正在运行,或者如果有多个,它将采用 pgrep 最后找到的那个。
【讨论】:
【参考方案6】:要设置没有自动密码/密码短语破解的自动化流程,
我使用没有密码的单独 IdentityFile,并限制目标机器的 authorized_keys 条目以 from="automated.machine.com" ...
等为前缀。
我为发送机器创建了一个公私密钥集,没有密码:
ssh-keygen -f .ssh/id_localAuto
(提示输入密码时按回车键)
我在.ssh/config
中设置了一个remoteAuto Host入口:
Host remoteAuto
HostName remote.machine.edu
IdentityFile ~/.ssh/id_localAuto
和 remote.machine.edu:.ssh/authorized_keys 与:
...
from="192.168.1.777" ssh-rsa ABCDEFGabcdefg....
...
那么ssh不需要ssh-agent或者keychain提供的外部认证授权,所以可以使用如下命令:
scp -p remoteAuto:watchdog ./watchdog_remote
rsync -Ca remoteAuto/stuff/* remote_mirror
svn svn+ssh://remoteAuto/path
svn update
...
【讨论】:
【参考方案7】:假设您已经配置了 SSH 设置并且该脚本在终端上运行良好,那么使用 keychain 绝对是确保脚本在 crontab 中也正常运行的最简单方法。
由于大多数 Unix/Linux 衍生版本中不包含钥匙串,因此这里是一步一步的过程。
1. 根据您的操作系统版本从http://pkgs.repoforge.org/keychain/ 下载适当的rpm 包。 CentOS 6 示例:
wget http://pkgs.repoforge.org/keychain/keychain-2.7.0-1.el6.rf.noarch.rpm
2.安装包:
sudo rpm -Uvh keychain-2.7.0-1.el6.rf.noarch.rpm
3. 为您的 SSH 密钥生成钥匙串文件,它们将位于 ~/.keychain 目录中。 id_rsa 示例:
keychain ~/.ssh/id_rsa
4. 将以下行添加到脚本中第一个使用 SSH 身份验证的命令之前的任何位置:
source ~/.keychain/$HOSTNAME-sh
我个人尝试避免为此使用其他程序,但我尝试的其他所有方法都不起作用。这工作得很好。
【讨论】:
我同意,我也讨厌使用其他程序,但这是一个非常简单的解决方案并且效果很好。【参考方案8】:受到此处其他一些答案(尤其是 vpk 的)的启发,我想出了以下 crontab 条目,它不需要外部脚本:
PATH=/usr/bin:/bin:/usr/sbin:/sbin
* * * * * SSH_AUTH_SOCK=$(lsof -a -p $(pgrep ssh-agent) -U -F n | sed -n 's/^n//p') ssh hostname remote-command-here
【讨论】:
我必须在sed
之前添加| uniq
,因为我的系统出于某种原因正在重新调整复制行
我必须添加| sort | uniq
,因为两条重复的行不相邻。【参考方案9】:
如果您无法使用钥匙串并且无法从脚本启动 ssh 代理(例如,因为您的密钥受密码保护),这里有一个解决方案。
运行一次:
nohup ssh-agent > .ssh-agent-file &
. ssh-agent-file
ssh-add # you'd enter your passphrase here
在您从 cron 运行的脚本中:
# start of script
. $HOME/.ssh-agent-file
# now your key is available
当然,这允许任何可以读取 '~/.ssh-agent-file' 和相应套接字的人使用您的 ssh 凭据,因此请在任何多用户环境中谨慎使用。
【讨论】:
另一种选择是设置一个空的密码密钥,并限制其在authorized_keys中的适用性。【参考方案10】:您的解决方案有效,但每次都会产生一个新的代理进程,正如其他答案所表明的那样。
我遇到了类似的问题,我发现这个 blogpost 以及 github 上的博客中提到的 Wayne Walker 的 shell 脚本很有用。
祝你好运!
【讨论】:
【参考方案11】:没有足够的声誉来评论@markshep 的答案,只是想添加一个更简单的解决方案。 lsof
没有为我列出没有sudo
的套接字,但find
就足够了:
* * * * * SSH_AUTH_SOCK="$(find /tmp/ -type s -path '/tmp/ssh-*/agent.*' -user $(whoami) 2>/dev/null)" ssh-command
find
命令在/tmp
目录中搜索其完整路径名与 ssh 代理套接字文件的路径名匹配并且归当前用户所有的套接字。它将stderr
重定向到/dev/null
以忽略许多权限被拒绝错误,这些错误通常是在它无权访问的目录上运行find
产生的。
该解决方案假定只会为该用户找到一个套接字。
目标和路径匹配可能需要针对其他发行版/ssh 版本/配置进行修改,但应该很简单。
【讨论】:
以上是关于ssh-agent 和 crontab - 有没有让这些满足的好方法?的主要内容,如果未能解决你的问题,请参考以下文章
在 macOS 上使用 ssh-agent 和 docker