Linux Login using SSH keys

Published 2012-10-23

Using SSH keys to login to a server provides a convenient alternative to typing your password each time. SSH key-based authentication also allows scripts to run unattended without leaving your password in plain text. And it does your laundry. Well, alright, maybe not that last one.

Once you have ssh auth setup, you can use commands like ssh, scp, sftp, and rsync without having to enter a password. Handy!

SSH Keys in 5 Minutes or Less

If you're lazy or adventurous and prefer to skip the details, you can follow these instructions:

Generate a key if you don't have one already, pressing enter at all the prompts:

$ ssh-keygen

Set permissions on your private key and upload your public key to the server:

$ chmod 400 ~/.ssh/id_rsa*
$ scp ~/.ssh/id_rsa.pub username@example.com:~/id_rsa.pub

Login to the remote server to create the .ssh folder, create the authorized keys file and set permissions:

$ ssh username@example.com
username@example.com's password: <enter password>
$ mkdir ~/.ssh/
$ cat id_rsa.pub >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
$ rm id_rsa.pub
$ exit

Now when you login via ssh, it should use your ssh key instead of prompting you for a password.

SSH Keys in Slightly More than 5 Minutes

If you got stuck in the <5 minutes version, would like to know a bit more about what just happened (or what you're about to do), or want to learn about some advanced use cases, read on.

Public vs. Private Keys

SSH relies on a mechanism called public key cryptography, which consists of a matching private key and public key, called a "key pair". Someone who holds the public key can encrypt a message that only the person with the private key can decrypt (this establishes secrecy). Further, the holder of the private key can sign a message that anyone with the public key can verify was created by the person holding the private key (this establishes identity).

When you connect to an SSH server, the SSH server signs a message and sends it to you. Your SSH client uses this signature to validate the identify of the server. Subsequently, you send your public key to the server and sign a message with your private key. The server validates both that the public key is allowed (via authorized_keys) and that the signature is valid (which verifies that you also have the private key). Following this both SSH processes work together to derive a symmetric key (usually using an AES cipher) that encrypts your communication with the server.

Usually the first time you connect to a server over SSH you will not have the server's public key, so your SSH client will record it into the ~/.ssh/known_hosts file. On subsequent connections SSH can prove that the server you're connecting to has the same private key as it did last time. Obviously this assumes you trust the remote side's key on the first connection. If you don't, you'll need public key infrastrcture to deploy and manage those keys so they can be trusted before you open a connection.

If you only remember one thing about key pairs, remember this: don't share your private key. Whenever you copy your key somewhere you should copy your public key, not your private key.

Generating a Key Pair

Note: If you're using git you may have a key pair already. You can use your existing key pair for other servers (or if you have reservations about that, see the "Managing Multiple Keys" section below).

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/cbednarski/.ssh/id_rsa):

By default, the generated key will be created in your home directory under ~/.ssh/. The private key is named id_rsa and the public key is id_rsa.pub. If you don't have a key pair yet, just press enter to accept the default.

Next, ssh-keygen will prompt you for a passphrase. If you enter a passphrase you will need to enter it each time your key is used, or use an ssh agent like the macOS keychain, pageant, gnome-keyring, etc. If you need to use this key headlessly (e.g. via cron or some other unattended operation) you should omit the passphrase.

Once you've entered (or skipped entering) your passphrase, ssh-keygen will output a signature and a randomart graphic.

As a final step, you'll need to change the permissions on your keyfiles so only you can read them:

$ chmod 400 ~/.ssh/id_rsa*

If you cat your keys you'll see something like this:

Private Key

$ cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAvKIl+MRGBX7+r0n5rfeWU4MypoWZEGX9JOtnfKSQ2HbolEUG
doypY5LQe3SE7Qxx9//Ls0EZ9yo926fQyAK5aBprykkSYA9MUx78a8LuNdPBLrw1
                             [ snip ]
wcWjQW9avTxJwGSq+o11KrxBHozpuApewkk2nqRPON/IJm118LS7/fv6u4tdNYrW
7xQQEqOud8ro1fMC1EBxv88h+qjH39gg2ej9vBxfIdW2Zec80Je1uRU=
-----END RSA PRIVATE KEY-----

Public Key

$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8oiX4xEYFfv6v...fLNCHvQBwGUFTa2v cbednarski@ubuntu-1204

You'll notice that the private key is arranged into a series of neat 64-column lines, while the public key is all crammed into one line (and wraps in your terminal). This whitespace is important. If you add or remove line breaks the keys won't work, so copy-paste carefully.

Installing the Public Key

Now that you have your key pair you'll need to copy the public key to the server and add it to the authorized_keys file for the user you want to login as.

$ scp ~/.ssh/id_rsa.pub username@example.com:~/

Once the key is uploaded you'll need to login to the server to create the .ssh folder and add your public key to the authorized_keys file on the remote host.

$ ssh username@example.com
username@example.com's password: <enter password>
$ mkdir ~/.ssh/
$ echo "<paste your private key here>" >> ~/.ssh/authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
$ exit

At this point, the public key should be installed and we're ready to try logging in.

Logging In

When you login, your ssh client will choose a key from ~/.ssh and try to login as the same user you're using on the local side.

For example, if I'm logged in as cbednarski and the remote host has a cbednarski user with my public key installed, I can login simply by doing this:

$ ssh example.com

If the account on the server is different from your client username, you'll need to specify it using one of these two methods:

$ ssh username@example.com
$ ssh -l username example.com

Use the second option if you are logging in with a personal account (e.g. cbednarski@). This way you can easily change it when you copy the URI, for example with cssh:

$ cssh username@example1.com username@example2.com username@example3.com
$ cssh -l username example1.com example2.com example3.com

If everyone needs to use a specific user to login (e.g. ubuntu@ instead of cbednarski@) include the user in the URI.

Other Considerations

Viewing a Key's Fingerprint

A key's fingerprint is a way to identify or "name" a key pair without exposing either key. The fingerprint is commonly used as a reference for keys that were previously installed on a service like github and AWS, because the fingerprints for the public and private keys will match.

You can view the fingerprint of a key with:

$ ssh-keygen -lf keyfile

Managing Multiple Keys

In some cases, you'll want to use different ssh keys. For example, AWS generates keys for you automatically, and you might want to use different keys for committing to github vs. logging into a production server. You have two options: You can specify a key when you connect, or you can configure hostname-specific keys.

Note: When you specify which key to use for a connection, make sure to specify your private key.

On Connection

If you want to specify a key for a specific ssh session, you can do so with -i.

$ ssh -i keyfile example.com

Passing in the key using -i is the default authentication model on AWS, but you may also find it useful if you want to login to different unix accounts on the same server.

By Hostname

If you frequently login to the same servers it's more convenient to configure SSH to remember which keys to use for which servers. You can do this by editing ~/.ssh/config on your client machine.

If you don't already have an ssh config file, create one and change the permissions so only you can read/write to it:

$ touch ~/.ssh/config
$ chmod 600 ~/.ssh/config

Edit this using your favorite text editor and arrange things like so:

Host example1.com
  IdentityFile ~/.ssh/keyfile1

Host *.consul
  User ubuntu
  IdentityFile ~/.ssh/keyfile2

Remember, you are specifying the private key in this file.

Afterwards, when you invoke ssh example1.com, ssh will use keyfile1, and it will use keyfile when you connect to any hostname ending with consul.


Related

linux ssh devops