If you've read my article One GPG key pair (to rule them all), you'll recall that we created a primary ("master") GPG key pair with three subkeys. One of the subkeys was assigned the Authentication [A] capability. In this article, I'll cover how to use that authentication subkey as your login key for remote secure shell (SSH) connections.
SSH public key authentication
The OpenSSH server supports various methods of user authentication, each with different degrees of inherent security. Basic password authentication (the default) is generally considered to be the least secure method. Password authentication only requires knowledge of a username and password in order to gain access to a host via SSH. Usernames can often be derived from things like email addresses or knowledge of the host operating system (for instance, most Unix-like systems have a
root account). Passwords can be guessed based on knowledge of the user or system owner, or via brute-force attacks that try thousands of common passwords in a short time.
One of the more commonly used methods of providing enhanced login security for SSH is public key authentication. Rather than a username and password, an OpenSSH server employing the public key authentication method requires that the remote user possess a cryptographic key in order to login. Access to the key files themselves are often tightly secured by file permissions, and the keys usually require a passphrase be entered in order to use them. This provides two factors of authentication for SSH access:
- The user must possess the private key file, and
- The user must know the key's passphrase.
To use public key authentication, a user who requires SSH access to one or more remote servers generates a key pair. The private key is stored in their local
~/.ssh directory, and the public key is copied into a file called
authorized_keys which is stored in the home directory of the account to which the user wants to authenticate. For example, to login as the user account 'bob' on a computer called 'serverA', a remote user's public key would be stored in the file
/home/bob/.ssh/authorized_keys on serverA. When the remote user connects via
ssh bob@serverA the OpenSSH server performs a cryptographic challenge using the public key stored in
authorized_keys, and the user's SSH client responds using the local private key to authenticate.
authorized_keys file for a user account can also contain multiple public keys, allowing more than one remote user to authenticate to the same account on a server. For example, a common method of providing
root access to a server managed by a small team is to add the SSH public key for each allowed admin to the
/root/.ssh/authorized_keys file on that server. This provides
root access to each admin without giving them the password for the
root account itself. If an admin leaves the team their access is revoked by removing their key from the
authorized_keys file. This is much less impactful than using password authentication, which would require changing the
root password when an admin leaves the team and updating the other admins with the new password.
This is also a fairly common method of providing temporary access to a server for the purpose of remote support.
Configure the server side
Configuring an OpenSSH server to use public key authentication is very simple, and the option is usually enabled by default. Simply add the following to the
If you want to disable password authentication completely, you can also use the option:
Remember to do this only after you have configured public key authentication, or you may find yourself locked out of your remote server.
You can also allow the
root account to login via SSH but force public key authentication for the account by using the option:
This is useful in the case where you want to allow normal users to authenticate with a password (for example, on an SFTP server where users are assigned the
rssh shell). You may also require
root login to administer the server, but you don't want
root to be able to login with a password. A combination of
PasswordAuthentication yes and
PermitRootLogin prohibit-password will achieve the desired results.
Any time you make changes to your
/etc/ssh/sshd_config be sure to restart OpenSSH for the changes to take effect:
# systemctl restart ssh
Public key authentication is only used for SSH sessions. Setting these options will have no effect on logging in via a TTY or console, where a password would still be required.
gpg-agent vs. ssh-agent
ssh-agent programs perform very similar tasks. Both are used to temporarily remember passphrases for private key access so that a user does not have to enter the passphrase every time they use the key. Generally, the user is prompted for the key passphrase the first time the key is accessed during a login session. The agent then caches the key and enters it on the user's behalf for some period of time. When the cache expires, the user is then prompted to re-enter the key passphrase the next time they access the key.
Traditionally, SSH keys and GPG keys have been regarded as separate things. A user's SSH key pair was separate and distinct from their GPG keyring.
ssh-agent is used to cache passphrases for SSH private keys, and
gpg-agent is used to cache passphrases for GPG private keys. However, a GPG public key with the Authentication [A] capability can be exported in a format capable of being used with OpenSSH. And recent versions of
gpg-agent are capable of performing as an agent for SSH requests if such a key is being used.
This new paradigm allows
gpg-agent to replace
ssh-agent and allows the user to employ their GPG key as their login key for SSH access. Key management is streamlined for the user by eliminating the need to manage different key pairs with different tools. This also opens up other possibilities like using a smartcard to store one's SSH key (because it's actually a GPG key).
If you're going to use
gpg-agent as a replacement for
ssh-agent you should disable
ssh-agent to prevent any conflict between the two. How exactly to do this will vary based on your distribution and the desktop environment you may be using. On Debian-based systems, you can usually disable
ssh-agent by removing or commenting the following line in
This should prevent
ssh-agent from starting the next time you login. For users of some desktop environments, the
gnome-keyring-daemon also has an SSH agent component that may need to be disabled from starting on login.
You'll need to add a line to your
~/.gnupg/gpg.conf file to instruct GPG to use
You'll also need to make some changes to your
~/.gnupg/gpg-agent.conf file. At a minimum, you will need the following option:
You may also define timers for how long
gpg-agent will cache the passphrase for your key. These are the default timers (the values are in seconds):
default-cache-ttl 600 default-cache-ttl-ssh 1800 max-cache-ttl 7200 max-cache-ttl-ssh 7200
default-cache-* options tell GPG to cache the passphrase for that length of time. Each time the key is accessed, if the timer has not yet expired it will be reset. The
max-cache-* options set the maximum time the passphrase may be cached, regardless of the last time the key was accessed.
If you have multiple
pinentry programs installed (e.g.,
pinentry-gnome3) you can instruct
gpg-agent to use a specific
pinentry with the
pinentry-program option. For example:
After you have disabled
ssh-agent and configured
gpg-agent for SSH authentication, be sure to log out of your session and log back in to pick up the new options.
Exporting your GPG key
In order to use your GPG authentication key, you'll need to export it in a form usable by OpenSSH. Use the following command to export the key to a file:
$ gpg --export-ssh -o ~/.ssh/filename.pub email@example.com
This is the key you'll copy to remote hosts for login access.
Adding your key to the agent
You'll need to add the keygrip for your authentication key to
~/.gnupg/sshcontrol. To get the keygrip for your key, use the following command:
gpg -K --with-keygrip firstname.lastname@example.org
Deploying your key
In order to login to a remote server with your GPG authentication key, you will need to first copy your exported public key to the server and store it in the file
~/user/.ssh/authorized_keys. If the server you are connecting to allows password authentication (and you have the account credentials), you can use the
ssh-copy-id command to copy your public key to the server:
$ ssh-copy-id user@remotehost
You will be prompted for the account password, and if you successfully authenticate your key will be copied to the
authorized_keys file in that user's home directory. You can then login using your key:
$ ssh user@remotehost
If the remote server does not allow password authentication then the public key must be added manually to the user's
authorized_keys file using an existing account with sufficient access:
# mkdir -p -m 700 /home/user/.ssh # cat filename.pub >> /home/user/.ssh/authorized_keys # chown -R user:user /home/user/.ssh && chmod 600 /home/user/.ssh/authorized_keys
Other configuration options
Depending on your choice of distribution,
gpg-agent may be largely configured by default and may work out of the box. If you have problems getting
gpg-agent to authenticate your SSH sessions, you may find the following useful to add to your
unset SSH_AGENT_PID export SSH_KEY_PATH="~/.ssh/filename.pub" export GPG_TTY="$(tty)" export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)" gpg-connect-agent updatestartuptty /bye >/dev/null
The first four set environment variables for your terminal session, and the last line tells
gpg-agent the TTY where it should send
pinentry prompts if you're using
/usr/bin/pinentry-curses. That option can be helpful if you have multiple terminals open and are moving between them or are using a multiplexer like
tmux. You may also want to add an alias for the last line, so that you can quickly update your current TTY if you have a problem with
pinentry authentication in the terminal:
alias fixga='gpg-connect-agent updatestartuptty /bye >/dev/null'
Using SSH key authentication
Once you have
gpg-agent configured, you should now be able to SSH to a remote server where your key has been added:
$ ssh user@remotehost
gpg-agent will prompt you for your key's passphrase, cache the passphrase, and then authenticate your SSH connection. If you start an SSH session again before the cache timer has expired, you will connect to your SSH session without being prompted for the GPG key passphrase.
When using public key authentication for SSH access, you should always secure your private key with a passphrase. A private key without a passphrase is a "bearer instrument" usable by anyone who obtains a copy of it. Use a strong passphrase, and configure
gpg-agent with reasonable cache TTLs. Remember that if your passphrase is cached, your key is subject to use with or without your knowledge by applications and scripts running under your user account.
To provide an even higher level of security for your GPG authentication key and the servers your key allows access to, check out my article Secure your GPG keys with a Yubikey 4 to learn how to move your GPG keys to a cryptographic smartcard. Doing so will help protect your authentication key (as well as your signing and encryption keys) from theft or compromise, and can provide the additional access control option of requiring that a physical button be pressed to access the private keys - even if the passphrase is cached by
I hope you've found the above information useful and interesting. If you have questions, corrections, or feedback feel free to send me an email. Thanks for reading!