Here’s yet another thing that hit me at work today, and getting the answer involved annoying searching & testing, so here it is for you!
I use a Debian jessie workstation, and my SSH key lives on a Yubikey. We don’t really use pubkey-based authentication in my area (we use Kerberos), so the first time I needed to do a pubkey-authenticated SSH connection was to clone one of my Github repositories. When doing the clone, I got the mysterious message “Agent admitted failure to sign”. GitHub talks about this error, but their article only talks about locally-stored keys (like id_rsa keys). My private key lives on the Yubikey, so their article didn’t really work for me.
Doing some investigation, I could see that my SSH client was trying to authenticate, and it did see my Yubikey, but still the authentication was failing. If you have this problem, there are two important things to check:
- Your GPG Agent must be running with SSH support.
- Your authentication key’s keygrip needs to be loaded in the .gnupg/sshcontrol file.
My problem was actually #2, but #1 is important to mention!
SSH Support in GPG Agent
The GPG Agent is able to act as an SSH Agent, speaking the ssh-agent protocol, as long as it has been told to do so. In order for this to work, you need to specify –enable-ssh-support in the gpg-agent command line, or add “enable-ssh-support” in ~/.gnupg/gpg-agent.conf.
To confirm this, check your gpg-agent, and check for the appropriate environment variables:
blargh:~> env | grep SSH SSH_AGENT_PID=7631 SSH_AUTH_SOCK=/tmp/gpg-VRUFdK/S.gpg-agent.ssh blargh:~> ps xaw | grep gpg-agent 7631 ? Ss 0:00 gpg-agent -c --daemon --enable-ssh-support 9425 pts/6 S+ 0:00 grep gpg-agent
SSH_AGENT_PID contains the process ID of the ssh-agent, which is actually gpg-agent. Also, SSH_AUTH_SOCK points to a special socket that gpg-agent creates, meant for connections speaking the ssh-agent protocol.
If SSH_AGENT_PID is pointing to a different process, you may have ssh-agent running somewhere else. You should find out what is running ssh-agent, and stop it. gpg-agent is able to manage locally-stored keys (like id_rsa), so I don’t think there’s a need to run ssh-agent, as long as you are running gpg-agent with SSH support.
If SSH_AGENT_PID isn’t specified at all, or you just added “enable-ssh-support” to ~/.gnupg/gpg-agent.conf, then you’ll need to restart gpg-agent. In many cases, it’s easier to log out and log back in, so that everything picks up the new gpg-agent.
The sshcontrol File
This is what affected me.
The file at path ~/.gnupg/sshcontrol contains a list of “keygrips” for SSH that gpg-agent will use for ssh-agent authentication. Even if gpg-agent is configured and can see your key, it will not work unless it’s listed in the sshcontrol file! For local keys, running ssh-add will automatically add them to the sshcontrol file, but that doesn’t work for keys that live on an OpenPGP card.
I had gpg-agent running with SSH support, but gpg-agent does not automatically add keys that are already on an OpenPGP card, so it’s up to you. What you need to do is…
- Extract the keygrip.
- Add the keygrip to the sshcontrol file.
- Restart gpg-agent.
Extracking the keygrip is pretty easy to do, using this string of commands:
blargh:~> echo 'scd learn --force' | gpg-connect-agent | grep KEYPAIRINFO S KEYPAIRINFO 6E6D1675B29724F4D4A2250EDE5A0634B4E06884 OPENPGP.1 S KEYPAIRINFO 83D4B4FA304DC7F74FD930B052D1694C0B0CEBB0 OPENPGP.2 S KEYPAIRINFO E1846F4F5B1D6ABF537BC738CC3E840106457F13 OPENPGP.3
Each line of output contains the keygrip for one of the three keys on your OpenPGP card: The encryption key, the signing key, and the authentication key (which is the one we want). The third line, for “OPENPGP.3”, contains the keygrip for the authentication key.
To update the sshcontrol file, simply add the keygrip to the file, on its own line. So, in my case I would add the following line to ~/.gnupg/sshcontrol:
After you update the sshcontrol file, you need to restart gpg-agent. Again, the safest way of doing that is to log out and log back in, so that everything picks up the new gpg-agent environment variables.