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