Securing Keyless SSH Logins Raw

Introduction
------------

In this guide, I will set up secure, keyless SSH access from a test
server, **server.example.com** to a client **client.example.com**.

I type "secure" since ordinary keyless SSH setups do *not* involve
entering a password for the SSH key. It is easy to see how this is
useful for `cron` jobs, for example, which might need access to client
machines. This also means that if the server is compromised, it is
trivially easy to gain access to its keyless clients.

This situation can be improved greatly with strong passwords,
`ssh-agent` and its delightful front-end,
[`keychain`](http://www.funtoo.org/Keychain).

Pre-flight - Pertinent folders and permissions
----------------------------------------------

Explained later

### Commands

*   `ssh-keygen` - Used to generate keys
*   `ssh-copy-id` - Copy a key from the server to client (CentOS *only*)

### Files and Folders

*   `/.ssh` - Folder which stores all keys for the
    user
    *   The access permissions *need* to be `700`!
*   `/.ssh/authorized_keys` - Plain text file with
    public keys authorized to ssh into the machine as this user
    *   The access permissions *need* to be `600`!

### This is Ridiculously *Crucial*

*   It is *vitally* important that the permissions on the `.ssh` folder
    and `authorized_keys` are `700` and `600`! Save yourself a lot of
    mental anguish by remembering this outright!
*   Never, ever, ever share your private key.
    [Please](http://www.google.com/search?q=site:pastebin.com+%22-----BEGIN+RSA+PRIVATE+KEY-----%22).

Generating SSH keys for keyless access
--------------------------------------

### Generating default keys

This is simple. For typical 'keyless' access, you would just hit `Enter`
when asked for a password. Not now! Choose a nice, secure password for
your default key and type it in twice.

    ssh-keygen -t rsa  
    Generating public/private rsa key pair.  
    Enter file in which to save the key (/var/user/.ssh/id_rsa):  
    Enter passphrase (empty for no passphrase):   
    Enter same passphrase again: 

You should now have two files in `.ssh` in your home folder. These are
`id_rsa`, your private key, and `id_rsa.pub`, your public key. Do not
share your private key.

### Copy the *Public* key to the Client

On CentOS, this is very simple:

    ssh-copy-id -i ~/.ssh/id-rsa user@client.example.com

**Note:** Don't worry; the command above doesn't copy the private key of
the identity pair. Since the command is a bash script, you can verify
this yourself.

On Mac OS X, you do it the traditional way (or you can port the
`ssh-copy-id` script over from CentOS):

    scp ~/.ssh/id_rsa.pub user@client.example.com:/var/user/.ssh/server-key.pub  
    ssh user@client.example.com  
    Password: (Enter Password)  
    cat ~/.ssh/server-key.pub >> ~/.ssh/authorized_keys  
    rm ~/.ssh/server-key.pub

### Verify Permissions

*   Make sure that `.ssh` and `authorized_keys` within it have
    permissions `700` and `600` respectively.
*   Make sure that your generated keys (public and private) have
    permissions of 600.

OpenSSH is picky like that.

### Test the Connection

Assuming you're logged in as `user` on the server:

    ssh client.example.com  
    Enter passphrase for /user/.ssh/id_rsa:

Enter the password to your SSH key, and you should be in! Yay!

Back to Square One? Not with `ssh-agent`!
-----------------------------------------

### Some background

So here's the deal: You might think this is pointless since you'll have
to enter a password anyway (for the key in this case.) However,
`ssh-agent` caches private keys (and, in our case, login information to
client machines) in memory. [From the horse's
mouth](http://www.openbsd.org/cgi-bin/man.cgi?query=ssh-agent):

> ssh-agent is a program to hold private keys used for public key  
> authentication (RSA, DSA).  The idea is that ssh-agent is started in the  
> beginning of an X-session or a login session, and all other windows or  
> programs are started as clients to the ssh-agent program.  Through use of  
> environment variables the agent can be located and automatically used for  
> authentication when logging in to other machines using ssh(1).

Although there exist many scripting examples which initialize and use
`ssh-agent`, we'll make that easier with [the amazing
**Keychain**](http://www.funtoo.org/Keychain). Why I like it is purely
because it maintains a single `ssh-agent` process per *system*, rather
than per *session*.

### Installation

On CentOS, just issue `yum install keychain` after installing DAG's
RPMForge repo (see Resources on this page). On OS X, check out [the
download page](http://www.funtoo.org/Keychain).

### Using Keychain

Remember that I'm trying to log in as `user` on both server and client.
I'll add this to `.bashrc` on CentOS, or `.profile` on OS X on the
client machine's user home folder:

    eval `keychain --eval --agents ssh id_rsa`

Now log out and log back into the server. You should see this:

     * keychain 2.6.10 ~ http://www.funtoo.org
     * Found existing ssh-agent: 274  
     * ssh-agent: All identities removed.  
     * Adding  1 ssh key(s): /var/user/.ssh/id_rsa  
    Enter passphrase for /var/user/.ssh/id_rsa:   
     * ssh-add: Identities added: /var/user/.ssh/id_rsa

You should have full keyless access to the client after entering the
password to the private key at this point. You may now have a drink.

### Not so fast

Remember that Keychain allows `ssh-agent` to cache private keys per
*system*. This means that the next time you log into the server,
*Keychain will not ask you for the private key's password* since it's
already cached it in memory. So if you entered the user password to the
server, here's what you get the *second* time you log in. For a
compromised server, this may be as good as a password-less login.

    user@server.example.com's password:   
    Last login: Sun May  2 23:53:38 2010 from 173-30-221-179.client.mchsi.com  
      
    KeyChain 2.6.8; http://www.gentoo.org/proj/en/keychain/
    Copyright 2002-2004 Gentoo Foundation; Distributed under the GPL  
      
     * Found existing ssh-agent (17986)  
     * Known ssh key: /user/.ssh/rsync-key

### Securing Keychain Further

How do you fix the situation? Simple!

1.  You assume that a user is an intruder until s/he has
    proven otherwise.
2.  If the user has not entered the correct passphrase for a private
    key, *flush the key from memory*

This works, because *keys are cleared by* `ssh-agent` *on log out, not
log in*. Here's how you'd edit `.bash_profile` or `.profile`:

    eval `keychain --clear --eval --agents ssh id_rsa`

At the next login, Keychain *will* ask you the passphrase for your
keypair. Try entering a bad one a few times and logging into the client
machine. If you've set this up right, you'll be asked for a password to
the machine!

Working with Multiple Identities
--------------------------------

In the example above, we've used the server's default SSH identity.
`id_dsa/.pub` and `id_rsa/.pub` are the keypair for this identity. It
may not be preferable to use this one single identity for multiple
clients. You're able to generate other identities using `ssh-keygen`, by
typing in the name of the keypair when it asks you for one:

    ssh-keygen -t rsa  
    Generating public/private rsa key pair.  
    Enter file in which to save the key (/var/user/.ssh/id_rsa): sample-ssh-key
    Enter passphrase (empty for no passphrase):   
    Enter same passphrase again: 

### Using the key for SSH

When you use the `id_dsa/.pub` or `id_rsa/.pub` keypairs, you don't need
to specify the `-i` (identity) switch with the SSH command since they're
default keys. This is how you'd use another identity to SSH in:

    ssh -i ~/.ssh/sample-ssh-key client2.example.com

**Note** that you used the *private* key in the example above! This
command will ask you for the password to the `sample-ssh-key` private
key, assuming you've copied over the public key to `authorized_keys` on
the client (as describe in earlier sections.)

### Using Keychain to Store Multiple Identities

Simple! For each secure identity you create, just add its appropriate
line to `.bash_profile` or `.profile` and ask Keychain to store this in
memory. For the example above:

    eval `keychain --clear --eval --agents ssh  `sample-ssh-key``

The next time you log in, you'll be asked the passphrases to *each
private key* you've defined via Keychain. For the `id_rsa` and
`sample-ssh-key` keypairs above, here's what I see:

     * keychain 2.6.10 ~ http://www.funtoo.org
     * Found existing ssh-agent: 274  
     * ssh-agent: All identities removed.  
     * Adding  1 ssh key(s): /var/user/.ssh/id_rsa  
    Enter passphrase for /var/user/.ssh/id_rsa:   
     * ssh-add: Identities added: /var/user/.ssh/id_rsa  

     * keychain 2.6.10 ~ http://www.funtoo.org
     * Found existing ssh-agent: 274  
     * ssh-agent: All identities removed.  
     * Adding  1 ssh key(s): /var/user/.ssh/sample-ssh-key  
    Enter passphrase for /var/user/.ssh/sample-ssh-key:   
     * ssh-add: Identities added: /var/user/.ssh/sample-ssh-key

All the keyless logins you've set up with multiple, passworded keys will
work now. All cron jobs will continue chugging along. Intruders won't
have direct access to clients. You'll sleep better.

Resources
---------

*   [Introduction to Keychain - Funtoo.org](http://www.funtoo.org/Keychain)