| contains 17 rules |
System Settings
[ref]groupContains rules that check correct system settings. |
| contains 15 rules |
Installing and Maintaining Software
[ref]groupThe following sections contain information on
security-relevant choices during the initial operating system
installation process and the setup of software
updates. |
| contains 3 rules |
System and Software Integrity
[ref]groupSystem and software integrity can be gained by installing antivirus, increasing
system encryption strength with FIPS, verifying installed software, enabling SELinux,
installing an Intrusion Prevention System, etc. However, installing or enabling integrity
checking tools cannot prevent intrusions, but they can detect that an intrusion
may have occurred. Requirements for integrity checking may be highly dependent on
the environment in which the system will be used. Snapshot-based approaches such
as AIDE may induce considerable overhead in the presence of frequent software updates. |
| contains 3 rules |
Software Integrity Checking
[ref]groupBoth the AIDE (Advanced Intrusion Detection Environment)
software and the RPM package management system provide
mechanisms for verifying the integrity of installed software.
AIDE uses snapshots of file metadata (such as hashes) and compares these
to current system files in order to detect changes.
The RPM package management system can conduct integrity
checks by comparing information in its metadata database with
files installed on the system. |
| contains 2 rules |
Verify Integrity with AIDE
[ref]groupAIDE conducts integrity checks by comparing information about
files with previously-gathered information. Ideally, the AIDE database is
created immediately after initial system configuration, and then again after any
software update. AIDE is highly configurable, with further configuration
information located in /usr/share/doc/aide-VERSION. |
| contains 2 rules |
Build and Test AIDE Database
[ref]ruleRun the following command to generate a new database:
$ sudo /usr/bin/aide --init
By default, the database will be written to the file
/var/lib/aide/aide.db.new.
Storing the database, the configuration file /etc/aide.conf, and the binary
/usr/bin/aide
(or hashes of these files), in a secure location (such as on read-only media) provides additional assurance about their integrity.
The newly-generated database can be installed as follows:
$ sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
To initiate a manual check, run the following command:
$ sudo /usr/bin/aide --check
If this check produces any unexpected output, investigate.Warning:
In RHEL Image Mode (bootc) systems, the AIDE database must be regenerated after each system update.
Image Mode systems receive updates through new container images that may include modified files.
After applying system updates, run the following commands to regenerate the AIDE database:
$ sudo /usr/bin/aide --init
Then replace the existing database:
$ sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
Failure to regenerate the AIDE database after updates will result in false positive alerts
for legitimate system changes introduced by the update process. Rationale:For AIDE to be effective, an initial database of "known-good" information about files
must be captured and it should be able to be verified against the installed files. References:
1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000445-GPOS-00199, R76, R79, 11.5.2, SLES-16-16016700 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
zypper -q --no-remote ref
zypper install -y "aide"
/usr/bin/aide --init
/bin/cp -p /var/lib/aide/aide.db.new /var/lib/aide/aide.db
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Build and Test AIDE Database - Ensure Repositories Are Updated
ansible.builtin.command: zypper -q --no-remote ref
failed_when: false
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Build and Test AIDE Database - Ensure AIDE Is Installed
ansible.builtin.package:
name: '{{ item }}'
state: present
with_items:
- aide
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Build and Test AIDE Database - Check Whether the Stock AIDE Database Exists
ansible.builtin.stat:
path: /var/lib/aide/aide.db.new
register: aide_database_stat
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Build and Test AIDE Database - Build and Test AIDE Database
ansible.builtin.command: /usr/bin/aide --init
changed_when: true
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- not (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists)
register: aide_database_init
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Build and Test AIDE Database - Stage AIDE Database
ansible.builtin.copy:
src: /var/lib/aide/aide.db.new
dest: /var/lib/aide/aide.db
backup: true
remote_src: true
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- aide_database_init is changed
- not ansible_check_mode
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_build_database
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
|
Configure Systemd Timer Execution of AIDE
[ref]ruleAt a minimum, AIDE should be configured to run a weekly scan.
To implement a systemd service and a timer unit to run the service periodically:
For example, if a systemd timer is expected to be started every day at 5AM
OnCalendar=*-*-* 05:00:0 [Timer] section in the timer unit and
a Unit section starting the AIDE check service unit should be referred.Rationale:AIDE provides a means to check if unauthorized changes are made to the system.
AIDE itself does not setup a periodic execution, so in order to detect unauthorized
changes a systemd service to run the check and a systemd timer to take care
of periodical execution of that systemd service should be defined. References:
1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, SI-7, SI-7(1), CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000363-GPOS-00150, SRG-OS-000446-GPOS-00200, SRG-OS-000447-GPOS-00201, R76, 11.5.2, SLES-16-16016700 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base && { ( rpm --quiet -q aide && rpm --quiet -q systemd ); }; then
zypper install -y "aide"
# create unit file for periodic aide database check
cat > /etc/systemd/system/aidecheck.service <<EOF
[Unit]
Description=Aide Check
[Service]
Type=simple
ExecStart=/usr/bin/aide --check
[Install]
WantedBy=multi-user.target
EOF
# create unit file for the aide check timer
cat > /etc/systemd/system/aidecheck.timer <<EOF
[Unit]
Description=Aide check every day at 5AM
[Timer]
OnCalendar=*-*-* 05:00:00
Unit=aidecheck.service
[Install]
WantedBy=multi-user.target
EOF
# setup service unit files attributes
chown root:root /etc/systemd/system/aidecheck.*
chmod 0644 /etc/systemd/system/aidecheck.*
# enable the aide related services
systemctl daemon-reload
systemctl enable aidecheck.service
systemctl enable aidecheck.timer
if [[ $(systemctl is-system-running) != "offline" ]]; then
systemctl start aidecheck.timer
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | configure |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-7
- NIST-800-53-SI-7(1)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_periodic_checking_systemd_timer
- configure_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Configure Systemd Timer Execution of AIDE - Define AIDE Periodic Check Service
ansible.builtin.blockinfile:
create: true
dest: /etc/systemd/system/aidecheck.service
owner: root
group: root
mode: '0644'
block: |
[Unit]
Description=Aide Check
[Service]
Type=simple
ExecStart=/usr/bin/aide --check
[Install]
WantedBy=multi-user.target
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- ( "aide" in ansible_facts.packages and "systemd" in ansible_facts.packages )
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-7
- NIST-800-53-SI-7(1)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_periodic_checking_systemd_timer
- configure_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Configure Systemd Timer Execution of AIDE - Define AIDE Periodic Check Service
Timer
ansible.builtin.blockinfile:
create: true
dest: /etc/systemd/system/aidecheck.timer
owner: root
group: root
mode: '0644'
block: |
[Unit]
Description=Aide check every day at 5AM
[Timer]
OnCalendar=*-*-* 05:00:00
Unit=aidecheck.service
[Install]
WantedBy=multi-user.target
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- ( "aide" in ansible_facts.packages and "systemd" in ansible_facts.packages )
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-7
- NIST-800-53-SI-7(1)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_periodic_checking_systemd_timer
- configure_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Configure Systemd Timer Execution of AIDE - Ensure AIDE Service is Enabled
ansible.builtin.systemd:
name: aidecheck.service
enabled: true
daemon_reload: true
masked: false
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- ( "aide" in ansible_facts.packages and "systemd" in ansible_facts.packages )
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-7
- NIST-800-53-SI-7(1)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_periodic_checking_systemd_timer
- configure_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- name: Configure Systemd Timer Execution of AIDE - Ensure AIDE Service Timer is Enabled
ansible.builtin.systemd:
name: aidecheck.timer
state: started
enabled: true
daemon_reload: true
masked: false
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- ( "aide" in ansible_facts.packages and "systemd" in ansible_facts.packages )
tags:
- CJIS-5.10.1.3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-7
- NIST-800-53-SI-7(1)
- PCI-DSS-Req-11.5
- PCI-DSSv4-11.5.2
- aide_periodic_checking_systemd_timer
- configure_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
|
Operating System Vendor Support and Certification
[ref]groupThe assurance of a vendor to provide operating system support and maintenance
for their product is an important criterion to ensure product stability and
security over the life of the product. A certified product that follows the
necessary standards and government certification requirements guarantees that
known software vulnerabilities will be remediated, and proper guidance for
protecting and securing the operating system will be given. |
| contains 1 rule |
The Installed Operating System Is Vendor Supported
[ref]ruleThe installed operating system must be maintained by a vendor.
SUSE Linux Enterprise is supported by SUSE. As the SUSE Linux Enterprise
vendor, SUSE is responsible for providing security patches. Warning:
There is no remediation besides switching to a different operating system. Rationale:An operating system is considered "supported" if the vendor continues to
provide security patches for the product. With an unsupported release, it
will not be possible to resolve any security issue discovered in the system
software. References:
18, 20, 4, APO12.01, APO12.02, APO12.03, APO12.04, BAI03.10, DSS05.01, DSS05.02, 4.2.3, 4.2.3.12, 4.2.3.7, 4.2.3.9, A.12.6.1, A.14.2.3, A.16.1.3, A.18.2.2, A.18.2.3, CM-6(a), MA-6, SA-13(a), ID.RA-1, PR.IP-12, SRG-OS-000480-GPOS-00227, SLES-16-16016005 |
Account and Access Control
[ref]groupIn traditional Unix security, if an attacker gains
shell access to a certain login account, they can perform any action
or access any file to which that account has access. Therefore,
making it more difficult for unauthorized people to gain shell
access to accounts, particularly to privileged accounts, is a
necessary part of securing a system. This section introduces
mechanisms for restricting access to accounts under
SUSE Linux Enterprise Server 16. |
| contains 3 rules |
Protect Accounts by Configuring PAM
[ref]groupPAM, or Pluggable Authentication Modules, is a system
which implements modular authentication for Linux programs. PAM provides
a flexible and configurable architecture for authentication, and it should be configured
to minimize exposure to unnecessary risk. This section contains
guidance on how to accomplish that.
PAM is implemented as a set of shared objects which are
loaded and invoked whenever an application wishes to authenticate a
user. Typically, the application must be running as root in order
to take advantage of PAM, because PAM's modules often need to be able
to access sensitive stores of account information, such as /etc/shadow.
Traditional privileged network listeners
(e.g. sshd) or SUID programs (e.g. sudo) already meet this
requirement. An SUID root application, userhelper, is provided so
that programs which are not SUID or privileged themselves can still
take advantage of PAM.
PAM looks in the directory /etc/pam.d for
application-specific configuration information. For instance, if
the program login attempts to authenticate a user, then PAM's
libraries follow the instructions in the file /etc/pam.d/login
to determine what actions should be taken.
One very important file in /etc/pam.d is
/etc/pam.d/system-auth. This file, which is included by
many other PAM configuration files, defines 'default' system authentication
measures. Modifying this file is a good way to make far-reaching
authentication changes, for instance when implementing a
centralized authentication service. Warning:
Be careful when making changes to PAM's configuration files.
The syntax for these files is complex, and modifications can
have unexpected consequences. The default configurations shipped
with applications should be sufficient for most users. |
| contains 1 rule |
Ensure PAM Displays Last Logon/Access Notification
[ref]ruleTo configure the system to notify users of last logon/access using pam_lastlog,
add or correct the pam_lastlog settings in /etc/pam.d/postlogin-session
to include showfailed option, such as:
session optional pam_lastlog2.so showfailed
And make sure that the silent option is not set for this specific line.Warning:
If the system relies on authselect tool to manage PAM settings, the remediation
will also use authselect tool. However, if any manual modification was made in
PAM files, the authselect 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. Warning:
authselect contains an authselect feature to easily and properly enable Last Logon
notifications with pam_lastlog2.so 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. 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. References:
1, 12, 15, 16, 5.5.2, DSS05.04, DSS05.10, DSS06.10, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-9, AC-9(1), PR.AC-7, Req-10.2.4, SRG-OS-000480-GPOS-00227, 10.2.1.4, 10.2.1, 10.2, SLES-16-16016515 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( rpm --quiet -q pam && rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base ); then
if [ -f /usr/bin/authselect ]; then
if authselect list-features sssd | grep -q with-silent-lastlog; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
authselect disable-feature with-silent-lastlog
authselect apply-changes -b
else
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# If not already in use, a custom profile is created preserving the enabled features.
if [[ ! $CURRENT_PROFILE == custom/* ]]; then
ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin-session")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
authselect apply-changes -b
if [ -e "$PAM_FILE_PATH" ] ; then
PAM_FILE_PATH="$PAM_FILE_PATH"
if [ -f /usr/bin/authselect ]; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# If not already in use, a custom profile is created preserving the enabled features.
if [[ ! $CURRENT_PROFILE == custom/* ]]; then
ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
PAM_FILE_NAME=$(basename "$PAM_FILE_PATH")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
authselect apply-changes -b
fi
if ! grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s*.*" "$PAM_FILE_PATH"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog2.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks "s/^(\s*session\s+).*(\bpam_lastlog2.so.*)/\1optional \2/" "$PAM_FILE_PATH"
else
LAST_MATCH_LINE=$(grep -nP "" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
if [ ! -z $LAST_MATCH_LINE ]; then
sed -i --follow-symlinks $LAST_MATCH_LINE" a session optional pam_lastlog2.so" "$PAM_FILE_PATH"
else
echo "session optional pam_lastlog2.so" >> "$PAM_FILE_PATH"
fi
fi
fi
# Check the option
if ! grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s*.*\sshowfailed\b" "$PAM_FILE_PATH"; then
sed -i -E --follow-symlinks "/\s*session\s+optional\s+pam_lastlog2.so.*/ s/$/ showfailed/" "$PAM_FILE_PATH"
fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
else
echo "$PAM_FILE_PATH was not found" >&2
fi
if [ -e "$PAM_FILE_PATH" ] ; then
PAM_FILE_PATH="$PAM_FILE_PATH"
if [ -f /usr/bin/authselect ]; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# If not already in use, a custom profile is created preserving the enabled features.
if [[ ! $CURRENT_PROFILE == custom/* ]]; then
ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
PAM_FILE_NAME=$(basename "$PAM_FILE_PATH")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
authselect apply-changes -b
fi
if grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then
sed -i -E --follow-symlinks "s/(.*session.*optional.*pam_lastlog2.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH"
fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
else
echo "$PAM_FILE_PATH was not found" >&2
fi
fi
else
if [ -e "/etc/pam.d/postlogin-session" ] ; then
PAM_FILE_PATH="/etc/pam.d/postlogin-session"
if [ -f /usr/bin/authselect ]; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# If not already in use, a custom profile is created preserving the enabled features.
if [[ ! $CURRENT_PROFILE == custom/* ]]; then
ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin-session")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
authselect apply-changes -b
fi
if ! grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s*.*" "$PAM_FILE_PATH"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog2.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks "s/^(\s*session\s+).*(\bpam_lastlog2.so.*)/\1optional \2/" "$PAM_FILE_PATH"
else
LAST_MATCH_LINE=$(grep -nP "" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
if [ ! -z $LAST_MATCH_LINE ]; then
sed -i --follow-symlinks $LAST_MATCH_LINE" a session optional pam_lastlog2.so" "$PAM_FILE_PATH"
else
echo "session optional pam_lastlog2.so" >> "$PAM_FILE_PATH"
fi
fi
fi
# Check the option
if ! grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s*.*\sshowfailed\b" "$PAM_FILE_PATH"; then
sed -i -E --follow-symlinks "/\s*session\s+optional\s+pam_lastlog2.so.*/ s/$/ showfailed/" "$PAM_FILE_PATH"
fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
else
echo "/etc/pam.d/postlogin-session was not found" >&2
fi
if [ -e "/etc/pam.d/postlogin-session" ] ; then
PAM_FILE_PATH="/etc/pam.d/postlogin-session"
if [ -f /usr/bin/authselect ]; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# If not already in use, a custom profile is created preserving the enabled features.
if [[ ! $CURRENT_PROFILE == custom/* ]]; then
ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin-session")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
authselect apply-changes -b
fi
if grep -qP "^\s*session\s+optional\s+pam_lastlog2.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then
sed -i -E --follow-symlinks "s/(.*session.*optional.*pam_lastlog2.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH"
fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
else
echo "/etc/pam.d/postlogin-session was not found" >&2
fi
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | configure |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.5.2
- NIST-800-53-AC-9
- NIST-800-53-AC-9(1)
- PCI-DSS-Req-10.2.4
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.4
- configure_strategy
- display_login_attempts
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when: ( "pam" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- CJIS-5.5.2
- NIST-800-53-AC-9
- NIST-800-53-AC-9(1)
- PCI-DSS-Req-10.2.4
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.4
- configure_strategy
- display_login_attempts
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- name: Ensure PAM Displays Last Logon/Access Notification - Collect the Available
authselect Features
ansible.builtin.command:
cmd: authselect list-features sssd
register: result_authselect_available_features
changed_when: false
check_mode: false
when:
- ( "pam" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- result_authselect_present.stat.exists
tags:
- CJIS-5.5.2
- NIST-800-53-AC-9
- NIST-800-53-AC-9(1)
- PCI-DSS-Req-10.2.4
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.4
- configure_strategy
- display_login_attempts
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog2.so
Using authselect Feature
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Displays Last Logon/Access Notification - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was not
selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific demand,
a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Displays Last Logon/Access Notification - Get authselect Features
Currently Enabled
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_check_cmd is success
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure "with-silent-lastlog"
Feature is Disabled Using authselect Tool
ansible.builtin.command:
cmd: authselect disable-feature with-silent-lastlog
register: result_authselect_disable_feature_cmd
when:
- result_authselect_check_cmd is success
- result_authselect_features.stdout is search("with-silent-lastlog")
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes
are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_disable_feature_cmd is not skipped
- result_authselect_disable_feature_cmd is success
when:
- ( "pam" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- result_authselect_present.stat.exists
- result_authselect_available_features.stdout is search("with-silent-lastlog")
tags:
- CJIS-5.5.2
- NIST-800-53-AC-9
- NIST-800-53-AC-9(1)
- PCI-DSS-Req-10.2.4
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.4
- configure_strategy
- display_login_attempts
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog2.so
in appropriate PAM files
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file
to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/postlogin-session
- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect custom
profile is used if authselect is present
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Displays Last Logon/Access Notification - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current
profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Ensure PAM Displays Last Logon/Access Notification - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Ensure PAM Displays Last Logon/Access Notification - Define the new authselect
custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current
features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Displays Last Logon/Access Notification - Check if any custom
profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Ensure PAM Displays Last Logon/Access Notification - Restore the authselect
features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Ensure PAM Displays Last Logon/Access Notification - Change the PAM file
to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: optional
- name: Ensure PAM Displays Last Logon/Access Notification - Check if expected PAM
module line is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog2.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
- name: Ensure PAM Displays Last Logon/Access Notification - Include or update the
PAM module line in {{ pam_file_path }}
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Check if required
PAM module line is present in {{ pam_file_path }} with different control
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*session\s+.*\s+pam_lastlog2.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure the correct
control for the required PAM module line in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: ^(\s*session\s+).*(\bpam_lastlog2.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure the required
PAM module line is included in {{ pam_file_path }}
ansible.builtin.lineinfile:
dest: '{{ pam_file_path }}'
insertafter: ^\s*session.*include\s+common-session$
line: session {{ pam_module_control }} pam_lastlog2.so
register: result_pam_module_add
when:
- result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
> 1
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- result_authselect_present.stat.exists
- |-
(result_pam_module_add is defined and result_pam_module_add.changed)
or (result_pam_module_edit is defined and result_pam_module_edit.changed)
when:
- result_pam_line_present.found is defined
- result_pam_line_present.found == 0
- name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: optional
- name: Ensure PAM Displays Last Logon/Access Notification - Check if the required
PAM module option is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog2.so\s*.*\sshowfailed\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_display_login_attempts_option_present
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "showfailed"
PAM option for "pam_lastlog2.so" is included in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
backrefs: true
regexp: ^(\s*session\s+{{ pam_module_control | regex_escape() }}\s+pam_lastlog2.so.*)
line: \1 showfailed
state: present
register: result_pam_display_login_attempts_add
when:
- result_pam_module_display_login_attempts_option_present.found is defined
- result_pam_module_display_login_attempts_option_present.found == 0
- name: Ensure PAM Displays Last Logon/Access Notification - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: optional
- name: Ensure PAM Displays Last Logon/Access Notification - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent"
option from "pam_lastlog2.so" is not present in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*session.*{{ pam_module_control | regex_escape() }}.*pam_lastlog2.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when: result_pam_file_present.stat.exists
when: ( "pam" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- CJIS-5.5.2
- NIST-800-53-AC-9
- NIST-800-53-AC-9(1)
- PCI-DSS-Req-10.2.4
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- PCI-DSSv4-10.2.1.4
- configure_strategy
- display_login_attempts
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
|
Protect Accounts by Restricting Password-Based Login
[ref]groupConventionally, Unix shell accounts are accessed by
providing a username and password to a login program, which tests
these values for correctness using the /etc/passwd and
/etc/shadow files. Password-based login is vulnerable to
guessing of weak passwords, and to sniffing and man-in-the-middle
attacks against passwords entered over a network or at an insecure
console. Therefore, mechanisms for accessing accounts by entering
usernames and passwords should be restricted to those which are
operationally necessary. |
| contains 2 rules |
Restrict Root Logins
[ref]groupDirect root logins should be allowed only for emergency use.
In normal situations, the administrator should access the system
via a unique unprivileged account, and then use su or sudo to execute
privileged commands. Discouraging administrators from accessing the
root account directly ensures an audit trail in organizations with
multiple administrators. Locking down the channels through which
root can connect directly also reduces opportunities for
password-guessing against the root account. The login program
uses the file /etc/securetty to determine which interfaces
should allow root logins.
The virtual devices /dev/console
and /dev/tty* represent the system consoles (accessible via
the Ctrl-Alt-F1 through Ctrl-Alt-F6 keyboard sequences on a default
installation). The default securetty file also contains /dev/vc/*.
These are likely to be deprecated in most environments, but may be retained
for compatibility. Root should also be prohibited from connecting
via network protocols. Other sections of this document
include guidance describing how to prevent root from logging in via SSH. |
| contains 2 rules |
Ensure that System Accounts Do Not Run a Shell Upon Login
[ref]ruleSome accounts are not associated with a human user of the system, and exist to perform some
administrative functions. Should an attacker be able to log into these accounts, they should
not be granted access to a shell.
The login shell for each local account is stored in the last field of each line in
/etc/passwd. System accounts are those user accounts with a user ID less than
1000. The user ID is stored in the third field. If any system account
other than root has a login shell, disable it with the command:
$ sudo usermod -s /sbin/nologin account Warning:
Do not perform the steps in this section on the root account. Doing so might cause the
system to become inaccessible. Rationale:Ensuring shells are not given to system accounts upon login makes it more difficult for
attackers to make use of system accounts. References:
1, 12, 13, 14, 15, 16, 18, 3, 5, 7, 8, DSS01.03, DSS03.05, DSS05.04, DSS05.05, DSS05.07, DSS06.03, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 6.2, A.12.4.1, A.12.4.3, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-6, CM-6(a), CM-6(b), CM-6.1(iv), DE.CM-1, DE.CM-3, PR.AC-1, PR.AC-4, PR.AC-6, SRG-OS-000480-GPOS-00227, 1491, 8.2.2, 8.2 Remediation Shell script: (show)
| Complexity: | low |
|---|
| Disruption: | medium |
|---|
| Reboot: | false |
|---|
| Strategy: | restrict |
|---|
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != root \
&& $7 != "\/sbin\/shutdown" && $7 != "\/sbin\/halt" && $7 != "\/bin\/sync") \
{ print $1 }' /etc/passwd)
for systemaccount in "${systemaccounts[@]}"; do
usermod -s /sbin/nologin "$systemaccount"
done
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | medium |
|---|
| Reboot: | false |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(b)
- NIST-800-53-CM-6.1(iv)
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.2
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- no_shelllogin_for_systemaccounts
- restrict_strategy
- name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local
Users From /etc/passwd
ansible.builtin.getent:
database: passwd
split: ':'
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(b)
- NIST-800-53-CM-6.1(iv)
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.2
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- no_shelllogin_for_systemaccounts
- restrict_strategy
- name: Ensure that System Accounts Do Not Run a Shell Upon Login - Create local_users
Variable From getent_passwd Facts
ansible.builtin.set_fact:
local_users: '{{ ansible_facts.getent_passwd | dict2items }}'
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(b)
- NIST-800-53-CM-6.1(iv)
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.2
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- no_shelllogin_for_systemaccounts
- restrict_strategy
- name: Ensure that System Accounts Do Not Run a Shell Upon Login - Disable Login
Shell for System Accounts
ansible.builtin.user:
name: '{{ item.key }}'
shell: /sbin/nologin
loop: '{{ local_users }}'
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- item.key not in ['root']
- item.value[1]|int < 1000
- item.value[5] not in ['/sbin/shutdown', '/sbin/halt', '/bin/sync']
tags:
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-6(b)
- NIST-800-53-CM-6.1(iv)
- PCI-DSSv4-8.2
- PCI-DSSv4-8.2.2
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- no_shelllogin_for_systemaccounts
- restrict_strategy
|
Restrict Serial Port Root Logins
[ref]ruleTo restrict root logins on serial ports,
ensure lines of this form do not appear in /etc/securetty:
ttyS0
ttyS1 Rationale:Preventing direct root login to serial port interfaces
helps ensure accountability for actions taken on the systems
using the root account. References:
12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.1.1, 3.1.5, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6, CM-6(a), PR.AC-4, PR.DS-5, SLES-16-16016010 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
sed -i '/ttyS/d' /etc/securetty
if ! grep -qP "^\s*auth\s+required\s+pam_securetty.so\s*.*" "/etc/pam.d/login"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s*auth\s+.*\s+pam_securetty.so\s*' "/etc/pam.d/login")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks "s/^(\s*auth\s+).*(\bpam_securetty.so.*)/\1required \2/" "/etc/pam.d/login"
else
echo "auth required pam_securetty.so" >> "/etc/pam.d/login"
fi
fi
# Check the option
if ! grep -qP "^\s*auth\s+required\s+pam_securetty.so\s*.*\snoconsole\b" "/etc/pam.d/login"; then
sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_securetty.so.*/ s/$/ noconsole/" "/etc/pam.d/login"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins
ansible.builtin.lineinfile:
dest: /etc/securetty
regexp: ttyS[0-9]
state: absent
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Define a fact for control already filtered
in case filters are used
ansible.builtin.set_fact:
pam_module_control: required
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Check if expected PAM module line is present
in /etc/pam.d/login
ansible.builtin.lineinfile:
path: /etc/pam.d/login
regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_securetty.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Include or update the PAM module line in
/etc/pam.d/login
block:
- name: Restrict Serial Port Root Logins - Check if required PAM module line is
present in /etc/pam.d/login with different control
ansible.builtin.lineinfile:
path: /etc/pam.d/login
regexp: ^\s*auth\s+.*\s+pam_securetty.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Restrict Serial Port Root Logins - Ensure the correct control for the required
PAM module line in /etc/pam.d/login
ansible.builtin.replace:
dest: /etc/pam.d/login
regexp: ^(\s*auth\s+).*(\bpam_securetty.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Restrict Serial Port Root Logins - Ensure the required PAM module line is
included in /etc/pam.d/login
ansible.builtin.lineinfile:
dest: /etc/pam.d/login
line: auth {{ pam_module_control }} pam_securetty.so
register: result_pam_module_add
when:
- result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
> 1
- name: Restrict Serial Port Root Logins - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- result_authselect_present.stat.exists
- |-
(result_pam_module_add is defined and result_pam_module_add.changed)
or (result_pam_module_edit is defined and result_pam_module_edit.changed)
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- result_pam_line_present.found is defined
- result_pam_line_present.found == 0
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Define a fact for control already filtered
in case filters are used
ansible.builtin.set_fact:
pam_module_control: required
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Check if the required PAM module option
is present in /etc/pam.d/login
ansible.builtin.lineinfile:
path: /etc/pam.d/login
regexp: ^\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_securetty.so\s*.*\snoconsole\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_restrict_serial_port_logins_option_present
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
- name: Restrict Serial Port Root Logins - Ensure the "noconsole" PAM option for "pam_securetty.so"
is included in /etc/pam.d/login
ansible.builtin.lineinfile:
path: /etc/pam.d/login
backrefs: true
regexp: ^(\s*auth\s+{{ pam_module_control | regex_escape() }}\s+pam_securetty.so.*)
line: \1 noconsole
state: present
register: result_pam_restrict_serial_port_logins_add
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- result_pam_module_restrict_serial_port_logins_option_present.found is defined
- result_pam_module_restrict_serial_port_logins_option_present.found == 0
tags:
- NIST-800-171-3.1.1
- NIST-800-171-3.1.5
- NIST-800-53-AC-6
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_serial_port_logins
- restrict_strategy
|
GRUB2 bootloader configuration
[ref]groupDuring the boot process, the boot loader is
responsible for starting the execution of the kernel and passing
options to it. The boot loader allows for the selection of
different kernels - possibly on different partitions or media.
The default SUSE Linux Enterprise Server 16 boot loader for x86 systems is called GRUB2.
Options it can pass to the kernel include single-user mode, which
provides root access without any authentication, and the ability to
disable SELinux. To prevent local users from modifying the boot
parameters and endangering security, protect the boot loader configuration
with a password and ensure its configuration file's permissions
are set properly. |
| contains 2 rules |
Ensure SMEP is not disabled during boot
[ref]ruleThe SMEP is used to prevent the supervisor mode from executing user space code,
it is enabled by default since Linux kernel 3.0. But it could be disabled through
kernel boot parameters.
Ensure that Supervisor Mode Execution Prevention (SMEP) is not disabled by
the nosmep boot parameter option.
Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub
doesn't contain the argument nosmep.
Run the following command to update command line for already installed kernels:
# grubby --update-kernel=ALL --remove-args="nosmep" Rationale:Disabling SMEP can facilitate exploitation of certain vulnerabilities because it allows
the kernel to unintentionally execute code in less privileged memory space. Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( rpm --quiet -q grub2 && rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base ); then
if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then
sed -i -E "/kargs\s*=\s*\[\s*\"nosmep=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml"
sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmep=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml"
else
# Correct the form of default kernel command line in GRUB
if grep -q -E '^GRUB_CMDLINE_LINUX=.*nosmep=?.*"' '/etc/default/grub' ; then
sed -i 's/\(^GRUB_CMDLINE_LINUX=".*\)nosmep=\?[^[:space:]]*\(.*"\)/\1 \2/' '/etc/default/grub'
fi
grub2-mkconfig -o /boot/grub2/grub.cfg
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | medium |
|---|
| Disruption: | low |
|---|
| Reboot: | true |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- grub2_nosmep_argument_absent
- low_disruption
- medium_complexity
- medium_severity
- reboot_required
- restrict_strategy
- name: Check nosmep argument exists
ansible.builtin.command: grep -E '^GRUB_CMDLINE_LINUX=.*nosmep=?.*"' /etc/default/grub
check_mode: false
failed_when: false
changed_when: false
register: argcheck
when: ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- grub2_nosmep_argument_absent
- low_disruption
- medium_complexity
- medium_severity
- reboot_required
- restrict_strategy
- name: Replace existing nosmep argument
ansible.builtin.replace:
path: /etc/default/grub
regexp: (^GRUB_CMDLINE_LINUX=\".*)nosmep(\s|=[0-9a-zA-Z]+)?(.*\")
replace: \1 \3
when:
- ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- argcheck is not skipped and argcheck.rc == 0
tags:
- grub2_nosmep_argument_absent
- low_disruption
- medium_complexity
- medium_severity
- reboot_required
- restrict_strategy
- name: Update grub defaults and the bootloader menu
ansible.builtin.command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
when: ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- grub2_nosmep_argument_absent
- low_disruption
- medium_complexity
- medium_severity
- reboot_required
- restrict_strategy
|
Enforce Spectre v2 mitigation
[ref]ruleSpectre V2 is an indirect branch poisoning attack that can lead to data leakage.
An exploit for Spectre V2 tricks the indirect branch predictor into executing
code from a future indirect branch chosen by the attacker, even if the privilege
level is different.
Since Linux Kernel 4.15 you can check the Spectre V2 mitigation state with the following command:
cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
Enforce the Spectre V2 mitigation by adding the argument
spectre_v2=on to the default
GRUB 2 command line for the Linux operating system.
Configure the default Grub2 kernel command line to contain spectre_v2=on as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) spectre_v2=on" Rationale:The Spectre V2 vulnerability allows an attacker to read memory that he should not have
access to. Remediation script: (show)
[customizations.kernel]
append = "spectre_v2=on"
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if ( rpm --quiet -q grub2 && rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base ); then
if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then
KARGS_DIR="/usr/lib/bootc/kargs.d/"
if grep -q -E "spectre_v2" "$KARGS_DIR/*.toml" ; then
sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spectre_v2=[^\"]*\"(.*]\s*)/\1\"spectre_v2=on\"\2/" "$KARGS_DIR/*.toml"
else
echo "kargs = [\"spectre_v2=on\"]" >> "$KARGS_DIR/10-spectre_v2.toml"
fi
else
# Correct the form of default kernel command line in GRUB
if grep -q '^\s*GRUB_CMDLINE_LINUX=.*spectre_v2=.*"' '/etc/default/grub' ; then
# modify the GRUB command-line if an spectre_v2= arg already exists
sed -i "s/\(^\s*GRUB_CMDLINE_LINUX=\".*\)spectre_v2=[^[:space:]]\+\(.*\"\)/\1spectre_v2=on\2/" '/etc/default/grub'
# Add to already existing GRUB_CMDLINE_LINUX parameters
elif grep -q '^\s*GRUB_CMDLINE_LINUX=' '/etc/default/grub' ; then
# no spectre_v2=arg is present, append it
sed -i "s/\(^\s*GRUB_CMDLINE_LINUX=\".*\)\"/\1 spectre_v2=on\"/" '/etc/default/grub'
# Add GRUB_CMDLINE_LINUX parameters line
else
echo "GRUB_CMDLINE_LINUX=\"spectre_v2=on\"" >> '/etc/default/grub'
fi
grub2-mkconfig -o /boot/grub2/grub.cfg
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | medium |
|---|
| Disruption: | low |
|---|
| Reboot: | true |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Check spectre_v2 argument exists
ansible.builtin.command: grep '^\s*GRUB_CMDLINE_LINUX=.*spectre_v2=' /etc/default/grub
check_mode: false
failed_when: false
changed_when: false
register: argcheck
when: ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Check spectre_v2 argument exists
ansible.builtin.command: grep '^\s*GRUB_CMDLINE_LINUX=' /etc/default/grub
check_mode: false
failed_when: false
changed_when: false
register: linecheck
when: ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Add spectre_v2 argument
ansible.builtin.lineinfile:
line: GRUB_CMDLINE_LINUX="spectre_v2=on "
state: present
dest: /etc/default/grub
create: true
mode: '0644'
when:
- ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- argcheck is not skipped and linecheck is not skipped and argcheck.rc != 0 and
linecheck.rc != 0
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Replace existing spectre_v2 argument
ansible.builtin.replace:
path: /etc/default/grub
regexp: spectre_v2=[a-zA-Z0-9,]+
replace: spectre_v2=on
when:
- ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- argcheck is not skipped and linecheck is not skipped and argcheck.rc == 0 and
linecheck.rc == 0
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Add spectre_v2 argument
ansible.builtin.replace:
path: /etc/default/grub
regexp: (^\s*GRUB_CMDLINE_LINUX=.*)"
replace: \1 spectre_v2=on"
when:
- ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
- argcheck is not skipped and linecheck is not skipped and argcheck.rc != 0 and
linecheck.rc == 0
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
- name: Update grub defaults and the bootloader menu
ansible.builtin.command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
when: ( "grub2" in ansible_facts.packages and ("kernel-default" in ansible_facts.packages
or "kernel-default-base" in ansible_facts.packages) )
tags:
- grub2_spectre_v2_argument
- high_severity
- low_disruption
- medium_complexity
- reboot_required
- restrict_strategy
|
Configure Syslog
[ref]groupThe syslog service has been the default Unix logging mechanism for
many years. It has a number of downsides, including inconsistent log format,
lack of authentication for received messages, and lack of authentication,
encryption, or reliable transport for messages sent over a network. However,
due to its long history, syslog is a de facto standard which is supported by
almost all Unix applications.
In SUSE Linux Enterprise Server 16, rsyslog has replaced ksyslogd as the
syslog daemon of choice, and it includes some additional security features
such as reliable, connection-oriented (i.e. TCP) transmission of logs, the
option to log to database formats, and the encryption of log data en route to
a central logging server.
This section discusses how to configure rsyslog for
best effect, and how to use tools provided with the system to maintain and
monitor logs. |
| contains 1 rule |
Rsyslog Logs Sent To Remote Host
[ref]groupIf system logs are to be useful in detecting malicious
activities, it is necessary to send logs to a remote server. An
intruder who has compromised the root account on a system may
delete the log entries which indicate that the system was attacked
before they are seen by an administrator.
However, it is recommended that logs be stored on the local
host in addition to being sent to the loghost, especially if
rsyslog has been configured to use the UDP protocol to send
messages over a network. UDP does not guarantee reliable delivery,
and moderately busy sites will lose log messages occasionally,
especially in periods of high traffic which may be the result of an
attack. In addition, remote rsyslog messages are not
authenticated in any way by default, so it is easy for an attacker to
introduce spurious messages to the central log server. Also, some
problems cause loss of network connectivity, which will prevent the
sending of messages to the central server. For all of these reasons, it is
better to store log messages both centrally and on each host, so
that they can be correlated if necessary. |
| contains 1 rule |
Ensure Logs Sent To Remote Host
[ref]ruleTo configure rsyslog to send logs to a remote log server,
open /etc/rsyslog.conf and read and understand the last section of the file,
which describes the multiple directives necessary to activate remote
logging.
Along with these other directives, the system can be configured
to forward its logs to a particular log server by
adding or correcting one of the following lines,
substituting logcollector appropriately.
The choice of protocol depends on the environment of the system;
although TCP and RELP provide more reliable message delivery,
they may not be supported in all environments.
To use UDP for log message delivery:
*.* @logcollector
Or in RainerScript:
*.* action(type="omfwd" ... target="logcollector" protocol="udp")
To use TCP for log message delivery:
*.* @@logcollector
Or in RainerScript:
*.* action(type="omfwd" ... target="logcollector" protocol="tcp")
To use RELP for log message delivery:
*.* :omrelp:logcollector
Or in RainerScript:
*.* action(type="omfwd" ... target="logcollector" protocol="relp")
There must be a resolvable DNS CNAME or Alias record set to "logcollector" for logs to be sent correctly to the centralized logging utility.Warning:
It is important to configure queues in case the client is sending log
messages to a remote server. If queues are not configured,
the system will stop functioning when the connection
to the remote server is not available. Please consult Rsyslog
documentation for more information about configuration of queues. The
example configuration which should go into /etc/rsyslog.conf
can look like the following lines:
$ActionQueueType LinkedList
$ActionQueueFileName queuefilename
$ActionQueueMaxDiskSpace 1g
$ActionQueueSaveOnShutdown on
$ActionResumeRetryCount -1
Or if using Rainer Script syntax, it could be:
*.* action(type="omfwd" queue.type="linkedlist" queue.filename="example_fwd" action.resumeRetryCount="-1" queue.saveOnShutdown="on" target="example.com" port="30514" protocol="tcp") Rationale:A log server (loghost) receives syslog messages from one or more
systems. This data can be used as an additional log source in the event a
system is compromised and its local logs are suspect. Forwarding log messages
to a remote loghost also provides system administrators with a centralized
place to view the status of multiple hosts within the enterprise. References:
1, 13, 14, 15, 16, 2, 3, 5, 6, APO11.04, APO13.01, BAI03.05, BAI04.04, DSS05.04, DSS05.07, MEA02.01, 164.308(a)(1)(ii)(D), 164.308(a)(5)(ii)(B), 164.308(a)(5)(ii)(C), 164.308(a)(6)(ii), 164.308(a)(8), 164.310(d)(2)(iii), 164.312(b), 164.314(a)(2)(i)(C), 164.314(a)(2)(iii), 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 7.1, SR 7.2, A.12.1.3, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.17.2.1, CIP-003-8 R5.2, CIP-004-6 R3.3, CM-6(a), AU-4(1), AU-9(2), PR.DS-4, PR.PT-1, SRG-OS-000479-GPOS-00224, SRG-OS-000480-GPOS-00227, SRG-OS-000342-GPOS-00133, R71, 0988, 1405, SLES-16-16016510 Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
rsyslog_remote_loghost_address='logcollector'
# If the key exists, comment it. Otherwise do nothing
# We search for the key string followed by a blank space,
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^\*\.\*[[:blank:]]" "/etc/rsyslog.conf"; then
LC_ALL=C sed -i --follow-symlinks "s/^\*\.\*[[:blank:]].*/#&/gi" "/etc/rsyslog.conf"
fi
# If the key exists, comment it. Otherwise do nothing
# We search for the key string followed by a blank space,
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^\*\.\*[[:blank:]]" "/etc/rsyslog.d/*.conf"; then
LC_ALL=C sed -i --follow-symlinks "s/^\*\.\*[[:blank:]].*/#&/gi" "/etc/rsyslog.d/*.conf"
fi
# Strip any search characters in the key arg so that the key can be replaced without
# adding any search characters to the config file.
stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "^\*\.\*")
# shellcheck disable=SC2059
printf -v formatted_output "%s %s" "$stripped_key" "@@$rsyslog_remote_loghost_address"
# If the key exists, change it. Otherwise, add it to the config_file.
# We search for the key string followed by a word boundary (matched by \>),
# so if we search for 'setting', 'setting2' won't match.
if LC_ALL=C grep -q -m 1 -i -e "^\*\.\*\\>" "/etc/rsyslog.d/remote.conf"; then
escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output")
LC_ALL=C sed -i --follow-symlinks "s/^\*\.\*\\>.*/$escaped_formatted_output/gi" "/etc/rsyslog.d/remote.conf"
else
if [[ -s "/etc/rsyslog.d/remote.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/rsyslog.d/remote.conf" || true)" ]]; then
LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/rsyslog.d/remote.conf"
fi
printf '%s\n' "$formatted_output" >> "/etc/rsyslog.d/remote.conf"
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- NIST-800-53-AU-4(1)
- NIST-800-53-AU-9(2)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- rsyslog_remote_loghost
- name: XCCDF Value rsyslog_remote_loghost_address # promote to variable
set_fact:
rsyslog_remote_loghost_address: !!str logcollector
tags:
- always
- name: Check for duplicate values in master configuration
ansible.builtin.lineinfile:
path: /etc/rsyslog.conf
create: false
regexp: ^\*\.\*\s+.*$
state: absent
changed_when: false
register: dupes_master
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AU-4(1)
- NIST-800-53-AU-9(2)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- rsyslog_remote_loghost
- name: Collect all config rsyslog files which configure remote logger
ansible.builtin.find:
paths: /etc/rsyslog.d/
contains: ^\*\.\*\s+.*$
patterns: '*.conf'
register: rsyslog_dropin_config_files
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AU-4(1)
- NIST-800-53-AU-9(2)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- rsyslog_remote_loghost
- name: Deduplicate values from rsyslog dropin configuration
ansible.builtin.lineinfile:
path: '{{ item.path }}'
create: false
regexp: ^\*\.\*\s+.*$
state: absent
loop: '{{ rsyslog_dropin_config_files.files }}'
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AU-4(1)
- NIST-800-53-AU-9(2)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- rsyslog_remote_loghost
- name: Set rsyslog remote loghost
ansible.builtin.lineinfile:
dest: /etc/rsyslog.d/remote.conf
regexp: ^\*\.\*\s+.*$
line: '*.* @@{{ rsyslog_remote_loghost_address }}'
create: true
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- NIST-800-53-AU-4(1)
- NIST-800-53-AU-9(2)
- NIST-800-53-CM-6(a)
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- rsyslog_remote_loghost
|
File Permissions and Masks
[ref]groupTraditional Unix security relies heavily on file and
directory permissions to prevent unauthorized users from reading or
modifying files to which they should not have access.
Several of the commands in this section search filesystems
for files or directories with certain characteristics, and are
intended to be run on every local partition on a given system.
When the variable PART appears in one of the commands below,
it means that the command is intended to be run repeatedly, with the
name of each local partition substituted for PART in turn.
The following command prints a list of all xfs partitions on the local
system, which is the default filesystem for SUSE Linux Enterprise Server 16
installations:
$ mount -t xfs | awk '{print $3}'
For any systems that use a different
local filesystem type, modify this command as appropriate. |
| contains 4 rules |
Verify Permissions on Important Files and
Directories
[ref]groupPermissions for many files on a system must be set
restrictively to ensure sensitive information is properly protected.
This section discusses important
permission restrictions which can be verified
to ensure that no harmful discrepancies have
arisen. |
| contains 2 rules |
Ensure All Files Are Owned by a Group
[ref]ruleIf any file is not group-owned by a valid defined group, the cause of the lack of
group-ownership must be investigated. Following this, those files should be deleted or
assigned to an appropriate group. The groups need to be defined in /etc/group
or in /usr/lib/group if nss-altfiles are configured to be used
in /etc/nsswitch.conf.
Locate the mount points related to local devices by the following command:
$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,)
For all mount points listed by the previous command, it is necessary to search for files which
do not belong to a valid group using the following command:
$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null Warning:
This rule only considers local groups as valid groups.
If you have your groups defined outside /etc/group or /usr/lib/group, the rule won't consider those. Warning:
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of files present on the system. It is not a
problem in most cases, but especially systems with a large number of files can be affected.
See https://access.redhat.com/articles/6999111. Rationale:Unowned files do not directly imply a security problem, but they are generally a sign that
something is amiss. They may be caused by an intruder, by incorrect software installation or
draft software removal, or by failure to remove all files belonging to a deleted account, or
other similar cases. The files should be repaired so they will not cause problems when
accounts are created in the future, and the cause should be discovered and addressed. References:
1, 11, 12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.06, DSS06.10, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, PR.PT-3, SRG-OS-000480-GPOS-00227, R53, 2.2.6, 2.2, SLES-16-16016100 |
Ensure All Files Are Owned by a User
[ref]ruleIf any files are not owned by a user, then the cause of their lack of ownership should be
investigated. Following this, the files should be deleted or assigned to an appropriate user.
Locate the mount points related to local devices by the following command:
$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,)
For all mount points listed by the previous command, it is necessary to search for files which
do not belong to a valid user using the following command:
$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null Warning:
For this rule to evaluate centralized user accounts, getent must be working properly
so that running the command getent passwd returns a list of all users in your organization.
If using the System Security Services Daemon (SSSD), enumerate = true must be configured
in your organization's domain to return a complete list of users Warning:
This rule can take a long time to perform the check and might consume a considerable
amount of resources depending on the number of files present on the system. It is not a
problem in most cases, but especially systems with a large number of files can be affected.
See https://access.redhat.com/articles/6999111. Rationale:Unowned files do not directly imply a security problem, but they are generally a sign that
something is amiss. They may be caused by an intruder, by incorrect software installation or
draft software removal, or by failure to remove all files belonging to a deleted account, or
other similar cases. The files should be repaired so they will not cause problems when
accounts are created in the future, and the cause should be discovered and addressed. References:
11, 12, 13, 14, 15, 16, 18, 3, 5, 9, APO01.06, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), AC-6(1), PR.AC-4, PR.AC-6, PR.DS-5, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, R53, 2.2.6, 2.2, SLES-16-16016105 |
Restrict Programs from Dangerous Execution Patterns
[ref]groupThe recommendations in this section are designed to
ensure that the system's features to protect against potentially
dangerous program execution are activated.
These protections are applied at the system initialization or
kernel level, and defend against certain types of badly-configured
or compromised programs. |
| contains 2 rules |
Enable Execute Disable (XD) or No Execute (NX) Support on
x86 Systems
[ref]groupRecent processors in the x86 family support the
ability to prevent code execution on a per memory page basis.
Generically and on AMD processors, this ability is called No
Execute (NX), while on Intel processors it is called Execute
Disable (XD). This ability can help prevent exploitation of buffer
overflow vulnerabilities and should be activated whenever possible.
Extra steps must be taken to ensure that this protection is
enabled, particularly on 32-bit x86 systems. Other processors, such
as Itanium and POWER, have included such support since inception
and the standard kernel for those platforms supports the
feature. This is enabled by default on the latest Oracle Linux, Red Hat and
Fedora systems if supported by the hardware. |
| contains 2 rules |
Enable NX or XD Support in the BIOS
[ref]ruleReboot the system and enter the BIOS or Setup configuration menu.
Navigate the BIOS configuration menu and make sure that the option is enabled. The setting may be located
under a Security section. Look for Execute Disable (XD) on Intel-based systems and No Execute (NX)
on AMD-based systems. Rationale:Computers with the ability to prevent this type of code execution frequently put an option in the BIOS that will
allow users to turn the feature on or off at will. References:
11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.7, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, SC-39, CM-6(a), PR.IP-1, SRG-OS-000433-GPOS-00192, SRG-APP-000450-CTR-001105, 2.2.1, 2.2, SLES-16-16016400 |
Install PAE Kernel on Supported 32-bit x86 Systems
[ref]ruleSystems that are using the 64-bit x86 kernel package
do not need to install the kernel-PAE package because the 64-bit
x86 kernel already includes this support. However, if the system is
32-bit and also supports the PAE and NX features as
determined in the previous section, the kernel-PAE package should
be installed to enable XD or NX support.
The kernel-PAE package can be installed with the following command:
$ sudo zypper install kernel-PAE
The installation process should also have configured the
bootloader to load the new kernel at boot. Verify this after reboot
and modify /etc/default/grub if necessary.Warning:
The kernel-PAE package should not be
installed on older systems that do not support the XD or NX bit, as
8this may prevent them from booting.8 Rationale:On 32-bit systems that support the XD or NX bit, the vendor-supplied
PAE kernel is required to enable either Execute Disable (XD) or No Execute (NX) support. References:
11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.7, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CM-6(a), PR.IP-1, R1, 2.2.1, 2.2, SLES-16-16016400 |
SELinux
[ref]groupSELinux is a feature of the Linux kernel which can be
used to guard against misconfigured or compromised programs.
SELinux enforces the idea that programs should be limited in what
files they can access and what actions they can take.
The default SELinux policy, as configured on SUSE Linux Enterprise Server 16, has been
sufficiently developed and debugged that it should be usable on
almost any system with minimal configuration and a small
amount of system administrator training. This policy prevents
system services - including most of the common network-visible
services such as mail servers, FTP servers, and DNS servers - from
accessing files which those services have no valid reason to
access. This action alone prevents a huge amount of possible damage
from network attacks against services, from trojaned software, and
so forth.
This guide recommends that SELinux be enabled using the
default (targeted) policy on every SUSE Linux Enterprise Server 16 system, unless that
system has unusual requirements which make a stronger policy
appropriate. |
| contains 2 rules |
SELinux - Booleans
[ref]groupEnable or Disable runtime customization of SELinux system policies
without having to reload or recompile the SELinux policy. |
| contains 1 rule |
Enable the selinuxuser_execmod SELinux Boolean
[ref]ruleBy default, the SELinux boolean selinuxuser_execmod is enabled.
If this setting is disabled, it should be enabled.
To enable the selinuxuser_execmod SELinux boolean, run the following command:
$ sudo setsebool -P selinuxuser_execmod on Rationale:Remediation Shell script: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
# Remediation is applicable only in certain platforms
if ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} && ([ -f /run/ostree-booted ] || [ -L /ostree ]) || [ "${container:-}" == "bwrap-osbuild" ] || selinuxenabled ) && rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
zypper install -y "policycoreutils"
zypper install -y "policycoreutils-python-utils"
zypper install -y "selinux-tools"
zypper install -y "python3-selinux"
zypper install -y "python3-semanage"
# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full
# path to setsebool command to avoid the issue with the command not being
# found.
var_selinuxuser_execmod='true'
/usr/sbin/setsebool -P selinuxuser_execmod $var_selinuxuser_execmod
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- sebool_selinuxuser_execmod
- name: Enable the selinuxuser_execmod SELinux Boolean - Ensure policycoreutils Installed
ansible.builtin.package:
name: policycoreutils
state: present
when:
- ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild"
or ansible_facts.selinux.status != "disabled" )
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- sebool_selinuxuser_execmod
- name: XCCDF Value var_selinuxuser_execmod # promote to variable
set_fact:
var_selinuxuser_execmod: !!str true
tags:
- always
- name: Enable the selinuxuser_execmod SELinux Boolean - Set SELinux Boolean selinuxuser_execmod
Accordingly
ansible.posix.seboolean:
name: selinuxuser_execmod
state: '{{ var_selinuxuser_execmod }}'
persistent: true
when:
- ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline or lookup("env", "container") == "bwrap-osbuild"
or ansible_facts.selinux.status != "disabled" )
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- sebool_selinuxuser_execmod
|
Install libselinux Package
[ref]ruleThe libselinux package can be installed with the following command:
$ sudo zypper install libselinux Rationale:Security-enhanced Linux is a feature of the Linux kernel and a number of utilities
with enhanced security functionality designed to add mandatory access controls to Linux.
The libselinux package contains the core library of the Security-enhanced Linux system. Remediation script: (show)
[[packages]]
name = "libselinux1"
version = "*"
Remediation Puppet snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
include install_libselinux1
class install_libselinux1 {
package { 'libselinux1':
ensure => 'installed',
}
}
Remediation Shell script: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base; then
zypper install -y "libselinux1"
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- PCI-DSSv4-1.2
- PCI-DSSv4-1.2.6
- enable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_libselinux_installed
- name: Ensure libselinux1 is installed
ansible.builtin.package:
name: libselinux1
state: present
when: ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
tags:
- PCI-DSSv4-1.2
- PCI-DSSv4-1.2.6
- enable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_libselinux_installed
|
System Accounting with auditd
[ref]groupThe audit service provides substantial capabilities
for recording system activities. By default, the service audits about
SELinux AVC denials and certain types of security-relevant events
such as system logins, account modifications, and authentication
events performed by programs such as sudo.
Under its default configuration, auditd has modest disk space
requirements, and should not noticeably impact system performance.
NOTE: The Linux Audit daemon auditd can be configured to use
the augenrules program to read audit rules files (*.rules)
located in /etc/audit/rules.d location and compile them to create
the resulting form of the /etc/audit/audit.rules configuration file
during the daemon startup (default configuration). Alternatively, the auditd
daemon can use the auditctl utility to read audit rules from the
/etc/audit/audit.rules configuration file during daemon startup,
and load them into the kernel. The expected behavior is configured via the
appropriate ExecStartPost directive setting in the
/usr/lib/systemd/system/auditd.service configuration file.
To instruct the auditd daemon to use the augenrules program
to read audit rules (default configuration), use the following setting:
ExecStartPost=-/sbin/augenrules --load
in the /usr/lib/systemd/system/auditd.service configuration file.
In order to instruct the auditd daemon to use the auditctl
utility to read audit rules, use the following setting:
ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules
in the /usr/lib/systemd/system/auditd.service configuration file.
Refer to [Service] section of the /usr/lib/systemd/system/auditd.service
configuration file for further details.
Government networks often have substantial auditing
requirements and auditd can be configured to meet these
requirements.
Examining some example audit records demonstrates how the Linux audit system
satisfies common requirements.
The following example from Red Hat Enterprise Linux 7 Documentation available at
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/selinux_users_and_administrators_guide/index#sect-Security-Enhanced_Linux-Fixing_Problems-Raw_Audit_Messages
shows the substantial amount of information captured in a
two typical "raw" audit messages, followed by a breakdown of the most important
fields. In this example the message is SELinux-related and reports an AVC
denial (and the associated system call) that occurred when the Apache HTTP
Server attempted to access the /var/www/html/file1 file (labeled with
the samba_share_t type):
type=AVC msg=audit(1226874073.147:96): avc: denied { getattr } for pid=2465 comm="httpd"
path="/var/www/html/file1" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file
type=SYSCALL msg=audit(1226874073.147:96): arch=40000003 syscall=196 success=no exit=-13
a0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 uid=48
gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm="httpd"
exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
msg=audit(1226874073.147:96)- The number in parentheses is the unformatted time stamp (Epoch time)
for the event, which can be converted to standard time by using the
date command.
{ getattr }- The item in braces indicates the permission that was denied.
getattr
indicates the source process was trying to read the target file's status information.
This occurs before reading files. This action is denied due to the file being
accessed having the wrong label. Commonly seen permissions include getattr,
read, and write.
comm="httpd"- The executable that launched the process. The full path of the executable is
found in the
exe= section of the system call (SYSCALL) message,
which in this case, is exe="/usr/sbin/httpd".
path="/var/www/html/file1"- The path to the object (target) the process attempted to access.
scontext="unconfined_u:system_r:httpd_t:s0"- The SELinux context of the process that attempted the denied action. In
this case, it is the SELinux context of the Apache HTTP Server, which is running
in the
httpd_t domain.
tcontext="unconfined_u:object_r:samba_share_t:s0"- The SELinux context of the object (target) the process attempted to access.
In this case, it is the SELinux context of
file1. Note: the samba_share_t
type is not accessible to processes running in the httpd_t domain.
- From the system call (
SYSCALL) message, two items are of interest:
success=no: indicates whether the denial (AVC) was enforced or not.
success=no indicates the system call was not successful (SELinux denied
access). success=yes indicates the system call was successful - this can
be seen for permissive domains or unconfined domains, such as initrc_t
and kernel_t.
exe="/usr/sbin/httpd": the full path to the executable that launched
the process, which in this case, is exe="/usr/sbin/httpd".
|
| contains 2 rules |
Enable auditd Service
[ref]ruleThe auditd service is an essential userspace component of
the Linux Auditing System, as it is responsible for writing audit records to
disk.
The auditd service can be enabled with the following command:
$ sudo systemctl enable auditd.service Rationale:Without establishing what type of events occurred, it would be difficult
to establish, correlate, and investigate the events leading up to an outage or attack.
Ensuring the auditd service is active ensures audit records
generated by the kernel are appropriately recorded.
Additionally, a properly configured audit subsystem ensures that actions of
individual system users can be uniquely traced to those users so they
can be held accountable for their actions. References:
1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, 3.3.2, 3.3.6, 164.308(a)(1)(ii)(D), 164.308(a)(5)(ii)(C), 164.310(a)(2)(iv), 164.310(d)(2)(iii), 164.312(b), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, CIP-004-6 R3.3, CIP-007-3 R6.5, AC-2(g), AU-3, AU-10, AU-2(d), AU-12(c), AU-14(1), AC-6(9), CM-6(a), SI-4(23), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1, Req-10.1, SRG-OS-000062-GPOS-00031, SRG-OS-000037-GPOS-00015, SRG-OS-000038-GPOS-00016, SRG-OS-000039-GPOS-00017, SRG-OS-000040-GPOS-00018, SRG-OS-000041-GPOS-00019, SRG-OS-000042-GPOS-00021, SRG-OS-000051-GPOS-00024, SRG-OS-000054-GPOS-00025, SRG-OS-000122-GPOS-00063, SRG-OS-000254-GPOS-00095, SRG-OS-000255-GPOS-00096, SRG-OS-000337-GPOS-00129, SRG-OS-000348-GPOS-00136, SRG-OS-000349-GPOS-00137, SRG-OS-000350-GPOS-00138, SRG-OS-000351-GPOS-00139, SRG-OS-000352-GPOS-00140, SRG-OS-000353-GPOS-00141, SRG-OS-000354-GPOS-00142, SRG-OS-000358-GPOS-00145, SRG-OS-000365-GPOS-00152, SRG-OS-000392-GPOS-00172, SRG-OS-000475-GPOS-00220, SRG-APP-000095-CTR-000170, SRG-APP-000409-CTR-000990, SRG-APP-000508-CTR-001300, SRG-APP-000510-CTR-001310, R33, R73, 1409, 10.2.1, 10.2, SLES-16-16016505 Remediation script: (show)
[customizations.services]
enabled = ["auditd"]
Remediation Puppet snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
include enable_auditd
class enable_auditd {
service {'auditd':
enable => true,
ensure => 'running',
}
}
Remediation Shell script: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base && { rpm --quiet -q audit; }; then
SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'auditd.service'
if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then
"$SYSTEMCTL_EXEC" start 'auditd.service'
fi
"$SYSTEMCTL_EXEC" enable 'auditd.service'
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | low |
|---|
| Disruption: | low |
|---|
| Reboot: | false |
|---|
| Strategy: | enable |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-171-3.3.2
- NIST-800-171-3.3.6
- NIST-800-53-AC-2(g)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-10
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-14(1)
- NIST-800-53-AU-2(d)
- NIST-800-53-AU-3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-4(23)
- PCI-DSS-Req-10.1
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- service_auditd_enabled
- name: Enable auditd Service - Enable service auditd
block:
- name: Gather the package facts
ansible.builtin.package_facts:
manager: auto
- name: Enable auditd Service - Enable Service auditd
ansible.builtin.systemd:
name: auditd
enabled: true
state: started
masked: false
when:
- '"audit" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-171-3.3.2
- NIST-800-171-3.3.6
- NIST-800-53-AC-2(g)
- NIST-800-53-AC-6(9)
- NIST-800-53-AU-10
- NIST-800-53-AU-12(c)
- NIST-800-53-AU-14(1)
- NIST-800-53-AU-2(d)
- NIST-800-53-AU-3
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-4(23)
- PCI-DSS-Req-10.1
- PCI-DSSv4-10.2
- PCI-DSSv4-10.2.1
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- service_auditd_enabled
- special_service_block
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"audit" in ansible_facts.packages'
|
Enable Auditing for Processes Which Start Prior to the Audit Daemon
[ref]ruleTo ensure all processes can be audited, even those which start
prior to the audit daemon, add the argument audit=1 to the default
GRUB 2 command line for the Linux operating system.
Configure the default Grub2 kernel command line to contain audit=1 as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) audit=1" Rationale:Each process on the system carries an "auditable" flag which indicates whether
its activities can be audited. Although auditd takes care of enabling
this for all processes which launch after it does, adding the kernel argument
ensures it is set for every process during boot. References:
1, 11, 12, 13, 14, 15, 16, 19, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.02, DSS05.03, DSS05.04, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, 164.308(a)(1)(ii)(D), 164.308(a)(5)(ii)(C), 164.310(a)(2)(iv), 164.310(d)(2)(iii), 164.312(b), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AC-17(1), AU-14(1), AU-10, CM-6(a), IR-5(1), DE.AE-3, DE.AE-5, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1, Req-10.3, SRG-OS-000037-GPOS-00015, SRG-OS-000042-GPOS-00020, SRG-OS-000062-GPOS-00031, SRG-OS-000392-GPOS-00172, SRG-OS-000462-GPOS-00206, SRG-OS-000471-GPOS-00215, SRG-OS-000473-GPOS-00218, SRG-OS-000254-GPOS-00095, 10.7.2, 10.7 Remediation script: (show)
[customizations.kernel]
append = "audit=1"
Remediation Shell script: (show)
# Remediation is applicable only in certain platforms
if rpm --quiet -q kernel-default || rpm --quiet -q kernel-default-base && { rpm --quiet -q grub2; }; then
if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then
KARGS_DIR="/usr/lib/bootc/kargs.d/"
if grep -q -E "audit" "$KARGS_DIR/*.toml" ; then
sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit=[^\"]*\"(.*]\s*)/\1\"audit=1\"\2/" "$KARGS_DIR/*.toml"
else
echo "kargs = [\"audit=1\"]" >> "$KARGS_DIR/10-audit.toml"
fi
else
# Correct the form of default kernel command line in GRUB
if grep -q '^\s*GRUB_CMDLINE_LINUX=.*audit=.*"' '/etc/default/grub' ; then
# modify the GRUB command-line if an audit= arg already exists
sed -i "s/\(^\s*GRUB_CMDLINE_LINUX=\".*\)audit=[^[:space:]]\+\(.*\"\)/\1audit=1\2/" '/etc/default/grub'
# Add to already existing GRUB_CMDLINE_LINUX parameters
elif grep -q '^\s*GRUB_CMDLINE_LINUX=' '/etc/default/grub' ; then
# no audit=arg is present, append it
sed -i "s/\(^\s*GRUB_CMDLINE_LINUX=\".*\)\"/\1 audit=1\"/" '/etc/default/grub'
# Add GRUB_CMDLINE_LINUX parameters line
else
echo "GRUB_CMDLINE_LINUX=\"audit=1\"" >> '/etc/default/grub'
fi
grub2-mkconfig -o /boot/grub2/grub.cfg
fi
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation Ansible snippet: (show)
| Complexity: | medium |
|---|
| Disruption: | low |
|---|
| Reboot: | true |
|---|
| Strategy: | restrict |
|---|
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Check audit argument exists
ansible.builtin.command: grep '^\s*GRUB_CMDLINE_LINUX=.*audit=' /etc/default/grub
check_mode: false
failed_when: false
changed_when: false
register: argcheck
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Check audit argument exists
ansible.builtin.command: grep '^\s*GRUB_CMDLINE_LINUX=' /etc/default/grub
check_mode: false
failed_when: false
changed_when: false
register: linecheck
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Add audit argument
ansible.builtin.lineinfile:
line: GRUB_CMDLINE_LINUX="audit=1 "
state: present
dest: /etc/default/grub
create: true
mode: '0644'
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
- argcheck is not skipped and linecheck is not skipped and argcheck.rc != 0 and
linecheck.rc != 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Replace existing audit argument
ansible.builtin.replace:
path: /etc/default/grub
regexp: audit=[a-zA-Z0-9,]+
replace: audit=1
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
- argcheck is not skipped and linecheck is not skipped and argcheck.rc == 0 and
linecheck.rc == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Add audit argument
ansible.builtin.replace:
path: /etc/default/grub
regexp: (^\s*GRUB_CMDLINE_LINUX=.*)"
replace: \1 audit=1"
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
- argcheck is not skipped and linecheck is not skipped and argcheck.rc != 0 and
linecheck.rc == 0
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
- name: Update grub defaults and the bootloader menu
ansible.builtin.command: /usr/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
when:
- ("kernel-default" in ansible_facts.packages or "kernel-default-base" in ansible_facts.packages)
- '"grub2" in ansible_facts.packages'
tags:
- CJIS-5.4.1.1
- NIST-800-171-3.3.1
- NIST-800-53-AC-17(1)
- NIST-800-53-AU-10
- NIST-800-53-AU-14(1)
- NIST-800-53-CM-6(a)
- NIST-800-53-IR-5(1)
- PCI-DSS-Req-10.3
- PCI-DSSv4-10.7
- PCI-DSSv4-10.7.2
- grub2_audit_argument
- low_disruption
- low_severity
- medium_complexity
- reboot_required
- restrict_strategy
|