Generate and Automatically Load SSH Keys for Convenient Passwordless Authentication

When correctly executed, public/private key authentication is more secure than shared secrets (passwords) for a number of reasons including but not limited to:

  • Disabling password-based authentication on remote hosts eliminates the potential for password brute-forcing.
  • Keyloggers installed on a local machine or keyboard firmware can only capture the key's passphrase as valid passwords for remote hosts are never typed.
  • A compromised, malicious, Man-in-the-Middle'd, DNS or ARP poisoned (and so on...) remote host can intercept passwords in the clear; a private key is a component in a randomized and unique cryptographic challenge and is never transmitted.
  • If a public key on a remote host is compromised or intercepted enumerating the private key is significantly more difficult (virtually impossible) than hash cracking/rainbow lookup.
  • Enforcing key authentication establishes a standard level of complexity regardless of users' choice in passwords.
  • One key can be used for any number of remote hosts under a variety of usernames permitting a diversity of remote-local account passwords and configurations.
  • Securing your private key with a password that only has to be entered once alleviates the influence of convenience in selecting a suitably complex password.

Note: It is a matter of personal policy that regardless of the method of authentication used, no management interface should be exposed to the wild wherever possible. Inherent in the term 0-day, there is always a potential for yet-unknown flaws in authentication methodology or any other part of the vast machinery of daemons and their host OS to come to light and render the most supposedly secure authentication scheme ineffective. Where full out-of-band administration is not possible I generally subscribe to an architecture wherein hosts are placed on a private internal network and only the essential public-facing ports are exposed to public address space by a firewall configured for DNAT (1-1 NAT). Access to management interfaces is obtained by VPN tunnel to the private network. Ideally VPN gateway services are provided by a separate host from the firewall - which should do nothing but firewall and itself expose no management interfaces to the wild. This has an added benefit of allowing one to "stack" services from multiple compartmentalized hosts (e.g. HTTP, SMTP, DNS) behind individual IPs, making more efficient use of (often costly) public address space.

Ten years ago I wrote an article for this site on how to implement Passwordless or Single Password SSH with Key Exchange. A lot has changed since then; most importantly ECDSA became available in 2011 and is now widely implemented.

From SSH.com https://www.ssh.com/ssh/keygen/:

SSH supports several public key algorithms for authentication keys. These include:

  • rsa - an old algorithm based on the difficulty of factoring large numbers. A key size of at least 2048 bits is recommended for RSA; 4096 bits is better. RSA is getting old and significant advances are being made in factoring. Choosing a different algorithm may be advisable. It is quite possible the RSA algorithm will become practically breakable in the foreseeable future. All SSH clients support this algorithm.
  • dsa - an old US government Digital Signature Algorithm. It is based on the difficulty of computing discrete logarithms. A key size of 1024 would normally be used with it. DSA in its original form is no longer recommended.
  • ecdsa - a new Digital Signature Algorithm standarized by the US government, using elliptic curves. This is probably a good algorithm for current applications. Only three key sizes are supported: 256, 384, and 521 (sic!) bits. We would recommend always using it with 521 bits, since the keys are still small and probably more secure than the smaller keys (even though they should be safe as well). Most SSH clients now support this algorithm.
  • ed25519 - this is a new algorithm added in OpenSSH. Support for it in clients is not yet universal. Thus its use in general purpose applications may not yet be advisable.

It should be noted that concerns over possible NSA tampering have been raised about the implementation of the NIST standardized P-curves used with ECDSA. EdDSA (Ed25519 which implements Curve25519 instead of P-curves) is purported to be faster than ECDSA in some cases. EdDSA became available in OpenSSH in 2014 and although we will use ECDSA for the purposes of this article due to its ubiquity, EdDSA is currently presumed to be as strong or stronger and you should feel free to use whichever you prefer. Take note that the maximum supported key size for ECDSA is 521 bits not 512. You may create additional keys using other algorithms to support older SSH daemons, however they should be updated if possible.

Use ssh-keygen to create the new key pair. The algorithm is specified by the -t flag and key size by -b:
ssh-keygen -t ecdsa -b 521 Generating public/private ecdsa key pair. Enter file in which to save the key (/home/user/.ssh/id_ecdsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_ecdsa. Your public key has been saved in /home/user/.ssh/id_ecdsa.pub. The key fingerprint is: SHA256:Z7HOerLL3vT2D5/Sj3AFk27eUaLtDCgWnViY26OhosY [email protected] The key's randomart image is: +---[ECDSA 521]---+ | o. | | o+ . . | | oo+ = .| | o.o+ + +.| | .So=.o +..| | . ...* * o.| | . . . + . B .| | E ..+...+ =.| | . .*=....+o=| +----[SHA256]-----+ Alternatively... ssh-keygen -t ed25519 ssh-keygen -t rsa -b 4096 ssh-keygen -t dsa

It is important that you protect your private key with a strong passphrase: if the file is compromised an adversary will immediately have access to any accessible accounts without further obstacles. This is especially important if you wish to use the same private key on multiple hosts (e.g. your phone).

If you chose the default key file name your private key will be located at ~/.ssh/id_ecdsa and your public key will be located at ~/.ssh/id_ecdsa.pub. You may configure any number of keys by changing the filename when prompted or using the -f ssh-keygen flag from the command line.

Your public key must now be copied to the remote host(s) you wish to authenticate with. You may specify either the private or public key to ssh-copy-id using the -i flag as .pub will automatically be added to the filename if it is missing:
ssh-copy-id -i ~/.ssh/id_ecdsa [email protected]
Alternatively you may directly paste the public key (in this example, ~/.ssh/id_ecdsa.pub) into the ~/.ssh/authorized_keys file on the remote host. Use a text editor to modify the file to avoid the key being logged (e.g. in ~/.bash_history). A host can accept any number of keys; place them each on an individual newline. If you are manually creating the authorized_keys file for the first time or copying it from another host it is important to ensure that the correct file permissions are configured:
chmod 600 ~/.ssh/authorized_keys ls -lsah ~/.ssh/authorized_keys 4.0K -rw------- 1 user group 270 Apr 28 04:07 /home/user/.ssh/authorized_keys

Every time you connect to a host that supports your key you will be asked to enter the key's passphrase. To avoid this such that you only need to enter the password once, one must add it to the ssh-agent daemon. First, see if your system is already configured to load the daemon automatically:
ps aux | grep ssh-agent user 836 0.0 0.0 5852 2504 ? Ss May06 0:01 /usr/bin/ssh-agent
If it is not running you can launch it in the background thus:
eval "$(ssh-agent -s)"
You may wish to add this line to your preferred autorun script (i.e. /etc/rc.local, /etc/conf.d/local.start, ~/.xinitrc, etc.)

You can now manually add your key to the agent by:
ssh-add -K ~/.ssh/id_ecdsa
However this must be performed every time you restart ssh-agent (every time you reboot). A more permanent method is to create a ~/.ssh/config file with the following:
Host * AddKeysToAgent yes ForwardAgent yes UseKeychain yes IdentityFile ~/.ssh/id_ecdsa
Note: only include the highlighted UseKeychain directive on OS X. It will fail on other operating systems.

You may specify multiple IdentifyFile directives for additional keys. They will be attempted in the order they are listed. This is an ideal way to support multiple key algorithms. To use different keys for different hosts you are encouraged to create separate Host configurations, replacing the wildcard (*) with their remote address. Keys with supported algorithms but no corresponding public key on the remote host will count against your maximum failure attempts and may temporarily or indefinitely lock you out or trigger tools like fail2ban to firewall you.

It is possible to take advantage of the agent forwarding capability to maintain your private keys only on your local host but shell out from a remote host to another remote host with a valid public key matching one of the identities loaded in your local ssh-agent. To view the list of currently registered identities run:
ssh-add -l 521 SHA256:Z7HOerLL3vT2D5/Sj3AFk27eUaLtDCgWnViY26OhosY [email protected] (ECDSA)
To enable forwarding ForwardAgent must be set to yes (the default when unspecified is 'no') in the global default ssh_config client configuration file (/etc/ssh/ssh_config) or your user's personal config file (~/.ssh/config) either under the default (wildcard, "*") Host block or individually for specific hosts. The AllowAgentForwarding directive must be set to yes in the remote host's sshd_config server configuration file (/etc/ssh/sshd_config), which is the default value.

Once key authentication has been configured for all necessary users it is important to disable password-based authentication outright on your remote host(s). Edit /etc/ssh/sshd_config to reflect:
PasswordAuthentication no ChallengeResponseAuthentication no
Additionally, if you are not using PAM (if you are only using key authentication you are not) you may wish to also set UsePAM to no.

Leave a shell session open to ensure you are able to modify the configuration if you are configuring sshd remotely and something goes wrong. Restart sshd to effect the new configuration. Test to ensure you are still able to log in. Attempting to connect from a host with no valid keys configured should now produce:
Permission denied (publickey).


There are no comments for this item.