Wednesday, January 21, 2009

Restricting su Access to System and Shared Accounts

This chapter shows how to restrict people from su-ing to system and shared accounts even if they know the passwords.
Example for Restricting su Access to root
Create a new group for each set of users that are allowed to su to the root
# groupadd rootmembers
Add all users who are allowed to su to the root account to the new member groups created above.
The following requirement will be configured:
- Only the user named hari should be able to su to root
-
# usermod -G rootmembers hari
Next add the three authentication lines highlighted in bold to the /etc/pam.d/su file as shown below:
auth sufficient /lib/security/$ISA/pam_rootok.so
auth required /lib/security/$ISA/pam_stack.so service=system-auth
auth sufficient /lib/security/$ISA/pam_stack.so service=su-root-members
auth required /lib/security/$ISA/pam_deny.so
account required /lib/security/$ISA/pam_stack.so service=system-auth
password required /lib/security/$ISA/pam_stack.so service=system-auth
session required /lib/security/$ISA/pam_selinux.so close
session required /lib/security/$ISA/pam_stack.so service=system-auth
session required /lib/security/$ISA/pam_selinux.so open multiple
session optional /lib/security/$ISA/pam_xauth.so

These additional authentication lines specify that nobody should be able to su to any account unless at least one of the PAM services or su-root-members returns
Success. The control flag sufficient means that a Success will bypass the remaining
authentication modules and overall Success is returned for the authentication part. Failure means that the failed authentication PAM service is ignored. If both authentication PAM services fail, then the last authentication module pam_deny is invoked which will deny all requests for any available authentication module. This will cause the authentication part to fail for the su command.

Next the new authentication PAM service configuration file /etc/pam.d/su-root-members needs to be created. The file /etc/pam.d/su-root-members referenced in /etc/pam.d/su should read like:

auth required /lib/security/pam_wheel.so use_uid group=rootmembers
auth required /lib/security/pam_listfile.so item=user sense=allow onerr=fail
file=/etc/security/su-rootmembers-access

The file /etc/security/su-rootmembers-access referenced in /etc/pam.d/su-root-members should read like:
# cat /etc/security/su-rootmembers-access
root

The control flag required which is specified for both modules means that both modules have to return Success. Otherwise this PAM service will return Failure to the "su" PAM service configured in /etc/pam.d/su. The first line returns Success only if the user is in the rootmembers groups.
second line allows only access (sense=allow) to those users specified in
/etc/security/rootusername, which is root, oracle, and postgres - these are the only users that will be accepted as a user argument to su. The item=user argument instructs pam_listfile that the entries in /etc/security/rootusername are usernames. If an error occurs, such as an unreadable configuration file, access is denied (onerr=fail).
NOTE: Once su access to root is working for users in the rootmembers, I recommend to avoid making any changes to the /etc/pam.d/su-root-members file in the future. Making a mistake in this file could revoke access to root for all users on the system. That's the reason why I created two PAM service files, /etc/pam.d/su-root-members for people in the rootmembers group, and /etc/pam.d/su-other-members (see below) for all other member groups since you will most probably add more member groups to this file in the future.
Now verify that user hari can su to root. No one else on the system should be able su to root even if they know the password.

Lock user account on frequent login failures

Add the following two lines highlighted in blue to the /etc/pam.d/system-auth file as shown below:
auth required pam_env.so
auth required pam_tally.so onerr=fail per_user deny=3 reset
auth required pam_access.so
auth sufficient pam_unix.so likeauth nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 500 quiet
auth required pam_deny.so
account required pam_unix.so
account required pam_tally.so
account sufficient pam_succeed_if.so uid < 500 quiet
account required pam_permit.so
password requisite pam_cracklib.so try_first_pass retry=3
password sufficient pam_unix.so md5 shadow nullok try_first_pass use_authtok
password required pam_deny.so
session optional pam_keyinit.so revoke
session required pam_limits.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session required pam_unix.so

The first added line counts failed login and failed su attempts for each user. The default location for attempted accesses is recorded in /var/log/faillog.
The second added line specifies to lock accounts automatically after 5 failed login or su attempts (deny=5). The counter will be reset to 0 (reset) on successful entry if deny=n was not exceeded.
But you don't want system or shared accounts to be locked after too many login failures (denial of service attack). To exempt system and shared accounts from the deny=n parameter. The per_user parameter instructs the module NOT to use the deny=n limit for accounts where the maximum number of login failures is set explicitly. For example:
# faillog -u root -m -1
# faillog -u root
Username Failures Maximum Latest
oracle 0 -1 Fri Dec 10 23:57:55 -0600 2005 on unknown
The faillog command with the option "-m -1" has the effect of not placing a limit on the number of failed logins. To instruct the module to activate the deny=n limit for this account again, run:
# faillog -u -m 0
To see failed login attempts, run:
# faillog
To unlock an account after too many login failures, run:
# faillog -u -r
Make sure to test these changes thoroughly on your system using e.g. ssh and su, and make sure root does not get locked!
To lock/unlock accounts manually, you can run one of the following commands:
# passwd -l
# usermod -L
# passwd -u
# usermod -U

Enforce stronger password in Linux

The pam_cracklib module checks the password against dictionary words and other constraints.
E.g. if you define password length minlen=10, then you will get 1 credit for e.g. using a single digit number in your password if you defined dredit=1. This means that pam_cracklib will accept a password of the length of minlen-credit. If you don't use a digit number, then the minimum length of the password would be minlen. There was no way to tell the module that a password _must_include a digit number.

The following example shows how to enforce the following password rules:
pam_cracklib.so minlen=8 Minimum length of password is 8
pam_cracklib.so lcredit=-1 Minimum number of lower case letters is 1
pam_cracklib.so ucredit=-1 Minimum number of upper case letters is 1
pam_cracklib.so dcredit=-1 Minimum number of digits is 1
pam_cracklib.so ocredit=-1 Minimum number of other characters is 1

To setup these password restrictions, edit the /etc/pam.d/system-auth file and add/change the following pam_cracklib arguments

auth required /lib/security/$ISA/pam_env.so
auth sufficient /lib/security/$ISA/pam_unix.so likeauth nullok
auth required /lib/security/$ISA/pam_deny.so
account required /lib/security/$ISA/pam_unix.so
account sufficient /lib/security/$ISA/pam_succeed_if.so uid < 100 quiet
account required /lib/security/$ISA/pam_permit.so
password requisite /lib/security/$ISA/pam_cracklib.so retry=3 minlen=8 lcredit=-1 ucredit=-1 dcredit=-1 ocredit=-1
password sufficient /lib/security/$ISA/pam_unix.so nullok use_authtok md5 shadow
password required /lib/security/$ISA/pam_deny.so
session required /lib/security/$ISA/pam_limits.so
session required /lib/security/$ISA/pam_unix.so