Kerberos KDC

Dependencies

In our current configuration, our kdc.conf lives in AFS. See file:///afs/acm.jhu.edu/readonly/group/admins.pub/kdc.conf and The Special Case of admins.pub. As such, the KDCs and kadminds should depend on:

  • the local entropy source (e.g. haveged)
  • ntpd
  • AFS client functionality

Note that depending on AFS does not introduce a circular dependency, as the krb5.conf file is public and the AFS servers do not depend on the KDC to get going.

Using Kadmin

Kerberos software seems not to use DNS to resolve admin servers. Add to /etc/krb5.conf on any machine from which you want to run kadmin at least

[realms]
  ACM.JHU.EDU = {
    admin_server = kdc1.acm.jhu.edu
  }

It should then suffice to run kadmin (assuming your default realm and user ID match ours) or kadmin -r ACM.JHU.EDU -p ${YOU}/admin (if not).

The ACLs for kadmin are very simple: */admin * and that’s it.

Please only run kadmin on machines you trust (or that you’re forced to trust); running it on random hosts within the cluster increases the odds that someone will snarf an admin password, and that’d be unfortunate.

Common kadmin tasks: changing a password.

Perhaps the most frequent thing we need to do using kadmin is change a user’s password, who has forgotten it. This can be done pretty simply; upon opening kadmin, simply run the following command from inside kadmin:

cpw principal

This will prompt for a password and then set the password for principal to whatever the user enters.

If you know what you are doing, the optional -pw password argument will set the principal’s password to the string “password”. I strongly suggest you only do this if you are, e.g. using pwgen to give a user a temporary password. But really, you shouldn’t be doing that, since you should only be changing a user’s password when they are in the room (for hopefully obvious security reasons).

Using Multiple Instances

Creating an Instance

When users want long-running jobs or noninteractive jobs or other such things, we should give them alternate hats (and keytabs for them) to do that with, since that’s really the right thing to do. (See also User keytabs and maintained tokens. Note that instances are also used for administrative commands; see Administrator Credentials.)

Fire up kadmin, then:

addprinc -randkey username/instancename
ktadd -k /path/to/put/the.keytab username/instancename

and give the user the keytab. Also do:

pts createuser username.instancename

Note the dot instead of a slash for pts.

The user then gives this brand new alternate hat the minimum permissions on the parts of their homedir needed for the job, remembering to include at least “l” on all parent directories thereof.

(Cross-realmed people can, of course, do the above themselves with a hat in their own realm; the pts part automatically happens the first time the user aklogs to the ACM with it, once we’ve done the proper cross-realming dance.)

Then, for non-long-running but noninteractive things, the user can do something like:

export KRB5CCNAME=/somewhere/besides/the/default
kinit -k -t the.keytab username/instancename
aklog -setpag
# do stuff

For long-running things started interactively (like screen sessions), stump’s solution is running a script similar to the following inside screen:

#!/bin/sh -e
TMPDIR=`mktemp -d /tmp/stump_irc_XXXXXX`
trap 'rm -rf "$TMPDIR"' 0 1 2 15
cp -a ~/irc.keytab "$TMPDIR"/keytab
k5start -U -f "$TMPDIR"/keytab -k "$TMPDIR"/krb5cc -t irssi

(The temp dir dance here is needed because k5start drops your AFS tokens before it reads the keytab, so if your keytab is in AFS, you’re going to be very sad otherwise. mktemp sets the dir it creates 0700, so you’re fairly safe permissions-wise with the copied keytab.)

How to use an alternate hat

You probably want to spawn a separate PAG; so first, run

pagsh -c $SHELL

After that, set yourself a private credential cache. I suggest the nice and modern

export KRB5CCNAME=KEYRING:session

which doesn’t use files and, if you’re feeling paranoid, can be locked out from even other instances of your uid, restricting to “possessor”. In any case, the next thing you want is

kinit ${USER}/admin

and finally

aklog

stump has the following in his .bashrc to more easily manage putting on his other hats

# The "grep ^" looks useless, but it causes the functions to return error
# if I have no Kerberos tickets.
kprincipal () { klist 2>/dev/null | grep '^Default principal: ' | sed -e 's/.*: //' | grep ^; }
krealm () { kprincipal | sed -e 's/.*@//' | grep ^; }
krbsh () { (set -e
  TMPDIR="`mktemp -d /tmp/krbsh_XXXXXX`"
  trap 'rm -rf "$TMPDIR"' 0 1 2 3 15
  export KRB5CCNAME=FILE:"$TMPDIR"/krb5cc
  kinit "$@"
  set +e
  pagsh -e -c "aklog '`krealm | tr 'A-Z' 'a-z'`' && exec bash"
  RETVAL="$?"
  kdestroy
  return "$RETVAL"); }
PS1="\`kprincipal | sed 's/.*/(&) /'\`$PS1"
alias put-admin-hat-on="krbsh stump/admin@ACM.JHU.EDU"

Configuration

Our KDC configuration is visible at file:///afs/acm.jhu.edu/readonly/group/admins.pub/kdc.conf . Note that this does not induce a circular dependency as the AFS servers can come up and begin talking to each other without the KDCs (as they all share a keytab) and this is a publicly readable file.

Replication

The master kdc, every few minutes, runs a script which dumps the database and then pushes it to all slaves. We use wrapsrv and DNS to maintain the set of slave KDCs (isn’t that cute; note that kpropd.acl still needs to be up-to-date, but it only contains host/typhon.acm.jhu.edu@ACM.JHU.EDU for the moment).

/usr/sbin/kdb5_util dump ${DUMPFILE}
/usr/bin/wrapsrv _krb_prop._udp.acm.jhu.edu "/bin/bash -c \"/usr/sbin/kprop -d -f ${DUMPFILE} -P %p %h; exit 1\""

Creating a new replica

Non-secret configuration details:

ln -s /afs/acm.jhu.edu/readonly/group/admins.pub/kdc.conf /etc/krb5kdc/kdc.conf
echo host/typhon.acm.jhu.edu@ACM.JHU.EDU > /etc/krb5kdc/kpropd.acl

Enable kpropd in /etc/inetd.conf (or equivalent service):

update-inetd --add "krb5_prop stream tcp nowait root /usr/sbin/kpropd kpropd"

SECURELY copy /etc/krb5kdc/stash from an existing master or replica to the new replica.

Manually run kpropd on the master:

kprop -d -f /tmp/krb5kdc-slave-datatrans echidna.acm.jhu.edu

Check that it succeeded. (Note that the file name here is the path used by our automagic replication script; i.e. it is ${DUMPFILE} from above. You may need to manually run kdb5_util dump if it doesn’t exist.)

Update DNS to also answer with the new replica as a SRV response to _krb_prop._udp.acm.jhu.edu. The master will begin propagation regularly.

Update DNS to also answer with the new replica for the other Kerberos records, namely a kdcN CNAME and _kerberos._udp (Strictly speaking, only the latter is necessary, but our convention is to use both.) This machine will now be used by clients.

Cross-Realming

Todo

The ACM will happily cross-realm with anyone who asks; our admins have a history of running their own vanity domains. However, it’s not always straightforward and so the process should be documented here.

Incoming

Use kadmin to create the cross-realm service principal

ank -policy service krbtgt/ACM.JHU.EDU@${REALM}

Choose a big password and share it SECURELY with the other side, or let them choose a big password and just use theirs, or use a shared-key derivation scheme, whatever. Same password on both sides.

Verify that the list of enctypes that exist for the cross-realm service principal is exactly the same on both ends. You may have to specify some -e options if there are different defaults. Mysterious issues may arise later otherwise.

Create an AFS PTS group for users from the remote realm, and optionally set the group quota

pts creategroup system:authuser@${realm} -owner system:administrators
pts setfields system:authuser@${realm} -groupquota 100

Test that it works by having the remote end obtain Kerberos tickets and then run aklog -d acm.jhu.edu. Afterwards, their Kerberos ticket cache should contain a service key for krbtgt/ACM.JHU.EDU@${REALM} and afs/acm.jhu.edu@ACM.JHU.EDU and aklog should have announced the successful first-time login creation of a UID on our side.

Outgoing

Same thing, but with the realm names, the realm in which you do each command, and any other reference to either end reversed (-;

If the other end doesn’t have AFS, try accessing some other service on the other end with an ACM ticket. If there isn’t a good one to try, just run kvno against some service principal on the other end with an ACM ticket and see if the resulting contents of your ticket cache look right.

The passwords don’t have to match between directions (though they of course need to match within each direction) - in fact, they probably shouldn’t.

Cross-realming with someone using a Samba 4 KDC

Have them create a user to hold the cross-realm service principal, mark its password as not expiring, and then create the service name

samba-tool user create JHUACM
samba-tool user setexpiry --noexpiry JHUACM
samba-tool spn add krbtgt/ACM.JHU.EDU JHUACM

Note

I do not know if this is the right approach, but it does seem to work, at least in the one direction. As of the time of this writing, Samba 4 does not support the other direction.