- Linux
- Microsoft
Managing system access with Linux-PAM
Recently I had the necessity to restrict who can SSH and access the console of a variety of Linux systems joined to Active Directory. With SSSD it’s fairly trivial as it’s sssd-ad provider has built in support for this scenario by using Active Directory Group Policy Objects and Windows User Rights Assignments.
Winbind does not have this capability so something more low-level was needed for systems joined to Active Directory with Winbind.
What are PAMs?
The Plugable Authentication Module is a series of library that implements various methods to perform authentication. They can (and usually are) be called by any application that does not want to reinvent the wheel and write it’s own authentication interface.
It exposes two channels to the application: an interface to handle authentication requests and decisions (the application itself does not handle the authentication, it knows nothing of the authentication methods you can potentially use via PAM) and the other is a messaging interface to the user (so you can be prompted for username/password/whatever via the application user interface)
The following is a schematics representation of the PAM architecture, courtesy of the “Linux-PAM System Administrators Guide“:

We are going to use a specific PAM library to restrict access to our system: pam_access.so.
Enter authselect
In modern RHEL systems, authselect
is used to manage most aspects of the PAM configuration. What it does is that it manages some predefined PAM stacks (these are configuration files in /etc/pam.d
that represent complete units) that are applied to most of the PAM service names defined on a system.
As an example, this is the /etc/pam.d/password-auth file created and managed by authselect:

This file is included in many other PAM configuration files called by different service names:

We need to tell authselect that we want to use the pam_access library so it can modify the default files to enable it.
WARNING: From now on you can potentially bork your system irreparabily. Read and understand the whole procedure and the man
pages of all the pieces involved, as well the “Linux-PAM System Administrators Guide“.
Do not perform this procedure without understanding what you are doing.
You have been warned.
sudo authselect enable-feature -b with-pamaccess
The verify we have correctly enabled the feature:
authselect current
Now we need to configure the library:
grep -v ^# /etc/security/access.conf
+:(2000512):ALL
+:(wheel):ALL
-:ALL:LOCAL
What I did here is I told the library to permit any PAM service for my Domain Admins, the members of the group wheel and prevent any other local access to the system.
For more information and an explanation of the syntax man access.conf
is your friend.
Now we need to take care of the SSH connections. Unfortunately, the pam-access library allows to specify PAM service names only for non-networked logins.
This last sentence bears some explaining to do: pam_access.so uses the calling service name when the value of the passed RHOST variable is undefined by the calling application (read: local daemons usually do that).
When RHOST is defined (read: the login process, sshd, et cetera…), it uses that. When you login via SSH RHOST is populated with your source IP so we can’t match against the service name.
What can be done is to modify the ssh PAM service file to specify a custom configuration file for the pam-access library:
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 required pam_access.so accessfile=/etc/security/access_ssh.conf <---
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 required pam_namespace.so
session optional pam_keyinit.so force revoke
session optional pam_motd.so
session include password-auth
session include postlogin
The line with the arrow is the one I’ve added, and following is the library custom configuration file:
grep -v ^# /etc/security/access_ssh.conf
+:(2000512):ALL
+:(wheel):ALL
-:ALL:ALL
It’s very similar to the global one we defined earlier on, but for SSH we use the “ALL” PAM service name.
Does it works?
Yes it does.

From the /var/log/secure
we can see that the PAM module we introduced is preventing the login attempt to conclude successfully even if some other modules permitted it.