SSH isn't only a great interactive tool but also a resource for
automation. Batch scripts, cron jobs, and other automated tasks can benefit from the
security provided by SSH, but only if implemented properly. The major challenge is
authentication: how can a client prove its identity when no human is available to
type a password? You must carefully select an authentication method, and then equally
carefully make it work. Once this infrastructure is established, you must invoke
SSH properly to avoid prompting the
user.
Note that all kind of unattended authentication presents a security
problem and requires compromise, and SSH is no exception. Without a human present when
needed to provide credentials (type a password, provide a thumbprint, etc.), those
credentials must be stored persistently somewhere on the host system. Therefore, an
attacker who compromises the system badly enough can use those credentials to impersonate
the program and gain whatever access it has. Selecting a technique is a matter of
understanding the pros and cons of the available methods, and picking your preferred
poison. If you can't live with this fact, you shouldn't expect strong security of
unattended remote jobs.
In this example, we show how to use the Public Key
Authentication together with an SSH Agent to backup files from a remote SSH
Server (Rabbit) to a local SSH client (Opal), fully automated and driven by cron.
In this example we use OpenSSH.
The following Tasks have to be setup:
- Create Cryptographic Keys with SSH-KEYGEN on the SSH
Client
- Install the generated Public Key on the SSH Server
- Activate Public Key Authentication in both SSH Client and SSH
Server
- Start the SSH Agent and load the Private Keys on the SSH
Client
- Start the Backup (e.g. ssh -2 rabbit "cat /u01/file.gz" >
file.gz
We will now show the needed steps in more detail.
A key is a digital identity. It's a unique string of
binary data that means, "This is me, honestly, I swear." And with a little cryptographic
magic, your SSH client can prove to a server that its key is genuine, and you are really
you.
An SSH identity uses a pair of keys, one
private and one public. The private key is a closely guarded secret only you have.
Your SSH clients use it to prove your identity to servers. The public key is, like the
name says, public. You place it freely into your accounts on SSH server machines. During
authentication, the SSH client and server have a little conversation about your private
and public key. If they match (according to a cryptographic test), your identity is
proven, and authentication succeeds.
Generating Key Pairs with ssh-keygen
To use cryptographic authentication, you must first
generate a key pair for yourself, consisting of a private key (your digital identity that
sits on the client machine) and a public key (that sits on the server machine). To do
this, use the ssh-keygen program. In this example we use
Go to the SSH Client and generate the RSA and DSA Keys. In the
example we only use the DSA Key Pairs (~/.ssh/id_dsa and ~/.ssh/id_dsa.pub). In the
example we used an empty passphrase.
zahn@opal:~/.ssh> ssh-keygen
Generating public/private rsa1 key pair.
Enter file in which to save the key (~/.ssh/identity):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/identity.
Your public key has been saved in ~/.ssh/identity.pub.
zahn@opal:~/.ssh> ssh-keygen -t
dsa
Generating public/private dsa key pair.
Enter file in which to save the key (~/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_dsa.
Your public key has been saved in ~/.ssh/id_dsa.pub.
zahn@opal:~/.ssh> ls -l
-rw------- 1 zahn dba 668 Mar 15 19:16 id_dsa
-rw-r--r-- 1 zahn dba 610 Mar 15 19:16 id_dsa.pub
-rw------- 1 zahn dba 535 Mar 15 19:15 identity
-rw-r--r-- 1 zahn dba 339 Mar 15 19:15 identity.pub
After creating the key pair on the SSH Client, you
must install your public key in your account on the SSH Server. A remote account
may have many public keys installed for accessing it in various ways. Copy the keys from
Opal to Rabbit using scp and Password Authentication.
zahn@opal:~/.ssh> scp id_dsa.pub
rabbit:/home/zahn/.ssh
zahn@rabbit's password:
zahn@opal:~/.ssh> scp identity.pub rabbit:/home/zahn/.ssh
zahn@rabbit's password:
zahn@opal:~/.ssh> ssh rabbit
zahn@rabbit's password:
zahn@rabbit:~/.ssh> cat identity.pub >> authorized_keys
zahn@rabbit:~/.ssh> cat id_dsa.pub >> authorized_keys2
zahn@rabbit:~/.ssh> rm id_dsa.pub identity.pub
zahn@rabbit:~/.ssh> chmod 644 *
Public Key Authentication is enabled in the SSH
Server Configuration File /etc/ssh/sshd_config for Red Hat Linux. This have to be
done as user root. After editing this file, restart your SSH Server.
PubkeyAuthentication yes
root@opal: /etc/rc.d/init.d/sshd restart root@rabbit: /etc/rc.d/init.d/sshd
restart
In public-key authentication, a private key
is the client's credentials. Therefore the batch job needs access to the key, which must
be stored where the job can access it. Store the key in an agent, which keeps secrets out
of the filesystem but requires a human to decrypt the key at system boot time.
The ssh-agent provides another, somewhat less
vulnerable method of key storage for batch jobs. A human invokes an agent and loads the
needed keys from passphrase-protected key files, just once. Thereafter, unattended jobs
use this long-running agent for authentication.
In this case, the keys are still in plaintext but
within the memory space of the running agent rather than in a file on disk. As a
matter of practical cracking, it is more difficult to extract a data structure from the
address space of a running process than to gain illicit access to a file. Also, this
solution avoids the problem of an intruder's walking off with a backup tape containing
the plaintext key.
Security can still be compromised by overriding
filesystem permissions, though. The agent provides access to its services via a
Unix-domain socket, which appears as a node in the filesystem. Anyone who can read
and write that socket can instruct the agent to sign authentication requests and thus
gain use of the keys. But this compromise isn't quite so devastating since the attacker
can't get the keys themselves through the agent socket. She merely gains use of the keys
for as long as the agent is running and as long as she can maintain her compromise of the
host.
Another bit of complication with the agent method is
that you must arrange for the batch jobs to find the agent. SSH clients locate an agent
via an environment variable pointing to the agent socket, such as SSH_AUTH_SOCK.
When you start the agent for batch jobs, you need to record its output where the jobs can
find it. For instance, if the job is a shell script you can store the environment values
in a file.
Generally, you run a single ssh-agent in your
local login session, before running any SSH clients. You can run the agent by hand, but
people usually edit their login files to run the agent automatically. SSH Clients
communicate with the agent via the process environment, so all clients within your login
session have access to the agent.
Start the Agent from your $HOME/.bash_profile
on the SSH Client (Opal)
# Start ssh-agent if not
already running
# The ssh-agent environment is setup by
# ~/.bashrc after ~/.bash_profile
if [ $LOGNAME = "zahn" ]
then
pid=`ps | grep ssh-agent | grep -v grep`
if [ "$pid" = "" ]
then
echo "Starting SSH Agent: ssh-agent"
exec ssh-agent $SHELL
else
echo "Setup Env for SSH Agent from ~/.agent_info"
. ./.agent_info
fi
fi
The line exec ssh-agent
$SHELL runs the agent and then invokes the given shell in
$SHELL as a child process. The visual effect is simply that another shell prompt appers,
but this shell has access to the agent. If an agent is already running, the environment
is stored in a file for all other SSH clients.
Setup SSH Agent Environment and load the Keys in
$HOME/.bashrc
Once the agent is running, it's time to load the
private keys into it using the ssh-add program. By default, ssh-add loads
the keys from your default identity files.
# Setup Environment for
ssh-agent
test -n "$SSH_AGENT_PID" && echo \
"SSH_AGENT_PID=$SSH_AGENT_PID; \
export SSH_AGENT_PID" > ~/.agent_info
test -n "$SSH_AUTH_SOCK" && echo \
"SSH_AUTH_SOCK=$SSH_AUTH_SOCK; \
export SSH_AUTH_SOCK" >> ~/.agent_info
# Load the Private Keys into the running SSH Agent
if [ $LOGNAME = "zahn" ]
then
pid=`ps | grep ssh-agent | grep -v grep`
if [ "$pid" != "" ]
then
if /usr/bin/tty 1> /dev/null 2>&1
then
ssh-add 1> /dev/null 2>&1
fi
fi
fi
You can now use the running SSH Agent from any
Backup Script. You have to read the SSH Agent Environment from your ~/.agent_info file.
No password or passphrase is needed.
This is an example of the Backup Script started by
cron on the SSH Client Opal (No error handling is show here).
#!/bin/sh
# Backup Script using unattended
SSH
AGENT_INFO=/home/zahn/.agent_info; export AGENT_INFO
# Fetch saved Files from RABBIT
cd ~/backup
# Source Environment for SSH Agent
. $AGENT_INFO
# Copy Data from Rabbit
ssh -2 rabbit "cat /u01/file.gz" > file.gz
If you have any troubles use the SSH Option "-v" to
display the debug output:
ssh -v -2 rabbit "cat /u01/file.gz" >
file.gz
Here are some other useful commands
$ ssh-add -l
|
List the keys the agent currently
holds |
$ ssh-add _D
|
Delete all keys from the agent |
$ ssh-agent -k
|
Kill the current agent |
|