Managing SSH Known Hosts With SSSD And LDAP
For various reasons, I manage on-premises, non-cloud infrastructure. For centralized authentication, I use PAM and
OpenLDAP along with SSSD for purposes of caching for availability and load reduction. I rely on the
openssh-lpk.openldap.schema
LDAP schema for passwordless authentication with OpenSSH, and, recently, I discovered that
the same schema can be used to centralize SSH known hosts. This post isn't intended to be a how-to, but documents some
of my findings that don't seem to be too well documented anywhere else.
Up until my discovery, I had been managing SSH known hosts with an Ansible playbook. In particular, each host public key
was added into a managed GlobalKnownHostsFile
that each client was configured to use. The SSH hosts keys were
manually added into a playbook that was then applied to all the infrastructure. Or, well, maybe applied to all of the
infrastructure. This approach worked well enough, but it was inconvenient because not all machines had 24/7 uptime.
If you're unfamiliar with the openssh-lpk.openldap.schema
, it allows you to add an arbitrary number of sshPublicKey
attributes to an LDAP entry. For example, a posixAccount
object may list all public SSH keys that the user may
authenticate with:
dn: uid=jsmith,ou=People,dc=example,dc=com
cn: John Smith
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: ldapPublicKey
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDDIqh1s3idPZ8h7aSOu9Xx4/tBlSkP1Xy...
When the SSH server is configured to use the AuthorizedKeysCommand
command with sss_ssh_authorizedkeys
binary, SSHD
will connect to the SSSD server and look-up the connecting user's public keys using the configured ldap_search_base
and/or ldap_user_search_base
SSSD configurations. If the authorized key is listed, authentication succeeds.
I recently discovered that this sshPublicKey
mechanism can further be used to manage SSH know hosts!
To accomplish this, SSSD ships with a binary, sss_ssh_knownhostsproxy
, that can be used as an SSH ProxyCommand
to
automatically look-up and cache SSH host keys within LDAP. When paired with an ldap_host_search_base
, the
sss_ssh_knownhostproxy
binary will have the SSSD server perform an LDAP search to get the sshPublicKey
attributes of
an object representing the SSH server. If the host key offered by the SSH server is listed in its list of sshPublicKey
attributes, the key is accepted without any user intervention and the connection succeeds.
The default configuration that SSSD uses didn't entirely match my current LDAP database (I'm probably using it wrong!),
but with some configuration, it can be made to work. Given a host
entry like this
dn: cn=somehost,ou=Hosts,dc=example,dc=com
objectClass: top
objectClass: device
objectClass: hostObject
objectClass: ldapPublicKey
cn: somehost
host: somehost.example.com
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4y3W1prXnx8tc6Amq+tN0fEjIPW6f+qM...
A matching SSSD configuration is capable of performing the SSH host key lookup
ldap_host_search_base = ou=Hosts,dc=example,dc=com
ldap_host_object_class = hostObject
ldap_host_fqdn = host
With SSH clients configured with a ProxyCommand
of sss_ssh_knownhostproxy
, the task of key management is completely
eliminated:
Host *.example.com
ProxyCommand /usr/bin/sss_ssh_knownhostsproxy -p %p %h
GlobalKnownHostsFile /var/lib/sss/pubconf/known_hosts
I struggled a fair bit to connect all the dots, but now that it's working, I hope this posting can be useful for somebody else.