Home / Alt manpages / pam_access(8)

  • pam_access(8)
  • Admin command
  • linux

Control PAM Logins Safely with pam_access and access.conf

By the end of this guide, you will have a first-match access policy for a PAM service, know which users and origins it covers, and have a recovery plan for a rule that locks out the wrong account. The examples use Ubuntu's installed libpam-modules version 1.5.3-5ubuntu5.7. Allow about 15 minutes for a careful change, plus time to test through the actual service.

Before you start

You need root or sudo, an existing test account, and a second administrator session that you will keep open. Do not test a new policy by closing your only root shell. A bad PAM account rule can deny a later login, including an SSH login.

This module does not create a policy on its own. A PAM service must call it from a file under /etc/pam.d/, and the rules normally live in /etc/security/access.conf. First inspect the service you intend to change:

sudo grep -nH pam_access /etc/pam.d/sshd /etc/pam.d/login 2>/dev/null

If that prints nothing for the service, editing access.conf will not affect that service. If it prints a line such as account required pam_access.so, the module is in the account stack. Follow the local PAM stack and its surrounding control flags; do not assume every service handles a denial in the same way.

Checkpoint

Keep the second administrator session open, identify the service, and record which PAM file calls pam_access.

Understand the rule that will win

Each rule has three colon-separated fields:

permission:users-or-groups:origins

A plus grants access and a minus denies it. The user field accepts login names, ALL, netgroups such as @admins, or groups written in parentheses, such as (wheel). The origin field can match ALL, LOCAL, a host, a domain, an address or network, a terminal, an X display, or a PAM service name.

Rules are evaluated from the top. The first matching entry decides the result, and later entries are not consulted. This is the main trap: a broad allow near the top can make a carefully written deny below it unreachable. Put narrow exceptions first and the broad fallback last.

On this installation, the module reads /etc/security/access.conf first and then matching *.conf files in /etc/security/access.d/, in locale order. A match stops further file parsing. An explicit accessfile=... option selects one alternative file and skips that directory.

Write a small, reviewable policy

Make a backup before changing the live file. This is reversible, but the backup is useful if a package update or another administrator has changed the file since you last looked.

sudo cp -p /etc/security/access.conf /etc/security/access.conf.before-pam-access

For a policy that allows the wheel group to use local consoles, allows one named account from a documented management network, and denies the remaining cases, the relevant lines could be:

+:(wheel):LOCAL
+:opsadmin:192.0.2.0/24
-:ALL:ALL

Spaces, commas and tabs separate items inside a field by default, while colons separate fields. Do not add decorative spaces around the colons. A comment is recognised when # is the first character on the line.

The address range above is documentation space, not a real management network. Replace it with the address or network that your service actually reports. Prefer a network with an explicit mask, such as 198.51.100.0/24, over a dotted prefix whose meaning depends on string matching. For a hostname domain, a leading dot matches that domain and its subdomains according to the module's host matching rules.

Use a temporary file while reviewing the order, then install it with an atomic rename:

umask 077
tmp=$(mktemp)
sudo cp -p /etc/security/access.conf "$tmp"
sudoedit "$tmp"
sudo install -o root -g root -m 0644 "$tmp" /etc/security/access.conf
rm -f "$tmp"

That sequence still needs a human review before the final command. Check that the last broad denial is present, that every intended exception appears above it, and that group names have parentheses. The module has no separate configuration checker in the documented interface, so a zero exit status from install only proves that the file was copied.

Checkpoint

Review the installed file as root and confirm the effective order:

sudo nl -ba /etc/security/access.conf | sed -n '1,120p'

Test through the real PAM service

Test each intended allow and deny using the service you inspected, from the origin you are matching. For SSH, open a new connection from the permitted network with the test account. Keep the existing administrator session untouched while you test.

For a local console or a service with an interactive test path, use a disposable account rather than testing a production administrator. The expected result is straightforward: a matching plus reaches the service, while a matching minus is rejected. A PAM denial can be logged by the service or by the system journal, but the exact message depends on the PAM stack and service.

sudo journalctl -b --no-pager | grep -E 'pam_access|access.conf' | tail -30

Do not treat a missing log line as proof that a rule did not match. The debug module option sends detailed information to syslog, but enabling it can expose login-policy details in logs. Use it only briefly, only while diagnosing a controlled test, and remove it afterwards. The noaudit option suppresses audit reporting for denials based on origin; it changes observability, not the access decision.

Common mistakes and recovery

  • Everything is denied: a final -:ALL:ALL is working as designed, but an earlier allow did not match. Check the exact user, group syntax, origin and service.
  • A rule below another one never runs: move the more specific rule above the first broad match. First-match ordering is intentional.
  • A group rule is ignored: write it as (groupname). The module's backwards-compatible default also tries group matching for unparenthesised tokens unless nodefgroup is set, so explicit parentheses avoid ambiguity.
  • Spaces in a domain or group behave oddly: the default list separators are spaces, commas and tabs. listsep=, can change that for a service, but then spaces become part of list items. Change this only with a tested, service-specific configuration.
  • You lost access: use the still-open administrator session or the machine's approved console or recovery path. Restore the backup, then retest: sudo cp -p /etc/security/access.conf.before-pam-access /etc/security/access.conf. Do not reboot merely to see whether the rule clears; the file remains in place.

After recovery, inspect both /etc/security/access.conf and /etc/security/access.d/*.conf. A rule in the directory may be the first match even when the main file looks correct.

Done means

  • The target PAM service calls pam_access.
  • The policy uses explicit three-field rules and puts exceptions first.
  • An allowed test and a denied test were performed through the real service.
  • The administrator kept a working session and has a tested backup restore command.
  • The final policy and any matching access.d files were reviewed together.