← All rules
SOCLE-CLD-SSH-008// SSHcriticaleffective runtime

Disable SSH Root Login

Forces PermitRootLogin no so the root account can never authenticate directly over SSH.

Checked against the resolved running state (e.g. sshd -T, sysctl, systemctl show), catches drop-ins and Includes a file read would miss. Caveat: runtime ≠ persistence; a value correct now may not survive a reboot.

A pass proves✓ running now✓ on disk✓ survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 8 / Rocky 8 / AlmaLinux 8CIS 4.0.0RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 22.04CIS 3.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04
One check, maps to 4 standards

Pavois asserts the effective configuration, the live, resolved state, not a file. File-based scanners (OVAL/SCAP, Lynis) miss Includes, drop-ins and runtime defaults; this check sees what is actually applied.

A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.

Why this rule matters

Allowing direct root SSH login removes individual accountability (everyone logs in as the same all-powerful account) and makes root a single, well-known target for online password-guessing and brute-force attacks. Requiring users to log in under their own account and then escalate via sudo provides per-user audit trails, enables least-privilege, and removes the most valuable credential from the network-facing login surface.

What Pavois checks

Pavois reads the effective value from sshd -T, after all Includes, /etc/ssh/sshd_config.d/ drop-ins and Match blocks. Cloud images frequently ship a drop-in that re-enables PermitRootLogin prohibit-password; only the resolved output catches it, where a read of /etc/ssh/sshd_config would report a stale value.

describe command('sshd -T') do
  its('stdout') { should match(/^permitrootlogin\s+no$/i) }
end

How to verify it is applied

Run sshd -T | grep -i '^permitrootlogin'. Expected output is permitrootlogin no. To resolve a Match block, test the value for a specific context with sshd -T -C user=deploy,host=app1,addr=10.0.0.5. A global permitrootlogin no with a narrow, intentional Match exception is not a finding (a common false positive); a Match block that re-opens root broadly is the real gap.

Inspect & investigate

Root login attempts (accepted or refused) are logged in /var/log/auth.log (Debian/Ubuntu) or journalctl -u sshd (RHEL family); a blocked attempt shows as ROOT LOGIN REFUSED or a failed authentication for root.

Remediation

Pavois's harden plan writes the sshd_setting directive PermitRootLogin no in a managed drop-in, validates with sshd -t, then reloads the ssh service. Apply it with pavois harden apply.

Pavois applies this with its own harden engine, the plan below, not a shell script:

directivepermitrootlogin
notifyaction: reload, service: ssh.service
resourcesshd_setting
valueno
verifysshd -t -f %{path}
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

Lockout risk, read before applying. Ensure at least one non-root account can log in over SSH and has working sudo/su to reach root; otherwise disabling root SSH locks you out entirely. Verify with a second, separate SSH session as that account before closing your current one. Watch for automation (backup jobs, Ansible, CI) that connects as root over SSH, it will break and must be repointed to a privileged user with sudo. The reload keeps current sessions alive, so an active root session is not killed immediately.

Standards mapping

StandardReferenceTypeVersionConfidence
ANSSI BP-028R33direct2.0high
CIS2.2.6, 5.1.20, 5.1.22directper OS, see the benchmark tablehigh
NIST3.1.1, AC-17(a), AC-6(2), CM-6(a), CM-7(a), CM-7(b), IA-2, IA-2(5)supporting800-53 Rev 5 · 800-171 Rev 2 (pinned)medium
PCI DSS2.2.6supporting4.0.1medium

Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.

Sources & references