How to set up Kerberos authentication in network services

Your organization has a Kerberos realm EXAMPLE.COM, or you set one up. You operate a service such as ssh, SMTP/IMAP/POP, or a web site. How do you kerberize the service to let users authenticate with Kerberos single sign-on instead of juggling passwords?

The answer will vary from service to service, and may sometimes be phrased in terms of GSS-API, but it will always have three parts:

  1. Determine the service's principal name, based on the protocol, the service's hostname, and the realm name.

    For example, IMAP uses imap/hostname (RFC 9051, IANA GSSAPI/Kerberos/SASL Service Names). So if your users are connecting to the IMAP host imap.example.com, the service principal name will be imap/imap.example.com (or imap/imap.example.com@EXAMPLE.COM if fully qualified with a realm name).

  2. Get a key for the service principal from the Kerberos KDC using kadmin(8): first kadmin add to generate a key for the service principal, and then kadmin ext to extract it into a keytab.

    The key is a secret shared between the service and the KDC. Anyone who knows the key can spoof the service, so you must keep it secret.

    You can run kadmin(8) on the KDC itself with kadmin -l (kadmin --local), or you can configure kadmind(8) on the KDC and run kadmin(8) remotely.

  3. Put the keytab in a file readable by the server software, for example /usr/pkg/etc/dovecot/private/keytab, and point the software at the keytab and service principal name.

    Some software that uses GSS-API will instead use the GSS-API spelling of a service principal name. For example, IMAP uses IMAP@hostname, and HTTPS uses HTTP@hostname. The realm name is omitted and must be determined separately, either by setting a default realm or domain-to-realm mapping in krb5.conf(5), or by creating _kerberos.host TXT records with the realm name in the DNS.

  1. sshd
  2. dovecot (IMAP, POP, SMTP/submission, or any protocol with SASL)
  3. postfix (submission)
  4. apache2 (HTTPS)
  5. nginx (HTTPS)

sshd

sshd(8) uses service principal names of the form host/hostname (not ssh/hostname).

sshd(8) always uses the default system keytab at /etc/krb5.keytab (or wherever it has been set as default_keytab_name in krb5.conf(5)).

XXX .k5login, aname2lname/auth_to_local mapping

XXX warn against pam_krb5

dovecot (IMAP, POP, SMTP/submission, or any protocol with SASL)

(Main documentation)

  1. Create principals for any relevant services—IMAP, POP, SMTP (for Postfix or other MTAs)—and export their keys into a keytab:

    # kadmin add --random-key --max-ticket-lifetime=unlimited \
        --max-renewable-life=unlimited --use-defaults \
        imap/imap.example.com
    # kadmin add --random-key --max-ticket-lifetime=unlimited \
        --max-renewable-life=unlimited --use-defaults \
        pop/pop.example.com
    # kadmin add --random-key --max-ticket-lifetime=unlimited \
        --max-renewable-life=unlimited --use-defaults \
        smtp/mail.example.com
    # mkdir -m 0700 /usr/pkg/etc/dovecot/private
    # cd /usr/pkg/etc/dovecot/private
    # kadmin ext -k keytab imap/imap.example.com
    # kadmin ext -k keytab pop/pop.example.com
    # kadmin ext -k keytab smtp/mail.example.com
    # chown dovecot:dovecot . keytab
    
  2. Make sure gssapi is included in auth_mechanisms:

    auth_mechanisms = gssapi
    
  3. Point Dovecot at the keytab and allow it to use any of the service principals listed there:

    auth_krb5_keytab = /usr/pkg/etc/dovecot/private/keytab
    auth_gssapi_hostname = "$ALL"
    

If you want to map users to local Unix accounts, or are otherwise using a Dovecot userdb without the realm name, so that the user account for Kerberos principal alice@EXAMPLE.COM is alice, set auth_username_format to %n to strip the @ and everything after:

auth_username_format = %n

To use Dovecot exclusively for SASL authentication in other applications like Postfix, you can simply disable all protocols (default includes imap and pop), and provide an auth service at a path used by the other applications:

protocols =
service auth {
    unix_listener /var/spool/postfix/private/auth {
        mode = 0660
        user = postfix
        group = postfix
    }
}

postfix (submission)

(Main documentation)

  1. Configure Dovecot for SASL authentication as above.

  2. Tell Postfix how to talk to Dovecot in main.cf (postconf(5)):

    smtpd_sasl_path = private/auth
    smtpd_sasl_type = dovecot
    

    Make sure smtpd_sasl_path, taken relative to Postfix's queue_directory, matches the unix_listener path in Dovecot's auth service.

  3. Create a submission (port 587) service in master.cf (master(5)) to handle authenticated mail submission (RFC 6409):

    # service  type private unpriv chroot wakeup maxproc command
    submission inet n       -      y      -      -       smtpd
       -o smtpd_tls_security_level_encrypt=yes
       -o smtpd_sasl_auth_enable=yes
       -o smtpd_client_restrictions=permit_sasl_authenticated,reject
       -o local_header_rewrite_clients=permit_sasl_authenticated
    

    You may also want to set options smtpd_sender_login_maps and smtpd_recipient_restrictions to restrict senders to submit MAIL FROM envelope addresses that match their login names.

apache2 (HTTPS)

HTTP/hostname

XXX mod_auth_gssapi (or legacy mod_auth_kerb)

XXX reverse-proxy remote-user

XXX single-sign-on option with session cookie

nginx (HTTPS)

HTTP/hostname

XXX spnego-http-auth-nginx-module? https://github.com/stnoonan/spnego-http-auth-nginx-module

XXX reverse-proxy remote-user