Using PAM for kerberos authentication and group access control

This article shows how to configure PAM on RHEL 6.x to use kerberos authentication and how to use group membership to restrict who can log in to a machine.

This example assumes that you have configured your machine to authenticate against the IASTATE.EDU Windows Domain Controllers. More information about configuring Kerberos to use the Domain Controllers can be found in the article Configuring Secure NFS in the IASTATE Domain.

Brief Intro to PAM

Pluggable Authentication Modules (PAM) is a highly configurable system for performing authentication, authorization, session creation, and changing passwords. In Linux, most applications use the PAM system instead of writing the authentication and authorization directly into the application code. This allows one to change the authentication for a application without having to modify the application code.

This article is not intended to be a complete introduction to PAM. For a really good intro, see Wayne Pollack's PAM Tutorial.

PAM uses a list of rules that can be tailored as needed. The collection of rules for a given application is frequently referred to as the PAM stack. All of the PAM stacks for various applications are found in the directory /etc/pam.d.

For instance, if SSH is configured to use PAM, it uses rules in /etc/pam.d/sshd. If we look at this file we see:

#%PAM-1.0
auth    required pam_sepermit.so
auth       include      password-auth
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    optional     pam_keyinit.so force revoke
session    include      password-auth

The first column indicates which "facility" the rule applies to. There are four facilities: auth, account, session, and password.

The auth facility contains the rules used for authenticating a user. The account rules are used for checking the validity of an account. The session facility sets up the session for a user. The password facility is used only when changing a password.

Notice that the sshd PAM stack contains the directive auth include password-auth. This says that the ssh PAM stack will use auth rules from the PAM stack called password-auth. This technique makes it easier to define the authentication process for many applications in a single location. If we modify the rules in /etc/pam.d/password-auth, the rules will apply to any PAM stack that includes these rules.

It should be noted that writing a PAM stack manually is not trivial. It requires knowing the purpose, behaviour, and interaction of the many modules available in PAM. There are some tools that can be used to prepare a simple but functional PAM stack. However, more advanced customization is usually done by editing the PAM stack files directly.

A Basic PAM Stack

The PAM stack below is what is created in /etc/pam.d/password-auth when you build a RHEL6 system "out of the box".

#%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        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 500 quiet
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    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

This PAM stack is fairly generic. Authentication is done using local password authentication (pam_unix.so) and the account must exist locally on the system (pam_localuser.so). The session receives standard resource limits (pam_limits.so). Changing a password is done locally and new passwords are checked to see if they are easy to crack (pam_cracklib.so). There are quite a few different modules available for PAM. A fairly complete list of what the different PAM modules do is available at the PAM Administrator's Guide.

Adding Kerberos Support

Let's say we've just built our machine with RHEL6 and we want to configure our system to use Kerberos. Of course, we also need to configure Kerberos on our system by modifying /etc/krb5.conf correctly (or possibly by using SSSD). But adding kerberos to PAM is pretty simple. We can just use the authconfig utility to enable kerberos in PAM:

# yum install pam_krb5
# authconfig --enablekrb5 --update

Note that if you have customized /etc/nsswitch.conf the authconfig command will overwrite your customizations.

That's it. Now, when we look at /etc/pam.d/password-auth, we see that all the facilities have added a rule that uses the PAM kerberos module pam_krb5.so:

#%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

Now, when a user enters their password to authenticate, in addition to checking local account passwords, it will also check the password using kerberos (provided that kerberos has been properly configured on the system). Using kerberos also adds some extra functionality to a user's session (e.g. setting the credential cache location) so the session facility is modified as well.

Adding A Rule to Check Group Membership

One thing to note about the above PAM stack is that it is possible for anyone who can authenticate to kerberos to log in. Let's say we'd like to limit logins on this system to only those users who are in a certain group. To do this, we're going to add a PAM rule that says the authentication will only succeed if a user also belongs to a particular group. We're going to use the pam_succeed_if PAM module. There are several kinds of checks we can do with the pam_succeed_if module. In this case, we're just going to add a rule to the auth facility that checks to see if the user is a member of the group engr_faculty. The syntax for this rule in pam_succeed_if is:

auth     requisite    pam_succeed_if.so user ingroup engr_faculty

Notice the term requisite. This is called the control flag. The control flags are very important. In this case, requisite means "if this rule is not satisfied then authentication fails". When you chain rules together, the control flags on the rules establish the policy for how the PAM stack will succeed or fail.Now, let's add this rule to our new kerberos-enabled PAM stack:

# 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 user ingroup engr_faculty
auth        requisite     pam_succeed_if.so uid >= 100 quiet
auth        sufficient    pam_krb5.so try_first_pass
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_succeed_if.so uid < 100 quiet
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3
password    sufficient    pam_unix.so md5 shadow nullok try_first_pass 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

Notice that we added the pam_succeed_if rule after the pam_unix module in the auth stack. This allows local accounts to be able to log in regardless if they are in the engr_faculty group. Also notice that both the pam_unix.so and pam_krb5.so rules have the sufficient control flag. Sufficient means "if this rule is met then authentication has succeeded". So a successful login is possible for either a local account or an account authenticated against kerberos.

Tested on: 
RHEL 6.3