I recently stumbled upon the rather intriguing idea of using your SSH agent to do… sudo authentication!
Sounds weird, right? But somebody implemented it. I haven’t audited the code, but it mostly does what it’s supposed to and doesn’t appear to be malicious.
What it is, though, is a PAM module that gives you an ‘auth’ module for PAM As we know, the ‘auth’ module does the whole business of validating that a user is who they claim to be by asking for credentials. Usually, we see e.g. sudo asking the user for their password.
The problem with that: remembering all those sudo passwords for remote hosts you’re administering – because, after all, you aren’t logging in as root directly, and you don’t use the same password at the other end all the time, right? Well, except if you’re using LDAP, anyway. But even then, you’d still have to enter the password (but it is the same, and you’re probably feeling fancy with ansible anyway.)
Enter pam_shh_agent_auth.so – just include it in your PAM configuration, have sudo keep SSH_AUTH_SOCK. If you now connect with your SSH agent forwarded, PAM will check the public key you specify against your forwarded SSH agent, and if that check succeeds, proceed along the PAM chain, you being happily authed! Entering a password? Only when you unlock the SSH agent.
Now that the concept has been explained, let’s think about consequences.
Is this method inherently insecure?
Well, not per se; if you think using SSH agent is okay, using it to replace a password, in principle, is okay.
Can this authentication be exploited?
There’s two possible scenarios I can imagine:
- Someone manages to take over the SSH agent.
- Someone modifies the specified authorized_keys file.
I personally do not assume that taking over the SSH agent is a significant risk; you’re probably the admin setting this up, so you trust the server and the machine you’re connecting from. The only person on the remote side that could abuse the auth socket is root, your user and someone using an 0day, but being afraid of the last won’t get you anywhere. Thus we can safely disregard that.
The only real problem I see is that somebody manages to overwrite the authorized_keys file. pam_ssh_agent_auth allows you to specify where the authorized key files are kept – you can allow them to be in any place you’d like, and there’s shorthand macros for the user’s home, the system’s hostname and the user name itself. A setup I personally like is using $HOME/.ssh/authorized_keys, because it’s a no change in place operation.
Anyone who can somehow modify or add to your authorized_keys file can take over your account and its sudo privileges!
Sample attack scenario:
- You’re an idiot and ~/.ssh/authorized_keys is world-writable.
- Someone else on the system appends their own key to your authorized_keys.
- They are connected with their own SSH agent and just do a sudo -l -u $you.
- This will now work because PAM asks the attacker’s SSH agent to unlock their key.
Is this an issue? Only if your users are idiots. Or 0day, but see above.
The easy way to work around this is to simply use a only root-controlled file, i.e. create something like /etc/security/sudoers/%u.key for each user. Or just a globally defined one where you pipe new keys in, whatever floats your boat.
But, except for taking care, this in my case is no particularly viable attack scenario either.
If anyone comes up with a good one, please let me know.
How to implement it
Simple! Just run this Puppet manifest if you’re running Debian/Ubuntu and trust me. You probably shouldn’t, but please look at the manifest anyway and improve my Puppetfu by giving clever comments about how I should approach this ‘style’ of sharing configuration.
Essentially, you need to do the following steps:
- Install pam_ssh_agent_auth, just use my Debian/Ubuntu repos (deb http://towo.eu/debian/ $your_release main)) or go to the official site.
- Add SSH_AUTH_SOCK to the env_keep defaults in /etc/sudoers.
- Add auth sufficient pam_ssh_agent_auth.so file=%h/.ssh/authorized_keys to /etc/pam.d/sudo, ideally before common-auth.
- That it’s. Open a new connection, sudo -k; sudo -l should work without you having to enter a password.
Simple as that.