--- title: Secure Shell --- # SSH There are a number of different methods for using SSH with a yubikey. Most of them however require either proprietary components, or modifications to servers. Such methods are broken and should not be promoted. Here we will cover only methods that use standard tools, standard protocols, and don't allow secret keys to come in contact with system memoy. Secondly solutions here do not require any server modifications. This is key because you will not be able to modify all systems you use that provide ssh interfaces such as Github ssh push. ## PKCS11 With this interface it is possible to generate an ssh private key in a particular format that can be stored inside a PKCS11 capable device such as a Yubikey 5. While this does not offer nearly as many assurances as the GPG setup detailed below, it is the simplest to setup. Note: Due to limitations in the PKCS11 spec, it is not possible to generate keys stronger than 2048 bit RSA with this method. Consider the security requirements of your organization before using this method. ### Generation For a set of manual steps on how to set this up see: [https://developers.yubico.com/PIV/Guides/SSH_with_PIV_and_PKCS11.html] To simplify this process consider the following script: [https://gist.github.com/lrvick/9e9c4641fab07f0b8dde6419f968559f] ### Usage Since SSH will by default only scan folders such as ~/.ssh/ for keys you will need to inform it that you wish it to also check for smartcards via the OpenSC interface. Before using ssh commands be sure you have started your ssh agent like so: ``` ssh-add -s $OPENSC_LIBS/opensc-pkcs11.so ``` ## GPG ### Configure SSH to use your Security Token This assumes you already have a Security Token configured with a GPG Authentication subkey. The end result will be that you distribute the SSH Public Key from your Security Token to all VCS systems and servers you normally connect to via SSH. From there you will need to have your key insert it, and tap it once for every connection. You will also be required to tap the key for all SSH Agent forwarding hops removing many of the security issues with traditional ssh agent forwarding on shared systems. #### Most Linux Distros If you are using a recent systemd based distribution then all the heavy lifting is likely already done for you. We recommend simply adding the following to "/home/$USER/.pam_environment": ``` SSH_AGENT_PID DEFAULT= SSH_AUTH_SOCK DEFAULT="${XDG_RUNTIME_DIR}/gnupg/S.gpg-agent.ssh" ``` #### Mac OS, WSL, Non-Systemd Linux Distros ``` echo >~/.gnupg/gpg-agent.conf <> ~/.gnupg/gpg-agent.conf ``` Edit your ~/.bash_profile (or similar) and add the following lines to use gpg-agent (and thus the Security Token) as your SSH key daemon: ``` # If connected locally if [ -z "$SSH_TTY" ]; then # setup local gpg-agent with ssh support and save env to fixed location # so it can be easily picked up and re-used for multiple terminals envfile="$HOME/.gnupg/gpg-agent.env" if [[ ! -e "$envfile" ]] || ( \ # deal with changed socket path in gnupg 2.1.13 [[ ! -e "$HOME/.gnupg/S.gpg-agent" ]] && \ [[ ! -e "/var/run/user/$(id -u)/gnupg/S.gpg-agent" ]] ); then killall gpg-agent # This isn't strictly required but helps prevents issues when trying to # mount a socket in the /run tmpfs into a Docker container, and puts # the socket in a consistent location under GNUPGHOME rm -r /run/user/`id -u`/gnupg touch /run/user/`id -u`/gnupg gpg-agent --daemon --enable-ssh-support > $envfile fi # Get latest gpg-agent socket location and expose for use by SSH eval "$(cat "$envfile")" && export SSH_AUTH_SOCK # Wake up smartcard to avoid races gpg --card-status > /dev/null 2>&1 fi # If running remote via SSH if [ ! -z "$SSH_TTY" ]; then # Copy gpg-socket forwarded from ssh to default location # This allows local gpg to be used on the remote system transparently. # Strongly discouraged unless GPG managed with a touch-activated GPG # smartcard such as a Yubikey 4. # Also assumes local .ssh/config contains host block similar to: # Host someserver.com # ForwardAgent yes # StreamLocalBindUnlink yes # RemoteForward /home/user/.gnupg/S.gpg-agent.ssh /home/user/.gnupg/S.gpg-agent if [ -e $HOME/.gnupg/S.gpg-agent.ssh ]; then mv $HOME/.gnupg/S.gpg-agent{.ssh,} elif [ -e "/var/run/user/$(id -u)/gnupg/S.gpg-agent" ]; then mv /var/run/user/$(id -u)/gnupg/S.gpg-agent{.ssh,} fi # Ensure existing sessions like screen/tmux get latest ssh auth socket # Use fixed location updated on connect so in-memory location always works if [ ! -z "$SSH_AUTH_SOCK" -a \ "$SSH_AUTH_SOCK" != "$HOME/.ssh/agent_sock" ]; then unlink "$HOME/.ssh/agent_sock" 2>/dev/null ln -s "$SSH_AUTH_SOCK" "$HOME/.ssh/agent_sock" fi export SSH_AUTH_SOCK="$HOME/.ssh/agent_sock" fi ``` Now switch to using this new setup immediately: ``` $ killall gpg-agent $ source ~/.bash_profile ``` ### Get SSH Public Key You (or anyone that has your GPG public key) can get your SSH key as follows: ``` $ gpg --export-ssh-key you@email.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCcjW34jewR+Sgsp1Kn4IVnkb7kxwZCi2gnqMTzSnCg5vABTbG jFvcjvj1hgD3CbEiuaDkDqCuXnYPJ9MDojwZre/ae0UW/Apy2vAG8gxo8kkXn9fgzJezlW8xjV49sx6AgS6BvOD iuBjT0rYN3EPQoNvkuqQmukgu+R1naNj4wejHzBRKOSIBqrYHfP6fkYmfpmnPyvgxbyrwmss2KhwwAvYgryx7eH HRkZtBi0Zb9/KRshvQ89nuXik50sGW6wWZm+6m3v6HNctbOI4TAE4xlJW7alGnNugt3ArQR4ic3BeIuOH2c/il4 4BGwdRIp7XlSkkf8cZX59l9kYLaDzw4Z cardno:000603703024 ``` You can paste that into your list of authorized keys on all VCS and systems you have access to. You should disable any other keys that are not backed by a Security Token.