For those of you unfamiliar with OpenStack, it is a collection of many independent pieces of cloud software, and they all tie into Keystone for user authentication and authorization. Keystone uses a MySQL database backend by default, and has some support for LDAP out-of-the-box. But what if you want to have it authenticate against some other service? Fortunately, the Keystone developers have already created a way to do that fairly easily; however, they haven’t documented it yet. Here’s how I did it:
- Grab the Keystone source from GitHub and checkout a stable branch:
% git clone git://github.com/openstack/keystone.git % cd keystone % git checkout stable/grizzly
- Since we still want to use the MySQL backend for user authorization, we will extend the default identity driver, keystone.identity.backends.sql.Identity, and simply override the password checking function. Create a new file called keystone/identity/backends/custom.py containing:
from __future__ import absolute_import
import pam
from . import sql
class Identity(sql.Identity):
def _check_password(self, password, user_ref):
username = user_ref.get('name')
if (username in ['admin', 'nova', 'swift']):
return super(Identity, self)._check_password(password, user_ref)
return pam.authenticate(username, password)In this snippet, we check the username and password against PAM, but that can be anything you want (Kerberos, Active Directory, LDAP, a flat file, etc.). If the username is one of the OpenStack service accounts, then the code uses the normal Keystone logic and checks it against the MySQL database.
- Build and install the code:
% python setup.py build % sudo python setup.py install
- Configure Keystone to use the custom identity driver. In /etc/keystone/keystone.conf add or change the following section:
[identity]
driver = keystone.identity.backends.custom.Identity - Start Keystone (keystone-all) and test, then save the changes to the Keystone source:
% git add keystone/identity/backends/custom.py % git commit -m "Created custom identity driver" -a
And that’s it. In reality, I would probably fork the Keystone repository on GitHub and create a new branch for this work (git checkout -b customauth stable/grizzly), but that’s not really necessary. Actually, you could probably even get away with not recompiling Keystone. Just put the custom class somewhere in Keystone’s PYTHONPATH. But I’m not a Python expert, so maybe that wouldn’t work. Either way, I like having everything together, and Git makes it brainless to maintain customizations to large projects.