Restrict account login attempts

I’m trying to do something that you would think would be straightforward and easy to do - that admins would do as a matter of course, but I cannot find any documentation or examples to indicate it is even possible:

I want to restrict account logins to n failed attempts in a given period after which the account is disabled for a given period BUT I want this for ALL login attempts regardless how they originate. eg. if Alice enters the wrong password at the Desktop login screen, then enters the wrong password via ssh on another machine and then enters the wrong password via cockpit on that 2nd machine, I want that to count as 3 tries and disable her account on the target machine. I want to do this with one entry somewhere, ideally for all accounts with overrides for specific accounts.

I have looked at pam, PAM, pam_faillock and faillock and from what I can gather the policy has to be applied for each and every utility/application through which access is attempted (and hence for every process listed under /etc/pam.d/ - at the very least. The doc, unless I’ve missed something or it’s incomplete (not unusual) implies that any application that mediates access and ISN’T in /etc/pam.d doesn’t have to comply with any rules - surely this can’t be right ?

I assume there is a kernel routine somewhere that ultimately grants or denies access and I would have thought there was a way to configure the above policy for that regardless what was calling it.

Any suggestions ?

1 Like

If you utilize faillock within system-auth and password-auth, that should be sufficient. Majority of the pam services import either of those two, and so how these are configured will dictate how the rest of the pam services will typically behave. This removes the need to have to edit each pam service individually.

Example. See how pam_faillock is used for auth and account in password-auth? If you look at sshd, you will see it includes password-auth for both its own auth and account section. So this policy applies.

$ cat /etc/pam.d/password-auth
# Generated by authselect on Sat Nov 20 18:07:43 2021
# Do not modify this file manually.

auth        required                                     pam_env.so
auth        required                                     pam_faildelay.so delay=2000000
auth        required                                     pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular
auth        [default=1 ignore=ignore success=ok]         pam_localuser.so
auth        sufficient                                   pam_unix.so  try_first_pass
auth        [default=1 ignore=ignore success=ok]         pam_usertype.so isregular
auth        sufficient                                   pam_sss.so forward_pass
auth        required                                     pam_faillock.so authfail audit deny=5 unlock_time=900 fail_interval=900
auth        required                                     pam_deny.so

account     required                                     pam_faillock.so
account     required                                     pam_unix.so
account     sufficient                                   pam_localuser.so
account     sufficient                                   pam_usertype.so issystem
account     [default=bad success=ok user_unknown=ignore] pam_sss.so
account     required                                     pam_permit.so

password    requisite                                    pam_pwquality.so try_first_pass local_users_only minlen=14 dcredit=-1 lcredit=-1 ucredit=-1 ocredit=-1 retry=3
password    requisite                                    pam_pwhistory.so use_authok remember=5
password    sufficient                                   pam_unix.so sha512 shadow  try_first_pass use_authtok
password    sufficient                                   pam_sss.so use_authtok
password    required                                     pam_deny.so

session     optional                                     pam_keyinit.so revoke
session     required                                     pam_limits.so
-session    optional                                     pam_systemd.so
session     optional                                     pam_oddjob_mkhomedir.so umask=0077
session     [success=1 default=ignore]                   pam_succeed_if.so service in crond quiet use_uid
session     required                                     pam_unix.so
session     optional                                     pam_sss.so

$ cat /etc/pam.d/sshd
#%PAM-1.0
auth       substack     password-auth
auth       include      postlogin
account    required     pam_sepermit.so
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    optional     pam_motd.so
session    include      password-auth
session    include      postlogin
1 Like

Thanks for the response Louis.

While those files do get around the problem of having to maintain multiple config files individually, they don’t address a related serious aspect: the whole PAM thing seems to require opt-in/compliance by the applications brokering access and that just seems insane - it appears to be saying if an app is, or chooses to be PAM compliant then the system will apply the rules and restrictions specified in your policy but if it isn’t then it just bypasses your policy.

It’s even crazier given RHEL uses selinux where all access is denied until specifically granted. PAM appears to be: all privileges (eg not having to negotiate faillock) are granted unless specifically withdrawn and accepted as such by the process !

The man file for password-auth/system-auth reads “The purpose of these configuration files are to provide a common interface for all applications and service daemons calling into the PAM library.”

You shouldn’t need to depend on every application implementing/going through PAM and being bug free about it for your security policy to work especially when the whole thing could be done reliably at the OS level instead of relying on application code.

I was hoping /etc/pam.conf would not depend on app compliance as it seems to be for specifying a general system-wide application-agnostic policy but the man page starts " When a PAM aware privilege granting application is started…" so that looks like another dead end.

Am I misreading the docs ? Have I misunderstood how this stuff works or is it really as I’ve described it ?

Bob.

Red Hat selects and packages applications for RHEL, so it is essentially up to them to choose applications that do use PAM and to pre-configure those to use the common *-auth (which you can now manage with authselect). (PAM) Configuration of all third-party applications is on us.

I don’t think Linux kernel has “deny everything by default”, at least not as primary principle.

The kernel has no real concept of usernames, authentication, logins, etc. It just has uids, gids, permissions, authorizations.

It’s up to userspace to set up these details…

In the long long distant past, there was pretty much just the one login program; “login”. It sat on serial ports (sometimes behind a getty), the user would enter their username and password, and the login program would read the password file directly (eg using the getpwent() call), check the password, set up the uid, gid, secondary groups, do any logging, and then run the shell.

When we started to get networking (telnet, ftp, rlogin) then all of those programs also did all the hard work themselves, in a similar way.

This started to get messy. When Sun invented Yellow Pages (aka NIS) every program now needed to understand NIS. We could kludge this a little in the C library so that getpwent() could transparently read from NIS, but this still meant a recompile of the code and a lot of testing.

Things got worse when we moved the encrypted passwords over to /etc/shadow. Now there’s a new call (getspent()) that programs needed to make. Not just a recompile, but a rewrite was needed.

Things got terrible when we started to add other authentication solutions (eg LDAP, Kerberos). So that’s why PAM was invented. It provides a “standard” set of methods for a program to handle authentication, session setup, logging, etc. It allows for new authentication methods to be added without the application even having to know about it.

It’s now considered the norm for “authentication applications” (eg login, su, ftpd, or even your X windows login process) that provide access to the OS to use PAM. Anything that doesn’t is the oddity.

(Applications that don’t provide access to the OS don’t have to use PAM; there’s an argument to be made that they possibly shouldn’t… why would a game server use the same authentication database as your Unix users?).

There is one big elephant in the room, though. SSH. If you use ssh key based authentication then it doesn’t use PAM for authentication; it handles the ssh keys internal to itself. If you set UsePAM yes then it will use PAM for session/audit setup so you still get some of the benefits.

Why doesn’t the kernel do all of this? Because authentication is really a user space construct. We have privileged tools that are expected to be the point of entry and what tells the kernel “This is user 500, group 500”. On SELinux protected systems, SELinux needs to be told what programs are allowed to do this type of user switching, simply because they are specially trusted.

2 Likes

With caveats…

modify /etc/security/faillock.conf (contains explanatory comments)

then run the command

authselect enable-feature with-faillock

…and that should be it.


You may get the message:

Make sure that SSSD service is configured and enabled. See SSSD documentation for more information.

…but I found sssd wasn’t necessary for faillock to take effect - on ssh or cockpit at any rate (problems with recent fedora releases mean sssd may not be running)

Caveats:

  1. As far as I can gather, for faillock to be comprehensively applied, all access brokering code on the system needs to be PAM compliant.
  2. Faillock does not work/ has no effect on ssh where PubkeyAuthentication yes in /etc/ssh/sshd_config (verified on fedora server 35).

Notes:

I didn’t see any difference in output with/without the faillock silent option.

Thanks

  • @nazunalika for mentioning system-auth and password-auth (one-stop config points)
  • @jlehtone for mentioning authselect (to manage one-stop config points) and trying to explain why things are as they should be.
  • @sweh for mentioning the sshd PubkeyAuthentication exception to the rules and trying harder to explain why things are as they should be.

See also man pages on

  • authselect system-wide, profile-based auth-profile and authentication-feature management
  • faillock to reset user or list the failed logins just prior to account lock
  • pam_faillock faillock configuration
  • lastb failed logins except for sshd with PubkeyAuthentication
  • pam “intended to offer a quick introduction to Linux−PAM”
  • pam.conf “pam.conf, pam.d − PAM configuration files”

Why things are (mostly) as they should be:

It turns out (I wasn’t aware) that responsibility for ensuring that security and system access is implemented in a coherent and sensible manner lies in the first instance with the Distro - it is outside of what the kernel covers.

Thereafter any related changes are the responsibility of the system administrator.

So, there shouldn’t normally be any non-PAM compliant access brokers on a PAM enabled system (ssh with PubkeyAuthentication being the obvious rule breaker).

(This is why the man page for pam.conf reading “When a PAM aware privilege granting application is started…” doesn’t imply that there might as a matter of course be applications running that weren’t PAM aware.)

So it is important in this case that only one machine has this access privilege to the others and none to it and it is also locked down as you have done above.

1 Like