Kerberos, mount.cifs and automounting

Table of contents


Goal

Allow users on independently-administered Linux workstations to access home folders on a centrally-administered Windows file server without having to authenticate multiple times.


Environment

The environment in which we need to operate involves two administrative groups of people. We want to avoid any overlap or dependencies between the two groups so that each can operate independently. The two groups are:

  1. Organisation providing centrally-administered file serving and user accounts in a Windows environment
  2. Affiliated organisation running Linux with users requiring access to centrally-administered hole folders

The diagram below shows the resources managed by each group in a bit more detail. The right-hand side of the diagram shows the main organisation's resources, and the left-hand side of the diagram shows the workstations administered by the affiliated organisation.

CIFS environment

There are basically three resources in play here:

  • Windows 2008 R2 Enterprise server running as a Domain Controller (2008 mode)
  • Windows file servers which are members of the domain
  • Centos 6.5 (Kernel = 2.6.32) workstations


Discussion

Kerberos was chosen as authentication service because a Windows Domain Controller (DC) contains both a Kerberos Authentication Server (AS) and a Kerberos Key Distribution Center (KDC) Domain Controller which a Linux workstation can use. This means that when we configure PAM (Pluggable Authentication Modules) on the Linux workstation to use Kerberos to authenticate users to the Windows DC, at the same time we get a Kerberos ticket-granting ticket (TGT) for the user which can subsequently be used when mounting the user's home folder via CIFS so they don't have to authenticate twice.

Additionally, in our case the Windows Domain Controller has the Identity Management for UNIX role service installed and all accounts have reasonable values for user ID, group ID, home directory, and so on. Because a Windows DC has a built-in LDAP server it means that the Linux workstation can also get account information from the DC.

It would be possible to mount the user's home folder with CIFS via PAM at the same time as they log on, but there are problems with this. The main one has to do with unmounting the home folder when the user is finished. If we simply unmount the home folder at the end of each Linux login session then there will be a conflict when the user has logged in multiple, overlapping times. This can occur when, for example, a user logs on to their desktop computer remotely from home, perhaps leaves a file or two open in an editor, and then comes to the office and logs on to their computer's console. When they finish for the day at the office PAM would attempt to unmount their home folder and this might then lead to the work being lost which they were doing from home.

Using an automounter solves such conflicts and race conditions because the automounter automatically mounts the home folder when the user tries to access it, and then automatically unmounts it when it's not being used any more. This takes away the "session-ness" from unmounting and is more robust. Even if an unmount occurs while a file is being edited, for example, the automounter will automatically re-mount it when the user goes to save the file.


/etc/krb5.conf

The Kerberos configuration on the Linux workstation points to the centrally-administered Windows DC and uses it as its Kerberos AS and KDC:

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 default_realm = AD.UNSW.EDU.AU
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true

[realms]
 AD.UNSW.EDU.AU = {
  kdc = ad.unsw.edu.au
  admin_server = ad.unsw.edu.au
 }

[domain_realm]
 ad.unsw.edu.au = AD.UNSW.EDU.AU
 .ad.unsw.edu.au = AD.UNSW.EDU.AU


/etc/pam.d/system-auth

When logging in, PAM uses the following configuration. When the user successfully authenticates via Kerberos, the pam_krb5 module puts a valid Kerberos TGT for the user in the user's ticket cache in /tmp. This TGT is then used for subsequent accesses to secured services (such as CIFS in this present case).

#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        sufficient    pam_krb5.so use_first_pass
auth        required      pam_deny.so

account     required      pam_unix.so broken_shadow
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 500 quiet
account     [default=bad success=ok user_unknown=ignore] pam_krb5.so
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    sufficient    pam_krb5.so use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
session     optional      pam_krb5.so


/etc/auto.master

The Centos 6 automounter, autofs, uses this file to identify all the mount points which should be managed by the automounter and how to map attempts to access subdirectories in these mount points to remote file systems. In our case the file contains just one line:

/unsw program /etc/unswmount/unsw

This says that any attempt to access a subdirectory of /unsw should invoke the script /etc/unswmount/unsw to determine the remote server and path to mount. The contents of the script are not presented here because it is the output which is important, not how it is determined. It is going to be different for each site.

In our case, when a user tries to access, say, /unsw/z9702847 (where "z9702847") is the account name of the user, the following is run by the automounter:

/etc/unswmount/unsw z9702847

The script returns:

-fstype=cifs,sec=krb5i,cruid=z9702847,uid=z9702847,gid=z9702847,dir_mode=0770,file_mode=0640 ://INFPWFS201.ad.unsw.edu.au/Staff006\$/z9702847

This says:

  1. The file system is mounted via CIFS
  2. The security model is krb5i, which is Kerberos authentication (not password authentication) with integrity checking
  3. cruid determines the credential cache to use for authenticating the user to the Windows file server. It will be the account name of a user who logged in using a Kerberos user name and password, or who authenticated using kinit. In both these cases a credential cache is created in /tmp which contains a Kerberos TGT in their name. This ticket is used to authenticate them during the CIFS mount operation
  4. uid will be the user ID of the owner of the CIFS-mounted shareand its contents. In other words, all the files and subdirectories in the share will appear to be owned by this user (if you run ls -l, for example) and this user will be treated as the owner by Linux and the Windows file server
  5. gid will be the ID of the group owner of the files and subdirectories as seen by any Linux users
  6. dir_mode is the permissions which will be set for all subdirectories in the mounted share
  7. file_mode is the permissions for all files in the mounted share
  8. //INFPWFS201.ad.unsw.edu.au/Staff006\$/z9702847 is the UNC of the remote server and path of the share. Note the escaped dollar sign and the use of forward slashes

Note that the dir_mode and file_mode permissions are what is presented to the Linux users. The ACLs at the Windows end may be completely different. The ACLs always win.


Finding a user's home folder/directory location

When you need to find the server and path (UNC) for a user's home folder under Windows, which is what the above mentioned script does in effect, you can use LDAP on the Linux client. Each Windows DC contains an LDAP server which can be used to search Active Directory (AD).

When ldapsearch is installed on the client, something like the following will do the trick to find the user's homeDirectory attribute, which is what we want:

ldapsearch -D z9702847_sa@ad.unsw.edu.au -H ldap://ad.unsw.edu.au -b dc=ad,dc=unsw,dc=edu,dc=au -x -w <password> ‘(name=z9702847)' homeDirectory

As hinted earlier, the UNC from AD contains backslashes which will need to be converted to forwards slashes before passing to mount.cifs, and some special characters, such as dollar signs, will need to be escaped.


mount.cifs

It is always the case that the CIFS mount is performed by the Linux kernel itself. The automounter simply invokes the kernel's mount functionality and passes the required parameters to the kernel. These parameters are the same ones output by the script above and are discussed in more detail there.

A mount can be performed from the command line or from a script using the /sbin/mount.cifs program (or with mount -t cifs ...). This simply invokes the Kernel's mount functionality with the supplied parameters.


cifs.upcall and request-key

When performing a Kerberos-authenticated CIFS mount, the Linux kernel needs to access the Kerberos tickets which are stored in user space (such as in the credential cache in /tmp). To do so, the kernel invokes the generic /sbin/request-key program which reads its /etc/request-key.conf configuration file to work out what to do for each request.

In the case of Kerberos-authenticated CIFS mounts, this configuration file contains the following two lines, the latter of which tells it to use the cifs.upcall program to get the appropriate Kerberos ticket(s).

create cifs.idmap * * /usr/sbin/cifs.idmap %k
create cifs.spnego * * /usr/sbin/cifs.upcall %k


Tickets

To access a service, such as a CIFS server, via Kerberos TWO tickets are required. One is the obvious user ticket and the other is the less obvious service ticket. This latter authenticates the client/computer (in this case, the Linux workstation) to connect to the service (the CIFS server) before we even get to the user authentication stage.

We can see these tickets after we first log in to the Linux workstation with our Kerberos ID and password.

When we run klist (which lists Kerberos tickets), we get:

[z9702847@client02 ~]$ klist
Ticket cache: FILE:/tmp/krb5cc_500
Default principal: z9702847@AD.UNSW.EDU.AU

Valid starting     Expires            Service principal
02/03/14 09:13:42  02/03/14 19:13:46  krbtgt/AD.UNSW.EDU.AU@AD.UNSW.EDU.AU
	renew until 02/10/14 09:13:42
[z9702847@client02 ~]$

In the above, there are a couple of things to note:

  1. The location and name of the ticket cache. The 500 is the UID of user z9702847
  2. The principal, which is the name of the user and the Kerberos realm ("AD.UNSW.EDU.AU")
  3. The TGT (krbtgt/..."), its validity (10 hours), and that it can be renewed for up to a week

After we have accessed the home folder, we run klist again and we get:

[z9702847@client02 z9702847]$ klist
Ticket cache: FILE:/tmp/krb5cc_500
Default principal: z9702847@AD.UNSW.EDU.AU

Valid starting     Expires            Service principal
02/03/14 09:13:42  02/03/14 19:13:46  krbtgt/AD.UNSW.EDU.AU@AD.UNSW.EDU.AU
	renew until 02/10/14 09:13:42
02/03/14 09:43:28  02/03/14 19:13:46  cifs/infpwfs201.ad.unsw.edu.au@AD.UNSW.EDU.AU
	renew until 02/10/14 09:13:42
[z9702847@client02 z9702847]$ 

We can see that we now have acquired a service ticket for the CIFS service on the server (cifs/infpwfs201.ad.unsw.edu.au@AD.UNSW.EDU.AU)

Generally speaking, Kerberos tickets have a limited life. The default is ten hours. Some tickets are renewable up to a certain time limit as we saw above.

For speed and efficiency reasons, some Linux software caches Kerberos credentials. Sometimes the software is unable to tell when a ticket has expired and will continue trying to present it to servers or the KDC after the ticket has expired. This doesn't have a good outcome.

When this unhelpful caching occurs the relevant program may need to be restarted to get it to refresh or replace the tickets in its cache.


Debugging

Automounter

In Centos 6, some of the automounter's operation is configured in the file /etc/sysconfig/autofs. Of particular interest is the OPTIONS variable which, when set to "-v -d", will cause a lot of useful debugging information to be written to /var/log/messages.

Kernel

Because the Linux kernel is what actually does the mounting and unmounting via CIFS, turning on debugging in the automounter itself is often of only limited usefulness. We can turn on kernel debug messages by running the following:

echo 1 > /proc/fs/cifs/cifsFYI

The debug messages will be written to syslog and we can cause them to appear in /var/log/messages by including the following two lines in /etc/rsyslog.conf:

*.debug /var/log/messages
kern.* /var/log/messages