SSH Certificate Notes 29 Nov 2023
There are lots of tutorials out there, but I want to compile my notes so if I walk away from playing with them again for a few years, I can pick it up again!
SSH Keys for different things are all the same (modulo chosen algo type)
User keys, host keys, CA keys -- they are all the same. Don't let ssh-keygen
docs, with all of its options and whatnot, convince you otherwise.
Use AuthorizedPrincipalsFile
to manage access
Don't go and create a local user account for everyone who may be accessing the host, just have a shared local user, probably even root
, where you differentiate who did what using the identity on the cert they authed with.
AuthorizedPrincipalsFile
is a file that lists the allowed principals for a given local user. Use groups as principals, not individual users, and list the groups which may use the local user in the file for the given local user. The groups an actual user is in are then added to that user's cert.
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
The %u
is the normal user placeholder, so /etc/ssh/auth_principals/root
would control the principals that may log in as root
. The file takes one principal per line. Copilot really wants me to add that you can use wildcards in the file, but that idea is making me queasy. Principals as groups sounds better to me.
The overall sshd_config
looks something like:
Port {{ port }}
Protocol 2
AcceptEnv LANG LC_*
LoginGraceTime 120
UsePAM no
PasswordAuthentication no
IgnoreRhosts yes
PubkeyAuthentication yes
HostKey {{ path }}/ssh_host_ed25519_key
TrustedUserCAKeys {{ path }}/ca.pub
AuthorizedPrincipalsFile {{ path }}/auth_principals/%u
Testing with sshd
You can run sshd as a normal user, as long as you only try to log in as that same user.
Invocation looks like, /opt/homebrew/sbin/sshd -d -D -f /tmp/my_ssh/sshd_config
. This will start it without forking behavior, process a single login, and give us debug output.
The sshd_config may need StrictModes no
depending on the directories in play and the permissions on them.
Various invocations
ssh with weird agent socket
Given I am doing this to test agent + cert muckery, invoking ssh to talk to the sshd mentioned above looks like:
ssh -v \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-F /dev/null \
-l $USER \
-o IdentityAgent=/path/to/agent.sock \
-p 2222 \
localhost
Same, but for a local cert instead of agent (assuming user_key
is the private key, and has user_key.pub
and user_key-cert.pub
alongside it):
ssh -v \
-o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-F /dev/null \
-l $USER \
-i path/to/user_key \
-p 2222 \
localhost
Given a CA key, generate a user cert locally
ssh-keygen -s path/to/ca -I wobble -n {{ principals }} .path/to/user_key
Add a comma seperated (no spaces) list of the principals (groups) for {{ principals }}
in that invocation (needs to align with the auth principals on sshd). The -I
is basically irrevalent for testing purposes, is just a cert identifier.