Friday, 17 October 2014

WildFly 9 - Kerberos Authentication for Domain Management Over HTTP

This blog post is in relation to a new feature added to WildFly 9 under WFCORE-105, however it is not currently included in a release so for now you will need to build WildFly yourself or use one of the nightly builds.

If you are not familiar with building WildFly have a look at HackingOnWildFly.

If you want to access a nightly build they are available from WildFly-latest-master.

Pre-Requisites

This blog post is specifically about the steps and configuration required to enable Kerberos based authentication for domain management over HTTP, this blog post does not describe how to define service principals and obtain the keytab or how to configure the web browser - there is already plenty of information out there covering those topics.

My Environment

The examples described in this blog post are all in the context of my test environment.

My KDC is service requests for the realm DAL.WILDFLY.ORG and the address of my KDC is kdc.dal.wildfly.org.

The HTTP management interface of my server installation is already listening on host web.dal.wildfly.org and I have a keytab called web.keytab which contains the service principal HTTP/web.dal.wildfly.org@DAL.WILDFLY.ORG.

Where you see any of these values in the following example obviously you will need to substitute in your own specific values for your own environment.

General Kerberos Settings

It is possible to rely on your local environments Kerberos configuration for things such as KDC identification and the resolution of the KDC's address, however for my own test environment where I am using a single KDC I prefer to just set a couple of system properties using the following CLI commands.

[standalone@web.dal.wildfly.org:9990 /] 
./system-property=java.security.krb5.realm:add(value=DAL.WILDFLY.ORG)
{"outcome" => "success"}
[standalone@web.dal.wildfly.org:9990 /] 
./system-property=java.security.krb5.kdc:add(value=kdc.dal.wildfly.org)
{"outcome" => "success"}

Enabling Kerberos Authentication

The steps to enable Kerberos authentication are split into two parts, first of all we need to define the servers own identity which is loaded from it's keytab and secondly once that is defined we need to enable the authentication.

Servers Identity

The first step is to now configure how the server will load it's own identity from a keytab, to do this I copy my web.keytab to the standalone/configuration folder of my installation and execute the following CLI commands: -

[standalone@web.dal.wildfly.org:9990 /] ./core-service=management/security-realm=ManagementRealm/server-identity=kerberos:add
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}
[standalone@web.dal.wildfly.org:9990 /] ./core-service=management/security-realm=ManagementRealm/server-identity=kerberos/keytab=HTTP\/web.dal.wildfly.org@DAL.WILDFLY.ORG:add(path=web.keytab, relative-to=jboss.server.config.dir, debug=true)
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

The first command adds a container resource to the security realm to say that we will be adding a Kerberos identity, the subsequent command adds a reference to the keytab.  take note of where the principal name is specified within the address for the keytab and see how it needed to be escaped, also for this keytab I have enabled some additional debug output for when we communicate with the KDC.

Also note that these commands have put the server in the reload-required state.

It is possible that a single server could be accessible using multiple host names, for this reason it is possible to add multiple keytabs to the security realm,  the keytab definitions also have a for-hosts attribute that can be used to specify which keytab should be used for which host, failing that there will be an attempt to match the host name to the principal name.

In general we could proceed to the next section but it worth now executing :reload so that we can test our new configuration before enabling the actual authentication.

[standalone@web.dal.wildfly.org:9990 /] :reload                                  
                                                                                
{            
    "outcome" => "success",
    "result" => undefined
}

The keytab resource then has a test operation that can be invoked to verify the identity can be obtained.

[standalone@web.dal.wildfly.org:9990 /] ./core-service=management/security-realm=ManagementRealm/server-identity=kerberos/keytab=HTTP\/web.dal.wildfly.org@DAL.WILDFLY.ORG:test
{
    "outcome" => "success",
    "result" => {"subject" => "Subject:
Principal: HTTP/web.dal.wildfly.org@DAL.WILDFLY.ORG
Private Credential: /home/darranl/src/wildfly9/wildfly/dist/target/wildfly-9.0.0.Alpha2-SNAPSHOT/standalone/configuration/web.keytab
Private Credential: Kerberos Principal HTTP/web.dal.wildfly.org@DAL.WILDFLY.ORGKey Version 1key EncryptionKey: keyType=17 keyBytes (hex dump)=
0000: 8C D1 9C 24 86 84 D4 25   A3 12 FF DE A9 0D 9B 26  ...$...%.......&

At this point it is absolutely critical that you verify in the above output that one of the Private Credentials is actually a 'Kerberos Principal' and not just the reference to the keytab location.

Switch on Authentication

To switch on authentication a simple addition to the realm is required: -

[standalone@web.dal.wildfly.org:9990 /] ./core-service=management/security-realm=ManagementRealm/authentication=kerberos:add
{
    "outcome" => "success",
    "response-headers" => {
        "operation-requires-reload" => true,
        "process-state" => "reload-required"
    }
}

At this point :reload needs to be executed again and now I can try and connect using my web browser.

Load the Admin Console

Firstly I make sure I have obtained my own ticket granting ticket from the KDC: -

[darranl@localhost tmp]$ kinit darranl@DAL.WILDFLY.ORG
Password for darranl@DAL.WILDFLY.ORG: 
[darranl@localhost tmp]$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: darranl@DAL.WILDFLY.ORG

Valid starting     Expires            Service principal
17/10/14 13:08:18  18/10/14 13:08:15  krbtgt/DAL.WILDFLY.ORG@DAL.WILDFLY.ORG
renew until 24/10/14 13:08:15

As the security realm is based on the default configuration username/password based authentication is still enabled, for this reason you will need to ensure at least one user is defined by running the add-user script.

Now I load my web browser and attempt to connect using the admin console.


With no additional password prompt I am now authenticated as the user I previously obtained the ticket granting ticket for.

It is worth pointing out that my identity here includes the name of the realm, if desired when I added the authentication=kerberos to the realm I could have added the attribute remove-realm=true to strip the realm name from the username.

Finally if my web browser had not been enabled for Kerberos authentication or if I had not already obtained the ticket granting ticket I would have been prompted for a username and password as normal.

XML Configuration

Finally all of this configuration could have been defined manually in the application server configuration, the following is the resulting realm definition after the above CLI commands have been executed.

<security-realm name="ManagementRealm">
    <server-identities>
        <kerberos>
            <keytab principal="HTTP/web.dal.wildfly.org@DAL.WILDFLY.ORG" path="web.keytab" relative-to="jboss.server.config.dir" debug="true"/>
        </kerberos>
    </server-identities>
    <authentication>
        <local default-user="$local" skip-group-loading="true"/>
        <kerberos/>
        <properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
    </authentication>
    <authorization map-groups-to-roles="false">
        <properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
    </authorization>
</security-realm>

Next Steps

The next steps now are to enable Kerberos authentication for our native interface so that clients such as the CLI and JMX Console can also take advantage of Kerberos based authentication.