When we first learn to connect to a server via SSH, we do it with the only means we know: passwords. Those small, predictable and insecure pieces of text. Once we figure out we can do better, we use a password manager or a similar mechanism to make our passwords safer and protect our servers from our lazy mind (which wants us to use the same password for everything).
After that we learn about public key cryptography and how we can use that to create SSH keys, which are considered a better practice than using passwords. We just tell our servers which is our public key and they will grant us access without more questions.
That’s working well, we have access to what we need to, and we are happy with our flow. Then our organization starts growing up and we start noticing that we must either grant access by hand to each user per server. Either that or use the same key for all servers and share the key (don’t).
It is getting out of hand. We need to remember who has access to what and if we want to restrict access, that’s going to be more complex over time.
What could be a good solution to this dilemma? Think about for a second. You want to manage access to your servers and know at every moment who has access to what. What we found out when looking for a solution of this kind, was LDAP (Lightweight Directory Access Protocol). In short, we can have an authentication server where the other servers can look for public keys and grant access if they are allowed to, without directly going to every server to update that information.
Working with LDAP
There is an open source implementation known as OpenLDAP. LDAP allows you to have a centralized database for your users, where you keep all the relevant information for them. You can add fields to the users schema, allowing you to have a field with the public key, which is the one the servers should ask for.
On every server, you install a LDAP client, you grant him access to read the information of your users in the LDAP server and change the way SSH looks for AuthorizedKeys so it uses the result of the query instead of the local ones. The client installation process may look like too much work at the beginning, because it has to be done server per server, but that can be easily automated.
Users can be allowed access by name, group, etc. That give us a lot more flexibility than what we had previously.
Advantages of this proposal
Assume that you have a group of database servers, and you want to allow access to those servers only to your dbadmins. You create a dbadmin group and grant access to that group in every db server. If you want to stop someone from login to those servers, you just remove them from the group and that’s it, they won’t be able to keep authenticating.
Another advantage is that you will know who logged where, because they will be using their own credentials, and even if this was not scalable without a centralized login servers, it is now. If something happens, you have the logs to tell you who was logged in when the incident happened.
There are always a million ways to do things and you must always look for the one that offers you a good trade-off between complexity and security. Managing many servers as your organization can get out of your hands quite fast, and this is a viable alternative to keep everything under control.
I have not added a single line of code or configuration because it is more important to me to expose the behavior I want than my specific implementation, which still may have space to improve.