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.