“Don’t repeat yourself.” This rule is such a core principal in programming it has been reduced to the acronym DRY. Yet, somehow, every web application framework out there ends up with a custom authorization framework; LDAP, SQL, and usually a Flat File authorization list.
Apache HTTPD can and should perform a cryptographic based authentication for your users. Even better, it should be able to return to you the user attributes necessary to perform accurate authorization. REMOTE_USER has been the standard ever since CGI first appeared for the web. Now we can extend that approach to a generic set of user attributes for authorization. mod_lookup_identity.
I’m starting on a proof-of-concept setup where, instead of using the LDAP backend for Keystone, I use mod_identity_lookup to fetch the data at the HTTPD layer. Here are the steps I went to configure the system.
This machine is already registered as a FreeIPA client. That has configured all of the LDAP and Kerberos setup already.
EDIT: It is no longer necessary to get sssd code from an external repo. I removed that section.
mod_identity_lookup uses DBUS to talk to SSSD. You can query SSSD via DBUS using dbus-send. One thing implemented in the modified version of sssd-dbus is a new set of connections in the namespace org.freedesktop.sssd.infopipe. For example, I can query the set of groups for a user via the call:
sudo dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe org.freedesktop.sssd.infopipe.GetUserGroups string:ayoung |
If I want to fetch additional attributes out of LDAP via SSSD, I can modify /etc/sssd/sssd.conf and add in the attributes. In the domain section:
[domain/cloudlab.freeipa.org] ldap_user_extra_attrs=email:mail, sn:sn, givenname:givenname |
For example, I added the following lines to the end of my sssd.conf file:
[ifp] allowed_uids = apache, root user_attributes = +mail, +givenname, +sn, +uid |
To make the changes effective, restart sssd and flush it’s cache:
sudo systemctl restart sssd.service sudo sss_cache -E |
And now I can query for those values via
sudo dbus-send --print-reply --system --dest=org.freedesktop.sssd.infopipe /org/freedesktop/sssd/infopipe org.freedesktop.sssd.infopipe.GetUserAttr string:keystone array:string:mail,givenname,sn |
Which returns:
method return sender=:1.87 -> dest=:1.91 reply_serial=2 array [ dict entry( string "mail" variant array [ string "keystone@cloudlab.freeipa.org" ] ) dict entry( string "givenname" variant array [ string "Key" ] ) dict entry( string "sn" variant array [ string "Stone" ] ) ] |
In order to confirm my setup is working, I created a simple wsgi app (HTTP server is already set to use mod_wsgi) and put it in /var/www/cgi-bin/keystone/hello.py
def application(environ, start_response): status = '200 OK' remote_user = environ.get('REMOTE_USER') email = environ.get('REMOTE_USER_EMAIL') remote_groups = environ.get('REMOTE_USER_GROUPS') output = """ <html> <head> <title>%(title)s </head> <body> <h1>%(title)s <dl> <dt>REMOTE_USER <dd>%(username)s <dt>REMOTE_USER_EMAIL <dd>%(email)s <dt>REMOTE_GROUPS <dd>%(remote_groups)s <dl/> </body> </html> """ % {'title':'Variable Test Page','username':remote_user, 'email': email, 'remote_groups':remote_groups} response_headers = [('Content-type', 'text/html'), ('Content-Length', str(len(output)))] start_response(status, response_headers) return [output]
To configure the web server, I have the following in /etc/httpd/conf.d/wsgi-keystone.conf. It just needs to be after the wsgi configuration in your HTTPD config directory.
LoadModule lookup_identity_module modules/mod_lookup_identity.so WSGIScriptAlias /keystone/hello /var/www/cgi-bin/keystone/hello.py WSGIDaemonProcess keystone_hello_wsgi user=fedora group=wheel maximum-requests=10000 <Location "/keystone/hello"> WSGIProcessGroup keystone_hello_wsgi AuthType Kerberos AuthName "Kerberos Login" KrbMethodNegotiate on KrbMethodK5Passwd off KrbServiceName HTTP KrbAuthRealms IPA.CLOUDLAB.FREEIPA.ORG Krb5KeyTab /etc/httpd/conf/openstack.keytab KrbSaveCredentials on KrbLocalUserMapping on Require valid-user NSSRequireSSL LookupUserAttr mail REMOTE_USER_EMAIL " " LookupUserGroups REMOTE_USER_GROUPS ";" </Location> |
Once it is configured, can test the output with a browser. This is what mine looks like:
A big thanks to Jan Pazdziora for his help in getting this set up.
Hey Adam,
pretty cool article, thanks for writing this all up!
I have one clarification, though — one sentence reads “SSSD uses DBUS to talk to remote services.”. That’s not quite accurate, the SSSD uses standard protocols such as LDAP to fetch data from remote services, saves them locally and only then makes the data available on the system bus.
While I’m already banging the SSSD drum 🙂 I’d like to point out what you get by using this integration instead of running the LDAP searches yourself. Basically it’s all the dirty work that might not be apparent at the Proof-of-Concept stage but is crucial for an enterprise environment, like service discovery, failover, easy GSSAPI configuration, offline caching, better performance etc.
Thanks again for the blog post!
Fixed that. Should have read “mod_identity_lookup uses DBUS to talk to SSSD.”
Besides Kerberos, you can make it work with mod_authnz_external via PAM as well. See
http://adam.younglogic.com/2015/03/key-fed-lookup-redux/comment-page-1/#comment-844457
BTW, the sssd d-bus package is not officially supported in Ubuntu 14.04 LTS (Trusty). You’ll have to get it from here
https://launchpad.net/~sssd/+archive/ubuntu/updates
mod_lookup_identity is also not supported. You’ll have to get the source and build it on Trusty.