JAAS and Kerberos: Failed to find any Kerberos tgt

Categories: Java

I recently wrote a simple Java app which used the Hive JDBC driver to connect to a Kerberos-protected Hive database. Running it gave:

  Caused by: GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos tgt)

Solving this took me a significant amount of time. Here is the answer..

When the JDBC driver sees the URL contains option “principal=xyz”, it knows that it needs to create a Kerberos service ticket from some Subject to the service specified by the principal option. However it is not the responsibility of the JDBC driver to create the subject - it just assumes that one is already bound to the thread’s security context.

So how does a suitable Subject get bound? Well one option is to write code to do it; a good example can be found in this Hive JIRA ticket. The constructor-method LoginContext(contextName, handler) and method login expect that system property java.security.auth.login.config points to a file with one or more LoginContext entries in it, and one of those entries matches the specified contextName.

Here is an example of setting the path to a jaas config file:

 java -Djava.security.auth.login.config=./some_jaas_config.conf ...

and here is an example of a config entry for kerberos authentication:

  Client {
   com.sun.security.auth.module.Krb5LoginModule required
   useTicketCache=true
   StoreKey=true
   useKeyTab=true
   keyTab="./some_user.keytab"
   principal="some_user@SOME_DOMAIN";
  };

One possible solution to building an app around the Hive JDBC driver is thus: add the code from the example linked above, and then pass a config-file with the appropriate LoginContext definition. More details can be found in the jaas documentation.

The loginContext name “Client” is a common choice; many (but not all) applications use this name.

However there is an easier way, and one that works with existing apps that cannot be modified: JAAS has an option to define a fallback mechanism for obtaining credentials. And the default fallback is to look for a Kerberos ticket in the standard place (often “/tmp/krb5cc_{uid}”) which kerberos tools like kinit put it. So given

  -Djavax.security.auth.useSubjectCredsOnly=false

the JVM will pick up an existing Kerberos ticket, and the app will run - without needing a jaas config-file at all. In general, that’s all that is needed. No authentication-specific code needs to be added to the simple JDBC-based app. Really trivial!

Of course this fails if there is no current Kerberos ticket. However flag useSubjectCredsOnly=false also enables a “fallback” section in the JAAS config file: if there is no section specifically for the required subject-name, then the section for subject-name “com.sun.security.jgss.initiate” will be used.

Thus with the options and JAAS config below, the JDBC Hive driver successfully connects without requiring a pre-existing Kerberos ticket:

  -Djava.security.auth.login.config=./some_jaas_config.conf -Djavax.security.auth.useSubjectCredsOnly=false

where the config file has:

  com.sun.security.jgss.initiate {
   com.sun.security.auth.module.Krb5LoginModule required
   useTicketCache=true
   StoreKey=true
   useKeyTab=true
   keyTab="./some_user.keytab"
   principal="some_user@SOME_DOMAIN";
  };

Further References