Over the years I've watched Kerberos and related tools from afar, interested in the idea, but not interested enough to figure out the installation, configuration, etc. Well, in an attempt to secure assorted NFS mounts around my home, I decided to take the plunge today and install NFSv4 + Kerberos. Here are my notes for my Gentoo systems, mostly following the Kerberos install guide. I'll use the following settings for my examples:
- Domain:
d.net
- Kerberos realm:
R.EDU
- Server:
server.d.net
- Client:
client.d.net
- User:
jdoe
(on both the client and server)
Setup the Kerberos server
Emerge the Kerberos server (app-crypt/mit-krb5
) and PAM module:
# USE=-openldap emerge -av pam_krb5
-openldap
breaks an OpenLDAP <-> Kerberos dependency loop.
Setup DNS to centralize service location management (krb manual):
# emacs /etc/bind/pri/d.net.zone
# /etc/init.d/named restart
I added the following entries to the $ORIGIN d.net.
section of my
zone file:
_kerberos TXT "R.EDU"
kerberos A 192.168.0.2
krb5 A 192.168.0.2
_kerberos-adm._tcp SRV 0 0 749 krb5
_kerberos._udp SRV 0 0 88 krb5
_kerberos-master._udp SRV 0 0 88 krb5
_kpasswd._udp SRV 0 0 464 krb5
Configure Kerberos and the KDC (krb manual):
# cp /etc/krb5.conf{.example,}
# emacs /etc/krb5.conf
# cat /etc/krb5.conf
[libdefaults]
default_realm = R.EDU
dns_fallback = yes
kdc_ports = 88
[realms]
R.EDU = {
kdc = "server.d.net" # HACK?
admin_server = "server.d.net" # DNS support not yet complete
}
[domain_realm]
.d.net = R.EDU
d.net = R.EDU
[logging]
kdc = FILE:/var/log/krb5/kdc.log
admin_server = FILE:/var/log/krb5/kadmind.log
default = FILE:/var/log/krb5/krblib.log
# cp /var/lib/krb5kdc/kdc.conf{.example,}
# emacs /var/lib/krb5kdc/kdc.conf
# cat /var/lib/krb5kdc/kdc.conf
[realms]
R.EDU = {
admin_server = server.d.net # DNS support not yet complete
database_name = /var/lib/krb5kdc/principal
admin_keytab = FILE:/etc/krb5.keytab
acl_file = /var/lib/krb5kdc/kadm5.acl
key_stash_file = /var/lib/krb5kdc/.k5.R.EDU
kdc_ports = 88
max_life = 10h 0m 0s
max_renewable_life = 7d 0h 0m 0s
}
Create the database and stash file (krb manual):
# kdb5_util create -r R.EDU -s
Add administrators to the access control list (krb manual):
# emacs /var/lib/krb5kdc/kadm5.acl
# cat /var/lib/krb5kdc/kadm5.acl
jdoe/admin@R.EDU x
# kadmin.local
kadmin.local: add_principal jdoe/admin@R.EDU
WARNING: no policy specified for jdoe/admin@R.EDU; defaulting to no policy
Enter password for principal "jdoe/admin@R.EDU":
Re-enter password for principal "jdoe/admin@R.EDU":
Principal "jdoe/admin@R.EDU" created.
kadmin.local: quit
Start the Kerberos daemons:
# /etc/init.d/mit-krb5kdc start
# /etc/init.d/mit-krb5kadmind start
Add them to your default runlevel with:
# eselect rc add /etc/init.d/mit-krb5kadmin default
# eselect rc add /etc/init.d/mit-krb5kadmind default
Add new principals (krb manual):
$ kadmin -p jdoe/admin
Authenticating as principal jdoe/admin with password.
Password for jdoe/admin@R.EDU:
kadmin: list_principals
...
kadmin: add_principal jdoe
WARNING: no policy specified for jdoe@R.EDU; defaulting to no policy
Enter password for principal "jdoe@R.EDU":
Re-enter password for principal "jdoe@R.EDU":
Principal "jdoe@R.EDU" created.
kadmin: quit
Now you can get your ticket granting ticket (TGT) with
$ kinit
and do all the other standard Kerberos stuff.
Setup the Kerberos client
Not much to do here, just
# emerge -av pam_krb5
and scp
/etc/krb5.conf
from your Kerberos server onto the client.
Check that everything works by running
$ kinit
Password for jdoe@R.EDU:
$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: jdoe@R.EDU
Valid starting Expires Service principal
06/02/11 10:32:30 06/02/11 20:32:30 krbtgt/R.EDU@R.EDU
renew until 06/03/11 10:32:30
Setup the NFS server
Now we'll setup NFSv4 using Kerberos authentication. There don't seem to be authoritative docs, but there are a number of good tutorials (1, 2, 3, 4).
Emerge nfs-utils
with the kerberos
USE flag set
(homepage). You may also want app-crypt/kstart
(homepage) to automatically renew your server and client
tickets. Now is also a good time to check your kernel config. I was
missing CRYPTO_CTS, which lead to
error writing to downcall channel /proc/net/rpc/auth.rpcsec.context/channel: Invalid argument
If your realm is not your uppercased domain name, you probably also want a version of libnfsidmap >0.21 to avoid the
get_ids: failed to map name 'nfs/<fqdn>@REALM' to uid/gid: Invalid argument
bug (discussion).
Since we'll be running the NFS service, we'll need a
nfs/<fqdn>@REALM
principal for the service. Because we want that
service to start automatically at boot, we neek to keep its key in a
keytab file (krb manual).
# kadmin.local -p jdoe/admin
Authenticating as principal jdoe/admin with password.
Password for jdoe/admin@R.EDU:
kadmin.local: add_principal -randkey nfs/server.d.net
WARNING: no policy specified for nfs/server.d.net@R.EDU; defaulting to no policy
Principal "nfs/server.d.net@R.EDU" created.
kadmin.local: ktadd nfs/server.d.net
Entry for principal nfs/server.d.net...
...
kadmin.local: quit
You need use kadmin.local
here (instead of kadmin
) so the process
has premission to create and edit the keytab file.
Read through /etc/idmapd.conf
to see if you need to make any changes
for your setup. I set Domain = d.net
and Local-Realms = R.EDU
.
You probably also want to look through /etc/conf.d/nfs
. I added
-vvv
to OPTS_RPC_GSSD
, OPTS_RPC_IDMAPD
, and OPTS_RPC_SVCGSSD
to aid in debugging.
Setup your export filesystem. NFSv4 wants all its exports to live under a single root, so do something like:
# mkdir /export
# mkdir /export/home
# mount --bind /home /export/home
And then setup /etc/exports
:
# cat /etc/exports
/export *(rw,fsid=0,insecure,sec=krb5p,root_squash,no_subtree_check,crossmnt)
/export/a/ *(rw,insecure,sec=krb5p,root_squash,no_subtree_check)
Note that the syntax has changed somewhat, and there seem to have been
a few versions of the NFSv4 syntax. exports(5)
should contain good
documentation for whatever version of nfs-utils
you have installed
on your system.
If you used mount --bind
to populate /export
, make sure you add
appropriate entries to /etc/fstab
so the mounts come up when you
reboot.
# cat /etc/fstab
...
/home /export/home none rw,bind 0 0
Start the NFS server:
# /etc/init.d/nfs start
Add it to your default runlevel with:
# eselect rc add /etc/init.d/nfs default
Setup the NFS client
In order to use private (sec=krb5p
) mounts, you'll need to enable
RPCSEC_GSS_KRB5. Without it, you'll get error
messages such as
gss_create: Pseudoflavor 390005 not found!
You'll also need nfs-utils
here
# USE="kerberos" emerge -av nfs-utils
You'll need a client principal for secured mounts, so head back over to the server and run
server.d.net# kadmin.local
kadmin.local: add_principal -randkey nfs/client.d.net
kadmin.local: ktadd -k /tmp/krb5.keytab nfs/client.d.net
Entry for principal nfs/client.d.net ...
...
kadmin.local: quit
Then scp
the new keyfile over to /etc/krb5.keytab
on the client
and remove the temporary version from the host. You can list the keys
in a keytab with klist -e -k /path/to/keytab
if you find a keytab
lying around but forget what's inside it.
On the client, you'll need gssd
and idmapd
running (both part of
nfs-utils
).
# /etc/init.d/rpc.gssd start
# /etc/init.d/rpc.idmapd start
There's no need to add these to your default runlevel, since they
should be started automatically if you have NFSv4 entries in your
/etc/fstab
(I have no idea how that works).
Now test your mount:
$ sudo mkdir /tmp/mnt
$ sudo mount -v -t nfs4 -o sec=krb5p server:/ /tmp/mnt
mount.nfs4: timeout set for Thu Jun 2 10:44:46 2011
mount.nfs4: trying text-based options '...'
server:/ on /tmp/mnt type nfs4 (rw,sec=krb5p)
$ ls /tmp/mnt
ls: cannot access /tmp/mnt: Permission denied
$ klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1000)
$ kinit
Password for jdoe@R.EDU:
$ ls /tmp/mnt/
home
Note that if you kestroy
your key, you can still access the files:
$ kdestroy
$ klist
klist: No credentials cache found (ticket cache FILE:/tmp/krb5cc_1000)
$ ls /tmp/mnt/
home
This is because your credentials have been cached in the client's kernel. On AIX there seems to be an nfsauthreset command to manually flush cached GSSAPI information. Linux support is waiting on a new key ring implementation.
Other stuff
If you hadn't had the kerberos
USE flag set before, you should
consider adding it to your /etc/make.conf
and running
$ sudo emerge -av --deep --newuse --update @world
to get Kerberized versions of any packages you have installed
(e.g. cups
, curl
, cvs
, emacs
, openssh
, most SASL libraries,
...).
For details on using Kerberos with SSH, check out the excellent
description in the SSH definative guide. The key elements are
host/<fqdn>@REALM
principals for each host (with keyfiles on each
server) and appropriate enabling of the GSSAPI*
options in
sshd_config
and ssh_config
.
There's also suite of Kerberos-aware utilities in
app-crypt/mit-krb5-appl
(krcp
, krlogin
, krsh
, ktelnet
, and
kftp
). I don't use the non-Kerberized versions, so I haven't tried
any of these.
If you're using MPD on an NFS-mounted music repository, you might
be interested in my kinit-mpd.sh script for granting the mpd
user access to the NFS-mounted music as the nobody
principal.
For debugging, check out the KRB5_TRACE environment variable. I
sent some patches upstream to integrate reverse DNS debugging
into the KRB5_TRACE
framework. The patches will go live with the
next major krb5 release after the 1.10 series.
If you end up compiling from source, you can run the unit tests and check coverage with something like:
$ git clone git://github.com/krb5/krb5.git
$ cd krb5/src
$ util/reconf
$ mkdir ../build
$ cd ../build
$ ../src/configure --disable-rpath CFLAGS="-fprofile-arcs -ftest-coverage -O0" LIBS=-lgcov
$ make
$ make check
$ cd lib/krb5/os
$ gcov -o sn2princ.so.gcno ../../../lib/krb5/os/sn2princ.c
$ gcov -o sn2princ.so.gcno sn2princ.c
$ less sn2princ.c.gcov
Running configure
from a separate directory creates a VPATH
build, which avoids polluting the source directory with generated
files.