Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor display_login_attempts rule for simplicity and avoid noise #10979

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@
# complexity = low
# disruption = low

{{% if product in ["sle12", "sle15"] or "ubuntu" in product %}}
{{{ ansible_ensure_pam_module_configuration('/etc/pam.d/login', 'session', 'required', 'pam_lastlog.so', 'showfailed', '', 'BOF') }}}
{{{ ansible_remove_pam_module_option_configuration('/etc/pam.d/login', 'session', '', 'pam_lastlog.so', 'silent') }}}
{{% else %}}
{{{ ansible_ensure_pam_module_configuration('/etc/pam.d/postlogin', 'session', 'required', 'pam_lastlog.so', 'showfailed', '', 'BOF') }}}
{{{ ansible_remove_pam_module_option_configuration('/etc/pam.d/postlogin', 'session', '', 'pam_lastlog.so', 'silent') }}}
{{% endif %}}
{{%- if "sle" in product or "ubuntu" in product %}}
{{%- set pam_lastlog_path = "/etc/pam.d/login" %}}
{{%- set after_match = "^\s*session.*include\s+common-session$" %}}
{{%- else %}}
{{%- set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{%- set after_match = "^\s*session\s+.*pam_succeed_if\.so.*" %}}
{{%- endif %}}

{{%- if "ol" in product or "ubuntu" in product %}}
{{%- set control = "required" %}}
{{%- elif "sle" in product %}}
{{%- set control = "optional" %}}
{{%- else %}}
{{%- set control = "[default=1]" %}}
{{%- endif %}}

{{{ ansible_pam_lastlog_enable_showfailed(pam_lastlog_path, control, after_match) }}}
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
# platform = multi_platform_sle,Red Hat Virtualization 4,multi_platform_fedora,multi_platform_ol,multi_platform_rhel,multi_platform_ubuntu

{{% if product in ["sle12", "sle15"] or "ubuntu" in product %}}
{{{ bash_ensure_pam_module_configuration('/etc/pam.d/login', 'session', 'required', 'pam_lastlog.so', 'showfailed', '', 'BOF') }}}
{{{ bash_remove_pam_module_option_configuration('/etc/pam.d/login', 'session', '', 'pam_lastlog.so', 'silent') }}}
{{% else %}}
{{{ bash_ensure_pam_module_configuration('/etc/pam.d/postlogin', 'session', 'required', 'pam_lastlog.so', 'showfailed', '', 'BOF') }}}
{{{ bash_remove_pam_module_option_configuration('/etc/pam.d/postlogin', 'session', '', 'pam_lastlog.so', 'silent') }}}
{{% endif %}}
{{%- if "sle" in product or "ubuntu" in product %}}
{{%- set pam_lastlog_path = "/etc/pam.d/login" %}}
{{%- set after_match = "^\s*session.*include\s+common-session$" %}}
{{%- else %}}
{{%- set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{%- set after_match = "^\s*session\s+.*pam_succeed_if\.so.*" %}}
{{%- endif %}}

{{%- if "ol" in product or "ubuntu" in product %}}
{{%- set control = "required" %}}
{{%- elif "sle" in product %}}
{{%- set control = "optional" %}}
{{%- else %}}
{{%- set control = "\[default=1\]" %}}
{{%- endif %}}

{{{ bash_pam_lastlog_enable_showfailed(pam_lastlog_path, control, after_match) }}}
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
{{% if product in ["sle12", "sle15"] or 'ubuntu' in product %}}
{{%- if "sle" in product or "ubuntu" in product %}}
{{% set pam_lastlog_path = "/etc/pam.d/login" %}}
{{% else %}}
{{% set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{% endif %}}
<def-group>
<definition class="compliance" id="display_login_attempts" version="1">
<definition class="compliance" id="{{{ rule_id }}}" version="1">
{{{ oval_metadata("Configure the system to notify users of last login/access using pam_lastlog.") }}}
<criteria operator="AND">
<criterion comment="Conditions for pam_lastlog are satisfied" test_ref="test_display_login_attempts" />
<criterion comment="silent option for pam_lastlog is not set" test_ref="test_display_login_attempts_silent" />
<criteria>
<criterion test_ref="test_display_login_attempts"
comment="conditions for pam_lastlog are satisfied"/>
</criteria>
</definition>

<ind:textfilecontent54_test check="all" comment="Check the pam_lastlog configuration" id="test_display_login_attempts" version="1">
<ind:textfilecontent54_test id="test_display_login_attempts" version="2"
check="all" check_existence="at_least_one_exists"
comment="Check the pam_lastlog is configured to show last login information">
<ind:object object_ref="obj_display_login_attempts" />
</ind:textfilecontent54_test>

<ind:textfilecontent54_object id="obj_display_login_attempts" version="1">
<!-- At least one line should include pam_lastlog.so without silent option
It sometimes intentional to include pam_lastlog.so with silent option and some previous
conditionals in order to avoid message duplication since some programs, like login,
implicitly shows the "Last login:" information regardless of pam_lastlog configuration.
An detailed documentation about these cases is found in
https://github.com/ComplianceAsCode/content/issues/9031 -->
<ind:textfilecontent54_object id="obj_display_login_attempts" version="2">
<ind:filepath>{{{ pam_lastlog_path }}}</ind:filepath>
<ind:pattern operation="pattern match">^\s*session\s+required\s+pam_lastlog\.so(?:\s+[\w=]+)*\s+showfailed(\s|$)</ind:pattern>
<ind:instance datatype="int" operation="equals">1</ind:instance>
</ind:textfilecontent54_object>

<!-- DISA STIG forbids the 'silent' option for SLE12/SLE15, OL7, RHEL7/RHEL8 -->
<ind:textfilecontent54_test check="all" check_existence="none_exist" comment="Forbid 'silent' option for pam_lastlog" id="test_display_login_attempts_silent" version="1">
<ind:object object_ref="obj_display_login_attempts_silent" />
</ind:textfilecontent54_test>
<ind:textfilecontent54_object id="obj_display_login_attempts_silent" version="1">
<ind:filepath>{{{ pam_lastlog_path }}}</ind:filepath>
<ind:pattern operation="pattern match">^\s*session\s+.*\s+pam_lastlog\.so(?:\s+[\w=]+)*\s+silent(\s|$)</ind:pattern>
<ind:pattern operation="pattern match">^\s*session\s+.*\s+pam_lastlog\.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$</ind:pattern>
<ind:instance datatype="int" operation="equals">1</ind:instance>
dodys marked this conversation as resolved.
Show resolved Hide resolved
</ind:textfilecontent54_object>
</def-group>
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
{{% if product in ["sle12", "sle15"] or 'ubuntu' in product %}}
{{% set pam_lastlog_path = "/etc/pam.d/login" %}}
{{% else %}}
{{% set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{% endif %}}
{{%- if "sle" in product or "ubuntu" in product %}}
{{%- set pam_lastlog_path = "/etc/pam.d/login" %}}
{{%- else %}}
{{%- set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{%- endif %}}

{{%- if "ol" in product or "ubuntu" in product %}}
{{%- set control = "required" %}}
{{%- elif "sle" in product %}}
{{%- set control = "optional" %}}
{{%- else %}}
{{%- set control = "[default=1]" %}}
{{%- endif %}}

documentation_complete: true

title: 'Ensure PAM Displays Last Logon/Access Notification'

description: |-
To configure the system to notify users of last logon/access
using <tt>pam_lastlog</tt>, add or correct the <tt>pam_lastlog</tt>
settings in
<tt>{{{ pam_lastlog_path }}}</tt> to read as follows:
<pre>session required pam_lastlog.so showfailed</pre>
And make sure that the <tt>silent</tt> option is not set for
<tt>pam_lastlog</tt> module.
To configure the system to notify users of last logon/access using <tt>pam_lastlog</tt>,
add or correct the <tt>pam_lastlog</tt> settings in <tt>{{{ pam_lastlog_path }}}</tt>
to include <tt>showfailed</tt> option, such as:
<pre>session {{{ control }}} pam_lastlog.so showfailed</pre>
And make sure that the <tt>silent</tt> option is not set for this specific line.

rationale: |-
Users need to be aware of activity that occurs regarding
their account. Providing users with information regarding the number
of unsuccessful attempts that were made to login to their account
allows the user to determine if any unauthorized activity has occurred
and gives them an opportunity to notify administrators.
Users need to be aware of activity that occurs regarding their account. Providing users with
information regarding the number of unsuccessful attempts that were made to login to their
account allows the user to determine if any unauthorized activity has occurred and gives them
an opportunity to notify administrators.

severity: low

Expand Down Expand Up @@ -57,20 +62,34 @@ references:

platform: package[pam]

ocil_clause: '"pam_lastlog" is missing from "{{{ pam_lastlog_path }}}" file, or the silent option is present'
ocil_clause: '"pam_lastlog.so" is not properly configured in "{{{ pam_lastlog_path }}}" file'

ocil: |-
Verify users are provided with feedback on when account accesses last occurred with the following command:

<pre>$ sudo grep pam_lastlog {{{ pam_lastlog_path }}}

session required pam_lastlog.so showfailed</pre>
session {{{ control }}} pam_lastlog.so showfailed</pre>

fixtext: |-
Configure {{{ full_name }}} to provide users with feedback on when account accesses last occurred by setting the required configuration options in "/etc/pam.d/postlogin".
Configure {{{ full_name }}} to provide users with feedback on when account accesses last occurred by setting the required configuration options in "{{{ pam_lastlog_path }}}".

Add the following line to the top of "/etc/pam.d/postlogin":
Add the following line to the top of "{{{ pam_lastlog_path }}}":

session required pam_lastlog.so showfailed
session {{{ control }}} pam_lastlog.so showfailed

srg_requirement: '{{{ full_name }}} must display the date and time of the last successful account logon upon logon.'

warnings:
- general: |-
If the system relies on <tt>authselect</tt> tool to manage PAM settings, the remediation
will also use <tt>authselect</tt> tool. However, if any manual modification was made in
PAM files, the <tt>authselect</tt> integrity check will fail and the remediation will be
aborted in order to preserve intentional changes. In this case, an informative message will
be shown in the remediation report.
- general: |-
<tt>authselect</tt> contains an authselect feature to easily and properly enable Last Logon
notifications with <tt>pam_lastlog.so</tt> module. If a custom profile was created and used
in the system before this authselect feature was available, the new feature can't be used
with this custom profile and the remediation will fail. In this case, the custom profile
should be recreated or manually updated.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
# packages = authselect
# platform = multi_platform_fedora,Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9

if authselect list-features minimal | grep -q with-silent-lastlog; then
authselect select sssd --force
authselect disable-feature with-silent-lastlog
else
authselect create-profile hardening -b sssd
CUSTOM_PROFILE="custom/hardening"
authselect select $CUSTOM_PROFILE --force

CUSTOM_POSTLOGIN="/etc/authselect/$CUSTOM_PROFILE/postlogin"
if [ "$(grep -c "^\s*session\s+\[default=1\]\s+pam_lastlog\.so\s+nowtmp\s+showfailed$" $CUSTOM_POSTLOGIN)" -eq 0 ]; then
sed -i --follow-symlinks '0,/^session.*/s/^session.*/session [default=1] pam_lastlog.so nowtmp showfailed\n&/' $CUSTOM_POSTLOGIN
fi
fi
authselect apply-changes -b

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
#!/bin/bash
# packages = authselect
# platform = Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
# platform = multi_platform_fedora,Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9
# remediation = none

SYSTEM_AUTH_FILE="/etc/pam.d/system-auth"
authselect create-profile hardening -b sssd
CUSTOM_PROFILE="custom/hardening"
authselect select $CUSTOM_PROFILE --force

CUSTOM_POSTLOGIN="/etc/authselect/$CUSTOM_PROFILE/postlogin"
sed -i --follow-symlinks '/session\s*\[default=1\]\s*pam_lastlog\.so.*showfailed.*/d' $CUSTOM_POSTLOGIN
authselect apply-changes -b

SYSTEM_AUTH_FILE="/etc/pam.d/system-auth"
# This modification will break the integrity checks done by authselect.
if ! $(grep -q "^[^#].*pam_pwhistory\.so.*remember=" $SYSTEM_AUTH_FILE); then
if ! grep -q "^[^#].*pam_pwhistory\.so.*remember=" $SYSTEM_AUTH_FILE; then
sed -i --follow-symlinks "/^password.*requisite.*pam_pwquality\.so/a password requisite pam_pwhistory.so" $SYSTEM_AUTH_FILE
else
sed -i --follow-symlinks "s/\(.*pam_pwhistory\.so.*remember=\)[[:digit:]]\+\s\(.*\)/\1/g" $SYSTEM_AUTH_FILE
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/bash
# packages = authselect
# platform = multi_platform_fedora,Oracle Linux 8,Oracle Linux 9,Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9

if authselect list-features minimal | grep -q with-silent-lastlog; then
authselect select sssd --force
authselect enable-feature with-silent-lastlog
else
authselect create-profile hardening -b sssd
CUSTOM_PROFILE="custom/hardening"
authselect select $CUSTOM_PROFILE --force

CUSTOM_POSTLOGIN="/etc/authselect/$CUSTOM_PROFILE/postlogin"
if [ "$(grep -c "^\s*session\s+\[default=1\]\s+pam_lastlog\.so\s+nowtmp\s+showfailed$" $CUSTOM_POSTLOGIN)" -eq 0 ]; then
sed -i --follow-symlinks '0,/^session.*/s/^session.*/session [default=1] pam_lastlog.so nowtmp silent\n&/' $CUSTOM_POSTLOGIN
fi
fi
authselect apply-changes -b

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
# platform = multi_platform_sle,multi_platform_ubuntu,Oracle Linux 7,Red Hat Enterprise Linux 7

{{%- if "sle" in product or "ubuntu" in product %}}
{{% set pam_lastlog_path = "/etc/pam.d/login" %}}
{{% else %}}
{{% set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{% endif %}}

rm -f {{{ pam_lastlog_path }}}

cat <<EOF > {{{ pam_lastlog_path }}}
session optional pam_umask.so silent
session [success=1 default=ignore] pam_succeed_if.so service !~ gdm* service !~ su* quiet
#session [default=1] pam_lastlog.so nowtmp showfailed
marcusburghardt marked this conversation as resolved.
Show resolved Hide resolved
session optional pam_lastlog.so silent noupdate showfailed
EOF
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#!/bin/bash
# platform = Red Hat Enterprise Linux 7,multi_platform_ol,multi_platform_ubuntu
# platform = multi_platform_all

{{% if product in ["sle12", "sle15"] or 'ubuntu' in product %}}
rm -f /etc/pam.d/login
echo "session required pam_lastlog.so showfailed" >> /etc/pam.d/login
{{%- if "sle" in product or "ubuntu" in product %}}
{{% set pam_lastlog_path = "/etc/pam.d/login" %}}
{{% else %}}
rm -f /etc/pam.d/postlogin
echo "session required pam_lastlog.so showfailed" >> /etc/pam.d/postlogin
{{% set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{% endif %}}

rm -f {{{ pam_lastlog_path }}}

cat <<EOF > {{{ pam_lastlog_path }}}
session optional pam_umask.so silent
session [success=1 default=ignore] pam_succeed_if.so service !~ gdm* service !~ su* quiet
session [default=1] pam_lastlog.so nowtmp showfailed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps make control part of the if above and refer to it here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of creating more conditionals, I ensured two pass scripts with different controls. It should be enough for testing purposes. 21ae1e1

session optional pam_lastlog.so silent noupdate showfailed
EOF

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
# platform = multi_platform_all

{{%- if "sle" in product or "ubuntu" in product %}}
{{% set pam_lastlog_path = "/etc/pam.d/login" %}}
{{% else %}}
{{% set pam_lastlog_path = "/etc/pam.d/postlogin" %}}
{{% endif %}}

rm -f {{{ pam_lastlog_path }}}

cat <<EOF > {{{ pam_lastlog_path }}}
session optional pam_umask.so silent
session [success=1 default=ignore] pam_succeed_if.so service !~ gdm* service !~ su* quiet
session required pam_lastlog.so nowtmp showfailed
session optional pam_lastlog.so noupdate showfailed
EOF
Loading
Loading