# yaml-language-server: $schema=../../../../schema/control.schema.json id: CB-UBU-NET-016 title: Restrict SSH authentication to named accounts with strong methods finding: title: The SSH server allows root logins, weak authentication methods or unlimited guessing description: Direct root logins, trust-based or empty-password authentication and generous retry limits make SSH an easy entry point. status: active profiles: [core] risk: severity: high assessment: automated tags: [ssh, authentication, root] applicability: facts: [openssh-server] description: | This control sets the OpenSSH server options that decide who may log in and how: - `PermitRootLogin no`: administrators log in with their own account, then use `sudo`; - `PermitEmptyPasswords no`: accounts without a password cannot log in; - `HostbasedAuthentication no` and `IgnoreRhosts yes`: no trust based on the client host or on `.rhosts`/`.shosts` files; - `GSSAPIAuthentication no`: no Kerberos/GSSAPI logins unless the host is part of such a realm; - `PermitUserEnvironment no`: users cannot pass environment variables (such as `LD_PRELOAD`) through `~/.ssh/environment` or `authorized_keys`; - `UsePAM yes`: account and session rules of PAM (locking, limits, logging) apply to SSH; - `MaxAuthTries` at most {{ ssh_max_auth_tries }} and `LoginGraceTime` between 1 and {{ ssh_login_grace_time }} seconds. rationale: | `root` exists on every system and is the first target of password guessing; logging in with named accounts also keeps a record of who did what. Host-based trust, empty passwords and user supplied environment variables bypass authentication or the restrictions placed on an account. Low retry and grace limits slow down guessing and free unauthenticated connections quickly. impact: | Root can no longer log in over SSH, even with a key: create a named administrator account in the `sudo` group and check that it can log in before applying. Scripts and backup tools that connect as root must use a dedicated account. Hosts joined to a Kerberos realm that use GSSAPI logins must keep `GSSAPIAuthentication yes` (exclude that check through tailoring). notes: | Ubuntu ships `PermitRootLogin prohibit-password` (key-only root logins), `MaxAuthTries 6` and `LoginGraceTime 120`. Cloud images add `/etc/ssh/sshd_config.d/60-cloudimg-settings.conf`, and cloud-init may write `50-cloud-init.conf`, both setting `PasswordAuthentication`. The fix writes the options in `/etc/ssh/sshd_config.d/00-cirsec.conf`, which is read first and therefore wins over those files, since sshd keeps the first value it reads for each option. On 24.04 and later, sshd is started by `ssh.socket`: the checks need `/run/sshd`, created when `ssh.service` first runs, and report an error before the first connection after boot. `LoginGraceTime 0` (no limit) is not fixed automatically. `UsePAM yes` without password authentication still lets PAM check account expiry and locks. setting: location: /etc/ssh/sshd_config.d/00-cirsec.conf default_value: PermitRootLogin prohibit-password, MaxAuthTries 6, LoginGraceTime 120 recommended_value: "PermitRootLogin no, MaxAuthTries <= {{ ssh_max_auth_tries }}, LoginGraceTime <= {{ ssh_login_grace_time }}" parameters: - name: ssh_max_auth_tries type: integer description: Maximum authentication attempts per SSH connection. default: 4 minimum: 1 maximum: 6 - name: ssh_login_grace_time type: integer description: Maximum time to authenticate after connecting. unit: seconds default: 60 minimum: 1 maximum: 120 audit: manual: | Run `sshd -T` and check: `permitrootlogin no`, `permitemptypasswords no`, `hostbasedauthentication no`, `ignorerhosts yes`, `gssapiauthentication no`, `permituserenvironment no`, `usepam yes`, `maxauthtries` at most {{ ssh_max_auth_tries }}, `logingracetime` between 1 and {{ ssh_login_grace_time }}. checks: - id: permit-root-login engine: sshd-config description: PermitRootLogin. spec: { key: permitrootlogin, value: "no" } - id: permit-empty-passwords engine: sshd-config description: PermitEmptyPasswords. spec: { key: permitemptypasswords, value: "no" } - id: hostbased-authentication engine: sshd-config description: HostbasedAuthentication. spec: { key: hostbasedauthentication, value: "no" } - id: ignore-rhosts engine: sshd-config description: IgnoreRhosts. spec: { key: ignorerhosts, value: "yes" } - id: gssapi-authentication engine: sshd-config description: GSSAPIAuthentication. spec: { key: gssapiauthentication, value: "no" } - id: permit-user-environment engine: sshd-config description: PermitUserEnvironment. spec: { key: permituserenvironment, value: "no" } - id: use-pam engine: sshd-config description: UsePAM. spec: { key: usepam, value: "yes" } - id: max-auth-tries engine: sshd-config description: MaxAuthTries. spec: { key: maxauthtries, operator: "<=", value: "{{ ssh_max_auth_tries }}" } - id: login-grace-time engine: sshd-config description: LoginGraceTime upper bound. spec: { key: logingracetime, operator: "<=", value: "{{ ssh_login_grace_time }}" } - id: login-grace-time-set engine: sshd-config description: LoginGraceTime is not 0 (unlimited). spec: { key: logingracetime, operator: ">=", value: 1 } remediation: manual: | 1. Make sure a named account in the `sudo` group can log in with SSH. 2. Create or edit `/etc/ssh/sshd_config.d/00-cirsec.conf`: ``` PermitRootLogin no PermitEmptyPasswords no HostbasedAuthentication no IgnoreRhosts yes GSSAPIAuthentication no PermitUserEnvironment no UsePAM yes MaxAuthTries {{ ssh_max_auth_tries }} LoginGraceTime {{ ssh_login_grace_time }} ``` 3. Check with `sshd -t`, run `systemctl reload ssh`, and test a new connection before closing the current one. effects: restart: service services: [ssh] disruption: low lockout_risk: true rollback: | Remove the lines from `/etc/ssh/sshd_config.d/00-cirsec.conf` and run `systemctl reload ssh`. scripts: - id: permit-root-login from_check: permit-root-login - id: permit-empty-passwords from_check: permit-empty-passwords - id: hostbased-authentication from_check: hostbased-authentication - id: ignore-rhosts from_check: ignore-rhosts - id: gssapi-authentication from_check: gssapi-authentication - id: permit-user-environment from_check: permit-user-environment - id: use-pam from_check: use-pam - id: max-auth-tries from_check: max-auth-tries - id: login-grace-time from_check: login-grace-time references: - title: sshd_config(5), Ubuntu manual pages url: https://manpages.ubuntu.com/manpages/noble/man5/sshd_config.5.html publisher: Canonical kind: vendor-doc accessed: 2026-10-19 - title: ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R33) url: https://messervices.cyber.gouv.fr/documents-guides/fr_np_linux_configuration-v2.0.pdf publisher: ANSSI kind: guide accessed: 2026-10-19 - title: NIST IR 7966 - Security of Interactive and Automated Access Management Using Secure Shell (SSH) url: https://csrc.nist.gov/pubs/ir/7966/final publisher: NIST kind: guide accessed: 2026-10-19 mappings: - framework: anssi-linux framework_version: "2.0" id: R33 relation: partial note: R33 asks for administration actions to be attributable; forbidding direct root logins over SSH is part of it. - framework: nist-800-53r5 framework_version: "5.1.1" id: AC-17 relation: partial - framework: nist-800-53r5 framework_version: "5.1.1" id: AC-7 relation: related - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.9" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.10" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.11" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.13" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.16" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.19" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.20" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.21" relation: equivalent - framework: cis-ubuntu-2004 framework_version: "3.0.0" id: "5.1.22" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.9" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.10" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.11" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.13" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.16" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.19" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.20" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.21" relation: equivalent - framework: cis-ubuntu-2204 framework_version: "3.0.0" id: "5.1.22" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.9" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.10" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.11" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.13" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.16" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.19" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.20" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.21" relation: equivalent - framework: cis-ubuntu-2404 framework_version: "2.0.0" id: "5.1.22" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.10" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.11" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.12" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.15" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.18" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.21" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.22" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.23" relation: equivalent - framework: cis-ubuntu-2604 framework_version: "1.0.0" id: "5.1.24" relation: equivalent threats: - framework: mitre-attack id: T1110 - framework: mitre-attack id: T1021.004 - framework: cwe id: CWE-307 related_controls: - id: CB-UBU-AUTH-011 type: related authors: - name: Alice github: Sn0wAlice verified: - date: 2026-10-19 by: Sn0wAlice versions: ["20.04"] environment: Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic, BIOS boot notes: "Root key-only login, MaxAuthTries 6 and LoginGraceTime 120 reported; generated drop-in fixes in 00-cirsec.conf; root login refused, SSH by key of a non-root user accepted on localhost and port 22 reachable from the lab host after the fix and after reboot." - date: 2026-10-19 by: Sn0wAlice versions: ["22.04"] environment: Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic, BIOS boot notes: "Root key-only login, MaxAuthTries 6 and LoginGraceTime 120 reported; generated drop-in fixes in 00-cirsec.conf; root login refused, SSH by key of a non-root user accepted on localhost and port 22 reachable from the lab host after the fix and after reboot." - date: 2026-10-19 by: Sn0wAlice versions: ["24.04"] environment: Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic, BIOS boot notes: "Root key-only login, MaxAuthTries 6 and LoginGraceTime 120 reported; generated drop-in fixes in 00-cirsec.conf; root login refused, SSH by key of a non-root user accepted on localhost and port 22 reachable from the lab host after the fix and after reboot." - date: 2026-10-19 by: Sn0wAlice versions: ["26.04"] environment: Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic, BIOS boot notes: "Root key-only login, MaxAuthTries 6 and LoginGraceTime 120 reported; generated drop-in fixes in 00-cirsec.conf; root login refused, SSH by key of a non-root user accepted on localhost and port 22 reachable from the lab host after the fix and after reboot." introduced_in: 0.1.0 created: 2026-10-19 updated: 2026-10-19