{
  "title": "How to Enforce Failed Login Thresholds on Linux and SSH to Meet AC.L2-3.1.8 — NIST SP 800-171 REV.2 / CMMC 2.0 Level 2 - Control - AC.L2-3.1.8",
  "date": "2026-04-23",
  "author": "Lakeridge Technologies",
  "featured_image": "/assets/images/blog/2026/4/how-to-enforce-failed-login-thresholds-on-linux-and-ssh-to-meet-acl2-318-nist-sp-800-171-rev2-cmmc-20-level-2-control-acl2-318.jpg",
  "content": {
    "full_html": "<p>AC.L2-3.1.8 (NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2) requires limiting the number of unsuccessful login attempts to systems that process, store, or transmit CUI — a straightforward control in principle but one that needs careful, auditable implementation on Linux and SSH to avoid blocking legitimate users or leaving gaps that attackers can exploit.</p>\n\n<h2>Why this control matters and the compliance context</h2>\n\n<p>For Compliance Framework readers: AC.L2-3.1.8 is a protective measure to reduce the likelihood of brute-force, credential-stuffing, and password-guessing attacks. NIST/CMMC expects organizations to implement technical controls and to document policies, settings, and monitoring that demonstrate enforcement. Evidence typically includes configuration files, change-control tickets, test results, and logs showing lockouts and alerts.</p>\n\n<h2>Recommended technical approaches</h2>\n\n<p>There are two complementary approaches you should implement on Linux systems: account-based lockouts via PAM (pam_faillock or pam_tally2 depending on your distro) and network/IP-based bans via Fail2Ban (or equivalent) for SSH. PAM enforces per-account mitigation; Fail2Ban mitigates repeated attempts from hostile IPs. Combine both for defense-in-depth.</p>\n\n<h3>1) Account lockouts using pam_faillock (modern RHEL/CentOS/Fedora, some modern Debian/Ubuntu)</h3>\n\n<p>Example configuration for RHEL/CentOS 7+ (edit /etc/pam.d/password-auth and /etc/pam.d/system-auth). Back up files before editing and test on a non-production host:</p>\n\n<p>Insert near top of the auth stack (preauth):<br />\nauth required pam_faillock.so preauth silent deny=5 unlock_time=900 fail_interval=900</p>\n\n<p>Replace the standard auth line with the following ordering snippet (simplified):<br />\nauth [success=1 default=bad] pam_unix.so nullok try_first_pass</p>\n\n<p>Insert post-failure handler:<br />\nauth sufficient pam_faillock.so authfail deny=5 unlock_time=900 fail_interval=900</p>\n\n<p>And ensure account module is present to reset counters on successful login:<br />\naccount required pam_faillock.so</p>\n\n<p>Meaningful parameter choices: deny=5 (lock after 5 failed attempts), unlock_time=900 (15 minutes) and fail_interval=900 (failures counted within 15 minutes). For higher assurance, set unlock_time=0 to require administrator reset; document exceptions and break-glass procedures.</p>\n\n<h3>2) Legacy systems and pam_tally2</h3>\n\n<p>On older Debian/Ubuntu or legacy systems that do not have pam_faillock, pam_tally2 can be used. Typical pam.d lines (example in /etc/pam.d/common-auth):<br />\nauth required pam_tally2.so deny=5 even_deny_root unlock_time=900 onerr=fail</p>\n\n<p>Note: pam_tally2 and pam_faillock behave differently; test and pick one consistent solution across your estate to simplify evidence collection.</p>\n\n<h3>3) SSH-specific hardening and Fail2Ban for IP banning</h3>\n\n<p>In /etc/ssh/sshd_config set conservative SSH parameters: MaxAuthTries 3, PermitRootLogin no (or prohibit-password), PasswordAuthentication no if using keys, and UsePAM yes. Example:</p>\n\n<p>MaxAuthTries 3<br />\nPermitRootLogin no<br />\nUsePAM yes</p>\n\n<p>Then install and configure Fail2Ban to ban offending IPs. Example jail.local (Debian/Ubuntu or CentOS w/ EPEL):</p>\n\n<p>[sshd]<br />\nenabled = true<br />\nport = ssh<br />\nfilter = sshd<br />\nlogpath = /var/log/auth.log  # or /var/log/secure on RHEL<br />\nmaxretry = 5<br />\nbantime = 86400<br />\nfindtime = 600</p>\n\n<p>This bans an IP for 24 hours after 5 failures in a 10-minute window. Fail2Ban complements account lockouts by protecting against distributed attacks from the same IP range.</p>\n\n<h2>Logging, monitoring, and evidence collection for audits</h2>\n\n<p>To meet Compliance Framework expectations, configure centralized logging (syslog/rsyslog -> SIEM, Splunk, or cloud logging) to capture /var/log/auth.log or /var/log/secure, and pam_faillock records. Create alerts for repeated lockouts and for admin unlock events. Documentation and evidence should include: change tickets approving config changes, the actual config files (timestamped), test results showing account lockouts, and log extracts demonstrating lockout events.</p>\n\n<h2>Small-business real-world scenario</h2>\n\n<p>Consider a small defense contractor with 12 Linux servers and ~30 users. Implementation steps: (1) Inventory which servers host CUI and apply stricter policies there, (2) standardize on pam_faillock where available; for older servers, use pam_tally2, (3) deploy Fail2Ban on all externally reachable hosts, (4) set MaxAuthTries=3 and PermitRootLogin=no in sshd_config, (5) configure centralized logging to a small SIEM or cloud log collector and create an alert for >3 lockouts in 15 minutes. Result: attackers face both account lockout and IP banning, reducing brute-force likelihood while the organization keeps records for auditors.</p>\n\n<h2>Compliance tips and best practices</h2>\n\n<p>- Test changes on a staging host and maintain an emergency “break-glass” admin process to unlock accounts or permit temporary access with strong auditing. - Avoid overly aggressive lockouts for administrative accounts; instead, require multi-factor authentication (MFA) for privileged logins. - Standardize settings across similar systems and document exceptions. - Keep timing and thresholds in your System Security Plan (SSP) and in Standard Operating Procedures (SOPs). - Monitor false positives (e.g., automated services using SSH keys) and whitelist those service accounts or use key-based auth with restricted commands.</p>\n\n<h2>Risk of not implementing AC.L2-3.1.8</h2>\n\n<p>Not enforcing failed-login thresholds leaves systems vulnerable to automated brute-force and credential-stuffing attacks. An attacker who obtains valid credentials or successfully guesses passwords can access systems containing CUI, leading to data theft, mission impact, and compliance violations. Additionally, lacking logs and documented enforcement increases the chance of failing audits and can result in contractual penalties for small businesses handling DoD-related information.</p>\n\n<p>In summary, implementing failed-login thresholds for Linux and SSH to satisfy AC.L2-3.1.8 requires combining PAM-based account lockouts, SSH hardening, IP-level bans (Fail2Ban), centralized logging, and thorough documentation. For small businesses, prioritize systems that handle CUI, test configurations carefully, document policies and exceptions, and ensure monitoring and evidence collection are in place to demonstrate compliance during assessment.</p>",
    "plain_text": "AC.L2-3.1.8 (NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2) requires limiting the number of unsuccessful login attempts to systems that process, store, or transmit CUI — a straightforward control in principle but one that needs careful, auditable implementation on Linux and SSH to avoid blocking legitimate users or leaving gaps that attackers can exploit.\n\nWhy this control matters and the compliance context\n\nFor Compliance Framework readers: AC.L2-3.1.8 is a protective measure to reduce the likelihood of brute-force, credential-stuffing, and password-guessing attacks. NIST/CMMC expects organizations to implement technical controls and to document policies, settings, and monitoring that demonstrate enforcement. Evidence typically includes configuration files, change-control tickets, test results, and logs showing lockouts and alerts.\n\nRecommended technical approaches\n\nThere are two complementary approaches you should implement on Linux systems: account-based lockouts via PAM (pam_faillock or pam_tally2 depending on your distro) and network/IP-based bans via Fail2Ban (or equivalent) for SSH. PAM enforces per-account mitigation; Fail2Ban mitigates repeated attempts from hostile IPs. Combine both for defense-in-depth.\n\n1) Account lockouts using pam_faillock (modern RHEL/CentOS/Fedora, some modern Debian/Ubuntu)\n\nExample configuration for RHEL/CentOS 7+ (edit /etc/pam.d/password-auth and /etc/pam.d/system-auth). Back up files before editing and test on a non-production host:\n\nInsert near top of the auth stack (preauth):\nauth required pam_faillock.so preauth silent deny=5 unlock_time=900 fail_interval=900\n\nReplace the standard auth line with the following ordering snippet (simplified):\nauth [success=1 default=bad] pam_unix.so nullok try_first_pass\n\nInsert post-failure handler:\nauth sufficient pam_faillock.so authfail deny=5 unlock_time=900 fail_interval=900\n\nAnd ensure account module is present to reset counters on successful login:\naccount required pam_faillock.so\n\nMeaningful parameter choices: deny=5 (lock after 5 failed attempts), unlock_time=900 (15 minutes) and fail_interval=900 (failures counted within 15 minutes). For higher assurance, set unlock_time=0 to require administrator reset; document exceptions and break-glass procedures.\n\n2) Legacy systems and pam_tally2\n\nOn older Debian/Ubuntu or legacy systems that do not have pam_faillock, pam_tally2 can be used. Typical pam.d lines (example in /etc/pam.d/common-auth):\nauth required pam_tally2.so deny=5 even_deny_root unlock_time=900 onerr=fail\n\nNote: pam_tally2 and pam_faillock behave differently; test and pick one consistent solution across your estate to simplify evidence collection.\n\n3) SSH-specific hardening and Fail2Ban for IP banning\n\nIn /etc/ssh/sshd_config set conservative SSH parameters: MaxAuthTries 3, PermitRootLogin no (or prohibit-password), PasswordAuthentication no if using keys, and UsePAM yes. Example:\n\nMaxAuthTries 3\nPermitRootLogin no\nUsePAM yes\n\nThen install and configure Fail2Ban to ban offending IPs. Example jail.local (Debian/Ubuntu or CentOS w/ EPEL):\n\n[sshd]\nenabled = true\nport = ssh\nfilter = sshd\nlogpath = /var/log/auth.log  # or /var/log/secure on RHEL\nmaxretry = 5\nbantime = 86400\nfindtime = 600\n\nThis bans an IP for 24 hours after 5 failures in a 10-minute window. Fail2Ban complements account lockouts by protecting against distributed attacks from the same IP range.\n\nLogging, monitoring, and evidence collection for audits\n\nTo meet Compliance Framework expectations, configure centralized logging (syslog/rsyslog -> SIEM, Splunk, or cloud logging) to capture /var/log/auth.log or /var/log/secure, and pam_faillock records. Create alerts for repeated lockouts and for admin unlock events. Documentation and evidence should include: change tickets approving config changes, the actual config files (timestamped), test results showing account lockouts, and log extracts demonstrating lockout events.\n\nSmall-business real-world scenario\n\nConsider a small defense contractor with 12 Linux servers and ~30 users. Implementation steps: (1) Inventory which servers host CUI and apply stricter policies there, (2) standardize on pam_faillock where available; for older servers, use pam_tally2, (3) deploy Fail2Ban on all externally reachable hosts, (4) set MaxAuthTries=3 and PermitRootLogin=no in sshd_config, (5) configure centralized logging to a small SIEM or cloud log collector and create an alert for >3 lockouts in 15 minutes. Result: attackers face both account lockout and IP banning, reducing brute-force likelihood while the organization keeps records for auditors.\n\nCompliance tips and best practices\n\n- Test changes on a staging host and maintain an emergency “break-glass” admin process to unlock accounts or permit temporary access with strong auditing. - Avoid overly aggressive lockouts for administrative accounts; instead, require multi-factor authentication (MFA) for privileged logins. - Standardize settings across similar systems and document exceptions. - Keep timing and thresholds in your System Security Plan (SSP) and in Standard Operating Procedures (SOPs). - Monitor false positives (e.g., automated services using SSH keys) and whitelist those service accounts or use key-based auth with restricted commands.\n\nRisk of not implementing AC.L2-3.1.8\n\nNot enforcing failed-login thresholds leaves systems vulnerable to automated brute-force and credential-stuffing attacks. An attacker who obtains valid credentials or successfully guesses passwords can access systems containing CUI, leading to data theft, mission impact, and compliance violations. Additionally, lacking logs and documented enforcement increases the chance of failing audits and can result in contractual penalties for small businesses handling DoD-related information.\n\nIn summary, implementing failed-login thresholds for Linux and SSH to satisfy AC.L2-3.1.8 requires combining PAM-based account lockouts, SSH hardening, IP-level bans (Fail2Ban), centralized logging, and thorough documentation. For small businesses, prioritize systems that handle CUI, test configurations carefully, document policies and exceptions, and ensure monitoring and evidence collection are in place to demonstrate compliance during assessment."
  },
  "metadata": {
    "description": "Practical, step-by-step guidance for implementing failed-login thresholds on Linux and SSH to satisfy AC.L2-3.1.8 (NIST SP 800-171 Rev.2 / CMMC 2.0 Level 2), including PAM and Fail2Ban examples, logging, and evidence collection.",
    "permalink": "/how-to-enforce-failed-login-thresholds-on-linux-and-ssh-to-meet-acl2-318-nist-sp-800-171-rev2-cmmc-20-level-2-control-acl2-318.json",
    "categories": [],
    "tags": []
  }
}