Description
su switches to another user, root by default, after asking for that user's password. The
pam_wheel module can restrict it to members of one group. Pointing it at an empty group
means only root can use su; administrators use sudo instead.
Rationale
Administration through su needs a shared root password and leaves no trace of who ran which
command. Restricting it pushes every privileged action through sudo, with per-user rules and
logs, and stops password guessing through su.
Impact
Users can no longer run su or su - otheruser. Use sudo -i or sudo -u otheruser -i.
Root keeps using su to switch to any account.
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
su_groupstring. Name of the group allowed to use su. Keep it empty. | sugroup | sugroup | sugroup | sugroup | sugroup |
The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.
Audit
/etc/pam.d/sumust contain an uncommentedauth required pam_wheel.so use_uid group={{ su_group }}line.- Run
getent group {{ su_group }}. The group must exist and have no members.
Automated: every check must pass. Scanners report each check by its id.
pam-wheel
pam_wheel restricts su to the configured group.
script: |
grep -Eq "^[[:space:]]*auth[[:space:]]+required[[:space:]]+pam_wheel\.so([[:space:]].*)?[[:space:]]group=$CB_SU_GROUP([[:space:]]|$)" /etc/pam.d/su \
|| { echo "no pam_wheel group=$CB_SU_GROUP line"; exit 1; }
echo "pam_wheel group=$CB_SU_GROUP"
group-empty
The su group exists and is empty.
script: |
g=$(getent group "$CB_SU_GROUP") || { echo "group $CB_SU_GROUP missing"; exit 1; }
m=${g##*:}
echo "members: ${m:-none}"
[ -z "$m" ]
Remediation
- Create the group:
groupadd {{ su_group }}. - Add to
/etc/pam.d/su, before the@include common-authline:auth required pam_wheel.so use_uid group={{ su_group }}
| Restart | none |
| Disruption | low |
Rollback
Remove the line from /etc/pam.d/su.
configure
getent group "$CB_SU_GROUP" >/dev/null || groupadd "$CB_SU_GROUP"
f=/etc/pam.d/su
if ! grep -Eq "^[[:space:]]*auth[[:space:]]+required[[:space:]]+pam_wheel\.so.*group=$CB_SU_GROUP" "$f"; then
cb_backup "$f"
sed -i "0,/^@include common-auth/s//auth required pam_wheel.so use_uid group=$CB_SU_GROUP\n&/" "$f"
fi
Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.
References
- pam_wheel(8), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- su(1), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R33) ANSSI, guide, accessed 2026-10-18
Mappings
| Framework | ID | Relation |
|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R33 | partial |
| NIST SP 800-53 Rev. 55.1.1 | AC-6 | related |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
| Taxonomy | ID |
|---|---|
| MITRE ATT&CK | T1548 |
| MITRE ATT&CK | T1110 |
People and lifecycle
| Authors |
|
| Verified | 2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Generated check, fix and check again for profiles core and server-hardened; state kept after reboot. |
| Verified | 2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Generated check, fix and check again for profiles core and server-hardened; state kept after reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-18, 2026-10-18 |
| Translations | fr |