Microservices and Kerberos Authentication

kerberos authentication is used to secure a variety of big data products like apache hadoop and more recently apache kafka (>0.9). in case of hadoop it is used to authenticate each user and service in order to use the hadoop ecosystem. also a lot of modern nosql databases offer support for kerberos, for example apache cassandra and mongodb. kerberos authentication can also be useful in microservice architectures. it can be used to achieve single sign on functionality. a property that is less known is the possibility to delegate tokens to sub services.

in a microservice architecture you probably have an api gateway which is a single entry point for a native mobile app or a html5 application. the gateway can forward requests to several microservices and aggregates the results in a single response.

image title

source: http://microservices.io/patterns/apigateway.html

the challenge here is to know which user is logged in at the backing rest services. in case of kerberos it is possible to delegate the user credentials to these rest services. these microservice can validate the credentials again.

how does this work in java?

since java is enterprise ready there is support for kerberos since the early days (jdk 1.4) by the gss-api . however, this api is pretty awkward to use. luckily there is a kerberos plugin for spring security but this plugin has no out of the box support for credential delegation. so i have written some code to create a delegated service ticket: (note that this ticket is also forwardable)

import org.ietf.jgss.*;
import org.springframework.security.core.context.securitycontextholder;
import org.springframework.security.kerberos.authentication.kerberosservicerequesttoken;

import javax.security.auth.subject;
import java.security.privilegedexceptionaction;

public static byte[] createservicetoken(string servicename) throws exception {
    kerberosservicerequesttoken authentication = (kerberosservicerequesttoken)
       securitycontextholder.getcontext().getauthentication();

    subject subject = authentication.getticketvalidation().subject();

    return subject.doas(subject, (privilegedexceptionaction<byte[]>) () -> {
        gssmanager manager = gssmanager.getinstance();
        gssname name = manager.createname("http@" + servicename, gssname.nt_hostbased_service);
        gsscontext context = manager.createcontext(name, 
                                    null, 
                                    authentication.getticketvalidation().getgsscontext().getdelegcred(), 
                                    gsscontext.indefinite_lifetime);
        context.requestcreddeleg(true);
        byte[] servicetoken = context.initseccontext(authentication.gettoken(), 0, authentication.gettoken().length);
        context.dispose();
        return servicetoken;
    });
}

some explanation:

line 9,10    retrieves the keberosservicetoken from the spring security context

line 12        get the current logged in subject

line 14        run the lambda expression as this subject

line 15        get the gssmanager

line 16        create a gssname for the rest endpoint

line 17-20  create a new gsscontext for this rest endpoint

line 21        request a forwardable kerberos token, so the new service ticket is also forwardable

line 22        initiate the secure context with the current kerberos token to get a new service ticket

line 23        close the context and

line 24         return the new ticket

a colleague of mine also created an extension to the spring security kerberos plugin to delegate the user credentials to an ldap server. so, there is no need to use a bind user (with special permissions) anymore. the major advantage is that you can create an audit trail of any user logged in to your systems.

 

 

 

 

Top