Kerberos, mount.cifs and automounting
Table of contents
- Goal
- Environment
- Discussion
- /etc/krb5.conf
- /etc/pam.d/system-auth
- /etc/auto.master
- mount.cifs
- cifs.upcall and request-key
- Tickets
- Debugging
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:
- Organisation providing centrally-administered file serving and user accounts in a Windows environment
- 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.
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:
- The file system is mounted via CIFS
- The security model is krb5i, which is Kerberos authentication (not password authentication) with integrity checking
- 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
- 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
- gid will be the ID of the group owner of the files and subdirectories as seen by any Linux users
- dir_mode is the permissions which will be set for all subdirectories in the mounted share
- file_mode is the permissions for all files in the mounted share
- //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:
- The location and name of the ticket cache. The 500 is the UID of user z9702847
- The principal, which is the name of the user and the Kerberos realm ("AD.UNSW.EDU.AU")
- 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