Automount Home Directories on CentOS 8 With FreeIPA

FreeIPA is an identity management solution combining LDAP, Kerberos, NTP, and DNS, among others. I have deployed this in production for our small business to manage users across several satellite retail and production locations. Currently I have no shared home directory set up so when a user moves to a different workstation, they must reconfigure their GNOME and Firefox settings. This has minimal impact right now as users are usually using a single workstation to complete computer-related tasks, but in preparation for business growth, as well as catering to the unique users moving across multiple facilities, I will be testing out NFS-based automounting home directories.

This guide expects you can configure your server securely and does not attempt to cover all possible configurations. Shortcuts are taken as this is a lab setup in a VLAN with limited ingress and egress access. I will utilize three VMs, all running CentOS 8 starting with a minimal install and additionally adding the standard and guest tools as via the graphical installer. Our lab environment is as follows:

  1. idm1.example.com as 10.0.51.150
  2. nfs.example.com as 10.0.51.151
  3. client.example.com as 10.0.51.152

idm1.example.com

idm1 will be our identity management (idm) server running FreeIPA. This will be set up as a standalone service (no replicas) with integrated DNS and with an integrated CA as the root CA.

Setup

After logging in as root, update the server and install the necessary packages, first enabling the module containing the idm software:

# dnf module enable idm:DL1
# dnf distro-sync
# dnf module install idm:DL1/dns

I chose idm:DL1/dns as I am installing with integrated DNS. Other options exist and you should familiarize yourself with them here.

Next, I’ll open the appropriate firewall ports using firewall-cmd. Service definitions found in /usr/lib/firewalld/services make this easy – just add freeipa-4 and dns (the freeipa-ldap/s and related service files have been deprecated).

# firewall-cmd --permanent --add-service={freeipa-4,dns}
# firewall-cmd --reload

You should now see these services added:

# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens18
  sources: 
  services: cockpit dhcpv6-client dns freeipa-4 ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

Finally, add the hostname and IP information to the /etc/hosts file so our server can reference itself for proper domain setup:

# echo "10.0.51.150 idm1.example.com idm1" >> /etc/hosts

Install

This part is relatively straightforward. I’ll run the install command and, for the most part, accept the default values. Pay attention to the prompts as some defaults cause an abort or can uncover configuration mistakes, particularly with the assumed domain. Much of the output of the command below has been cut for brevity’s sake:

# ipa-server-install 

The log file for this installation can be found in /var/log/ipaserver-install.log
==============================================================================
This program will set up the IPA Server.
Version 4.9.2

Do you want to configure integrated DNS (BIND)? [no]: yes
Server host name [idm1.example.com]: 
Please confirm the domain name [example.com]: 
Please provide a realm name [EXAMPLE.COM]: 

Directory Manager password: 
Password (confirm): 

IPA admin password: 
Password (confirm): 

Do you want to configure DNS forwarders? [yes]:

Following DNS servers are configured in /etc/resolv.conf: 1.1.1.1, 1.0.0.1
Do you want to configure these servers as DNS forwarders? [yes]: 
Enter an IP address for a DNS forwarder, or press Enter to skip: 

Do you want to search for missing reverse zones? [yes]: 
Do you want to create reverse zone for IP 10.0.51.150 [yes]: 
Please specify the reverse zone name [51.0.10.in-addr.arpa.]: 

Do you want to configure chrony with NTP server or pool address? [no]: 

The IPA Master Server will be configured with:
Hostname:       idm1.example.com
IP address(es): 10.0.51.150
Domain name:    example.com
Realm name:     EXAMPLE.COM

The CA will be configured with:
Subject DN:   CN=Certificate Authority,O=EXAMPLE.COM
Subject base: O=EXAMPLE.COM
Chaining:     self-signed

BIND DNS server will be configured to serve IPA domain with:
Forwarders:       1.1.1.1, 1.0.0.1
Forward policy:   only
Reverse zone(s):  51.0.10.in-addr.arpa.

Continue to configure the system with these values? [no]: yes

...

==============================================================================
Setup complete

Next steps:
	1. You must make sure these network ports are open:
		TCP Ports:
		  * 80, 443: HTTP/HTTPS
		  * 389, 636: LDAP/LDAPS
		  * 88, 464: kerberos
		  * 53: bind
		UDP Ports:
		  * 88, 464: kerberos
		  * 53: bind
		  * 123: ntp

	2. You can now obtain a kerberos ticket using the command: 'kinit admin'
	   This ticket will allow you to use the IPA tools (e.g., ipa user-add)
	   and the web user interface.

Be sure to back up the CA certificates stored in /root/cacert.p12
These files are required to create replicas. The password for these
files is the Directory Manager password
The ipa-server-install command was successful

That’s it for the idm server. I’ll use the ipa command line utilities for adding users and NFS service in the next part.

nfs.example.com

This server will be enrolled in our idm and provide our NFS server.

Setup

Again, we’re starting on a fresh minimal install as root. I’ll update the server and make sure the necessary utilities are installed. No need for installing the idm:DL1 stream – the ipa-client is available in the repositories.

# dnf update
# dnf install nfs-utils ipa-client

I’ll go ahead and add additional services allowed via firewalld:

# firewall-cmd --permanent --add-service={nfs,mountd,rpc-bind}
# firewall-cmd --reload

Output should confirm:

# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens18
  sources: 
  services: cockpit dhcpv6-client mountd nfs rpc-bind ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

For the last setup task, I’ll enroll this host with our previously created idm host. Make sure your nameserver in /etc/resolv.conf points to the idm host and verify your search domain is correct as well. Once again, pay attention to default values.

# cat /etc/resolv.conf
search example.com
nameserver 10.0.51.150

# ipa-client-install -p admin -W
This program will set up IPA client.
Version 4.9.2

Discovery was successful!
Do you want to configure chrony with NTP server or pool address? [no]: 
Client hostname: nfs.example.com
Realm: EXAMPLE.COM
DNS Domain: example.com
IPA Server: idm1.example.com
BaseDN: dc=x,dc=example,dc=net

Continue to configure the system with these values? [no]: yes
Synchronizing time
No SRV records of NTP servers found and no NTP server or pool address was provided.
Using default chrony configuration.
Attempting to sync time with chronyc.
Time synchronization was successful.
Password for admin@EXAMPLE.COM: 
Successfully retrieved CA cert
    Subject:     CN=Certificate Authority,O=EXAMPLE.COM
    Issuer:      CN=Certificate Authority,O=EXAMPLE.COM
    Valid From:  2021-08-23 21:00:55
    Valid Until: 2041-08-23 21:00:55

Enrolled in IPA realm EXAMPLE.COM
Created /etc/ipa/default.conf
Configured sudoers in /etc/authselect/user-nsswitch.conf
Configured /etc/sssd/sssd.conf
Configured /etc/krb5.conf for IPA realm EXAMPLE.COM
Systemwide CA database updated.
Hostname (nfs.example.com) does not have A/AAAA record.
Missing reverse record(s) for address(es): 10.0.51.151.
Adding SSH public key from /etc/ssh/ssh_host_ecdsa_key.pub
Adding SSH public key from /etc/ssh/ssh_host_ed25519_key.pub
Adding SSH public key from /etc/ssh/ssh_host_rsa_key.pub
SSSD enabled
Configured /etc/openldap/ldap.conf
Configured /etc/ssh/ssh_config
Configured /etc/ssh/sshd_config
Configuring example.com as NIS domain.
Client configuration complete.
The ipa-client-install command was successful

Install

To start I will obtain a Kerberos ticket:

# kinit admin

Next I’ll create an NFS service entry:

# ipa service-add nfs/nfs.example.com
---------------------------------------------------------------------------
Added service "nfs/nfs.example.com@EXAMPLE.COM"
---------------------------------------------------------------------------
  Principal name: nfs/nfs.example.com@EXAMPLE.COM
  Principal alias: nfs/nfs.example.com@EXAMPLE.COM
  Managed by: nfs.example.com

Follow this with a keytab retrieval:

# ipa-getkeytab -s idm1.example.com -p nfs/nfs.example.com -k /etc/krb5.keytab
Keytab successfully retrieved and stored in: /etc/krb5.keytab

I’ll verify that everything looks good using ipa service-show:

# ipa service-show nfs/nfs.example.com
  Principal name: nfs/nfs.example.com@EXAMPLE.COM
  Principal alias: nfs/nfs.example.com@EXAMPLE.COM
  Keytab: True
  Managed by: nfs.example.com

Configure the NFS settings:

# ipa-client-automount
Searching for IPA server...
IPA server: DNS discovery
Location: default
Continue to configure the system with these values? [no]: yes
Configured /etc/idmapd.conf
Restarting sssd, waiting for it to become available.
Started autofs

We’re getting close. Next I’ll add the exports using the krb5p security setting. I’m just going to export the home directory but you can use a different directory (or multiple directories) if you so desire.

# echo "/home  *(rw,sec=krb5:krb5i:krb5p)" > /etc/exports

Let’s enable and start NFS, and verify our directory exports:

# systemctl enable --now nfs-server.service
# export -rav
exporting *:/home
# showmount -e
Export list for nfs.example.com:
/home *

Finally, I am going to create the automount map:

# ipa automountmap-add-indirect default auto.home --mount=/home
-------------------------------
Added automount map "auto.home"
-------------------------------
  Map: auto.home

…and key:

# ipa automountkey-add default auto.home --key "*" --info "nfs.example.com:/home/&"
-----------------------
Added automount key "*"
-----------------------
  Key: *
  Mount information: nfs.example.com:/home/&

Now we can create a user and their home directory. As we are exporting home, we won’t need to move anything around.

# ipa user-add --first McCoy --last Pauley --password --shell=/bin/bash
User login [mpauley]: 
Password: 
Enter Password again to verify: 
--------------------
Added user "mpauley"
--------------------
  User login: mpauley
  First name: McCoy
  Last name: Pauley
  Full name: McCoy Pauley
  Display name: McCoy Pauley
  Initials: MP
  Home directory: /home/mpauley
  GECOS: McCoy Pauley
  Login shell: /bin/bash
  Principal name: mpauley@EXAMPLE.COM
  Principal alias: mpauley@EXAMPLE.COM
  User password expiration: 20210823214024Z
  Email address: mpauley@example.com
  UID: 873600003
  GID: 873600003
  Password: True
  Member of groups: ipausers
  Kerberos keys available: True

# mkhomedir_helper mpauley 077

I’m going to create a text file to verify our NFS automounted home on our client next:

# echo "It works!" > /home/mpauley/test-file.txt
# chown mpauley: /home/mpauley/test-file.txt

client.example.com

Our client will have no services installed but will be enrolled in the idm server to see if our effort has paid off. We should see that our test file exists in the user’s home directory.

Setup

I won’t repeat the full steps here. Refer back to the previous sections if you need guidance.

  1. Update packages.
  2. Install ipa-client.
  3. Ensure the resolv.conf points to the idm server.
  4. Run ipa-client-install.
  5. Run ipa-client-automount.

I briefly tested this with GNOME as well, receiving subsequent AVC denials. In my case, this easily resolved by enabling an SELinux boolean*:

# sebool -P use_nfs_home_dirs 1

* Thanks to /u/Smithore for the reminder!

The Big Test

Once these steps are complete, log out of the server and log in as our newly created user, mpauley:

$ ssh mpauley@client.example.com

(mpauley@10.0.51.152) Password:

$ ls -lh
total 4.0K
-rw-r--r--. 1 mpauley mpauley 43 Aug 23 19:43 test-file.txt
$ cat test-file.txt
It works!

Conclusion

While this example was merely a proof-of-concept for my further planning and was deliberately quite simple, we can of course dive in to the rabbit-hole of complexity these tools provide. I look forward to rolling this out, but perhaps I’ll wait until I can beg for a few more bits through tiny pipes at a couple of sites. ¯\_(ツ)_/¯