Poll HN: Do you use SSH certificates (not mere public-key authentication)?
Do you use SSH certificates for work and/or personal SSH logins?
I have just switched, for my personal machines, but dealing with the CA keys is a royal pain.
What on earth do people to do keep their CA keys accessible but secure?
(You can choose multiple options below)
155 comments
[ 38.6 ms ] story [ 426 ms ] threadIf you don't know about them, you can probably answer "no" in this poll :)
Note that this is a blog about X509 certificates, not SSH certificates! That blog page does link to https://smallstep.com/blog/diy-single-sign-on-for-ssh/ which is about SSH certificates.
I have wanted to go that step further and implement certificates for a good few years now, I absolutely see the value, no question about it (i.e. no more out of date authorized_keys files, no need to even install authorized_keys files in the first place, the list goes on).
I wish YubiKeys were more flexible in allowing SSH certificates to be hosted on them (currently can only host X509 type). Because if I could use a Yubi for SSH certificate signing I would have already been using certificates ! (Yes I know, theoretically you can do it with GPG keys, but frankly that's a PITA with many issues).
My current plan is to take inspiration from this : https://smallstep.com/blog/diy-single-sign-on-for-ssh/
However, if the author of a piece of security software tells me something is a bad idea, I tend to accept that, especially if that author is mjg59.
- https://keepassxc.org/docs/#faq-ssh-agent-how
- https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.ht...
You could probably also put the SSH key itself as a resident key on the YubiKey. But personally I like the fact the key and 2FA aren't on the same device (and the fact you can only get my key when you know the KeepassXC master password).
what doesn't work is storing the signed certificates
A FIDO token can also act as CA, though the certificates it issues will be limited to use by relatively recent SSH versions as FIDO support was only added in 2019.
So you get extra security (credentials are dynamic and short -lived, and also per-user if needed) and lower maintenance because you only have the SSH CA public key to setup on all machines and that one needs less rotation/updates than public keys.
The main difference is that with an ssh key, you install the public key directly on the target host. With a certificate, you Just tell the host to trust a CA, and use that CA to sign client certificates.
This is hardly "lower maintenance" than pushing updates to the authorized_keys across servers.
Or having servers poll for such file.
I think the certificate system is especially great for certificate login from multiple devices. At some point I was just constantly copying/updating authorized_keys files and with SSH certificates I can just provision my clients once and the problem is solved, assuming I use the same username everywhere.
On the server side it's kind of annoying to set up right because there's no easy process like ACME for SSH certificates. Depending on how much effort I want to put into (temporary) virtual machines I'll either TOFU the host certificate or go through the effort to properly sign it if I have easy access to the CA key from the device I'm working on.
For signing SSH certificates, we run a small service (prototype code dump at https://github.com/pardot/sshsigner) that uses this key to sign short lived certificates. Auth to the service is via OIDC issued ID tokens.
On the client side we have a custom SSH agent that uses an ephemeral in-memory private key. The agent manages the OIDC web flow and calling out to the service for signing on demand. This lets us keep the cert duration small and scoped, and allows us to force re-auth for sudo etc. via the web flow.
We also do a similar thing for host keys, IAM auth the instances and sign certificates.
Altogether works well, provides a nice user experience, and keeps long-lived/leakable creds out of out environment.
On the other side, as a personal user of SSH with basically one person to worry about, the effort of setting up a certificate seems like just a waste versus the existing key-based infrastructure; I don't understand at all what attack it would prevent or what convenience it would provide for the cost of learning it.
A general principle is you get good at what you do a lot, and you aren't good at what you do rarely. Key-based management has its issues, but people have been doing it for a while and they're good at it. Not necessarily "great" and not necessarily "unable to be improved", but they're good at it. People understand it and know how to use it. Nobody uses certificates, so nobody understands how they work or what to do with them, and they have the weakness I cited above. So, even though in a perfect world certificates may be superior, in the world we live in now, the competition between the existing polished infrastructure for pure key-based management is pretty good, even if you think it's a polished turd, and the infrastructure for SSH certs is pretty bad, even if you think it's an uncut diamond in the rough. It's difficult to look at that situation and honestly choose to proceed with the certificates.
As others point out, the cloud services are proceeding in other directions as well which will probably continue to make using SSH certificates directly a very difficult choice to practically justify.
To your point about clouds making it more difficult in the future, it's becoming more challenging to scale the CA across auto scaling groups with dynamic IPs and where you can't control TXT records. We've found that SSH keys are very flexible, and we simply needed a centralized management point (which we have now), but with decentralized operation in case anything is offline along the way. Also, it's very important to us to be able to kill active sessions globally when a user is removed, and there doesn't seem to be any other tools that do that except Userify.
The main benefit I get from using SSH certs at home is expiration. Before, I always had a niggling feeling at the back of my mind that the public key I’d been using for four years could have been surreptitiously exfiltrated by some shell script three years ago, and I’d never notice.
Now my certificates expire regularly, so I no longer have to worry about whether my machine remained secure throughout the entire continuous past; I only have to worry if my machine is secure in the present.
Compared to my desktop, where over the years I ran all kinds of stuff from the package manager, downloaded Python scripts and configure scripts from GitHub and Sourceforge… I tried to be careful but you can’t audit everything.
No, the only files served to the LAN are the certificates, which contain the signatures by the CA of the public keys of other machines. Those are safe to distribute openly because they’re useless without the private key of the public key that was signed.
If so, how do you issue the certificates that live on RPi? Those certificates have some limited validity period, so that you can worry less about leaking them, which was your concern in the first place. Therefore, you must reissue them on a regular basis. How do you do that? What’s your process for that?
Yep.
> There are some other machines that you want to SSH into. They trust CA public key.
Yep, with TrustedUserCAKeys.
> The remote servers trust the certificate issuer, verify that you own the certificate’s private key, and let you in.
Yep. Additionally, the servers themselves present CA‐signed certificates alongside their host keys. My GlobalKnownHostsFile contains the CA public key, so when I connect to a host for the first time, there’s no “unknown host” warning and my user’s known_hosts file is not updated.
> If so, how do you issue the certificates that live on RPi?
The CA has a directory containing the public keys of every user and host that I set up. A cronjob periodically runs ssh-keygen -s against these files, and copies them to htdocs. Each host and user has a cronjob that periodically fetches its certificate and copies it to /etc/ssh or ~/.ssh, respectively.
https://man.openbsd.org/ssh-keygen.1#CERTIFICATES
Userify also lets you force key rotation for your team and automatically removes their accounts from servers if they don't rotate quickly enough.
In another comment I went into more detail about how I keep the CA secure.
Or, just paste your public key into your Userify profile and the same thing happens in seconds for every server that you have authorization for. Even better, there's no dependency on having a CA up and running in order to be able to log in; since your account is a regular local Linux account (just managed centrally), you log directly into the server with no need for that server to confirm your login elsewhere.
But I've been burned before when a central auth server was down and I couldn't log into my servers (through no fault of my own), so I wouldn't want to go back to the old "please wait until we check your login against a central server" model again.
> But I've been burned before when a central auth server was down and I couldn't log into my servers
There is no central auth server involved here. My servers check login credentials against the CA’s public key, which is installed alongside my sshd config file. I make my certificates valid for three weeks, but regenerate them every two, so if some failure happens with creating or fetching certificates I have a week to notice and fix the problem.
0. https://github.com/userify/shim/blob/master/shim.py
> I only have to worry if my machine is secure in the present
No. If a host has been accessed by an attacker due to an exfiltrated key in the past it's tainted forever.
It’s more convenient for me than updating authorized_keys. When I build a new machine, for example, I first generate a new SSH keypair on the machine. Then I copy the server and user public keys to the CA. Once I drop them in the right folder, certificates get generated automatically and served over HTTP. Then on the new machine I set up cronjobs to refresh the certificates every two weeks. I didn’t have to update authorized_keys on a dozen other machines, and I didn’t have to inspect any host fingerprints.
> If a host has been accessed by an attacker due to an exfiltrated key in the past it's tainted forever.
Yes, that’s obvious (although I did mention shell script in my previous comment—been a while since I thought this through). The scenario I imagined at the time was more like, did I ever copy my private key to an unencrypted flash drive, and then lose the flash drive? I never let private keys leave a machine anymore, but maybe I wasn’t so strict about that five years ago, and when did I generate my main SSH keypair? Was it four, five, six years ago? I no longer have to worry about such things. I could have just rotated my keys, but with short‐lived certificates I now get the benefits of key rotation without having to do any of the work.
Now I tie all my SSH keys to a WebAuthn key, which provides even more protection, because within the three‐week window that my certificates are valid, an attacker would have to also physically possess my Yubikey.
I have no mechanism at the moment for revoking host keys, which is a harder problem to solve as it would involve updating a number of laptops, phones, etc. that may not be powered on at a given time, but that’s less of a problem since if I knew a host key had been compromised I wouldn’t be logging into it anyway.
Now you have two critical systems to protect instead of one: the Raspberry Pi and the CA.
Have you considered integrating this with the SSO provider you are almost certainly already using as 1k strong org? Basically, create groups in Okta or whatever you’re using, delegate management of these groups to whoever you want, and then configure Teleport to use those groups for authorization in various contexts.
If "no long-lived keys on laptops" and "central authority for who gets access to what with which credentials" aren't principles for your security practice, then you're right: there's not much of a win to switching to a CA model.
Thanks for calling it out though; if you read it that way, they might have too, which would be a little mortifying.
I know it's not perfect, which is why I contrasted "polished turd" to the "uncut diamond in the rough". We're at a size where it's really hard to justify a whole lot of work on the uncut diamond, in contrast with the various cloud efforts to fix their problems. Given that such things now exist it's more a matter of moving over to them than developing anything ourselves now, which is probably an improvement over where we were two years ago. We probably couldn't have beaten the clouds even if we did put the effort in; this is in that class of problem where the effort is nominally small but the price of not breaking things is so large than it ends up a multi-year project anyhow. (One of my least favorite classes of project.)
I'd also add that I report this not in the spirit of "we've solved this problem", but just an experience report.
Cert sigantures expired after 30 min so leaks were not a problem.
It was backed by DynamoDB and the keys were in memory so everytime the containers rebooted someone would have to manually unseal before SSH would work again.
[1] - https://www.hashicorp.com/blog/managing-ssh-access-at-scale-...
I wrote a little tool that allowed you to "#include" other DNS records etc, but "hesinfo" is generally easily installable/available so it's just easier.
Also, can the DNS server be public facing? Any issues with the authorized keys being public (AFAICT there isnt but i am not a security expert)?
Someone can take your authorized keys and add them to a box they control, and trick you into logging in.
However, this would trigger the "new host" warning SSH gives you, and you can minimize this by minimizing which hosts you allow your private keys to be used on.
And if someone is so actively trying to attack you they probably have more direct methods available.
EDIT: I mixed up authorized_keys and known_hosts. But, the remote server doesn't need your authorized_keys file to grant you access so not sure the visibility of authorized_keys matters.
& as bombcar said, obviously if you ignore "unknown host" warnings, you can be tricked into logging into an attacker-controlled machine.
Often key files also contain "user@host" for the user&host the key was generated by&on. This identifier is then leaked, and you might want to avoid that. On my personal (and very objective! /s) paranoia scale this a 8/10. I'd definitely point it out to a customer during a pentest, but wouldn't really care if they "fixed" this (most of the time there is a lot of stuff that's more serious than knowing that the devops person is 'bro2000@jims-laptop').
https://en.m.wikipedia.org/wiki/Hesiod_(name_service)
Introducing any outside actors at all objectively diminishes the security of the whole model by becoming another link in the chain, even if that link isn't necessarily the weakest (and I certainly believe it would be, because both DNSSEC and the public Certificate Authority industry are object lessons for the abject failure of highly centralized global, government-wide, or even just company-wide security), but simply increasing any of the surface area is enough to decrease the security of the system.
1) You don't have to ssh-copy-id to new boxes, which is nice.
2) You can de-auth a key for all machines by changing the DNS record. This would depend on some propagation time but perhaps you can point the resolver at your nameserver directly which would avoid that.
In that case, use the SSL certs directly. You'd have add support OpenSSH of course, or just convert the certificates to SSH format, but it would be architecturally much simpler.
As to the original question here, the benefit compared to other PKI alternatives (including the SSH PKI in the original question) is that revocation is much easier.
Auth is handled in a browser e.g. by Google, and the CA will sign a key and return a cert with a valid token.
But certificates - no. I don't see the need for this in my home environment. In my opinion it only makes sense if you have a PKI, in which case you already have the whole CA scenario covered.
I found these SSH features while studying the ssh-keygen(1) man page. I don't use extra tools aside what SSH ships.
Every approach has strengths and weaknesses, the password-less method is convenient... but is the number one target for worms/bots. =)
But they are both systems intended to provide secure storage of key material with policy-based access to that key material. As an SSH CA, you can configure Vault to sign SSH pubkeys but never divulge the key material. Depending on your threat model, it might get you what you want for this use-case, but you should definitely be aware of the limitations of Vault's security model.
I think this approach has fallen out of favour these days compared to PKI, but I haven't been an enterprise sysadmin in a few years.
Edit: for those curious, ephemeral access in this case is easily enough managed via e.g. the usual AD-on-*nix methods. It doesn't scale beyond a few dozen systems, but the scenario described above was back before scale-out became the fashion.
I could be missing some less obvious use cases, but if you're just authenticating to your personal machines, it doesn't seem worth it. It's not any more secure than SSH keys, and you have to also manage and secure your CA key.
Sadly, the Windows GPG build and Win32-OpenSSH don't talk to the agent the same way, so it doesn't work there. (AFAIR Windows GPG - and Putty - uses "Assuan" while Win32-OpenSSH uses named pipes just like *nix SSH/GPG do.) I don't think PIV would help that though :(
Like the other reply though, I keep my private SSH key on the YubiKey, protected with both a PIN and a password. I can SSH from any computer as long as I can install gpg on it.
And it means I have to care less about what agent I'm running most of the time.
I also created a "playground" which can be used to stand up such an environment running in Docker containers to better understand the process: https://github.com/dmuth/ssh-principal-and-ca-playground
Hope folks here find them helpful.
Only downside is that at the moment it doesn't play with SELinux which is a bit unhelpful for me given I mostly use Fedora.
At work we deployed Tailscale company wide but we almost entirely use subnet routers and don't have Tailscale on each node. So it only gets you as far as an SSH bastion. We instead rely on standard SSH keys to reach individual nodes and another third party service that dynamically provisions accounts and authorized_keys on machines when you try to login.
I would kill for something as simple and clean as Tailscale SSH for all of our nodes at work. Especially since it has ACLs and optional "check mode" which forces re-auth/2FA for high risk nodes.
[0] https://roumenpetrov.info/secsh/