Kerberizing Keystone in HTTPD

Configuring Kerberos as the authentication mechanism for Keystone is not much different than Kerberizing any other Web application. The general steps are:

  1. Configure Keystone to Run with an LDAP backend
  2. Configure Keystone to Run in Apache HTTPD
  3. Register the Keystone server as an Kerberos Client (I use FreeIPA)
  4. Establish a Kerberized URL for $OS_AUTH_URL

Continue reading

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.

Continue reading

FreeIPA web call from Python

This was a response to a post of mine in 2010. The comment was unformatted in the response, and I wanted to get it readable. Its a great example of making a Kerberized web call.

Courtesy of Rich Megginson

Note: requires MIT kerberos 1.11 or later if you want to skip doing the kinit, and just let the script do the kinit implicitly with the keytab.

import kerberos
import sys
import os
from requests.auth import AuthBase
import requests
import json
 
class IPAAuth(AuthBase):
    def __init__(self, hostname, keytab):
        self.hostname = hostname
        self.keytab = keytab
        self.token = None
 
        self.refresh_auth()
 
    def __call__(self, request):
        if not self.token:
            self.refresh_auth()
 
        request.headers['Authorization'] = 'negotiate ' + self.token
 
        return request
 
    def refresh_auth(self):
        if self.keytab:
            os.environ['KRB5_CLIENT_KTNAME'] = self.keytab
        else:
            LOG.warn('No IPA client kerberos keytab file given')
        service = "HTTP@" + self.hostname
        flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG
        try:
            (_, vc) = kerberos.authGSSClientInit(service, flags)
        except kerberos.GSSError, e:
            LOG.error("caught kerberos exception %r" % e)
            raise e
        try:
            kerberos.authGSSClientStep(vc, "")
        except kerberos.GSSError, e:
            LOG.error("caught kerberos exception %r" % e)
            raise e
        self.token = kerberos.authGSSClientResponse(vc)
 
 
hostname, url, keytab, cacert = sys.argv[1:]
 
request = requests.Session()
request.auth = IPAAuth(hostname, keytab)
ipaurl = 'https://%s/ipa' % hostname
jsonurl = url % {'hostname': hostname}
request.headers.update({'Content-Type': 'application/json',
                        'Referer': ipaurl})
request.verify = cacert
 
myargs = {'method': 'dnsrecord_add',
          'params': [["testdomain.com", "test4.testdomain.com"],
                     {'a_part_ip_address': '172.31.11.4'}],
          'id': 0}
resp = request.post(jsonurl, data=json.dumps(myargs))
print resp.json()
 
myargs = {'method': 'dnsrecord_find', 'params': [["testdomain.com"], {}], 'id': 0}
resp = request.post(jsonurl, data=json.dumps(myargs))
print resp.json()

Run the script like this:

python script.py ipahost.domain.tld ‘https://%(hostname)s/ipa/json’ myuser.keytab /etc/ipa/ca.crt