SSH Start to Finish Architecture – AuthorizedKeysCommand

Last week we brushed upon this briefly, but this week, I’ve stood up a scenario in my lab, and am digging into the details a bit deeper.

So to set this up, there are three systems involved, currently.
1) The windows 10 laptop with the “ubuntu on windows 10 on crack” option. Using the bash shell, I created an ssh key pair, and stopped there until everything else was ready.
2) The “target” system to log into. This is an OpenBSD server that I stood up to play with asciinema earlier this weekend, and decided to utilize for this particular lab. This is the machine that will be configured to use AuthorizedKeysCommand and AuthorizedKeysCommandUser instead of AuthorizedKeysFile. On this server, I created two new groups, and two new users:
groupadd testgrp
groupadd sshpub
useradd -m -g testgrp -G testgrp -c “Test User” -s /bin/ksh -d /home/testuser testuser
useradd -m -g sshpub -G sshpub -c “SSH Public Key Provider” -s /bin/ksh -d /home/sshpub sshpub

I also created a new script: /usr/local/bin/query_ssh_pub.ksh with permissions 750 and owned by root:sshpub.
##############################################################################
#!/bin/ksh

PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
HOSTNAME=$(hostname -s)
USER=${1}
ssh -i ~sshpub/.ssh/id_rsa sshpub@192.168.0.89 “/usr/local/bin/query_ssh_pub_keys.ksh ${USER} ${HOSTNAME}”
##############################################################################

3) The “query server” system to be a central repository of ssh keys for system accounts and/or human users (hypothetically.) I created the same sshpub user and group on this system, but added a new script: /usr/local/bin/query_ssh_pub_keys.ksh with permissions 750 and owned by root:sshpub as well.
##############################################################################
#!/bin/ksh
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

if [ $# -ne 2 ]; then
exit 255
fi

USER=${1}
TARGET=${2}

echo ${USER} | grep -q -E -e ‘^[a-zA-Z0-9]+$’ || exit 255
echo ${TARGET} | grep -q -E -e ‘^[a-zA-Z0-9]+$’ || exit 255

ls /home/sshpub/key-store/ | grep -q “^${TARGET}\.${USER}\.pub\$” || exit 255
cat /home/sshpub/key-store/${TARGET}.${USER}.pub
##############################################################################

I generated an ssh key pair from sshpub on the “TARGET” server, then copied the public key file over to the “QUERY” server so that it could do a remote ssh call. If I were going to use a system like this in production, I would apply a few more sanity checks on all of the inputs, as well as consider a force command for this user either by sshd_config or by modifying the public key file, but that’s neither here, nor there. This is not an ideal way of retrieving the keys, but it demonstrates how it works in a simple manner.

Once everything was in place, I dropped a copy of the public key from the “CLIENT” laptop into /home/sshpub/key-store/asciicast.testuser.pub file on the “QUERY” server, then tested that all commands worked as intended.

Finally, I updated sshd_config to use the following entries on the “TARGET” server, and restarted sshd:
AuthorizedKeysCommand /usr/local/bin/query_ssh_pub.ksh
AuthorizedKeysCommandUser sshpub

After all of this was done, I was able to test that I could log in as “testuser” to the “TARGET” machine, and it retrieved the public key from the “QUERY” machine successfully, allowing login as expected.

The query script can call any service, really. You can call keys stored in LDAP, SQL, or any other database. The final returned result from the script should be zero or more public keys, and nothing else. The most common use of this is to query LDAP, and there are examples of an LDIF file for OpenLDAP floating around freely on the internet, if you choose to go that route. Just make sure your LDIF works for your particular LDAP service, and that you are able to sanitize the output to only present the keys in the end, when you query.

Later in the day on Monday, I may modify this post to include the asciinema player embedded to show off how this whole thing works. I’m still working on getting WordPress to let me do that, but it has gotten late on me.

I would like feedback if anyone likes this kind of thing, though. Just leave a comment!