I found this question when trying to answer it myself. After some searching and experimentation, I've found a few other options for this. I'm going to skip the part about distributing keys as an alternative since Matt Simmons covered that. Also, I know there are times when that is not good enough. For example, if you are GitHub and have to store millions of public keys against a single user, continuously updating SSH authorized_keys files and keeping them synchronized across potentially dozens to hundreds of edge boxes is not feasible or desirable.
First of all, RedHat (and variants) have a supported patch for OpenSSH that adds the
AuthorizedKeysCommandRunAs options. The patch has been merged upstream in openssh 6.2. To quote from the man page:
Specifies a program to be used for lookup of the
user's public keys. The program will be invoked with its first
argument the name of the user being authorized, and should produce on
standard output AuthorizedKeys lines (see AUTHORIZED_KEYS in sshd(8)).
By default (or when set to the empty string) there is no
AuthorizedKeysCommand run. If the AuthorizedKeysCommand does not
successfully authorize the user, authorization falls through to the
AuthorizedKeysFile. Note that this option has an effect only with
PubkeyAuthentication turned on.
Specifies the user under whose account the
AuthorizedKeysCommand is run. Empty string (the default value) means
the user being authorized is used.
In my experiments tonight, I found that out of the box, this doesn't work due to default SELinux policies. You can get around this by turning off SELinux enforcement with
setenforce 0. Since turning of SELinux is probably a bad idea, instead you can generate the correct policy. In my case, that was as simple as attempting to log in with the
AuthorizedKeysCommand option set up in
/etc/ssh/sshd_config and then using
audit2allow -a -M local && semodule -i local.pp. This basically looks through the audit logs and finds things that were prevented and generates exceptions for them. If you are likely to have other stuff in there that might get whitelisted, you should probably learn more about
audit2allow to make sure you get the new policies just right.
There are other various (probably less tested and trusted) patches out there to add similar functionality. For example there is, openssh-script-auth. You can also find the patch that RedHat used and apply that directly. A quick bout of Googling uncovers https://launchpadlibrarian.net/89063205/openssh-5.3p1-authorized-keys-command.patch and https://launchpadlibrarian.net/105938151/openssh-authorized-keys-command.patch which are based on the RH versions but which have been updated for newer versions of OpenSSH.
Patch OpenSSH to perform key lookups directly from some store (e.g. like GitHub and CodeBaseHQ and others have done). GitHub has not open sourced this patch, to the best of my knowledge, but I know in the past I've come across versions for MySQL and PostgreSQL key lookup. I tried to find them again just now but have not had much luck.
There are also some FUSE-based options. For example there is LPKFuse which lets you serve public keys from LDAP by changing the
AuthorizedKeysFile location to one on the LPKFuse filesystem. The LPKFuse FS creates virtual files whose content are backed by fields from a directory server.
All in all, I think option #1 is by far the best as it is officially supported by RedHat. Furthermore, it lets you put any logic you like in that script (including talking to a database) in any language you want.