Enabling AES-encrypted single sign-on to Apache in a Win2008 domain

5,812

It turns out that the major problem here is one of the problems AES256 was intended to solve.

TL;DR: The principal name in the keytab now needs to match the account name.

The Problem

If we had run KRB5_TRACE=/dev/stderr kinit [email protected] back when the account was enabled for only RC4-HMAC encryption, we would have seen this line in the output:

[8192] 1441829478.537451: Selected etype info: etype rc4-hmac, salt "", params ""

Now that we have AES256 enabled, though, that line looks like this:

[8200] 1441829508.947208: Selected etype info: etype aes256-cts, salt "REALM.COMHostServiceAccount", params ""

When the switch was made from NTLM authentication to Kerberos, the RC4-HMAC algorithm was specified to reuse the NTLM hash. Microsoft declined to put a salt into the hash to make it easier for existing systems to interoperate with Kerberos. Now that users have the opportunity to upgrade, a salt is specified for the AES256 and AES128 algorithms, and the salt is the user name.

We can see this if we generate keytabs for RC4-HMAC and AES256 using different usernames. With RC4-HMAC:

fluggo@host:~$ ktutil
ktutil:  add_entry -password -p HTTP/[email protected] -k 1 -e rc4-hmac
Password for HTTP/[email protected]: 12345
ktutil:  add_entry -password -p [email protected] -k 1 -e rc4-hmac
Password for [email protected]: 12345
ktutil:  write_kt rc4.keytab
ktutil:  q
fluggo@host:~$ klist -Kek rc4.keytab
Keytab name: FILE:rc4.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   1 HTTP/[email protected] (arcfour-hmac)  (0x7a21990fcd3d759941e45c490f143d5f)
   1 [email protected] (arcfour-hmac)  (0x7a21990fcd3d759941e45c490f143d5f)

...the hash is the same, so these two entries are equivalent. But with AES256:

fluggo@host:~$ ktutil
ktutil:  add_entry -password -p HTTP/[email protected] -k 1 -e aes256-cts-hmac-sha1-96
Password for HTTP/[email protected]: 12345
ktutil:  add_entry -password -p [email protected] -k 1 -e aes256-cts-hmac-sha1-96
Password for [email protected]: 12345
ktutil:  write_kt aes.keytab
ktutil:  q
fluggo@host:~$ klist -Kek aes.keytab
Keytab name: FILE:aes.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   1 HTTP/[email protected] (aes256-cts-hmac-sha1-96)  (0x5746fa6f9b0c990ba7fb20acd85065040d66e843a043508569841768ef2b7917)
   1 [email protected] (aes256-cts-hmac-sha1-96)  (0x6a98fdccbce4db77f40192f4e916e0900a1b9cba2f6ca8bc737d968e4b961c25)

...the hashes are different. The principal name matters, and it needs to match the UPN of the account.

A Solution

Since the username must be correct for the keytab to work, we generate a new keytab with the principal name Active Directory uses on the ticket:

# rm /etc/apache2/service.keytab
# ktutil
ktutil:  add_entry -password -p [email protected] -k 1 -e aes256-cts-hmac-sha1-96
Password for [email protected]: <enter password here>
ktutil:  add_entry -password -p [email protected] -k 1 -e aes128-cts-hmac-sha1-96
Password for [email protected]: <enter password here>
ktutil:  write_kt /etc/apache2/service.keytab
ktutil:  q
# chown -v www-data:root /etc/apache2/service.keytab
# chmod -v 440 /etc/apache2/service.keytab

Apache cares about the principal name in the keytab, and so it won't find these entries on its own. Instead, we just direct Apache to use whatever working principal it can find:

KrbServiceName Any

I wanted Apache to find the principal by the correct name, but it hardly matters since our principals are the only ones in the keytab.

Restart Apache, refresh the page, and the authentication should work now.

Share:
5,812

Related videos on Youtube

mrdecemberist
Author by

mrdecemberist

Updated on September 18, 2022

Comments

  • mrdecemberist
    mrdecemberist almost 2 years

    All of the tutorials I could find on setting up single-sign on into an Apache-hosted website using Active Directory authentication do so by configuring Kerberos with insecure settings. It's been best practice for awhile now to disable RC4-HMAC encryption for Kerberos in Active Directory, but a lot of tutorials call for overriding krb5.conf's defaults and making everything work with RC4-HMAC.

    I wanted to try setting up single sign-on with AES256 encryption, and I managed to make it work, so I'm recording this question and answer for anyone else who wants better security for their site.

    Starting with RC4-HMAC

    We'll start by getting it working with RC4-HMAC first, since this is easier. The standard steps to set up SSO start with creating a domain account with an associated SPN, which browsers will use to get encrypted credentials to send to the server. For this example, my user is REALM\HostServiceAccount:

    • UPN: [email protected] (and therefore the Kerberos principal name is [email protected])
    • servicePrincipalName attribute (also settable by setspn): HTTP/host.example.com; HTTP/host (Kerberos: HTTP/[email protected])
    • Leave encryption settings alone; by default, this makes RC4-HMAC the strongest encryption allowed, so tickets from the domain will have this encryption

    We add the following entries to /etc/krb5.conf on our target server:

    [libdefaults]
        default_realm = REALM.COM
    
    [domain_realm]
        .realm.com = REALM.COM
        realm.com = REALM.COM
    

    We create the keytab and let the server read it:

    # ktutil
    ktutil:  add_entry -password -p HTTP/[email protected] -k 1 -e rc4-hmac
    Password for HTTP/[email protected]: <enter password here>
    ktutil:  write_kt /etc/apache2/service.keytab
    ktutil:  q
    # chown -v www-data:root /etc/apache2/service.keytab
    # chmod -v 440 /etc/apache2/service.keytab
    

    (At this point, of course, you would want to use kinit -kt service.keytab -S HTTP/[email protected] [email protected] to test the keytab.)

    Finally, we set Apache to authenticate users using our keytab:

    KrbDelegateBasic off
    KrbAuthoritative on
    KrbMethodK5Passwd off
    Krb5Keytab /etc/apache2/service.keytab
    KrbAuthRealms REALM.COM
    
    LogLevel debug
    

    After we restart Apache, if all goes well, we do a request to the server from our Windows domain machine and see the following in Apache's error log:

    [debug] src/mod_auth_kerb.c(1641): [client ****] kerb_authenticate_user entered with user (NULL) and auth_type Kerberos, referer: ****
    [debug] src/mod_auth_kerb.c(1395): [client ****] Verifying client data using KRB5 GSS-API , referer: ****
    [debug] src/mod_auth_kerb.c(1411): [client ****] Client didn't delegate us their credential, referer: ****
    [debug] src/mod_auth_kerb.c(1430): [client ****] GSS-API token of length 185 bytes will be sent back, ****
    

    Running klist on our client machine (or Wireshark to see the ticket in the request), we see that indeed we have used an RC4-HMAC ticket to authenticate:

    #4>     Client: fluggo @ REALM.COM
            Server: HTTP/host.example.com @ REALM.COM
            KerbTicket Encryption Type: RSADSI RC4-HMAC(NT)
    

    Moving up to better encryption

    All is well, but again, this is not our goal. RC4-HMAC is considered insecure, so let's disable that and try to make the same setup work with AES256.

    First, we'll ask our friendly neighborhood domain admin to enable the advanced encryption on REALM\HostServiceAccount, which will be two checkboxes labeled:

    • This account supports Kerberos AES 128 bit encryption
    • This account supports Kerberos AES 256 bit encryption

    These appear in various places depending on the tools you're using; the end result should be that the LDAP attribute msDS-SupportedEncryptionTypes should be 0x18 or decimal 24, which represents that only AES128 and AES256 are supported.

    To make this effective, we'll kill our local client tickets:

    C:>klist purge
    
    Current LogonId is 0:0xdeadbeef
            Deleting all tickets:
            Ticket(s) purged!
    

    If we perform our request again, we'll see that the request has failed, but we've got an updated ticket:

    C:>klist
          ...
    #3>     Client: fluggo @ REALM.COM
            Server: HTTP/host.example.com @ REALM.COM
            KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
    

    Now we should just need to update our keytab with the new algorithms, and we should be golden:

    # mv /etc/apache2/service.keytab ~/old.keytab
    # ktutil
    ktutil:  add_entry -password -p HTTP/[email protected] -k 1 -e aes256-cts-hmac-sha1-96
    Password for HTTP/[email protected]: <enter password here>
    ktutil:  add_entry -password -p HTTP/[email protected] -k 1 -e aes128-cts-hmac-sha1-96
    Password for HTTP/[email protected]: <enter password here>
    ktutil:  write_kt /etc/apache2/service.keytab
    ktutil:  q
    # chown -v www-data:root /etc/apache2/service.keytab
    # chmod -v 440 /etc/apache2/service.keytab
    

    We don't even need to restart Apache. Just resubmit the request.

    Oops... it doesn't work. If we look at Apache's error log, we see:

    [debug] src/mod_auth_kerb.c(1641): [client ****] kerb_authenticate_user entered with user (NULL) and auth_type Kerberos
    [debug] src/mod_auth_kerb.c(1249): [client ****] Acquiring creds for [email protected]
    [debug] src/mod_auth_kerb.c(1395): [client ****] Verifying client data using KRB5 GSS-API
    [debug] src/mod_auth_kerb.c(1411): [client ****] Client didn't delegate us their credential
    [debug] src/mod_auth_kerb.c(1430): [client ****] GSS-API token of length 9 bytes will be sent back
    [debug] src/mod_auth_kerb.c(1110): [client ****] GSS-API major_status:000d0000, minor_status:000186a5
    [error] [client ****] gss_accept_sec_context() failed: Unspecified GSS failure.  Minor code may provide more information (, )
    

    Well that's a ridculously unhelpful error message, but what went wrong? The answer, and one solution, to follow!

  • DarkMoon
    DarkMoon over 6 years
    As this question already has an accepted answer and is over 2 years old, I'm not sure how this is helpful?
  • Thorston
    Thorston over 6 years
    It is a different solution, and allows people to use multiple SPNs in a keytab, or create a keytab when the SPN and UPN differ. There is not much documentation on how to do this available so I posted....
  • Thorston
    Thorston over 6 years
    To be specific it allows for SSO setup for a cluster or web farm behind an LB...