mod_lookup_identity

“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:

variable_test_page

A big thanks to Jan Pazdziora for his help in getting this set up.

3 thoughts on “mod_lookup_identity

  1. 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!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.