{"id":9992,"date":"2022-08-06T12:51:04","date_gmt":"2022-08-06T09:51:04","guid":{"rendered":"https:\/\/kifarunix.com\/?p=9992"},"modified":"2024-03-09T21:01:48","modified_gmt":"2024-03-09T18:01:48","slug":"lock-linux-user-account-after-multiple-failed-login-attempts","status":"publish","type":"post","link":"https:\/\/kifarunix.com\/lock-linux-user-account-after-multiple-failed-login-attempts\/","title":{"rendered":"Lock Linux User Account after Multiple Failed Login Attempts"},"content":{"rendered":"\n<p>Follow through this guide to learn how to lock Linux user account after multiple failed login attempts. Linux through Pluggable Authentication Modules, PAM, can be configured to lock accounts after specific number of failed login attempts. Such are some of the security measures that aims at curbing  brute force authentication attacks.<\/p>\n\n\n\n<p>This can be achieve specifically through <strong>pam_faillock<\/strong> module. <a href=\"https:\/\/linux.die.net\/man\/8\/pam_faillock\" target=\"_blank\" rel=\"noreferrer noopener\">pam_faillock<\/a> module <em>maintains a list of failed authentication attempts per user during a specified interval and locks the account in case there were more than&nbsp;deny&nbsp;consecutive failed authentications.<\/em><\/p>\n\n\n\n<p>&#8220;<em><strong>Normally, failed attempts to authenticate&nbsp;root&nbsp;user will&nbsp;not&nbsp;cause the root account to become blocked, to prevent denial-of-service: if your users aren&#8217;t given shell accounts and root may only login via&nbsp;su&nbsp;or at the machine console (not telnet\/ssh, etc), this is safe<\/strong><\/em>&#8220;, pam_faillock man page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Lock Linux User Account after Multiple Failed Login Attempts<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Files to Update<\/h3>\n\n\n\n<p>As already stated, <strong><code>pam_faillock<\/code><\/strong> module can be used to limit the number of allowed failed logins within a specified time period on Linux systems before an account is locked.<\/p>\n\n\n\n<p>There are a number of files which you need to edit in order to define the failed authentication policies.<\/p>\n\n\n\n<p>These include;<\/p>\n\n\n\n<p>On CentOS and Similar Derivatives<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\/etc\/pam.d\/system-auth<\/li>\n\n\n\n<li>\/etc\/pam.d\/password-auth<\/li>\n<\/ul>\n\n\n\n<p>On Ubuntu\/Debian and Similar Derivatives<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\/etc\/pam.d\/common-auth<\/li>\n\n\n\n<li>\/etc\/pam.d\/common-account<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">PAM_FAILLOCK Modules Syntax<\/h3>\n\n\n\n<p>The pam_faillock module takes the syntax below when being configured.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>auth CONTROL_FLAGS pam_faillock.so<\/strong>&nbsp;{preauth|authfail|authsucc} &#91;dir=<em>\/path\/to\/tally-directory<\/em>] &#91;even_deny_root] &#91;deny=<em>n<\/em>] &#91;fail_interval=<em>n<\/em>] &#91;unlock_time=<em>n<\/em>] &#91;root_unlock_time=<em>n<\/em>] &#91;audit] &#91;silent] &#91;no_log_info]<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>account <strong>CONTROL_FLAGS<\/strong> pam_faillock.so &#91;dir=\/path\/to\/tally-directory] &#91;no_log_info]<\/code><\/pre>\n\n\n\n<p><strong><code>auth<\/code><\/strong> and <strong><code>account<\/code><\/strong> defines different PAM module interfaces:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><strong>auth<\/strong><\/code>: requests and validates account password<\/li>\n\n\n\n<li><strong><code>account<\/code><\/strong>: verifies user account, it checks if a user account has expired or if a user is allowed to log in.<\/li>\n<\/ul>\n\n\n\n<p>Other module interfaces include;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code><strong>password<\/strong><\/code>: manages user password including changing user passwords.<\/li>\n\n\n\n<li><code><strong>session<\/strong><\/code>:  configures and manages user sessions.<\/li>\n<\/ul>\n\n\n\n<p>In this particular guide, we are only interested in <strong>auth<\/strong> PAM interface.<\/p>\n\n\n\n<p><strong>CONTROL_FLAGS<\/strong> defines what to do with a failed\/successful result of a PAM module. They include;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><em><code><strong>required<\/strong><\/code>: The module result must be successful for authentication to continue. If the test fails at this point, the user is not notified until the results of all module tests that reference that interface are complete.<\/em><\/li>\n\n\n\n<li><em><code><strong>requisite<\/strong><\/code>: The module result must be successful for authentication to continue. However, if a test fails at this point, the user is notified immediately with a message reflecting the first failed&nbsp;<code>required<\/code>&nbsp;or&nbsp;<code>requisite<\/code>&nbsp;module test.<\/em><\/li>\n\n\n\n<li><em><code><strong>sufficient<\/strong><\/code>: The module result is ignored if it fails. However, if the result of a module flagged&nbsp;<code>sufficient<\/code>&nbsp;is successful&nbsp;and&nbsp;no previous modules flagged&nbsp;<code>required<\/code>&nbsp;have failed, then no other results are required and the user is authenticated to the service.<\/em><\/li>\n\n\n\n<li><em><code><strong>optional<\/strong><\/code>: The module result is ignored. A module flagged as&nbsp;<code>optional<\/code>&nbsp;only becomes necessary for successful authentication when no other modules reference the interface.<\/em><\/li>\n\n\n\n<li><em><code><strong>include<\/strong><\/code>: Unlike the other controls, this does not relate to how the module result is handled. This flag pulls in all lines in the configuration file which match the given parameter and appends them as an argument to the module.<\/em><\/li>\n<\/ul>\n\n\n\n<p>The CONTROL_FLAGS can take the format;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;value1=action1 value2=action2 ...]<\/code><\/pre>\n\n\n\n<p>Thus the above control flags can be represented as;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>required<\/strong>: [success=ok new_authtok_reqd=ok ignore=ignore default=bad]<\/li>\n\n\n\n<li><strong>requisite<\/strong>: [success=ok new_authtok_reqd=ok ignore=ignore default=die]<\/li>\n\n\n\n<li><strong>sufficient<\/strong>: [success=done new_authtok_reqd=done default=ignore]<\/li>\n\n\n\n<li><strong>optional<\/strong>: [success=ok new_authtok_reqd=ok default=ignore]<\/li>\n<\/ul>\n\n\n\n<p>The <strong>valueN<\/strong> can take one of the following forms:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>abort<\/strong>: Critical error (module fail now request)<\/li>\n\n\n\n<li><strong>acct_expired<\/strong>: User account has expired<\/li>\n\n\n\n<li><strong>auth_err<\/strong>: Authentication failure<\/li>\n\n\n\n<li><strong>authinfo_unavail<\/strong>: Underlying authentication service can not retrieve authentication information<\/li>\n\n\n\n<li><strong>authtok_err<\/strong>: Authentication token manipulation error<\/li>\n\n\n\n<li><strong>authtok_expired<\/strong>: User&#8217;s authentication token has expired<\/li>\n\n\n\n<li><strong>authtok_disable_aging<\/strong>: Authentication token aging disabled<\/li>\n\n\n\n<li><strong>authtok_recover_err<\/strong>: Authentication information cannot be recovered<\/li>\n\n\n\n<li><strong>cred_err<\/strong>: Failure setting user credentials<\/li>\n\n\n\n<li><strong>cred_expired<\/strong>: User credentials expired<\/li>\n\n\n\n<li><strong>cred_insufficient<\/strong>: Can not access authentication data due to insufficient credentials<\/li>\n\n\n\n<li><strong>cred_unavail<\/strong>: Underlying authentication service can not retrieve user credentials unavailable<\/li>\n\n\n\n<li><strong>default<\/strong>: all not explicitly mentioned values<\/li>\n\n\n\n<li><strong>ignore<\/strong>: Ignore underlying account module regardless of whether the control flag is required, optional, or sufficient<\/li>\n\n\n\n<li><strong>maxtries<\/strong>: An authentication service has maintained a retry count which has been reached. No further retries should be attempted<\/li>\n\n\n\n<li><strong>module_unknown<\/strong>: module is not known<\/li>\n\n\n\n<li><strong>new_authtok_reqd<\/strong>: New authentication token required. This is normally returned if the machine security policies require that the password should be changed because the password is NULL or it has aged<\/li>\n\n\n\n<li><strong>perm_denied<\/strong>: Permission denied<\/li>\n\n\n\n<li><strong>session_err<\/strong>: Can not make or remove an entry for the specified session<\/li>\n\n\n\n<li><strong>success<\/strong>: Successful function return<\/li>\n\n\n\n<li><strong>try_again<\/strong>: Preliminary check by password service<\/li>\n\n\n\n<li><strong>user_unknown<\/strong>: User not known to the underlying authentication module<\/li>\n<\/ul>\n\n\n\n<p>The <strong>actionN<\/strong> can take one of the following forms:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>ignore<\/strong>: when used with a stack of modules, the module&#8217;s return status will not contribute to the return code the application obtains.<\/li>\n\n\n\n<li><strong>bad<\/strong>: this action indicates that the return code should be thought of as indicative of the module failing. If this module is the first in the stack to fail, its status value will be used for that of the whole stack.<\/li>\n\n\n\n<li><strong>die<\/strong>: equivalent to bad with the side effect of terminating the module stack and PAM immediately returning to the application.<\/li>\n\n\n\n<li><strong>ok<\/strong>: this tells PAM that the administrator thinks this return code should contribute directly to the return code of the full stack of modules. In other words, if the former state of the stack would lead to a return of PAM_SUCCESS, the module&#8217;s return code will override this value. Note, if the former state of the stack holds some value that is indicative of a modules failure, this &#8216;ok&#8217; value will not be used to override that value.<\/li>\n\n\n\n<li><strong>done<\/strong>: equivalent to ok with the side effect of terminating the module stack and PAM immediately returning to the application.<\/li>\n\n\n\n<li><strong>reset<\/strong>: clear all memory of the state of the module stack and start again with the next stacked module.<\/li>\n<\/ul>\n\n\n\n<p>Read more on <strong><code>man pam.conf<\/code><\/strong>.<\/p>\n\n\n\n<p>Some of the OPTIONS that you can use with <strong><code>auth<\/code><\/strong> PAM interface are:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>{preauth|authfail|authsucc}<\/strong>:\n<ul class=\"wp-block-list\">\n<li><strong><code>preauth<\/code><\/strong>: <em>must be used when the module is called before the modules which ask for the user credentials such as the password. The module just examines whether the user should be blocked from accessing the service in case there were anomalous number of failed consecutive authentication attempts recently. This call is optional if&nbsp;authsucc&nbsp;is used.<\/em><\/li>\n\n\n\n<li><strong><code>authfail<\/code><\/strong>: <em>must be used when the module is called after the modules which determine the authentication outcome, failed. Unless the user is already blocked due to previous authentication failures, the module will record the failure into the appropriate user tally file.<\/em><\/li>\n\n\n\n<li><strong><code>authsucc<\/code><\/strong>: <em>must be used when the module is called after the modules which determine the authentication outcome, succeded. Unless the user is already blocked due to previous authentication failures, the module will then clear the record of the failures in the respective user tally file. Otherwise it will return authentication error. If this call is not done, the pam_faillock will not distinguish between consecutive and non-consecutive failed authentication attempts.<\/em><\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong><code>dir=\/path\/to\/tally-directory<\/code><\/strong>: The directory where the user files with the failure records are kept. The default is \/var\/run\/faillock.<\/li>\n\n\n\n<li><strong><code>audit<\/code><\/strong>: Will log the user name into the system log if the user is not found.<\/li>\n\n\n\n<li><strong><code>silent<\/code><\/strong>: Don&#8217;t print informative messages. This option is mostly associated with authfail and authsucc functions.<\/li>\n\n\n\n<li><strong><code>no_log_info<\/code><\/strong>: Don&#8217;t log informative messages via syslog(3).<\/li>\n\n\n\n<li><strong><code>deny=n<\/code><\/strong>: Deny access if the number of consecutive authentication failures for this user during the recent interval exceeds n. The default is 3.<\/li>\n\n\n\n<li><strong><code>fail_interval=n<\/code><\/strong>: The length of the interval during which the consecutive authentication failures must happen for the user account lock out is n seconds. The default is 900 (15 minutes).<\/li>\n\n\n\n<li><strong><code>unlock_time=n<\/code><\/strong>: The access will be re-enabled after n seconds after the lock out. The default is 600 (10 minutes).<\/li>\n\n\n\n<li><strong><code>even_deny_root<\/code><\/strong>: Root account can become locked as well as regular accounts.<\/li>\n\n\n\n<li><strong><code>root_unlock_time=n<\/code><\/strong>: This option implies even_deny_root option. Allow access after n seconds to root account after the account is locked. In case the option is not specified the value is the same as of the unlock_time option.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Enable Account Locking after Multiple Failed Login Attempts<\/h3>\n\n\n\n<p>In order to enable account locking after a specific number of failed logins;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On Debian Based Systems (we tried this specifically on Ubuntu 22.04 and Debian 11)<\/li>\n<\/ul>\n\n\n\n<p>Open the <strong>\/etc\/pam.d\/common-auth<\/strong> file for editing using your preferred editor;<\/p>\n\n\n\n<p>Before that, backup the config.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp \/etc\/pam.d\/common-auth{,.original}<\/code><\/pre>\n\n\n\n<p>By default, this is how this file looks like with comment lines removed;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep -Ev \"^$|^#\" \/etc\/pam.d\/common-auth<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>auth\t&#91;success=1 default=ignore]\tpam_unix.so nullok\nauth\trequisite\t\t\tpam_deny.so\nauth\trequired\t\t\tpam_permit.so\nauth\toptional\t\t\tpam_cap.so<\/code><\/pre>\n\n\n\n<p>The open it for editing;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vim \/etc\/pam.d\/common-auth<\/code><\/pre>\n\n\n\n<p>and add these line;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    required pam_faillock.so preauth audit silent deny=3 fail_interval=60 unlock_time=120<\/code><\/pre>\n\n\n\n<p>Before the line;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    &#91;success=1 default=ignore]      pam_unix.so nullok<\/code><\/pre>\n\n\n\n<p>Then, add these lines;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    &#91;default=die] pam_faillock.so authfail audit deny=3 fail_interval=60 unlock_time=120\nauth    sufficient pam_faillock.so authsucc audit deny=3 fail_interval=60 unlock_time=120<\/code><\/pre>\n\n\n\n<p>Before the line;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    requisite                       pam_deny.so<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>This will cause a user account to locked for 3 consecutive failed login attempts in a period of one minute.<\/li>\n\n\n\n<li>The account will be temporarily locked for 2 minutes after which a user can again try to authenticate. You can adjust the timings as you wish.<\/li>\n<\/ul>\n\n\n\n<p>The lines above should be added such that they look <strong>exactly<\/strong> like as shown below;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\n<strong>auth    required pam_faillock.so preauth audit silent deny=3 fail_interval=60 unlock_time=120<\/strong>\nauth\t[success=1 default=ignore]\tpam_unix.so nullok\n<strong>auth    [default=die] pam_faillock.so authfail audit deny=3 fail_interval=60 unlock_time=120\nauth    sufficient pam_faillock.so authsucc audit deny=3 fail_interval=60 unlock_time=120<\/strong>\nauth\trequisite\t\t\tpam_deny.so\nauth\trequired\t\t\tpam_permit.so\nauth\toptional\t\t\tpam_cap.so \n<\/code><\/pre>\n\n\n\n<p>Save and exit the file when done making changes.<\/p>\n\n\n\n<p>Next, add the line, <strong><code>account required pam_faillock.so<\/code><\/strong>, to the end of the <strong><code>\/etc\/pam.d\/common-account<\/code><\/strong> configuration file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp \/etc\/pam.d\/common-account{,.original}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>echo \"account    required pam_faillock.so\" &gt;&gt; \/etc\/pam.d\/common-account<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On CentOS and Similar Derivates (we tried this specifically on Rocky Linux)<\/li>\n<\/ul>\n\n\n\n<p>Make a backup of the configuration files;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cp \/etc\/pam.d\/system-auth{,.original}<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>cp \/etc\/pam.d\/password-auth{,.original}<\/code><\/pre>\n\n\n\n<p>The two files have almost same configurations.<\/p>\n\n\n\n<p>Thus, open each file for editing;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>vim \/etc\/pam.d\/system-auth<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>vim \/etc\/pam.d\/password-auth<\/code><\/pre>\n\n\n\n<p>Under the auth section, add these lines;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    required pam_faillock.so preauth audit silent deny=3 fail_interval=60 unlock_time=120<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>auth    &#91;default=die] pam_faillock.so authfail audit deny=3 fail_interval=60 unlock_time=120<\/code><\/pre>\n\n\n\n<p>Under the account section, add these lines;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>account     required      pam_faillock.so<\/code><\/pre>\n\n\n\n<p>As shown below;<\/p>\n\n\n\n<p><strong>\/etc\/pam.d\/password-auth:<\/strong><\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nauth        required                                     pam_env.so\nauth        required                                     pam_faildelay.so delay=2000000\n<strong>auth        required                                     pam_faillock.so preauth audit silent deny=3 fail_interval=60 unlock_time=120\n<\/strong>auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular\nauth        [default=1 ignore=ignore success=ok]         pam_localuser.so\nauth        sufficient                                   pam_unix.so nullok try_first_pass\n<strong>auth        [default=die]                                pam_faillock.so authfail audit deny=3 fail_interval=60 unlock_time=120\n<\/strong>auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular\nauth        sufficient                                   pam_sss.so forward_pass\nauth        required                                     pam_deny.so\n<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>\naccount     required                                     pam_unix.so\naccount     sufficient                                   pam_localuser.so\naccount     sufficient                                   pam_usertype.so issystem\naccount     [default=bad success=ok user_unknown=ignore] pam_sss.so\naccount     required                                     pam_permit.so\n<strong>account     required                                     pam_faillock.so<\/strong>\n<\/code><\/pre>\n\n\n\n<p><strong>\/etc\/pam.d\/system-auth:<\/strong><\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nauth        required                                     pam_env.so\nauth        required                                     pam_faildelay.so delay=2000000\n<strong>auth        required                                     pam_faillock.so preauth audit silent deny=3 fail_interval=60 unlock_time=120<\/strong>\nauth        sufficient                                   pam_fprintd.so\nauth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular\nauth        [default=1 ignore=ignore success=ok]         pam_localuser.so\nauth        sufficient                                   pam_unix.so nullok try_first_pass\n<strong>auth        [default=die]                                pam_faillock.so authfail audit deny=3 fail_interval=60 unlock_time=120<\/strong>\nauth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular\nauth        sufficient                                   pam_sss.so forward_pass\nauth        required                                     pam_deny.so\n<\/code><\/pre>\n\n\n\n<pre class=\"scroll-box\"><code>\naccount     required                                     pam_unix.so\naccount     sufficient                                   pam_localuser.so\naccount     sufficient                                   pam_usertype.so issystem\naccount     [default=bad success=ok user_unknown=ignore] pam_sss.so\naccount     required                                     pam_permit.so\n<strong>account     required                                     pam_faillock.so<\/strong>\n<\/code><\/pre>\n\n\n\n<p>Save the changes and exit the files.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Test User Account Lock after Multiple Failed Login Attempts<\/h3>\n\n\n\n<p>That is all set now.<\/p>\n\n\n\n<p>You can now test failed user account logins.<\/p>\n\n\n\n<p>First of all while logged in as another user, tail the authentication logs;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -f \/var\/log\/auth.log<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>tail -f \/var\/log\/secure<\/code><\/pre>\n\n\n\n<p>Perform attempted failed login, 3 times within a minute. Sample console logs in my system;<\/p>\n\n\n\n<p>Ubuntu;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nAug  6 08:21:48 jellyfish login[51642]: pam_unix(login:auth): authentication failure; logname=LOGIN uid=0 euid=0 tty=\/dev\/tty1 ruser= rhost=  user=kifarunix\nAug  6 08:21:52 jellyfish login[51642]: FAILED LOGIN (1) on '\/dev\/tty1' FOR 'kifarunix', Permission denied\nAug  6 08:21:59 jellyfish login[51642]: FAILED LOGIN (2) on '\/dev\/tty1' FOR 'kifarunix', Permission denied\n<strong>Aug  6 08:22:03 jellyfish login[51642]: pam_faillock(login:auth): Consecutive login failures for user kifarunix account temporarily locked\n<\/strong>Aug  6 08:22:06 jellyfish login[51642]: FAILED LOGIN (3) on '\/dev\/tty1' FOR 'kifarunix', Permission denied\nAug  6 08:22:11 jellyfish login[51642]: FAILED LOGIN (4) on '\/dev\/tty1' FOR 'kifarunix', Authentication failure\n\n<\/code><\/pre>\n\n\n\n<p>Rocky;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nAug  6 12:16:07 localhost unix_chkpwd[1333]: password check failed for user (kifarunix)\nAug  6 12:16:07 localhost login[1325]: pam_unix(login:auth): authentication failure; logname= uid=0 euid=0 tty=\/dev\/tty1 ruser= rhost=  user=kifarunix\nAug  6 12:16:10 localhost login[1325]: FAILED LOGIN SESSION FROM tty1 FOR kifarunix, Permission denied\nAug  6 12:16:21 localhost unix_chkpwd[1339]: password check failed for user (kifarunix)\nAug  6 12:16:21 localhost login[1336]: pam_unix(login:auth): authentication failure; logname= uid=0 euid=0 tty=\/dev\/tty1 ruser= rhost=  user=kifarunix\nAug  6 12:16:23 localhost login[1336]: FAILED LOGIN SESSION FROM tty1 FOR kifarunix, Permission denied\nAug  6 12:16:35 localhost unix_chkpwd[1342]: password check failed for user (kifarunix)\nAug  6 12:16:35 localhost login[1340]: pam_unix(login:auth): authentication failure; logname= uid=0 euid=0 tty=\/dev\/tty1 ruser= rhost=  user=kifarunix\n<strong>Aug  6 12:16:35 localhost login[1340]: pam_faillock(login:auth): Consecutive login failures for user kifarunix account temporarily locked\n<\/strong>Aug  6 12:16:37 localhost login[1340]: FAILED LOGIN SESSION FROM tty1 FOR kifarunix, Permission denied\nAug  6 12:16:47 localhost unix_chkpwd[1352]: password check failed for user (kifarunix)\n...\n<\/code><\/pre>\n\n\n\n<p>As you can see, at the third attempt, user account is temporarily locked.<\/p>\n\n\n\n<p>You can also confirm using the command below;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>faillock --user kifarunix<\/code><\/pre>\n\n\n\n<p>Ubuntu output;<\/p>\n\n\n\n<pre class=\"scroll-sz\"><code>\nkifarunix:\nWhen                Type  Source                                           Valid\n2022-08-06 08:21:48 RHOST                                                      V\n2022-08-06 08:21:55 RHOST                                                      V\n2022-08-06 08:22:03 RHOST                                                      V\n\n<\/code><\/pre>\n\n\n\n<p>Rocky output;<\/p>\n\n\n\n<pre class=\"scroll-sz\"><code>\nkifarunix:\nWhen                Type  Source                                           Valid\n2022-08-06 12:16:07 TTY   \/dev\/tty1                                            V\n2022-08-06 12:16:21 TTY   \/dev\/tty1                                            V\n2022-08-06 12:16:35 TTY   \/dev\/tty1                                            V\n<\/code><\/pre>\n\n\n\n<p>You can view for all users by just running;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>faillock<\/code><\/pre>\n\n\n\n<p>Sample SSH authentication logs Ubuntu;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nAug  6 08:43:05 jellyfish sshd[51672]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1  user=kifarunix\nAug  6 08:43:08 jellyfish sshd[51672]: Failed password for kifarunix from 192.168.56.1 port 39310 ssh2\nAug  6 08:43:12 jellyfish sshd[51672]: Failed password for kifarunix from 192.168.56.1 port 39310 ssh2\n<strong>Aug  6 08:43:14 jellyfish sshd[51672]: pam_faillock(sshd:auth): Consecutive login failures for user kifarunix account temporarily locked\n<\/strong>Aug  6 08:43:16 jellyfish sshd[51672]: Failed password for kifarunix from 192.168.56.1 port 39310 ssh2\nAug  6 08:43:16 jellyfish sshd[51672]: Connection closed by authenticating user kifarunix 192.168.56.1 port 39310 [preauth]\nAug  6 08:43:16 jellyfish sshd[51672]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1  user=kifarunix\nAug  6 08:43:36 jellyfish sshd[51674]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1  user=kifarunix\nAug  6 08:43:38 jellyfish sshd[51674]: Failed password for kifarunix from 192.168.56.1 port 39314 ssh2\n\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>faillock --user kifarunix<\/code><\/pre>\n\n\n\n<pre class=\"scroll-sz\"><code>\nkifarunix:\nWhen                Type  Source                                           Valid\n2022-08-06 08:43:05 RHOST 192.168.56.1                                         V\n2022-08-06 08:43:10 RHOST 192.168.56.1                                         V\n2022-08-06 08:43:14 RHOST 192.168.56.1                                         V\n<\/code><\/pre>\n\n\n\n<p>Sample SSH auth logs Rocky;<\/p>\n\n\n\n<pre class=\"scroll-box\"><code>\nAug  6 12:21:13 localhost unix_chkpwd[1361]: password check failed for user (kifarunix)\nAug  6 12:21:13 localhost sshd[1359]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1  user=kifarunix\nAug  6 12:21:15 localhost sshd[1359]: Failed password for kifarunix from 192.168.56.1 port 37388 ssh2\nAug  6 12:21:20 localhost unix_chkpwd[1362]: password check failed for user (kifarunix)\nAug  6 12:21:22 localhost sshd[1359]: Failed password for kifarunix from 192.168.56.1 port 37388 ssh2\nAug  6 12:21:26 localhost unix_chkpwd[1363]: password check failed for user (kifarunix)\n<strong>Aug  6 12:21:26 localhost sshd[1359]: pam_faillock(sshd:auth): Consecutive login failures for user kifarunix account temporarily locked\n<\/strong>Aug  6 12:21:28 localhost sshd[1359]: Failed password for kifarunix from 192.168.56.1 port 37388 ssh2\nAug  6 12:21:28 localhost sshd[1359]: Connection closed by authenticating user kifarunix 192.168.56.1 port 37388 [preauth]\nAug  6 12:21:28 localhost sshd[1359]: PAM 2 more authentication failures; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.56.1  user=kifarunix\n<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code\"><code>faillock --user kifarunix<\/code><\/pre>\n\n\n\n<pre class=\"scroll-sz\"><code>\nkifarunix:\nWhen                Type  Source                                           Valid\n2022-08-06 12:21:13 RHOST 192.168.56.1                                         V\n2022-08-06 12:21:20 RHOST 192.168.56.1                                         V\n2022-08-06 12:21:26 RHOST 192.168.56.1                                         V\n<\/code><\/pre>\n\n\n\n<p>Any subsequent attempted login even with correct password will not go through, until after the time defined by the the unlock_time option, which is 2 minutes in our example.<\/p>\n\n\n\n<p>If you want to enable unlock user account before the defined unlock time, use the command;<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>faillock --user kifarunix --reset<\/code><\/pre>\n\n\n\n<p>And you should be able to login again.<\/p>\n\n\n\n<p>And that is how you can enable account locking in Linux after multiple failed login attempts.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Other Tutorials<\/h3>\n\n\n\n<p><a href=\"https:\/\/kifarunix.com\/enforce-password-complexity-policy-on-centos-7-rhel-derivatives\/\" target=\"_blank\" rel=\"noreferrer noopener\">Enforce Password Complexity Policy On CentOS 7\/RHEL Derivatives<\/a><\/p>\n\n\n\n<p><a href=\"https:\/\/kifarunix.com\/enforce-password-complexity-policy-on-ubuntu-18-04\/\" target=\"_blank\" rel=\"noreferrer noopener\">Enforce Password Complexity Policy On Ubuntu 18.04<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Follow through this guide to learn how to lock Linux user account after multiple failed login attempts. Linux through Pluggable Authentication Modules, PAM, can be<\/p>\n","protected":false},"author":1,"featured_media":13660,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rank_math_lock_modified_date":false,"footnotes":""},"categories":[34,121,49],"tags":[5634,5635,5637,5632,5638,5630,5631,5633,5639],"class_list":["post-9992","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security","category-howtos","category-command-cheatsheets","tag-etc-pam-d-common-auth","tag-etc-pam-d-password-auth","tag-etc-pam-d-system-auth","tag-linux-pam","tag-linux-pam-modules","tag-lock-linux-user-account-after-multiple-failed-login-attempts","tag-lock-linux-user-account-using-pam_faillock-module","tag-pam_faillock","tag-secure-linux-account-using-pam","generate-columns","tablet-grid-50","mobile-grid-100","grid-parent","grid-50","resize-featured-image"],"_links":{"self":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/9992"}],"collection":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/comments?post=9992"}],"version-history":[{"count":7,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/9992\/revisions"}],"predecessor-version":[{"id":20606,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/posts\/9992\/revisions\/20606"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media\/13660"}],"wp:attachment":[{"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/media?parent=9992"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/categories?post=9992"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kifarunix.com\/wp-json\/wp\/v2\/tags?post=9992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}