Using SSH for cron jobs

Let's face it, effective operation on a large LAN requires that some machines be able to ask other machines to do tasks. The trick is to do this with minimal network security risk.

Automated remote operation via the BSD rsh programs and its relations requires that the user on the remote machine have a .rhosts file. This permits anyone who can subvert the network enough to spoof the user on the originating machine also has the ability to gain access to the remote machine.

Automated remote operation via the ssh programs permits

Cryptographic authentication of the hosts at both ends of the transaction
This means that the remote host can be quite certain that the requester is authentic, and that the originating host can be quite certain that it is not handing out secrets to an impostor.
Different RSA key pairs for individual transactions
It is possible to restrict the operations that an originating host can invoke on a remote host. The remote host can restrict the use of a key to invoke only one particular command when requested by one particular initiator. Within the practical limits of manageability of the RSA keys, there can be a separate key for each distinct transaction.

Example of an individual, privileged, remote transaction

Suppose there are two users on two machines: A user paris@ilium who wants to permit user priam@sparta to perform an rdist of some files (labelled helen) from sparta to ilium.

We presume that this is the free rdist originally from USC, not the rdist as supplied by most operating system/hardware vendors. This free rdist is a client/server application which uses rsh by default, but permits the specification of ssh as a non-default transport mechanism. The example could apply to any other client/server application such as CVS which also permits itself to use a non-default transport mechanism. It also applies to remote invocation of simple shell commands where there is no need for a client/server mechanism.

In the absence of ssh the command for running rdist would be

/path/to/sparta/rdist -f /path/to/distfile helen
or, if the free rdistd server is not in the default path at the remote end
/path/to/sparta/rdist -f /path/to/distfile -p /path/to/ilium/rdistd helen

Setting up ssh for the transaction

ssh must be installed on the originating host (sparta)
sshd must be installed and running on the remote host (ilium)
ssh need not be installed setuid root on sparta.
sshd must be fully installed and running as root on ilium.

Priam must interactively test the ssh connection from sparta to ilium using ssh or slogin. This will verify that the pieces are correctly installed. This also permits priam@sparta to obtain and/or verify the public key of the sshd on ilium before attempting non-interactive tasks. Without this step ssh will deny access because the default configuration of ssh requires that the public key of the remote machine be verified interactively.

priam@sparta must use ssh-keygen to create an RSA key pair
This key pair will be specific to this rdist transaction. When ssh-keygen asks for a key file name it should be given a suitably mnemonic reply; for our example let us use ~priam/.ssh/nohorse as the name. Because it is to be used in a fully automatic fashion by cron, this private key should have no passphrase. (The lack of passphrase opens what may be the largest security hole in this scheme. All keys for interactive use should have passphrases. See appendix for a scheme by which a passphrase might be possible even with automatically-used keys such as this.)
priam@sparta must transmit his public key to paris@ilium
This means that the content of the ~priam/.ssh/nohorse.pub file containing the public key must be securely transferred from sparta to ilium. Typically this would be accomplished using scp, but it could also be done via e-mail with PGP.
paris@ilium must modify the public key for the specific use
Upon generation Priam's public key consist of a single, long line of text that looks something like
	NNNN MM 89012[bulk of huge decimal prime number omitted
	for the sake of example]34567 priam@sparta
where NNNN is the key length, MM is the encryption modulus, and the huge prime number is the public key.

Paris will want to modify this key and append it to his file of authorized RSA keys. The key is modified by prepending a restriction in the way it may be used.

	command="/path/to/ilium/rdistd -S" NNNN MM 89012[bulk still gone
	for the sake of example]34567 priam@sparta
As soon as this modified key is appended to ilium:~paris/.ssh/authorized_keys it will be possible for Priam, and only Priam, to invoke rdistd, and only rdistd, on ilium.

Further restrictions on this key are possible and highly advisable; e.g.

	from="sparta",command="/path/to/ilium/rdistd -S",no-port-forwarding,
	no-pty NNNN MM 89012[bulk still gone for sake of example]34567
See the man page on sshd for full details on restricting use of keys.
priam@sparta should create a ssh wrapper script
By design the nohorse key is not Priam's default ssh identity. Priam could modify his ssh configuration file (~priam/.ssh/config) to assert that the nohorse key was to be used in transactions with ilium, but this might befuddle interactive logins from priam@sparta to paris@ilium.

Fortunately, there is another way to specify the identity via a simple shell script wrapper:

	#! /bin/sh
	exec /path/to/sparta/ssh -x -a -i ~priam/.ssh/nohorse $*
Here Priam has used the -i switch to specfy that the nohorse key should be used, and the -x and -a switches to specify that no X11 forwarding or authentication agent forwarding should be performed.

Note that even with explicit specification of the nohorse key ssh may fail if Priam attempts to invoke this while also running ssh-agent. It appears that ssh always prefers an agent over the command line switch, and if the agent does not contain an authorized identity ssh gives up without even trying the nohorse key. I'm not sure if this should be considered a bug in ssh.

In order to avoid the use of the agent, Priam has used the unset line to assure that any active ssh-agent be ignored. If Priam typically uses ssh-agent as part of his interactive session, this will be very important for interactive tests of the scheme with an unpassphrased nohorse key. However, if Priam wants to use a passphrased key (as described in the appendix) then he should ensure that the agent holds only the nohorse key and not do the unset.

priam@sparta must set up cron job
The command would be something like
	/path/to/sparta/rdist -P /path/to/ssh_wrapper -f /path/to/distfile helen
which asserts that rdist should use Priam's ssh wrapper script as its transport mechanism.

The wrapper is required because rdist does not permit embedded spaces in the string following the -P switch. Things are simpler if paris@sparta does not need a client/server app, but merely a remote command invocation. In such cases the cron job could simply directly invoke ssh with the -i switch.

With all this in place Priam should be able to use rdist to transport Helen from Sparta to Paris at Ilium with minimal risk.

Security implications of this scheme

This scheme is more robust than rdist via rsh or rexec. Priam's cron job can verify that it is actually talking to ilium, which means that nobody can trick Priam's cron job into sending sensitive files to some other machine. The files are encrypted in transit. Paris can ensure that only Priam is permitted to send files.

Naturally, this presumes that the superusers on sparta and ilium are trustworthy. A malicious or stupid superuser on ilium could relax the security provisions in the ~paris/.ssh/authorized_keys file to permit others in. A malicious superuser on sparta could steal Priam's private key from ~priam/.ssh/nohorse and attempt to use rdist to overwrite sensitive files on ilium.

The worst security hole is probably that routine backup tapes on sparta contain Priam's un-passphrased nohorse private key. This makes it somewhat more important that backup tapes be handled securely (especially if Paris is, in actuality, a superuser at ilium). Otherwise some agent, say poseidon@aegean, might just obtain a backup tape containing the nohorse key and deliver it to odysseus@ithaca while he is walking along the beach.

Appendix: a scheme for using passphrased keys

It is possible that Priam could place a phassphrase on the key and still permit its use with a non-interactive cron job. This would require Priam to use ssh-agent. If Priam were to startup an ssh-agent process, he could give it the passphrase for the nohorse key. The cron job could be modified to set its environment such that it would find the authentication agent when it ran ssh. (Note that in this case the wrapper script described above should not do the unset and need not specify the name of the nohorse key. It is perhaps for this very reason that the behavior where ssh prefers an agent to the explicit command-line specification of a key is not a bug.)

So long as the ssh-agent process remained running Priam's cron job would be able to perform the rdist. If that ssh-agent were to terminate, then Priam would have to re-start and re-authorize it interactively. A sufficiently sophisticated cron job could detect the non-existence of the authentication agent, and send mail to Priam reminding him to get back over to sparta and re-authorize it.

In this case, the nohorse key cannot be as easily compromised. Instead of simply having to capture the private key file (which would happen routinely with backups), it becomes necessary for the superuser on sparta to locate and interrogate Priam's ssh-agent process.

In a manual test I have demonstrated that this idea does work. I have also written a smart shell script which hunts for the agent and sends mail if it cannot be found. (CAVEAT: The shell script has been in regular use for several months, but it has not been employed widely enough to be considered more than beta-level software.)

This scheme is probably worth adopting in cases where it is absolutely necessary to prevent backup tapes from compromising the keys.

In a truly paranoid world, Priam and Paris are well advised to change the RSA keys often even if there is a passphrase. Realistically, however, since current ssh keys do not have embedded expiration dates, human nature dictates that Priam and Paris will never get around to doing this. Eventually, even if the superusers at Ilium are not so stupid as to open the gates to a comely horse, the compute power of the gods will be sufficient that Poseidon can factorize or otherwise employ brute force to obtain Priam's private key, hand it to Odysseus, and the horse will get in.

The identities of the users and machines in this example are not intended to resemble anyone living or dead within the past 3 millennia, notwithstanding the mascot at the origin of the free version of rdist.

Back to Steve's ssh page.
Steve Allen <sla@ucolick.org>

Initial deployment: 1999-01-19
Updated: 2001-01-19