July 2010
Warning | |
---|---|
Some key details twisted, and others omitted, for the sake of security. |
We use NFSv4 with Kerberos, so on both the NFS servers and the NFS clients, we need to extract Kerberos principal keys into keytabs. We want to do this as securely as possible, so fetching them across HTTP with the rest of the unattended install is not a good idea.
So we have the Kerberos client port-knock on a server where knockd is running.
The user running the daemon also holds a Kerberos principal that is allowed to create nfs/*@REALM
principals, and to extract their keytabs.
When a client knocks, the server creates a principal and extracts a keytab for it, and uses SSH to copy it to the client.
Note | |
---|---|
This setup is still sensitive to spoofing of IP numbers. But if a rogue steals an IP number, the legitimate owner will cease being able to use NFS, so the attack will be noticed. |
Note | |
---|---|
This setup doesn't work too well with clients running behind NATting firewalls. |
The knockd config in /etc/knockd.conf
:
[Kerberizer] sequence = 13214,12986,28765 seq_timeout = 15 command = /usr/local/bin/kerberos-nfs-key %IP% tcpflags = syn
The script that creates principals and extracts keys (/usr/local/bin/kerberos-nfs-key
):
#!/bin/bash set -e set -u REALM=MYDOMAIN.COM [ -n "${1}" ] || exit 1 IP=${1} FQDN=$(host ${IP}|awk '{print $5}'|sed 's/\.$//g') # Against the occasional fixed-file attack rm -f /var/tmp/nfs-${FQDN}.keytab # Delete the old principal kadmin -l delete nfs/${FQDN}@${REALM} || true # (Re-)create the nfs/host principal kadmin -l add \ -r \ --max-ticket-life=unlimited \ --max-renewable-life=unlimited \ --expiration-time=never \ --pw-expiration-time=never \ --attributes='' \ nfs/${FQDN}@${REALM} # Extract the principal's keytab kadmin -l ext_keytab \ -k /var/tmp/nfs-${FQDN}.keytab \ nfs/${FQDN}@${REALM} # Scp the keytabl to the host scp -o StrictHostKeyChecking=no /var/tmp/nfs-${FQDN}.keytab root@${FQDN}:/etc/krb5.keytab rm /var/tmp/nfs-${FQDN}.keytab
And the script that sollicits a new key by knocking (it also enables the NFSv4 client, port knocking is at the bottom end):
#!/bin/bash # This should get us a Kerberos principal set -e NFS_COMMON='/etc/default/nfs-common' KRB5CONF=/etc/krb5.conf HOME=/home NFSSERVER=nfs.mydomain.com IDMAPD_CONF=/etc/idmapd.conf KADMIN=kadm.mydomain.com # Adjust /etc/default/nfs-common if ! grep '^NEED_STATD=no$' ${NFS_COMMON} ; then echo "NEED_STATD=no" >> ${NFS_COMMON} fi if ! grep '^NEED_IDMAPD=yes$' ${NFS_COMMON} ; then echo "NEED_IDMAPD=yes" >> ${NFS_COMMON} fi if ! grep '^NEED_GSSD=yes$' ${NFS_COMMON} ; then echo "NEED_GSSD=yes" >> ${NFS_COMMON} fi # Adjust /etc/krb5.conf if ! grep '^allow_weak_crypto = true$' ${KRB5CONF} ; then sed -i.bak '/\[libdefaults\]/ a\ allow_weak_crypto = true' ${KRB5CONF} fi # Make sure gssd is started at boot update-rc.d gssd defaults # Create a mount point install -d ${HOME} || true # Create an fstab entry if ! grep "^${NFSSERVER}:/ ${HOME} nfs4" /etc/fstab ; then echo "${NFSSERVER}:/ ${HOME} nfs4 sec=krb5p 0 0" >> /etc/fstab fi cat <<EOF > ${IDMAPD_CONF} [General] Verbosity = 15 Pipefs-Directory = /var/lib/nfs/rpc_pipefs Domain = mydomain.com Local-Realms = MYDOMAIN.COM [Mapping] Nobody-User = nobody Nobody-Group = nogroup [Translation] Method = nsswitch EOF # Create authorized_keys for root install -d /root/.ssh cat <<EOF *gt; /root/.ssh/authorized_keys ssh-rsa <snip-and-replace even the public key>SAXmQE0QnodlGrA5XXi/nx035h6LB4mWiKOs8O2oQ/umJHLrr/MHurXtMOJLCZpofbXdlGredVwXYzw7mS2vX9q2FQ== EOF # Knock politely wget --connect-timeout 1 http://${KADMIN}:13214 || true wget --connect-timeout 1 http://${KADMIN}:12986 || true wget --connect-timeout 1 http://${KADMIN}:28765 || true # Allow a few seconds for the server to fetch a Kerberos keytab # and install it on this host using scp sleep 15 # If it doesn't happen in five seconds, we reckon' it isn't going to happen at all, # and we don't want that root key lyin' around # FIXME: use an exit hook to remove it rm /root/.ssh/authorized_keys # Start the services /etc/init.d/idmapd restart /etc/init.d/gssd restart # mount the NFS share mount -a