A Linux PAM module which automates the management of subuid and subgid entries for creation of container images by normal system users.
Scenario: You have a large scale Linux system (HPC facility, clustered Linux servers, etc) and you want to give your users the ability to create container images (think Apptainer, Podman, Docker) without the need for root/sudo/setuid binaries.
Normally you add entries to /etc/subuid and /etc/subgid to manually assign unique UID ranges to each user.
Problem: This does not scale if you have hundreds (or thousands) of user accounts.
Solution: Use pam_subid and have the ranges managed automatically upon login.
- Python 3 (no module dependencies - uses 'os', 'sys' and 'fcntl')
- A shared filesystem that all servers can read and write to (e.g. an NFS mount).
- Subuid and subgid file support - this is normally added by your Linux systems shadow-utils, uuid-tools or similar system packages. Check for
/etc/subuid.
If you only have a single server that users can login to, then the need for a shared filesystem disappears, it is only needed for multiple servers to maintain consistency of assigned UID ranges.
On login a user is added to an index file if an entry is not already present.
The line number of the user in the index file is used to generate a consistent range of UIDs in subuid and subgid for that user.
Entries are created in /etc/subgid and /etc/subuid if they don't exist.
- Copy
subid.pyto /etc/pam.d (or some other location of your choosing) - Set
subid.pyexecutable. - Create a folder to hold your user index file
You also need to add an entry to your PAM unit files. This will vary depending on Linux distribution, but for Redhat based systems you will want to add an entry to /etc/pam.d/sshd. I suggest after pam_keyinit, but before pam_motd or postlogin, i.e:
session required pam_selinux.so open env_params
session required pam_namespace.so
session optional pam_keyinit.so force revoke
# Create subuid/subgid entries - production mode
session optional pam_exec.so /etc/pam.d/subid.py
session required pam_motd.so
session include password-auth
session include postlogin
If you have interactive logins at the terminal you may also need the same entry adding to /etc/pam.d/login or /etc/pam.d/system-auth. This will vary depending on your PAM configuration.
Locations of your subuid and subgid files - these are created in /etc on most default Linux distributions.
SUBUID_FILE="/etc/subuid" SUBGID_FILE="/etc/subgid"
Location of your user index file which is used to generate a consistent range of UIDs for a given username. The file should be writeable by root only. Put this on NFS, writeable by all nodes if you wish to have consistent UIDs across multiple servers.
Contents of the file is just one username per line. No sensitive data.
INDEX_FILE="/mnt/nfs/home/users.index"
This should always be set to 64K, as required by most container tools.
RANGE=65536
This is the difference between one user and the next. While you could count up in 64K chunks, it is easier to let each user have a block which is large enough to not cause any issues, in the default we allocate 100K.
RANGE_OFFSET=100000
To account for any existing entries in your subuid/subgid file, you can offset the entries in your index file.
If your subuid file already has 9 contiguous entries managed by some other mechanism, for example:
bob:100000:65536
john:200000:65536
jane:300000:65536
frank:400000:65536
raj:500000:65536
niamh:600000:65536
sue:700000:65536
mike:800000:65536
neil:900000:65536
... you will want your first entry managed by pam_subid to start at 1000000:
next_user:1000000:65536
To accomplish this, set an offset of 10:
INDEX_FILE_OFFSET=10
Turn on text output. You will need to add extra parameters to your pam.d entry to create the logfile.
DEBUG=0
To enable logging via PAM, change your entry in the pam.d files to the following:
# Create subuid/subgid entries - production mode
session optional pam_exec.so debug log=/tmp/subid.log /etc/pam.d/subid.py
Whilst every possible care has been taken in writing this module, and it should handle concurrent access to the files okay (it wraps each write in a POSIX locking call) no guarantees are made. You should test this thoroughly before implementing on any production system.
This code is made available under GPL v3.0. Please see LICENSE for further details.
- John Snowdon
- https://github.com/megatron-uk