You can share NFS home directories without enabling Kerberos for more secure authentication. But with the standard system authentication, it’s trivial for a remote user to change the UID of a local account on their PC and gain access to someone else’s home directory. Kerberos adds a requirement that the end user have a special security token to access the home directory. You can only acquire that security token from the designated key server by providing the correct password.
This guide shows you how to integrate a Fedora server with Active Directory so you can share user home directories over NFS more securely. This guide assumes you already have an Active Directory domain.
Install and configure NTP
The Kerberos protocol requires all the computers participating in cryptographic communication to have clocks synchronized to within five minutes.
First, synchronize the NFS server’s clock with the ntpdate command and then commit the change to the hardware clock with the hwclock command:
$ sudo -i # MY_HOSTNAME=$(</etc/hostname) # MY_DOMAIN=${MY_HOSTNAME#*.} # dnf install -y ntpdate # ntpdate $MY_DOMAIN # hwclock -u -w
The # prompt shows commands that need to be run as root. The $ prompt shows commands that can be run as an unprivileged user. The sudo -i command allows you to become root to issue necessary commands.
This guide is meant to be copy-and-paste friendly. Any value you might need to customize appears as a MY_* variable you can tweak before running the remaining commands. Note that if you log out, these variable assignments are cleared.
The above commands assume the domain name part of your server’s hostname matches the domain name of your Active Directory. Unless you set special configuration options in Active Directory, you’ll probably need to set your hostname so the domain part matches your Active Directory domain name.
Now, install the ntp package:
# dnf install -y ntp
Next, configure the NTP service:
# MY_NETWORK=192.0.2.0 # MY_NETMASK=255.255.255.0 # MY_ADSERVER1=192.0.2.91 # MY_ADSERVER2=192.0.2.92 # cat << END > /etc/ntp.conf tinker panic 0 restrict -6 default ignore driftfile /var/lib/ntp/drift includefile /etc/ntp/crypto/pw keys /etc/ntp/keys restrict default ignore restrict $MY_NETWORK mask $MY_NETMASK restrict 127.0.0.1 server $MY_ADSERVER1 server $MY_ADSERVER2 END
If you need to quickly look up the IP addresses of your Active Directory servers, run this command:
# nslookup $MY_DOMAIN
Finally, add an exception to the firewall and start the service:
# firewall-cmd --add-service ntp # firewall-cmd --runtime-to-permanent # systemctl enable ntpd.service # systemctl start ntpd.service
To verify that NTP is working, run this command:
$ ntpq -4 -p
Install and configure Kerberos
To enable Kerberos authentication on our server, install the krb5-workstation package:
# dnf install -y krb5-workstation
Then configure your default realm:
# MY_REALM=${MY_DOMAIN^^} # cat << END > /etc/krb5.conf.d/${MY_DOMAIN%%.*} [libdefaults] default_realm = $MY_REALM dns_lookup_kdc = true [domain_realm] .$MY_DOMAIN = $MY_REALM END
The default realm is your Active Directory domain name in all upper-case letters.
Install and configure SSSD
The next thing you need for KRB5 authenticated home directories is user IDs. You could create them manually on the NFS server. But if you have more than a few users, you’ll want to get the list of usernames and their associated UIDs from Active Directory. Use sssd to fetch the user IDs from Active Directory.
Begin by installing the sssd package:
# dnf install -y sssd
Now configure SSSD to use Active Directory as an ID provider:
# cat << END > /etc/sssd/sssd.conf [sssd] services = nss config_file_version = 2 domains = $MY_DOMAIN [domain/$MY_DOMAIN] id_provider = ad ldap_idmap_range_min = 0 ldap_idmap_range_max = 2100000000 ldap_idmap_range_size = 100000000 ldap_idmap_default_domain_sid = S-1-5-21-0-0-0 krb5_store_password_if_offline = true cache_credentials = true ignore_group_members = true override_gid = 100 override_shell = /bin/bash override_homedir = /home/%u END # chmod 600 /etc/sssd/sssd.conf
The ldap_idmap* values are important to ensure the UIDs Active Directory reports are consistent between the NFS server and all of its clients. Here’s a reference on how SID to uid/gid mapping works in sssd.
Even though you didn’t configure SSSD for authentication by including pam in the services list, end users may still be able to log in to the netboot server over SSH using PubkeyAuthentication or GSSAPIAuthentication methods. You may want to set an explicit limit for who can log in to your netboot server over SSH. For example:
# echo DenyGroups users >> /etc/ssh/sshd_config && systemctl restart sshd.service
Join Active Directory
Next, join the server to the Active Directory domain. Before performing the join, delete any computer accounts by the same name in the domain. This helps ensure you don’t carry over any incorrect settings from a previous join attempt:
# MY_USERNAME=jsmith # adcli delete-computer "${MY_HOSTNAME%%.*}" -U "$MY_USERNAME"
Also, delete any previous version of the system keytab, to avoid carrying over any incorrect settings from a previous join attempt:
# rm -f /etc/krb5.keytab
Now you should be able to join the Active Directory domain:
# MY_OU="cn=computers,dc=${MY_DOMAIN//./,dc=}" # adcli join $MY_DOMAIN --login-user="$MY_USERNAME" --computer-name="${MY_HOSTNAME%%.*}" --host-fqdn="$MY_HOSTNAME" --user-principal="host/$MY_HOSTNAME@$MY_REALM" --service-name="host" --service-name="nfs" --domain-ou="$MY_OU"
By default, Active Directory only allows normal users to join up to 10 computers to its domain (KB243327).
If adcli warns you about DNS not updating, your primary DNS servers may not be forwarding queries properly to the Active Directory domain controllers. Set your network configuration to reference the Active Directory servers directly for DNS.
The –service-name=”nfs” flag in the above command is important. The NFS service cannot serve Kerberized home directories without the nfs “serviceprincipalname”.
If the join succeeded, you should be able to start the SSSD service:
# systemctl start sssd.service
Configure PAM
Once sssd is running, configure the NFS server to resolve UIDs using it:
# cp -r /usr/share/authselect/default/sssd /etc/authselect/custom # echo 'initgroups: files' >> /etc/authselect/custom/sssd/nsswitch.conf # authselect select custom/sssd --force
Set initgroups to files as a performance optimization to prevent group information from being fetched from Active Directory. You can omit that line. If you do, though, you may see delays when you list files or perform other actions that try to look up UID and GID information.
At this point, you should be able to look up a user’s UID:
$ id $MY_USERNAME
You may find it necessary to run systemctl restart sssd.service before the above command works.
Create the home directories
Now that the ID provider is working, create the home directories by cloning the /etc/skel directory and setting permissions:
# cp -a /etc/skel /home/$MY_USERNAME
# chown -R $MY_USERNAME:users /home/$MY_USERNAME
# chmod -R go-rwx /home/$MY_USERNAME
Configure NFS ID mapping
Before you can export the home directories, you must configure NFS’s idmap service:
# cat << END > /etc/idmapd.conf [General] Domain = $MY_DOMAIN Local-Realms = $MY_REALM [Mapping] Nobody-User = nfsnobody Nobody-Group = nfsnobody [Translation] Method = static,nsswitch GSS-Methods = static,nsswitch [Static] END
You must also define the special nfsnobody user for cases where a UID might not resolve to a username:
# echo 'nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin' >> /etc/passwd # echo 'nfsnobody:!!:::::::' >> /etc/shadow # echo 'nfsnobody:x:65534:' >> /etc/group # echo 'nfsnobody:!::' >> /etc/gshadow
Enable Kerberos and share the home directories
Enable KRB5 authentication on the NFS pseudo filesystem:
# MY_SUBNET=192.0.2.0 # MY_PREFIX=24 # echo "/export -fsid=0,ro,sec=sys:krb5,root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports
Now create and mount the home filesystem:
# mkdir /export/home # echo '/home /export/home none bind 0 0' >> /etc/fstab # mount /export/home
Last, we define the home export and restart the NFS server to ensure all configuration changes are registered:
# echo "/export/home -rw,sec=krb5,root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports.d/home.exports # systemctl restart nfs-server.service
Make sure everything looks right on the export. In particular, make sure the krb5 flag is set on both the root export and the home sub-filesystem:
# exportfs -v
The output from the above command should include at least the following two lines (emphasis added):
/export 192.0.2.0/24(sync,wdelay,hide,no_subtree_check,fsid=0,sec=sys:krb5,ro,secure,root_squash,no_all_squash) /export/home 192.0.2.0/24(sync,wdelay,hide,no_subtree_check,sec=krb5,rw,secure,root_squash,no_all_squash)
The Kerberos protocol can also provide encryption (krb5p) or integrity (krb5i) for the NFS export, but these variants of the krb5 option will cause a significant reduction in performance. You probably don’t want to use them unless you really need them.
Photo by Pietro Jeng on Unsplash.
Andrej
Thanks Gregory for a nice tutorial about kerberized NFS. I tried something similar a while ago, and I managed to set-up what you described (although with OpenLDAP, not AD), but I had difficulty understanding how 3rd party services can automatically obtain and keep kerberos tickets which would provide them a persistent access (rw) to the kerberized NFS storage. For example, if I have a backup script that copies files to the NFS storage and it is run by cron… Could you give references for that scenario? Thanks.
Gregory Bartholomew
Sure, you should be able to use the “ktutil” command to store a kerberos account password:
$ ktutil
ktutil: add_entry -password -p admin@EXAMPLE.EDU -k 1 -e RC4-HMAC
ktutil: write_kt admin.keytab
ktutil: quit
You should then be able to use the “kinit” command in your script to initialize a kerberos ticket using the admin.keytab file:
kinit -kt admin.keytab admin@EXAMPLE.EDU
Or, in the case of a continuously running service, you may want to create a cron job for the service with a line like the following which renews the kerberos ticket every 6 hours:
0 */6 * * * /usr/bin/kinit -kt $HOME/admin.keytab -l 6:00
In the case of a backup script, you might also have to map the kerberos account principal to the root user by adding a line like the following to the “[Static]” section of the /etc/idmapd.conf file on the NFS server:
admin@EXAMPLE.EDU = root
And set the “no_root_squash” flag on “/export/home” in /etc/exports.d/home.exports (maybe /export as well).
Andrej
Thanks for the reply! OK, I’ll try it – makes sense, since I’m already familiar with the keytab file. What about systemd services which need to access kerberized NFS? Isn’t there some more “systematic” approach besides granting tickets by cron to them?
Gregory Bartholomew
Honestly, you are asking about things that I haven’t done since before systemd existed, so I don’t really know for sure. My guess is that you could wrap your systemd process in a bash script that would keep the ticket renewed. Maybe something like the following:
#!/usr/bin/bash
kinit -kt /path/to/service.keytab -l 6:00
service_exec &
while true; do
sleep 21600
kinit -kt /path/to/service.keytab -l 6:00
done
I’m not sure if that would work though. It might depend on the type of the systemd service and any number of other things.
Gregory Bartholomew
Hi Andrej: I was just skimming through my comments and I realized that my last response to you may have seemed a bit negative. I didn’t mean to come across that way at all.
Also, I thought I should point out that there is another way for services to get access to the user home directories — a second share of the “/home” filesystem can be made that does not require kerberos authentication. For example, you could add a line like the following to /etc/exports.d/home.exports:
/export/home -rw,sec=sys,root_squash 192.168.0.0/24
You would then have a second NIC in your server assigned an address on that private network that would connect directly to a separate server on which you could run services that you wanted to have access to the user home directories without needing kerberos (e.g. apache).
That may work for some things like apache and backups but not for others like services that the end users may need to run on their client systems.
Hope that helps,
Greg
Andrej
Hello Gregory. An interesting point, although I have to use a protected/private network in that case. Nevertheless, by suggesting those solutions, you made me think if my ideas about sharing data across a network are bad by design.
P.S. No worries, I didn’t negatively receive your previous comment.
Kenyon Ralph
Why would you disable IPv6 for ntpd, with no explanation, here in 2018? Stop spreading bad configurations.
Gregory Bartholomew
The reasons to use IPv4 for NTP are:
1) Compatibility – I doubt there are many (if any) IPv6-only Active Directory domains. I’m sure that there are, however, many networks still using IPv4-only routers.
2) Stability – The IPv6 support that was added to NTP is an “imperfect” hack. See: https://tools.ietf.org/html/draft-boudreault-ipv6-ntp-refid-00
3) Manageability – Among the thing that NTP’s IPv6 reworking didn’t include was an IPv6-compatible “mask” parameter. The mask parameter only supports the IPv4 “dotted decimal” notation (255.255..). Without a mask parameter, one is limited to either listing their Active Directory domain controllers individually one both the “restrict” lines AND the “server” lines (which creates a manageability “gotcha” for the user later on when Active Directory domain controllers are replaced because they are likely to update the server name in one place and not the other) or opening NTPD to the world (as the default configuration does albeit with some protocol restrictions).
4) Security – NTP is still one of the biggest reflectors used for DDoS attacks (see: https://blogs.akamai.com/2018/06/summer-soti—ddos-by-the-numbers.html). If you don’t have to open your NTPD to the world, why would you want to?
So, the configuration that I provided is more likely to “just work” (point 1), “work well” (point 2), “be manageable” (point 3), and “be more secure” (point 4).
If someone wants to just change the “server” lines in the default configuration, I expect that they can figure out how to do that themselves.
Vincent Brobald
Of course, it is interesting to talk about the integration with the Windows world, but it is a bit disappointing to see the article aiming exclusively at Active Directory considering the title. Let’s not forget that protocols like Kerberos and LDAP have very robust FOSS implementation.
AD is not a prerequisite for secure NFS, you can create your own KDC using packages or use enterprise-grade solutions like (Free)IPA to ensure a coherent management of the platform security.
Gregory Bartholomew
Actually, I completely agree.
The real reason that this article uses Active Directory is because it is meant to be used in conjunction with the NetBoot series and those articles are targeted at people who’s clients are probably not running FOSS. This sort of kerberized NFS server can be setup independently of the NetBoot server though, so it was decided to make this a stand-alone article.
Paul
Thanks for the article. These two lines can be condensed into one:
systemctl enable ntpd.service
systemctl start ntpd.service
Becomes:
systemctl enable –now ntpd.service
Gregory Bartholomew
Thanks Paul, I didn’t know about that short cut. I expect that I’ll make good use of it in my day-to-day job. I might stick with the long form for the guides though. Sometimes it is better to show people the long way of doing things so that they get a better understanding of what is going on before you show the trick that makes it all happen with the push of a button. ????
Paul
You’re welcome, I only learnt about it recently in another fedoramagazine article! I agree, depending on the audience, a series of steps may be more informative than dense commands with too much magic.
Phozzy
You may automate most of these tasks by using FreeIPA