Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

i have a cronjob:

0 9 * * * rsync -a mydir remote_machine:

i installed this with 'crontab -e'. i have an ssh-agent running, and when i execute the rsync command itself it works w/o any user interaction or password entry, but the cronjob fails with the following message:

Date: Wed,  9 Dec 2009 11:11:00 -0600 (CST)
From: Cron Daemon <me@my_machine.my_domain>
To: me@my_machine.my_domain
Subject: Cron <me@my_machine> rsync -a /home/me/mydir remote_machine:

Permission denied, please try again.
Permission denied, please try again.
Permission denied (publickey,gssapi-with-mic,password).
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at /SourceCache/rsync/rsync-35.2/rsync/io.c(452)
[sender=2.6.9]

why doesn't this work? i know the cronjobs run w/ me as the user (if i run '* * * * * touch /tmp/a' i own the file) so i assume the rsync is logging in as me using my private key...

share|improve this question
add comment

5 Answers 5

up vote 5 down vote accepted

Your cron session shell has no knowledge of the ssh agent, so can't talk to it.

When the agent is started, you can put the information needed for the agent someplace for the cron session to pick up.

Example:

AGENT="ssh-agent -s"
if [ ! -d $HOME/.ssh/agent ]; then
        mkdir -p $HOME/.ssh/agent
fi
#
# Start an agent if there isn't one running already.
#
pid=`ps -u$LOGNAME | grep ssh-age | awk '{print $1}'`
if [ -z "$pid" ]; then
        $AGENT | grep -v echo > $HOME/.ssh/agent/$HOST & pid=$!
        sleep 1 # Let it fork and stuff
fi

Then add your key to the agent.

ssh-add $HOME/.ssh/id_dsa

Now your cron job should do this before attempting to use ssh:

#
# Get our parent to pick up the required SSH env vars.
#
. $HOME/.ssh/agent/$HOST

...after which, the ssh session should proceed normally.

share|improve this answer
    
so do i put all of the agent stuff in a script followed by the rsync command, or can i put that in some .profile or .bashrc file that cron loads automatically when it starts a shell for a cronjob? –  aaron Dec 9 '09 at 17:53
    
I would put the agent stuff in the script that runs the rsync command. –  David Mackintosh Dec 9 '09 at 18:09
2  
all i needed was to source the SSH_AUTH_SOCK and SSH_AGENT_PID env variables (i put them in .ssh-agent instead of .ssh/agent/) so this was what i ended up with: "0 9 * * * . $HOME/.ssh-agent && rsync -av $HOME/mydir remote_machine:" –  aaron Dec 9 '09 at 18:22
    
All of this unnecessary, use keychain –  Casey Jul 13 '11 at 21:40
add comment

keychain is what you need! Just install it and add the follow code in your .bash_profile (or equivalent):

if [ -x /usr/bin/keychain ]; then
  /usr/bin/keychain --quiet --clear $HOME/.ssh/id_rsa
fi

If your key have a passhphrase, keychain will ask you once (valid until you reboot the machine or kill the ssh-agent).

So use the code below in your script to load the ssh-agent environment variables:

. ~/.keychain/`/bin/hostname`-sh

Note: keychain also generates code to csh and fish shells, so just replace the suffix "-sh" to "-csh" or "-fish".

share|improve this answer
    
$HOSTNAME is not defined in cron environment, but other than that this is the best solution –  Casey Jul 13 '11 at 21:39
    
if I use rsa keys, do I change keychain ~/.ssh/id_dsa to keychain ~/.ssh/id_rsa ? –  Katafalkas Aug 21 '12 at 11:02
    
@Katafalkas exactly! –  semente Aug 22 '12 at 17:41
    
@Casey I've updated my answer. Now is compatible with cron. –  semente Aug 22 '12 at 17:43
add comment

I don't have enough rep to vote up the first answer, but it solved the issue that I was having. In terms of ssh-agent, you may already have one running. Here's a script to extract the SSH_AGENT_PID & SSH_AUTH_SOCK from the environment without any additional stuff to save on startup of ssh-agent. (Assumes that you have perl)

Put the following in a script. (for example findagent.pl)

and inside your cron script add the line:

eval `{path to script}/findagent.pl`


\#!/usr/bin/perl -w
use strict;
my $agents = `ls -tr /tmp/ssh-*/*`;
my @agents;
(@agents) = split/\n/,$agents;

my $sshpid = `ps aux|grep ssh-agent|grep -v grep|awk '{print \$2}'|head -1`;
chomp($sshpid);
my @parts;
for (@agents) {
  chomp($_);
  if (!$_) { next; }
  my $agentfile = $_;
  (@parts) = split/\./,$agentfile;
  my $masterpid = `ps aux|grep $parts[1]|grep enlightenment`;
  if ($agentfile =~ m/$parts[1]/) {
    my $line1 = "SSH_AUTH_SOCK=" . $agentfile . '; export SSH_AUTH_SOCK';
    my $line2 = 'SSH_AGENT_PID=' . $sshpid . '; export SSH_AGENT_PID;';
    my $line3 = 'echo Agent pid ' . $sshpid . ';';
    print("$line1\n$line2\n$line3\n");
    last;
  } else {
    next;
  }
}
share|improve this answer
add comment

I suppose you're using key based auth to authenticate yourself with the remote machine. Try the line below:

rsync -av --delete -e "ssh -i .ssh/id_rsa" mydir user@host.tld:~/backupDir

Where .ssh/id_rsa is the path to your private key. This is the exact line I'm using to do my backups and it always works fine for me.

Best wishes,
Fabian

share|improve this answer
add comment

As an alternative, instead of using the ssh agent I made my script do export RSYNC_RSH="ssh -i /home/user/.ssh/id_rsa" unset SSH_AGENT_PID unset SSH_AUTH_SOCK before invoking rsync. By putting it in RSYNC_RSH instead of using '-e ...' it made it easy to adjust the id file being used based on the host.

Hope this helps, B

share|improve this answer
    
I don't think this works if you have a passphrase on your key –  Casey Jul 13 '11 at 21:32
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.