PAM and Account PolicyLesson 1 of 3
How PAM decides, and authselect
Read a PAM stack line by line, understand control flags, and change it the supported way with authselect.
authselectauthselect currentauthselect listauthselect selectauthselect enable-featureauthselect apply-changesauthselect check/etc/pam.d/etc/authselectman pam.dls -l /etc/pam.d/system-auth
After this lesson you can
- Name the four PAM management groups and explain required, requisite, sufficient and optional.
- Read /etc/pam.d/sshd and system-auth and say which modules run in which order.
- Switch profile or enable a feature with authselect, and recover a damaged PAM configuration.
The idea
PAM (Pluggable Authentication Modules) is how programs ask “may this user do this?” without knowing how the answer is produced. sshd, login, sudo, su, cockpit and crond do not read /etc/shadow themselves; they call PAM, and PAM runs a configured list of small modules that each check one thing: the password, whether the account has expired, whether /etc/nologin exists, how many failed attempts there have been.
Each service has a file in /etc/pam.d/ named after it. The file is a list of lines; PAM runs the lines for the kind of check that is needed.
The four groups
| Group | Question | Examples |
|---|---|---|
auth | Who are you? Prove it | Password, key, token, pam_faillock counting failures |
account | Are you allowed in now? | Expired account, locked, /etc/nologin, pam_access |
password | Changing credentials | pam_pwquality (strength), pam_unix (store) |
session | Set up and tear down the session | pam_limits, pam_systemd, pam_selinux, pam_lastlog |
A login runs auth, then account, then session. Changing a password runs password. A failure in the wrong group gives a different symptom: a wrong password fails in auth; a correct password for an expired account fails in account.
One line
auth required pam_faillock.so preauth silent deny=3 unlock_time=600
type control module arguments
The control flag decides what the module’s answer means for the whole stack:
| Flag | On success | On failure |
|---|---|---|
required | Continue | Remember the failure, keep running the rest of the group, then fail |
requisite | Continue | Stop immediately with failure |
sufficient | Stop with success (if no earlier required failed) | Ignore and continue |
optional | Ignored unless it is the only module | Ignored |
include / substack | Run the lines of another file; substack has its own result scope | |
[success=1 default=ignore] | Advanced form: jump over the next line(s) | man pam.conf |
Running on after a required failure is deliberate: an attacker should not learn which check failed by how fast the answer came back.
Where the files come from on RHEL
You will see include system-auth or substack password-auth in many service files. On RHEL those two files, and a few others, are not edited by hand. They are generated by authselect from a profile:
ls -l /etc/pam.d/system-auth
lrwxrwxrwx. 1 root root 28 Nov 4 10:12 /etc/pam.d/system-auth -> /etc/authselect/system-auth
The symlinks point into /etc/authselect/, where authselect writes the result of the selected profile plus optional features. The profile and features are chosen with authselect:
authselect list # available profiles: local ("minimal"), sssd, winbind
authselect current # the profile in use and its enabled features
authselect select sssd with-mkhomedir # choose a profile and features
authselect list-features sssd # features available for a profile
authselect enable-feature with-faillock # add a feature to the current profile
authselect apply-changes # regenerate files from the current selection
authselect check # verify that files match what authselect would write
The safety rule
A mistake in PAM can lock everyone out, including root at the console, with no way to log in and fix it. So:
- Keep a root shell open (a second terminal, or the console already logged in) before you change anything.
- Test with a new login (a second ssh session) before closing the working one.
- Prefer
authselect, which writes consistent files, to hand edits. - If you are locked out, boot with
rd.break(or rescue media), mount the system, and runauthselect select/apply-changesfrom the chroot.
Try it
What is selected
authselect current
Profile ID: sssd
Enabled features:
- with-mkhomedir
- with-sudo
Read sshd
cat /etc/pam.d/sshd
#%PAM-1.0
auth substack password-auth
auth include postlogin
account required pam_sepermit.so
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
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
session include password-auth
session include postlogin
Read it as a script. For auth, run the auth lines of password-auth (as a substack: its success or failure is judged on its own, then summed up), then postlogin. For account, check SELinux’s sepermit, then pam_nologin: if /etc/nologin exists, ordinary users are refused. Then the account checks of password-auth, which include pam_unix (expired? locked?). For session, set the SELinux context, record the login id, apply namespace and keyring setup, and include more from password-auth.
The auth stack of system-auth
grep '^auth' /etc/pam.d/system-auth
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth [default=1 ignore=ignore success=ok] pam_usertype.so isregular
auth [default=1 ignore=ignore success=ok] pam_localuser.so
auth sufficient pam_unix.so nullok
auth [default=1 ignore=ignore success=ok] pam_usertype.so isregular
auth sufficient pam_sss.so forward_pass
auth required pam_deny.so
Two things stand out. pam_unix.so is sufficient: if the local password is right, authentication succeeds and the rest is skipped. The last line, pam_deny.so, is required: if nothing earlier succeeded, the stack ends in an unconditional failure. That final pam_deny is normal. The fault in the challenge exercise is the same module appearing at the top, where it fails every login.
When the PAM edit goes wrong
| Symptom | Likely cause | Fix |
|---|---|---|
| Every password login fails after an edit | A hand edit of system-auth/password-auth | authselect check; authselect apply-changes -b |
authselect apply-changes refuses | Files modified outside authselect | -b to back up and force, after you have read the diff |
authselect select removes my change | Local edit overwritten (as designed) | Use features or a custom profile |
sssd profile selected but pam_sss.so fails | sssd not running or no domain | systemctl status sssd, /etc/sssd/sssd.conf mode 600 |
| New user has no home on first login | with-mkhomedir not enabled | authselect enable-feature with-mkhomedir and oddjobd enabled |
| Login fails only for some services | The service’s own file in /etc/pam.d differs | Compare sshd, login, sudo, su |
| Locked out entirely | Broken stack | rd.break, chroot, authselect select ... --force |
Going further
Custom profiles. authselect create-profile site -b sssd --symlink-meta copies a profile into /etc/authselect/custom/site/ so you can add your own lines and keep authselect in control. Beyond the exam: pam_wheel restricts su, pam_listfile allows or denies by file, pam_tally2 is gone (replaced by pam_faillock), and pam_debug.so can be added to a stack to log what each module returned.
Practice
0 of 3 done
Do these on your own system. They get harder. Check each result, then tick it off.
- Warm-up
Read a stack
Print
/etc/pam.d/sshdand answer: which file does it include forauth, which module checks/etc/nologin, and which module opens the session. Then print theauthsection of/etc/pam.d/system-authand identify the module that checks the password.Check your result
auth substack password-auth(orinclude) appears insshd.account required pam_nologin.soappears;sessionlines includepam_systemd.soviapassword-auth.- In the
authsection the password check ispam_unix.so(possibly afterpam_sss.soif the SSSD profile is active).
Hint
A PAM line has four fields: type, control, module, arguments.
include/substackpull in another file. Files under/etc/pam.dare named after the service (sshd,login,sudo).Solution
cat /etc/pam.d/sshd grep '^auth' /etc/pam.d/system-auth ls -l /etc/pam.d/system-auth /etc/pam.d/password-auth - Practice
Enable a feature the supported way
Show the current authselect profile and enabled features. Enable
with-faillockwithout editing any file in/etc/pam.d, apply it, and prove that thepam_faillocklines now appear insystem-authandpassword-auth. Runauthselect check. Then disable the feature again and confirm the lines are gone.Check your result
authselect currentprintsProfile ID: ...and a feature list.- After enabling:
grep -c faillock /etc/pam.d/system-authis greater than 0. authselect checkprintsCurrent configuration is valid.- After disabling:
grep -c faillock /etc/pam.d/system-authis 0.
Hint
authselect enable-feature with-faillockchanges the selection and regenerates the files;authselect apply-changesre-applies the current selection. Do not editsystem-auth: it is a generated file, andauthselect checkreports a manual edit.Solution
authselect current sudo authselect enable-feature with-faillock sudo authselect apply-changes grep -c faillock /etc/pam.d/system-auth authselect check sudo authselect disable-feature with-faillock sudo authselect apply-changes grep -c faillock /etc/pam.d/system-auth - Challenge
Someone edited system-auth by hand
Setup (lab VM, keep a root console open in another terminal before you start):
sudo cp -a /etc/pam.d/system-auth /root/system-auth.good sudo sed -i 's/^auth .*pam_unix.so.*/auth required pam_deny.so/' /etc/pam.d/system-authNobody can log in with a password any more. From your open root shell, prove with
authselect checkthat the file was modified outside authselect, restore a correct configuration without copying the old file back, and confirm a login works. Explain why the supported repair is better than restoring a copy.Check your result
authselect checkreports the files are not what authselect would generate.- After
sudo authselect apply-changes -b(orauthselect select PROFILE --force),grep pam_deny /etc/pam.d/system-authshows only the normal deny line at the end of a stack, not the firstauthline. su - testuseror an ssh login with a password succeeds.
Hint
authselect apply-changesfails with an error if files were hand-edited;-bmakes a backup and forces the regeneration. A copy would restore this file but not necessarily a consistent state with the selected profile and features.Solution
authselect check sudo authselect apply-changes -b authselect check grep -n '^auth' /etc/pam.d/system-auth su - testuser -c id