diff --git a/salt/stig/files/sos-oscap.xml b/salt/stig/files/sos-oscap.xml index f3f9f446f..aa5b2ed31 100644 --- a/salt/stig/files/sos-oscap.xml +++ b/salt/stig/files/sos-oscap.xml @@ -1,6 +1,6 @@ - - + + @@ -14,6 +14,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -22,10 +139,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + Oracle Linux 9 @@ -33,9 +267,9 @@ - + - draft + draft Guide to the Secure Configuration of Oracle Linux 9 This guide presents a catalog of security-relevant configuration settings for Oracle Linux 9. It is a rendering of @@ -78,8 +312,8 @@ trademarks or trademarks of Red Hat, Inc. in the United States and other countries. All other names are registered trademarks or trademarks of their respective companies. anssi - app-srg - app-srg-ctr + app-srg + app-srg-ctr bsi ccn cis @@ -88,344 +322,64 @@ respective companies. cobit5 cui dcid - disa + disa hipaa isa-62443-2009 isa-62443-2013 ism iso27001-2013 - nerc-cip + nerc-cip nist nist-csf - os-srg + os-srg ospp pcidss pcidss4 - stigid - stigref + stigid + stigref - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - + - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -448,9 +402,9 @@ respective companies. - + - + @@ -458,9 +412,9 @@ respective companies. - + - + @@ -468,38 +422,24 @@ respective companies. - + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - @@ -520,6 +460,87 @@ respective companies. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -528,14 +549,269 @@ respective companies. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - 0.1.76 + 0.1.79 SCAP Security Guide Project SCAP Security Guide Project @@ -549,14 +825,18 @@ respective companies. Gabe Alford <redhatrises@gmail.com> Firas AlShafei <firas.alshafei@us.abb.com> Rodrigo Alvares <ralvares@redhat.com> + am-tux <andrew.miller11@gmail.com> Christopher Anderson <cba@fedoraproject.org> Craig Andrews <candrews@integralblue.com> angystardust <angystardust@users.noreply.github.com> anivan-suse <anastasija.ivanovic@suse.com> anixon-rh <55244503+anixon-rh@users.noreply.github.com> + Anna-Koudelkova <akoudelk@redhat.com> + Arden97 <arden2545@gmail.com> Steve Arnold <sarnold@vctlabs.com> Ikko Ashimine <eltociear@gmail.com> Chuck Atkins <chuck.atkins@kitware.com> + axuan <axuan@redhat.com> Bharath B <bhb@redhat.com> Ryan Ballanger <root@rballang-admin-2.fastenal.com> Alex Baranowski <alex@euro-linux.com> @@ -574,6 +854,7 @@ respective companies. Joseph Bisch <joseph.bisch@gmail.com> Jeff Blank <blank@eclipse.ncsc.mil> Olivier Bonhomme <ptitoliv@ptitoliv.net> + bontreger <bontreger@users.noreply.github.com> Lance Bragstad <lbragstad@gmail.com> Ted Brunell <tbrunell@redhat.com> Marcus Burghardt <maburgha@redhat.com> @@ -585,6 +866,7 @@ respective companies. Carlos <64919342+carlosmmatos@users.noreply.github.com> James Cassell <james.cassell@ll.mit.edu> Frank Caviggia <fcaviggia@users.noreply.github.com> + Sinong Chen <costinchen@tencent.com> Eric Christensen <echriste@redhat.com> Dan Clark <danclark@redhat.com> Jayson Cofell <1051437+70k10@users.noreply.github.com> @@ -600,9 +882,9 @@ respective companies. cueball23 <christoph.alms@westnetz.de> cyarbrough76 <42849651+cyarbrough76@users.noreply.github.com> Maura Dailey <maura@eclipse.ncsc.mil> + Benjamin Deering <ben_deering@jeepingben.net> Klaas Demter <demter@atix.de> denknorr <dennis.knorr@suse.com> - dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> dhanushkar-wso2 <dhanushkar@wso2.com> Andrew DiPrinzio <andrew.diprinzio@jhuapl.edu> dom <dominique.blaze@devinci.fr> @@ -614,8 +896,11 @@ respective companies. François Duthilleul <francoisduthilleul@gmail.com> Greg Elin <gregelin@gitmachines.com> eradot4027 <jrtonmac@gmail.com> + ericeberry <ericeberry@gmail.com> ermeratos <manuel.ermer@eviden.net> + Evelyn <evansvevelyn@gmail.com> Alexis Facques <alexis.facques@mythalesgroup.io> + Jan Fader <jan.fader@web.de> Henry Finucane <hfinucane@zscaler.com> Leah Fisher <lfisher047@gmail.com> Marco Fortina <marco_fortina@hotmail.it> @@ -632,11 +917,14 @@ respective companies. Patrik Greco <sikevux@sikevux.se> Steve Grubb <sgrubb@redhat.com> guangyee <gyee@suse.com> + Bhargavi Gudi <bgudi@bgudi-thinkpadt14sgen2i.remote.csb> Christian Hagenest <christian.hagenest@suse.com> Marek Haicman <mhaicman@redhat.com> + Sun, Haoxiang <haoxiang.sun@intel.com> Vern Hart <vern.hart@canonical.com> Alex Haydock <alex@alexhaydock.co.uk> Rebekah Hayes <rhayes@corp.rivierautilities.com> + hazerre <kotadouglas2@gmail.com> Trey Henefield <thenefield@gmail.com> Henning Henkel <henning.henkel@helvetia.ch> hex2a <hex2a@users.noreply.github.com> @@ -675,19 +963,21 @@ respective companies. Amit Kumar <amitkuma@redhat.com> Fen Labalme <fen@civicactions.com> Dexter Le <dexter.le@sap.com> + Dimitri John Ledkov <dimitri.ledkov@surgut.co.uk> Ade Lee <alee@redhat.com> Christopher Lee <Crleekwc@gmail.com> Ian Lee <lee1001@llnl.gov> Jarrett Lee <jarrettl@umd.edu> Joseph Lenox <joseph.lenox@collins.com> + Stefano Libero <stefano.libero@nozominetworks.com> lichtblaugue <guenther.lichtblau@eviden.com> Jan Lieskovsky <jlieskov@redhat.com> Markus Linnala <Markus.Linnala@knowit.fi> Flos Lonicerae <lonicerae@gmail.com> Simon Lukasik <slukasik@redhat.com> + Andrew Lukoshko <andrew.lukoshko@gmail.com> Milan Lysonek <mlysonek@redhat.com> Fredrik Lysén <fredrik@pipemore.se> - Mab879 <207087+Mab879@users.noreply.github.com> Mackemania <8738793+Mackemania@users.noreply.github.com> Caitlin Macleod <caitelatte@gmail.com> Dmitry Makovey <dmakovey@yahoo.com> @@ -763,6 +1053,7 @@ respective companies. Jesse Roland <jesse.roland@onyxpoint.com> Joshua Roys <roysjosh@gmail.com> rrenshaw <bofh69@yahoo.com> + Daniel Ruf <daniel@daniel-ruf.de> Chris Ruffalo <chris.ruffalo@gmail.com> Benjamin Ruland <benjamin.ruland@gmail.com> rumch-se <77793453+rumch-se@users.noreply.github.com> @@ -802,8 +1093,10 @@ respective companies. steven.y.gui <steven_ygui@163.com> Brian Stinson <brian@bstinson.com> Jake Stookey <jakestookey@gmail.com> + Nathan Strahs <135379779+nathanstrahs@users.noreply.github.com> Jonathan Sturges <jsturges@redhat.com> svet-se <svetlin.boychev@suse.com> + Kaushik Talathi <kaushik.talathi1@ibm.com> teacup-on-rockingchair <315160+teacup-on-rockingchair@users.noreply.github.com> Ian Tewksbury <itewk@redhat.com> Philippe Thierry <phil@reseau-libre.net> @@ -823,6 +1116,7 @@ respective companies. VadimDor <29509093+VadimDor@users.noreply.github.com> Trevor Vaughan <tvaughan@onyxpoint.com> vtrubovics <82443408+vtrubovics@users.noreply.github.com> + Sophia Wang <huiwang@redhat.com> Samuel Warren <swarren@redhat.com> wcushen <54533890+wcushen@users.noreply.github.com> Shawn Wells <shawn@redhat.com> @@ -841,6 +1135,9 @@ respective companies. Guang Yee <guang.yee@suse.com> Achilleas John Yfantis <ayfantis@redhat.com> YiLin.Li <YiLin.Li@linux.alibaba.com> + yu410621 <lihuanyu410621@gmail.com> + Xiaojie Yuan <xiyuan@redhat.com> + yungcero <133906218+yungcero@users.noreply.github.com> yunimoo <yunimoo@nekocake.cafe> YuQing <yyq0391@163.com> zhaoyun <zhaoyun@kylinos.cn> @@ -851,11 +1148,11 @@ respective companies. https://github.com/ComplianceAsCode/content/releases/latest - V1R1 + V1R3 DISA STIG for Oracle Linux 9 This profile contains configuration checks that align to the -DISA STIG for Oracle Linux 9 V1R1. - https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux +DISA STIG for Oracle Linux 9 V1R3. + https://www.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux @@ -867,9 +1164,9 @@ DISA STIG for Oracle Linux 9 V1R1. + - @@ -878,10 +1175,11 @@ DISA STIG for Oracle Linux 9 V1R1. + + - @@ -928,6 +1226,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -983,12 +1282,14 @@ DISA STIG for Oracle Linux 9 V1R1. + + @@ -1045,6 +1346,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1122,8 +1424,8 @@ DISA STIG for Oracle Linux 9 V1R1. + - @@ -1138,6 +1440,8 @@ DISA STIG for Oracle Linux 9 V1R1. + + @@ -1188,6 +1492,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1209,11 +1514,11 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1232,6 +1537,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1254,6 +1560,7 @@ DISA STIG for Oracle Linux 9 V1R1. + @@ -1281,7 +1588,6 @@ DISA STIG for Oracle Linux 9 V1R1. - @@ -1328,7 +1634,7 @@ DISA STIG for Oracle Linux 9 V1R1. - + @@ -1373,25 +1679,28 @@ DISA STIG for Oracle Linux 9 V1R1. + - - + + + + @@ -1400,10 +1709,11 @@ DISA STIG for Oracle Linux 9 V1R1. + - + @@ -1418,31 +1728,33 @@ DISA STIG for Oracle Linux 9 V1R1. + + - + - V1R1 + V1R3 DISA STIG with GUI for Oracle Linux 9 This profile contains configuration checks that align to the -DISA STIG for Oracle Linux 9 V1R1. +DISA STIG for Oracle Linux 9 V1R3. Warning: The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your overall security posture. If your Information Systems Security Officer (ISSO) lacks a documented operational requirement for a graphical user interface, please consider using the standard DISA STIG for Oracle Linux 9 profile. - https://public.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux + https://www.cyber.mil/stigs/downloads/?_dl_facet_stigs=operating-systems%2Cunix-linux @@ -1454,9 +1766,9 @@ standard DISA STIG for Oracle Linux 9 profile. + - @@ -1465,10 +1777,11 @@ standard DISA STIG for Oracle Linux 9 profile. + + - @@ -1515,6 +1828,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1570,12 +1884,14 @@ standard DISA STIG for Oracle Linux 9 profile. + + @@ -1632,6 +1948,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1709,8 +2026,8 @@ standard DISA STIG for Oracle Linux 9 profile. + - @@ -1725,6 +2042,8 @@ standard DISA STIG for Oracle Linux 9 profile. + + @@ -1775,6 +2094,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1795,11 +2115,11 @@ standard DISA STIG for Oracle Linux 9 profile. - + @@ -1818,6 +2138,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1840,6 +2161,7 @@ standard DISA STIG for Oracle Linux 9 profile. + @@ -1867,7 +2189,6 @@ standard DISA STIG for Oracle Linux 9 profile. - @@ -1914,7 +2235,7 @@ standard DISA STIG for Oracle Linux 9 profile. - + @@ -1958,26 +2279,29 @@ standard DISA STIG for Oracle Linux 9 profile. + - - + + + + @@ -1986,10 +2310,11 @@ standard DISA STIG for Oracle Linux 9 profile. + - + @@ -2004,17 +2329,19 @@ standard DISA STIG for Oracle Linux 9 profile. + + - + @@ -2079,6 +2406,96 @@ modification of important files. To list which files on the system differ from w $ rpm -qVa See the man page for rpm to see a complete explanation of each column. + + Verify crypto-policies with RPM + Without cryptographic integrity protections, system executables and files can be altered by +unauthorized users without detection. The RPM package management system can check the hashes +of installed software packages, including many that are important to system security. + +If the file was not expected to change, investigate the cause of the change using audit logs +or other means. The package can then be reinstalled to restore the file. Run the following +command to determine which package owns the file: +$ rpm -qf FILENAME + + +The package can be reinstalled from a yum repository using the command: +$ sudo yum reinstall crypto-policies + + SRG-OS-000478-GPOS-00223 + SRG-OS-000396-GPOS-00176 + OL09-00-000244 + SV-271481r1117272_rule + The crypto-policies package defines the cryptography policies for the system. +If the files are changed from those shipped with the operating system, +It may be possible for Oracle Linux 9 to use cryptographic functions that are not FIPS 140-3 approved. + # 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 ]) ); then + +files_with_incorrect_hash="$(rpm -V crypto-policies)" + +if [ -n "$files_with_incorrect_hash" ]; then + yum reinstall -y crypto-policies +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + +- name: Verify crypto-policies with RPM - Read files with incorrect hash + ansible.builtin.command: rpm -V crypto-policies + register: files_with_incorrect_hash + changed_when: false + failed_when: files_with_incorrect_hash.rc > 1 + check_mode: false + when: not ( "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 ) + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + +- name: Verify crypto-policies with RPM - Reinstall packages of files with incorrect + hash + ansible.builtin.command: yum reinstall -y crypto-policies + when: + - not ( "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 ) + - files_with_incorrect_hash.stdout_lines is defined + - (files_with_incorrect_hash.stdout_lines | length > 0) + tags: + - DISA-STIG-OL09-00-000244 + - high_complexity + - high_severity + - medium_disruption + - no_reboot_needed + - restrict_strategy + - rpm_verify_crypto_policies + + + + + + + + Verify File Hashes with RPM Without cryptographic integrity protections, system executables and files can be altered by @@ -2123,8 +2540,6 @@ can be affected. DSS06.02 3.3.8 3.4.1 - CCI-000366 - CCI-001749 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -2158,15 +2573,16 @@ can be affected. PR.DS-8 PR.IP-1 Req-11.5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1409 11.5.2 - OL09-00-000243 - SV-271480r1091152_rule + OL09-00-000243 + SV-271480r1091152_rule The hashes of important files like system executables should match the information given by the RPM database. Executables with erroneous hashes could be a sign of nefarious activity on the system. # 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 ;} ); then +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 ]) ); then # Find which files have incorrect hash (not in /etc, because of the system related config files) and then get files names files_with_incorrect_hash="$(rpm -Va --noconfig | grep -E '^..5' | awk '{print $NF}' )" @@ -2208,13 +2624,14 @@ fi - rpm_verify_hashes - name: 'Set fact: Package manager reinstall command' - set_fact: + ansible.builtin.set_fact: package_manager_reinstall_cmd: yum reinstall -y when: - not ( "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 - ) - - ansible_distribution in [ "Fedora", "RedHat", "CentOS", "OracleLinux" ] + and "ostree" in ansible_proc_cmdline ) + - ansible_distribution in [ "Fedora", "RedHat", "CentOS", "OracleLinux", "AlmaLinux" + ] tags: - CJIS-5.10.4.1 - DISA-STIG-OL09-00-000243 @@ -2236,12 +2653,12 @@ fi - rpm_verify_hashes - name: 'Set fact: Package manager reinstall command (zypper)' - set_fact: + ansible.builtin.set_fact: package_manager_reinstall_cmd: zypper in -f -y when: - not ( "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 ) - ansible_distribution == "SLES" tags: - CJIS-5.10.4.1 @@ -2264,8 +2681,8 @@ fi - rpm_verify_hashes - name: Read files with incorrect hash - command: rpm -Va --nodeps --nosize --nomtime --nordev --nocaps --nolinkto --nouser - --nogroup --nomode --noghost --noconfig + ansible.builtin.command: rpm -Va --nodeps --nosize --nomtime --nordev --nocaps --nolinkto + --nouser --nogroup --nomode --noghost --noconfig register: files_with_incorrect_hash changed_when: false failed_when: files_with_incorrect_hash.rc > 1 @@ -2273,7 +2690,7 @@ fi when: - not ( "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 ) - (package_manager_reinstall_cmd is defined) tags: - CJIS-5.10.4.1 @@ -2296,7 +2713,7 @@ fi - rpm_verify_hashes - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_hash.stdout_lines | map(''regex_findall'', ''^[.]+[5]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2306,7 +2723,7 @@ fi when: - not ( "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 ) - files_with_incorrect_hash.stdout_lines is defined - (files_with_incorrect_hash.stdout_lines | length > 0) tags: @@ -2330,13 +2747,13 @@ fi - rpm_verify_hashes - name: Reinstall packages of files with incorrect hash - command: '{{ package_manager_reinstall_cmd }} ''{{ item }}''' + ansible.builtin.command: '{{ package_manager_reinstall_cmd }} ''{{ item }}''' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "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 ) - files_with_incorrect_hash.stdout_lines is defined - (package_manager_reinstall_cmd is defined and (files_with_incorrect_hash.stdout_lines | length > 0)) @@ -2413,8 +2830,6 @@ can be affected. MEA02.01 3.3.8 3.4.1 - CCI-001494 - CCI-001496 4.3.3.3.9 4.3.3.5.8 4.3.3.7.3 @@ -2466,11 +2881,11 @@ can be affected. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 CM-6(d) CM-6(c) SI-7 @@ -2482,15 +2897,16 @@ can be affected. PR.IP-1 PR.PT-1 Req-11.5 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000278-GPOS-00108 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000278-GPOS-00108 + 1409 11.5.2 Ownership of binaries and configuration files that is incorrect could allow an unauthorized user to gain privileges that they should not have. The ownership set by the vendor should be maintained. Any deviations from this baseline should be investigated. # 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 ;} ); then +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 ]) ); then # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -2540,15 +2956,15 @@ fi - rpm_verify_ownership - name: Read list of files with incorrect ownership - command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev - --nocaps --nolinkto --nomode + ansible.builtin.command: rpm -Va --nodeps --nosignature --nofiledigest --nosize + --nomtime --nordev --nocaps --nolinkto --nomode register: files_with_incorrect_ownership failed_when: files_with_incorrect_ownership.rc > 1 changed_when: false check_mode: false when: not ( "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 ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2569,7 +2985,7 @@ fi - rpm_verify_ownership - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_ownership.stdout_lines | map(''regex_findall'', ''^[.]+[U|G]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2579,7 +2995,7 @@ fi when: - not ( "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 ) - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2601,13 +3017,13 @@ fi - rpm_verify_ownership - name: Correct file ownership with RPM - command: rpm --restore '{{ item }}' + ansible.builtin.command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "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 ) - (files_with_incorrect_ownership.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2686,10 +3102,6 @@ can be affected. MEA02.01 3.3.8 3.4.1 - CCI-001493 - CCI-001494 - CCI-001495 - CCI-001496 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -2746,11 +3158,11 @@ can be affected. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-003-8 R6 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 + CIP-003-8 R4.2 + CIP-003-8 R6 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 CM-6(d) CM-6(c) SI-7 @@ -2763,16 +3175,17 @@ can be affected. PR.IP-1 PR.PT-1 Req-11.5 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - SRG-OS-000278-GPOS-00108 + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + SRG-OS-000278-GPOS-00108 + 1409 11.5.2 Permissions on system binaries and configuration files that are too generous could allow an unauthorized user to gain privileges that they should not have. The permissions set by the vendor should be maintained. Any deviations from this baseline should be investigated. # 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 ;} ); then +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 ]) ); then # Declare array to hold set of RPM packages we need to correct permissions for declare -A SETPERMS_RPM_DICT @@ -2827,15 +3240,15 @@ fi - rpm_verify_permissions - name: Read list of files with incorrect permissions - command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev - --nocaps --nolinkto --nouser --nogroup + ansible.builtin.command: rpm -Va --nodeps --nosignature --nofiledigest --nosize + --nomtime --nordev --nocaps --nolinkto --nouser --nogroup register: files_with_incorrect_permissions failed_when: files_with_incorrect_permissions.rc > 1 changed_when: false check_mode: false when: not ( "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 ) tags: - CJIS-5.10.4.1 - NIST-800-171-3.3.8 @@ -2857,7 +3270,7 @@ fi - rpm_verify_permissions - name: Create list of packages - command: rpm -qf "{{ item }}" + ansible.builtin.command: rpm -qf "{{ item }}" with_items: '{{ files_with_incorrect_permissions.stdout_lines | map(''regex_findall'', ''^[.]+[M]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'') | list | unique }}' @@ -2867,7 +3280,7 @@ fi when: - not ( "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 ) - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2890,13 +3303,13 @@ fi - rpm_verify_permissions - name: Correct file permissions with RPM - command: rpm --restore '{{ item }}' + ansible.builtin.command: rpm --restore '{{ item }}' with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: - not ( "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 ) - (files_with_incorrect_permissions.stdout_lines | length > 0) tags: - CJIS-5.10.4.1 @@ -2973,8 +3386,6 @@ $ sudo yum install aide DSS05.07 DSS06.02 DSS06.06 - CCI-002696 - CCI-001744 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -2985,10 +3396,6 @@ $ sudo yum install aide SR 4.1 SR 6.2 SR 7.6 - 1034 - 1288 - 1341 - 1417 A.11.2.4 A.12.1.2 A.12.2.1 @@ -3012,12 +3419,16 @@ $ sudo yum install aide PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000445-GPOS-00199 + SRG-OS-000445-GPOS-00199 R76 R79 + 1034 + 1288 + 1341 + 1417 11.5.2 - OL09-00-000300 - SV-271496r1091200_rule + OL09-00-000300 + SV-271496r1091200_rule The AIDE package must be installed if it is to be available for integrity checking. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -3047,7 +3458,7 @@ fi - package_aide_installed - name: Ensure aide is installed - package: + ansible.builtin.package: name: aide state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -3107,6 +3518,14 @@ The newly-generated database can be installed as follows: To initiate a manual check, run the following command: $ sudo /usr/sbin/aide --check If this check produces any unexpected output, investigate. + 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/sbin/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. 1 11 12 @@ -3139,8 +3558,6 @@ If this check produces any unexpected output, investigate.DSS05.07 DSS06.02 DSS06.06 - CCI-002696 - CCI-001744 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -3174,7 +3591,7 @@ If this check produces any unexpected output, investigate.PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000445-GPOS-00199 + SRG-OS-000445-GPOS-00199 R76 R79 11.5.2 @@ -3228,9 +3645,10 @@ fi - no_reboot_needed - restrict_strategy -- name: Build and Test AIDE Database - Build and Test AIDE Database - ansible.builtin.command: /usr/sbin/aide --init - changed_when: true +- name: Build and Test AIDE Database - Check Whether the Stock AIDE Database Exists + ansible.builtin.stat: + path: /var/lib/aide/aide.db.new.gz + register: aide_database_stat when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 @@ -3244,11 +3662,13 @@ fi - 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.gz - register: aide_database_stat - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) +- name: Build and Test AIDE Database - Build and Test AIDE Database + ansible.builtin.command: /usr/sbin/aide --init + changed_when: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" 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) @@ -3269,7 +3689,8 @@ fi remote_src: true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists) + - aide_database_init is changed + - not ansible_check_mode tags: - CJIS-5.10.1.3 - NIST-800-53-CM-6(a) @@ -3292,15 +3713,11 @@ fi Configure AIDE to Verify the Audit Tools The operating system file integrity tool must be configured to protect the integrity of the audit tools. - CCI-001496 - CCI-001494 - CCI-001495 - CCI-001493 AU-9(3) AU-9(3).1 - SRG-OS-000278-GPOS-00108 - OL09-00-000710 - SV-271569r1091419_rule + SRG-OS-000278-GPOS-00108 + OL09-00-000710 + SV-271569r1091419_rule Protecting the integrity of the tools used for auditing purposes is a critical step toward ensuring the integrity of audit information. Audit information includes all information (e.g., audit records, audit settings, @@ -3336,44 +3753,44 @@ fi -if grep -i '^.*/usr/sbin/auditctl.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/auditctl.*#/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/auditctl.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/auditctl.*#/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/auditd.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/auditd.*#/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/auditd.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/auditd.*#/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/ausearch.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/ausearch.*#/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/ausearch.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/ausearch.*#/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/aureport.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/aureport.*#/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/aureport.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/aureport.*#/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/autrace.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/autrace.*#/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/autrace.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/autrace.*#/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/augenrules.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/augenrules.*#/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/augenrules.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/augenrules.*#/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi -if grep -i '^.*/usr/sbin/rsyslogd.*$' /etc/aide.conf; then -sed -i "s#.*/usr/sbin/rsyslogd.*#/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf +if grep -i -E '^.*(/usr)?/sbin/rsyslogd.*$' /etc/aide.conf; then +sed -i -r "s#.*(/usr)?/sbin/rsyslogd.*#/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512#" /etc/aide.conf else echo "/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512" >> /etc/aide.conf fi @@ -3413,7 +3830,7 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - name: Ensure aide is installed - package: + ansible.builtin.package: name: '{{ item }}' state: present with_items: @@ -3430,8 +3847,23 @@ fi - no_reboot_needed - restrict_strategy +- name: Configure AIDE to Verify the Audit Tools - Gather the package facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000710 + - NIST-800-53-AU-9(3) + - NIST-800-53-AU-9(3).1 + - aide_check_audit_tools + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Set audit_tools fact - set_fact: + ansible.builtin.set_fact: audit_tools: - /usr/sbin/auditctl - /usr/sbin/auditd @@ -3453,12 +3885,15 @@ fi - restrict_strategy - name: Ensure existing AIDE configuration for audit tools are correct - lineinfile: + ansible.builtin.lineinfile: path: /etc/aide.conf regexp: ^{{ item }}\s line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' + create: true with_items: '{{ audit_tools }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) @@ -3471,11 +3906,14 @@ fi - restrict_strategy - name: Configure AIDE to properly protect audit tools - lineinfile: + ansible.builtin.lineinfile: path: /etc/aide.conf line: '{{ item }} p+i+n+u+g+s+b+acl+xattrs+sha512' + create: true with_items: '{{ audit_tools }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000710 - NIST-800-53-AU-9(3) @@ -3536,9 +3974,6 @@ The usage of cron's special time codes, such as @daily a DSS05.07 DSS06.02 DSS06.06 - CCI-002702 - CCI-001744 - CCI-002699 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -3574,13 +4009,13 @@ The usage of cron's special time codes, such as @daily a PR.IP-1 PR.IP-3 Req-11.5 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 R76 11.5.2 - OL09-00-000301 - SV-271497r1092471_rule + OL09-00-000301 + SV-271497r1092471_rule By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files. @@ -3603,11 +4038,21 @@ if ! rpm -q --quiet "aide" ; then yum install -y "aide" fi -if ! grep -q "/usr/sbin/aide --check" /etc/crontab ; then - echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab + +if ! rpm -q --quiet "cronie" ; then + yum install -y "cronie" +fi + + + +CRON_FILE="/etc/crontab" + + +if ! grep -q "/usr/sbin/aide --check" "${CRON_FILE}" ; then + echo "05 4 * * * root /usr/sbin/aide --check" >> "${CRON_FILE}" else - sed -i '\!^.* --check.*$!d' /etc/crontab - echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab + sed -i '\!^.* --check.*$!d' "${CRON_FILE}" + echo "05 4 * * * root /usr/sbin/aide --check" >> "${CRON_FILE}" fi else @@ -3633,11 +4078,9 @@ fi - restrict_strategy - name: Ensure AIDE is installed - package: - name: '{{ item }}' + ansible.builtin.package: + name: aide state: present - with_items: - - aide when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.3 @@ -3654,51 +4097,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Set cron package name - RedHat - set_fact: - cron_pkg_name: cronie - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_os_family == "RedHat" or ansible_os_family == "Suse" - tags: - - CJIS-5.10.1.3 - - DISA-STIG-OL09-00-000301 - - 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_cron_checking - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - -- name: Set cron package name - Debian - set_fact: - cron_pkg_name: cron - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_os_family == "Debian" - tags: - - CJIS-5.10.1.3 - - DISA-STIG-OL09-00-000301 - - 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_cron_checking - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - name: Install cron - package: - name: '{{ cron_pkg_name }}' + ansible.builtin.package: + name: cronie state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: @@ -3716,15 +4117,36 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of installed packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.3 + - DISA-STIG-OL09-00-000301 + - 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_cron_checking + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Configure Periodic Execution of AIDE - cron: + ansible.builtin.cron: name: run AIDE check minute: 5 hour: 4 - weekday: 0 user: root job: /usr/sbin/aide --check - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + register: crontab_check + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '''cronie'' in ansible_facts.packages' tags: - CJIS-5.10.1.3 - DISA-STIG-OL09-00-000301 @@ -3779,9 +4201,6 @@ AIDE can be executed periodically through other means; this is merely one exampl DSS05.02 DSS05.05 DSS05.07 - CCI-002702 - CCI-001744 - CCI-002699 4.3.4.3.2 4.3.4.3.3 SR 6.2 @@ -3801,12 +4220,12 @@ AIDE can be executed periodically through other means; this is merely one exampl DE.CM-7 PR.IP-1 PR.IP-3 - SRG-OS-000363-GPOS-00150 - SRG-OS-000446-GPOS-00200 - SRG-OS-000447-GPOS-00201 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 R76 - OL09-00-000301 - SV-271497r1092471_rule + OL09-00-000301 + SV-271497r1092471_rule Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may @@ -3868,7 +4287,7 @@ fi - always - name: Ensure AIDE is installed - package: + ansible.builtin.package: name: '{{ item }}' state: present with_items: @@ -3886,7 +4305,7 @@ fi - restrict_strategy - name: Configure Notification of Post-AIDE Scan Details - cron: + ansible.builtin.cron: name: run AIDE check minute: 5 hour: 4 @@ -3945,7 +4364,6 @@ submits to this process. BAI06.01 DSS06.02 3.13.11 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -3962,9 +4380,9 @@ submits to this process. CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 - OL09-00-000302 - SV-271498r1091206_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000302 + SV-271498r1091206_rule File integrity tools use cryptographic hashes for verifying file contents and directories have not been altered. These hashes must be FIPS 140-2 approved cryptographic hashes. # Remediation is applicable only in certain platforms @@ -4065,14 +4483,34 @@ fi - medium_severity - no_reboot_needed +- name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Gather the package + facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000302 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_use_fips_hashes + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Configure AIDE to Use FIPS 140-2 for Validating Hashes - Remove forbidden hashes ansible.builtin.replace: path: '{{ aide_conf }}' regexp: (^\s*[A-Z][A-Za-z_]*\s*=.*?)({{ item }}\+|\+?{{ item }})(.*) replace: \1\3 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' loop: '{{ forbidden_hashes }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000302 - NIST-800-171-3.13.11 @@ -4091,7 +4529,9 @@ fi path: '{{ aide_conf }}' regexp: (^\s*[A-Z][A-Za-z_]*\s*=)((?:(?!\+?sha512).)*)\s*$ replace: \1\2+sha512 - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"aide" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000302 - NIST-800-171-3.13.11 @@ -4132,7 +4572,6 @@ The remediation provided with this rule adds acl to all r BAI03.05 BAI06.01 DSS06.02 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -4149,10 +4588,10 @@ The remediation provided with this rule adds acl to all r CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R76 - OL09-00-000303 - SV-271499r1091209_rule + OL09-00-000303 + SV-271499r1091209_rule ACLs can provide permissions beyond those permitted through the file mode and must be verified by the file integrity tools. # Remediation is applicable only in certain platforms @@ -4188,7 +4627,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -4203,14 +4642,32 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000303 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_verify_acls + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - name: Get rules groups - shell: | + ansible.builtin.shell: | set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results + changed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000303 - NIST-800-53-CM-6(a) @@ -4224,7 +4681,7 @@ fi - restrict_strategy - name: Ensure the acl rule is present when aide is installed. - replace: + ansible.builtin.replace: path: /etc/aide.conf regexp: (^\s*{{ item }}\s*=\s*)(?!.*acl)([^\s]*) replace: \g<1>\g<2>+acl @@ -4271,7 +4728,6 @@ The remediation provided with this rule adds xattrs to al BAI03.05 BAI06.01 DSS06.02 - CCI-000366 4.3.4.4.4 SR 3.1 SR 3.3 @@ -4288,10 +4744,10 @@ The remediation provided with this rule adds xattrs to al CM-6(a) PR.DS-6 PR.DS-8 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R76 - OL09-00-000304 - SV-271500r1091212_rule + OL09-00-000304 + SV-271500r1091212_rule Extended attributes in file systems are used to contain arbitrary data and file metadata with security implications. # Remediation is applicable only in certain platforms @@ -4327,7 +4783,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -4342,14 +4798,32 @@ fi - no_reboot_needed - restrict_strategy +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000304 + - NIST-800-53-CM-6(a) + - NIST-800-53-SI-7 + - NIST-800-53-SI-7(1) + - aide_verify_ext_attributes + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - name: Get rules groups - shell: | + ansible.builtin.shell: | set -o pipefail LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '''aide'' in ansible_facts.packages' register: find_rules_groups_results + changed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000304 - NIST-800-53-CM-6(a) @@ -4363,7 +4837,7 @@ fi - restrict_strategy - name: Ensure the xattrs rule is present when aide is installed. - replace: + ansible.builtin.replace: path: /etc/aide.conf regexp: (^\s*{{ item }}\s*=\s*)(?!.*xattrs)([^\s]*) replace: \g<1>\g<2>+xattrs @@ -4397,25 +4871,48 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have the correct group owner. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002570 - SV-271824r1092184_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002570 + SV-271824r1092184_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /sbin/auditctl -chgrp 0 /sbin/aureport -chgrp 0 /sbin/ausearch -chgrp 0 /sbin/autrace -chgrp 0 /sbin/auditd -chgrp 0 /sbin/rsyslogd -chgrp 0 /sbin/augenrules +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/sbin/auditctl" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/auditctl +fi +if ! stat -c "%g %G" "/sbin/aureport" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/aureport +fi +if ! stat -c "%g %G" "/sbin/ausearch" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/ausearch +fi +if ! stat -c "%g %G" "/sbin/autrace" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/autrace +fi +if ! stat -c "%g %G" "/sbin/auditd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/auditd +fi +if ! stat -c "%g %G" "/sbin/rsyslogd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/rsyslogd +fi +if ! stat -c "%g %G" "/sbin/augenrules" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /sbin/augenrules +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -4434,8 +4931,23 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_audit_tools_group_ownership_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_audit_tools_group_ownership_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002570 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4449,10 +4961,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/auditctl - file: +- name: Ensure group owner on /sbin/auditctl + ansible.builtin.file: path: /sbin/auditctl - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4467,7 +4980,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4481,10 +4994,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/aureport - file: +- name: Ensure group owner on /sbin/aureport + ansible.builtin.file: path: /sbin/aureport - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4499,7 +5013,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4513,10 +5027,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/ausearch - file: +- name: Ensure group owner on /sbin/ausearch + ansible.builtin.file: path: /sbin/ausearch - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4531,7 +5046,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4545,10 +5060,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/autrace - file: +- name: Ensure group owner on /sbin/autrace + ansible.builtin.file: path: /sbin/autrace - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4563,7 +5079,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4577,10 +5093,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/auditd - file: +- name: Ensure group owner on /sbin/auditd + ansible.builtin.file: path: /sbin/auditd - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4595,7 +5112,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4609,10 +5126,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/rsyslogd - file: +- name: Ensure group owner on /sbin/rsyslogd + ansible.builtin.file: path: /sbin/rsyslogd - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4627,7 +5145,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4641,10 +5159,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /sbin/augenrules - file: +- name: Ensure group owner on /sbin/augenrules + ansible.builtin.file: path: /sbin/augenrules - group: '0' + follow: false + group: '{{ file_audit_tools_group_ownership_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4672,25 +5191,48 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have the correct owner. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002571 - SV-271825r1092187_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002571 + SV-271825r1092187_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /sbin/auditctl -chown 0 /sbin/aureport -chown 0 /sbin/ausearch -chown 0 /sbin/autrace -chown 0 /sbin/auditd -chown 0 /sbin/rsyslogd -chown 0 /sbin/augenrules +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/sbin/auditctl" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/auditctl +fi +if ! stat -c "%u %U" "/sbin/aureport" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/aureport +fi +if ! stat -c "%u %U" "/sbin/ausearch" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/ausearch +fi +if ! stat -c "%u %U" "/sbin/autrace" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/autrace +fi +if ! stat -c "%u %U" "/sbin/auditd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/auditd +fi +if ! stat -c "%u %U" "/sbin/rsyslogd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/rsyslogd +fi +if ! stat -c "%u %U" "/sbin/augenrules" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /sbin/augenrules +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -4709,8 +5251,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_audit_tools_ownership_newown variable if represented by uid + ansible.builtin.set_fact: + file_audit_tools_ownership_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002571 + - NIST-800-53-AU-9 + - configure_strategy + - file_audit_tools_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4724,10 +5280,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/auditctl - file: +- name: Ensure owner on /sbin/auditctl + ansible.builtin.file: path: /sbin/auditctl - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4742,7 +5299,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4756,10 +5313,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/aureport - file: +- name: Ensure owner on /sbin/aureport + ansible.builtin.file: path: /sbin/aureport - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4774,7 +5332,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4788,10 +5346,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/ausearch - file: +- name: Ensure owner on /sbin/ausearch + ansible.builtin.file: path: /sbin/ausearch - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4806,7 +5365,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4820,10 +5379,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/autrace - file: +- name: Ensure owner on /sbin/autrace + ansible.builtin.file: path: /sbin/autrace - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4838,7 +5398,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4852,10 +5412,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/auditd - file: +- name: Ensure owner on /sbin/auditd + ansible.builtin.file: path: /sbin/auditd - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4870,7 +5431,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4884,10 +5445,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/rsyslogd - file: +- name: Ensure owner on /sbin/rsyslogd + ansible.builtin.file: path: /sbin/rsyslogd - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4902,7 +5464,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -4916,10 +5478,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /sbin/augenrules - file: +- name: Ensure owner on /sbin/augenrules + ansible.builtin.file: path: /sbin/augenrules - owner: '0' + follow: false + owner: '{{ file_audit_tools_ownership_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -4947,13 +5510,12 @@ fi Audit tools include, but are not limited to, vendor-provided and open source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. Audit tools must have a mode of 0755 or less permissive. - CCI-001493 AU-9 - SRG-OS-000256-GPOS-00097 - SRG-OS-000257-GPOS-00098 - SRG-OS-000258-GPOS-00099 - OL09-00-002572 - SV-271826r1092190_rule + SRG-OS-000256-GPOS-00097 + SRG-OS-000257-GPOS-00098 + SRG-OS-000258-GPOS-00099 + OL09-00-002572 + SV-271826r1092190_rule Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operations on audit information. # Remediation is applicable only in certain platforms @@ -4991,7 +5553,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditctl - stat: + ansible.builtin.stat: path: /sbin/auditctl register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5006,7 +5568,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/auditctl - file: + ansible.builtin.file: path: /sbin/auditctl mode: u-s,g-ws,o-wt when: @@ -5023,7 +5585,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/aureport - stat: + ansible.builtin.stat: path: /sbin/aureport register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5038,7 +5600,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/aureport - file: + ansible.builtin.file: path: /sbin/aureport mode: u-s,g-ws,o-wt when: @@ -5055,7 +5617,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/ausearch - stat: + ansible.builtin.stat: path: /sbin/ausearch register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5070,7 +5632,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/ausearch - file: + ansible.builtin.file: path: /sbin/ausearch mode: u-s,g-ws,o-wt when: @@ -5087,7 +5649,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/autrace - stat: + ansible.builtin.stat: path: /sbin/autrace register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5102,7 +5664,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/autrace - file: + ansible.builtin.file: path: /sbin/autrace mode: u-s,g-ws,o-wt when: @@ -5119,7 +5681,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/auditd - stat: + ansible.builtin.stat: path: /sbin/auditd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5134,7 +5696,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/auditd - file: + ansible.builtin.file: path: /sbin/auditd mode: u-s,g-ws,o-wt when: @@ -5151,7 +5713,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/rsyslogd - stat: + ansible.builtin.stat: path: /sbin/rsyslogd register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5166,7 +5728,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/rsyslogd - file: + ansible.builtin.file: path: /sbin/rsyslogd mode: u-s,g-ws,o-wt when: @@ -5183,7 +5745,7 @@ fi - no_reboot_needed - name: Test for existence /sbin/augenrules - stat: + ansible.builtin.stat: path: /sbin/augenrules register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -5198,7 +5760,7 @@ fi - no_reboot_needed - name: Ensure permission u-s,g-ws,o-wt on /sbin/augenrules - file: + ansible.builtin.file: path: /sbin/augenrules mode: u-s,g-ws,o-wt when: @@ -5238,7 +5800,6 @@ Security Levels 1, 2, 3, or 4 for use on Oracle Linux 9. See http://csrc.nist.gov/publications/PubsFIPS.html for more information. - Enable Dracut FIPS Module @@ -5263,13 +5824,8 @@ undergone this certification. This means providing documentation, test results, information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 @@ -5277,16 +5833,17 @@ this process. CM-6(a) SC-12 FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000478-GPOS-00223 + 1446 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. - + # Remediation is applicable only in certain platforms -if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +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" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then fips-mode-setup --enable FIPS_CONF="/etc/dracut.conf.d/40-fips.conf" @@ -5317,15 +5874,14 @@ fi - restrict_strategy - name: Check to see the current status of FIPS mode - command: /usr/bin/fips-mode-setup --check + ansible.builtin.command: /usr/bin/fips-mode-setup --check register: is_fips_enabled changed_when: false failed_when: false - when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "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 ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000070 @@ -5343,12 +5899,12 @@ fi - restrict_strategy - name: Enable FIPS mode - command: /usr/bin/fips-mode-setup --enable + ansible.builtin.command: /usr/bin/fips-mode-setup --enable when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + - ( not ( "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 ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - is_fips_enabled.stdout.find('FIPS mode is enabled.') == -1 tags: @@ -5367,14 +5923,13 @@ fi - restrict_strategy - name: Enable Dracut FIPS Module - lineinfile: + ansible.builtin.lineinfile: path: /etc/dracut.conf.d/40-fips.conf line: add_dracutmodules+=" fips " - when: - - ( not ( lookup("env", "container") == "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "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 ) and not ( lookup("env", "container") == + "bwrap-osbuild" ) and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000070 @@ -5418,13 +5973,8 @@ Enabling FIPS mode on a preexisting system involves a number of modifications to You can find the list of FIPS certified modules at https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search. This rule checks if the system is running in FIPS mode. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-3(6) SC-12(2) SC-12(3) @@ -5440,18 +5990,20 @@ This rule checks if the system is running in FIPS mode. FCS_CKM.2 FCS_TLSC_EXT.1 FCS_RBG_EXT.1 - SRG-OS-000478-GPOS-00223 - SRG-OS-000396-GPOS-00176 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000478-GPOS-00223 + SRG-OS-000396-GPOS-00176 + 1446 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + # Remediation is applicable only in certain platforms if ( ! ( [ "${container:-}" == "bwrap-osbuild" ] ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then cat > /usr/lib/bootc/kargs.d/01-fips.toml << EOF kargs = ["fips=1"] EOF @@ -5498,11 +6050,8 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000068 - CCI-000803 - CCI-002450 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 @@ -5513,6 +6062,7 @@ submits to this process. protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + @@ -5520,6 +6070,45 @@ and validated. + + System Wide Crypto Policy Files Must Point to FIPS Policy + All files in /etc/crypto-policies/back-ends/ except for nss.config should be symlinks pointing +to /usr/share/crypto-policies/FIPS/ + +$ stat -c%N /etc/crypto-policies/back-ends/* +'/etc/crypto-policies/back-ends/bind.config' -> '/usr/share/crypto-policies/FIPS/bind.txt' +'/etc/crypto-policies/back-ends/gnutls.config' -> '/usr/share/crypto-policies/FIPS/gnutls.txt' +'/etc/crypto-policies/back-ends/java.config' -> '/usr/share/crypto-policies/FIPS/java.txt' +'/etc/crypto-policies/back-ends/javasystem.config' -> '/usr/share/crypto-policies/FIPS/javasystem.txt' +'/etc/crypto-policies/back-ends/krb5.config' -> '/usr/share/crypto-policies/FIPS/krb5.txt' +'/etc/crypto-policies/back-ends/libreswan.config' -> '/usr/share/crypto-policies/FIPS/libreswan.txt' +'/etc/crypto-policies/back-ends/libssh.config' -> '/usr/share/crypto-policies/FIPS/libssh.txt' +'/etc/crypto-policies/back-ends/nss.config' +'/etc/crypto-policies/back-ends/openssh.config' -> '/usr/share/crypto-policies/FIPS/openssh.txt' +'/etc/crypto-policies/back-ends/opensshserver.config' -> '/usr/share/crypto-policies/FIPS/opensshserver.txt' +'/etc/crypto-policies/back-ends/opensslcnf.config' -> '/usr/share/crypto-policies/FIPS/opensslcnf.txt' +'/etc/crypto-policies/back-ends/openssl.config' -> '/usr/share/crypto-policies/FIPS/openssl.txt' +'/etc/crypto-policies/back-ends/openssl_fips.config' -> '/usr/share/crypto-policies/FIPS/openssl_fips.txt' + + + SC-13 + MA-4(6) + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + OL09-00-000242 + SV-271479r1092621_rule + Centralized cryptographic policies simplify applying secure ciphers across an operating +system and the applications that run on that operating system. Use of weak or untested +encryption algorithms undermines the purposes of using encryption to protect data. + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 System running in FIPS mode is indicated by kernel parameter @@ -5547,32 +6136,29 @@ undergone this certification. This means providing documentation, test results, information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-002450 - CCI-000068 - CCI-002418 - CCI-000877 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-12(2) SC-12(3) IA-7 SC-13 CM-6(a) SC-12 - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000396-GPOS-00176 - SRG-OS-000423-GPOS-00187 - SRG-OS-000478-GPOS-00223 - OL09-00-000070 - SV-271454r1092458_rule + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000396-GPOS-00176 + SRG-OS-000423-GPOS-00187 + SRG-OS-000478-GPOS-00223 + OL09-00-000070 + SV-271454r1092458_rule Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated. + @@ -5612,7 +6198,7 @@ configured according to elapsed time. Specify the time component of the rekey limit. The session key is renegotiated after the defined amount of time passes. The number is followed by units such as H or M for hours or minutes. Note that the RekeyLimit can -be also configured according to amount of transfered data. +be also configured according to amount of transferred data. 1h 1h @@ -5624,6 +6210,7 @@ be also configured according to amount of transfered data.DEFAULT:NO-SHA1 FIPS FIPS:OSPP + FIPS:STIG LEGACY FUTURE NEXT @@ -5634,9 +6221,6 @@ be also configured according to amount of transfered data. $ sudo yum install crypto-policies - CCI-002890 - CCI-002450 - CCI-003123 FCS_COP.1(1) FCS_COP.1(2) FCS_COP.1(3) @@ -5644,11 +6228,11 @@ $ sudo yum install crypto-policies FCS_CKM.1 FCS_CKM.2 FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - OL09-00-000240 - SV-271477r1091143_rule + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + OL09-00-000240 + SV-271477r1091143_rule Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. @@ -5658,7 +6242,7 @@ if ! rpm -q --quiet "crypto-policies" ; then fi - name: Ensure crypto-policies is installed - package: + ansible.builtin.package: name: crypto-policies state: present tags: @@ -5705,17 +6289,15 @@ In the options section of /etc/named.confinclude "/etc/crypto-policies/back-ends/bind.config"; - CCI-002418 - CCI-002422 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-13 SC-12(2) SC-12(3) - SRG-OS-000423-GPOS-00187 - SRG-OS-000426-GPOS-00190 - OL09-00-002421 - SV-271759r1091989_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000426-GPOS-00190 + OL09-00-002421 + SV-271759r1091989_rule Overriding the system crypto policy makes the behavior of the BIND service violate expectations, and makes system configuration more fragmented. @@ -5845,22 +6427,14 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000068 - CCI-003123 - CCI-002450 - CCI-000877 - CCI-002418 - CCI-001453 - CCI-002890 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) 164.312(e)(1) 164.312(e)(2)(ii) - 1446 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -5875,23 +6449,26 @@ submits to this process. FCS_CKM.1 FCS_CKM.2 FCS_TLSC_EXT.1 - SRG-OS-000396-GPOS-00176 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 + SRG-OS-000396-GPOS-00176 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 A.5.SEC-OL4 + 1446 2.2.7 2.2 - OL09-00-000070 - OL09-00-000241 - SV-271454r1092458_rule - SV-271478r1092620_rule + OL09-00-000070 + OL09-00-000241 + SV-271454r1092458_rule + SV-271478r1092620_rule Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. - + var_system_crypto_policy='' + + stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null) rc=$? @@ -5913,12 +6490,12 @@ fi tags: - always -- name: Configure System Cryptography Policy - lineinfile: - path: /etc/crypto-policies/config - regexp: ^(?!#)(\S+)$ - line: '{{ var_system_crypto_policy }}' - create: true +- name: Configure System Cryptography Policy - Check current crypto policy (runtime) + ansible.builtin.command: /usr/bin/update-crypto-policies --show + register: current_crypto_policy + changed_when: false + failed_when: false + check_mode: false tags: - DISA-STIG-OL09-00-000070 - DISA-STIG-OL09-00-000241 @@ -5938,8 +6515,90 @@ fi - no_reboot_needed - restrict_strategy -- name: Verify that Crypto Policy is Set (runtime) - command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy }} +- name: Configure System Cryptography Policy - Get mtime of /etc/crypto-policies/config + ansible.builtin.stat: + path: /etc/crypto-policies/config + register: config_file_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Get mtime of /etc/crypto-policies/state/current + ansible.builtin.stat: + path: /etc/crypto-policies/state/current + register: current_file_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Check existence of /etc/crypto-policies/back-ends/nss.config + ansible.builtin.stat: + path: /etc/crypto-policies/back-ends/nss.config + register: nss_config_stat + changed_when: false + failed_when: false + check_mode: false + tags: + - DISA-STIG-OL09-00-000070 + - DISA-STIG-OL09-00-000241 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure System Cryptography Policy - Verify that Crypto Policy is Set (runtime) + ansible.builtin.command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy + }} + when: (current_crypto_policy.stdout.strip() != var_system_crypto_policy) or (config_file_stat.stat.exists + and current_file_stat.stat.exists and config_file_stat.stat.mtime > current_file_stat.stat.mtime) + or (not nss_config_stat.stat.exists) tags: - DISA-STIG-OL09-00-000070 - DISA-STIG-OL09-00-000241 @@ -5975,18 +6634,17 @@ set up to ignore it. To check that Crypto Policies settings for Kerberos are configured correctly, examine that there is a symlink at /etc/krb5.conf.d/crypto-policies targeting /etc/cypto-policies/back-ends/krb5.config. If the symlink exists, Kerberos is configured to use the system-wide crypto policy settings. - CCI-000803 - 0418 - 1055 - 1402 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 SC-13 SC-12(2) SC-12(3) - SRG-OS-000120-GPOS-00061 - OL09-00-002424 - SV-271762r1091998_rule + SRG-OS-000120-GPOS-00061 + 0418 + 1055 + 1402 + OL09-00-002424 + SV-271762r1091998_rule Overriding the system crypto policy makes the behavior of Kerberos violate expectations, and makes system configuration more fragmented. @@ -5994,7 +6652,7 @@ rm -f /etc/krb5.conf.d/crypto-policies ln -s /etc/crypto-policies/back-ends/krb5.config /etc/krb5.conf.d/crypto-policies - name: Configure Kerberos to use System Crypto Policy - file: + ansible.builtin.file: src: /etc/crypto-policies/back-ends/krb5.config path: /etc/krb5.conf.d/crypto-policies state: link @@ -6029,22 +6687,24 @@ In /etc/ipsec.conf, make sure that the following line is not commented out or superseded by later includes: include /etc/crypto-policies/back-ends/libreswan.config - CCI-000068 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-6(a) MA-4(6) SC-13 SC-12(2) SC-12(3) Req-2.2 - SRG-OS-000033-GPOS-00014 - OL09-00-002404 - SV-271743r1092635_rule + SRG-OS-000033-GPOS-00014 + OL09-00-002404 + SV-271743r1092635_rule Overriding the system crypto policy makes the behavior of the Libreswan service violate expectations, and makes system configuration more fragmented. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + function remediate_libreswan_crypto_policy() { CONFIG_FILE="/etc/ipsec.conf" if ! grep -qP "^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$" "$CONFIG_FILE" ; then @@ -6055,12 +6715,35 @@ function remediate_libreswan_crypto_policy() { } remediate_libreswan_crypto_policy + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure Libreswan to use System Crypto Policy - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002404 + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-12(2) + - NIST-800-53-SC-12(3) + - NIST-800-53-SC-13 + - PCI-DSS-Req-2.2 + - configure_libreswan_crypto_policy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Configure Libreswan to use System Crypto Policy + ansible.builtin.lineinfile: path: /etc/ipsec.conf line: include /etc/crypto-policies/back-ends/libreswan.config create: true + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002404 - NIST-800-53-CM-6(a) @@ -6092,10 +6775,9 @@ To check that Crypto Policies settings are configured correctly, you have to exa available under /etc/pki/tls/openssl.cnf. This file has the ini format, and it enables crypto policy support if there is a [ crypto_policy ] section that contains the .include = /etc/crypto-policies/back-ends/opensslcnf.config directive. - CCI-001453 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -6113,7 +6795,7 @@ if there is a [ crypto_policy ] section that contains the FCS_TLSC_EXT.1 FCS_TLSC_EXT.1.1 Req-2.2 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 Overriding the system crypto policy makes the behavior of the Java runtime violates expectations, and makes system configuration more fragmented. @@ -6259,15 +6941,14 @@ set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the CRYPTO_POLICY variable is either commented or not set at all in the /etc/sysconfig/sshd. - CCI-001453 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) 164.312(e)(1) 164.312(e)(2)(ii) - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) @@ -6277,22 +6958,50 @@ in the /etc/sysconfig/sshd. FCS_SSHS_EXT.1 FCS_SSHC_EXT.1 Req-2.2 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 A.5.SEC-OL6 + 0418 2.2.7 2.2 Overriding the system crypto policy makes the behavior of the SSH service violate expectations, and makes system configuration more fragmented. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + SSH_CONF="/etc/sysconfig/sshd" sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure SSH to use System Crypto Policy - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - PCI-DSS-Req-2.2 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.7 + - configure_ssh_crypto_policy + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + +- name: Configure SSH to use System Crypto Policy + ansible.builtin.lineinfile: dest: /etc/sysconfig/sshd state: absent regexp: (?i)^\s*CRYPTO_POLICY.*$ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(2) - NIST-800-53-AC-17(a) @@ -6322,18 +7031,18 @@ sed -i "/^\s*CRYPTO_POLICY.*$/Id" $SSH_CONF To override the system wide crypto policy for Openssh client, place a file in the /etc/ssh/ssh_config.d/ so that it is loaded before the 05-redhat.conf. In this case it is file named 02-ospp.conf containing parameters which need to be changed with respect to the crypto policy. This rule checks if the file exists and if it contains required parameters and values which modify the Crypto Policy. During the parsing process, as soon as Openssh client parses some configuration option and its value, it remembers it and ignores any subsequent overrides. The customization mechanism provided by crypto policies appends eventual customizations at the end of the system wide crypto policy. Therefore, if the crypto policy customization overrides some parameter which is already configured in the system wide crypto policy, the SSH client will not honor that customized parameter. - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 AC-17(a) AC-17(2) CM-6(a) MA-4(6) SC-13 - SRG-OS-000033-GPOS-00014 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 + SRG-OS-000033-GPOS-00014 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 The Common Criteria requirements specify how certain parameters for OpenSSH Client are configured. Particular parameters are RekeyLimit, GSSAPIAuthentication, Ciphers, PubkeyAcceptedKeyTypes, MACs and KexAlgorithms. Currently particular requirements specified by CC are stricter compared to any existing Crypto Policy. #the file starts with 02 so that it is loaded before the 05-redhat.conf which activates configuration provided by system vide crypto policy @@ -6382,21 +7091,39 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-001453 AC-17(2) - SRG-OS-000033-GPOS-00014 - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - SRG-OS-000393-GPOS-00173 - SRG-OS-000394-GPOS-00174 - SRG-OS-000423-GPOS-00187 - OL09-00-000261 - SV-271489r1092627_rule + SRG-OS-000033-GPOS-00014 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + SRG-OS-000393-GPOS-00173 + SRG-OS-000394-GPOS-00174 + SRG-OS-000423-GPOS-00187 + OL09-00-000261 + SV-271489r1092627_rule Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the strongest cipher for securing SSH connections. + +sshd_approved_ciphers='' + + +if [ -e "/etc/crypto-policies/back-ends/openssh.config" ] ; then + + LC_ALL=C sed -i "/^.*Ciphers\s\+/d" "/etc/crypto-policies/back-ends/openssh.config" +else + touch "/etc/crypto-policies/back-ends/openssh.config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/crypto-policies/back-ends/openssh.config" + +cp "/etc/crypto-policies/back-ends/openssh.config" "/etc/crypto-policies/back-ends/openssh.config.bak" +# Insert at the end of the file +printf '%s\n' "Ciphers ${sshd_approved_ciphers}" >> "/etc/crypto-policies/back-ends/openssh.config" +# Clean up after ourselves. +rm "/etc/crypto-policies/back-ends/openssh.config.bak" + - name: XCCDF Value sshd_approved_ciphers # promote to variable set_fact: sshd_approved_ciphers: !!str @@ -6407,7 +7134,7 @@ strongest cipher for securing SSH connections. block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6417,7 +7144,7 @@ strongest cipher for securing SSH connections. register: dupes - name: Deduplicate values from /etc/crypto-policies/back-ends/openssh.config - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6425,7 +7152,7 @@ strongest cipher for securing SSH connections. when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/crypto-policies/back-ends/openssh.config - lineinfile: + ansible.builtin.lineinfile: path: /etc/crypto-policies/back-ends/openssh.config create: true regexp: (?i)^.*Ciphers\s+ @@ -6478,17 +7205,17 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 - OL09-00-000254 - SV-271485r1092625_rule + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000254 + SV-271485r1092625_rule Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more fragmented. By specifying a cipher list with the order of ciphers being in a “strongest to weakest” orientation, the system will automatically attempt to use the strongest cipher for securing SSH connections. + @@ -6526,14 +7253,77 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000877 - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000262 + SV-271490r1092628_rule Overriding the system crypto policy makes the behavior of the OpenSSH client violate expectations, and makes system configuration more fragmented. + +sshd_approved_macs='' + + +if [ -e "/etc/crypto-policies/back-ends/openssh.config" ] ; then + + LC_ALL=C sed -i "/^.*MACs\s\+/d" "/etc/crypto-policies/back-ends/openssh.config" +else + touch "/etc/crypto-policies/back-ends/openssh.config" +fi +# make sure file has newline at the end +sed -i -e '$a\' "/etc/crypto-policies/back-ends/openssh.config" + +cp "/etc/crypto-policies/back-ends/openssh.config" "/etc/crypto-policies/back-ends/openssh.config.bak" +# Insert at the end of the file +printf '%s\n' "MACs ${sshd_approved_macs}" >> "/etc/crypto-policies/back-ends/openssh.config" +# Clean up after ourselves. +rm "/etc/crypto-policies/back-ends/openssh.config.bak" + + - name: XCCDF Value sshd_approved_macs # promote to variable + set_fact: + sshd_approved_macs: !!str + tags: + - always + +- name: 'Configure SSH Daemon to Use FIPS 140-2 Validated MACs: openssh.config' + block: + + - name: Check for duplicate values + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + state: absent + check_mode: true + changed_when: false + register: dupes + + - name: Deduplicate values from /etc/crypto-policies/back-ends/openssh.config + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + state: absent + when: dupes.found is defined and dupes.found > 1 + + - name: Insert correct line to /etc/crypto-policies/back-ends/openssh.config + ansible.builtin.lineinfile: + path: /etc/crypto-policies/back-ends/openssh.config + create: true + regexp: (?i)^.*MACs\s+ + line: MACs {{ sshd_approved_macs }} + state: present + tags: + - DISA-STIG-OL09-00-000262 + - NIST-800-53-AC-17(2) + - harden_sshd_macs_openssh_conf_crypto_policy + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + @@ -6571,14 +7361,15 @@ documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process. - CCI-000877 - CCI-001453 AC-17(2) - SRG-OS-000125-GPOS-00065 - SRG-OS-000250-GPOS-00093 + SRG-OS-000125-GPOS-00065 + SRG-OS-000250-GPOS-00093 + OL09-00-000255 + SV-271486r1092626_rule Overriding the system crypto policy makes the behavior of the OpenSSH server violate expectations, and makes system configuration more fragmented. + @@ -6613,7 +7404,6 @@ Linux vendor, Oracle Corporation is responsible for providing security patches.< BAI03.10 DSS05.01 DSS05.02 - CCI-000366 4.2.3 4.2.3.12 4.2.3.7 @@ -6628,9 +7418,9 @@ Linux vendor, Oracle Corporation is responsible for providing security patches.< SA-13(a) ID.RA-1 PR.IP-12 - SRG-OS-000480-GPOS-00227 - OL09-00-000010 - SV-271438r1091026_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000010 + SV-271438r1117152_rule 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 @@ -6677,7 +7467,7 @@ used to monitor, detect, and defend computer networks and systems. Install McAfee Endpoint Security for Linux (ENSL) Install McAfee Endpoint Security for Linux antivirus software -which is provided for DoD systems and uses signatures to search for the +which is provided for systems and uses signatures to search for the presence of viruses on the filesystem. The McAfeeTP package can be installed with the following command: @@ -6686,10 +7476,8 @@ $ sudo yum install McAfeeTP Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 SI-2(2) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 Virus scanning software can be used to detect if a system has been compromised by computer viruses, as well as to limit their spread to other systems. @@ -6702,14 +7490,12 @@ computer viruses, as well as to limit their spread to other systems. Ensure McAfee Endpoint Security for Linux (ENSL) is running Install McAfee Endpoint Security for Linux antivirus software -which is provided for DoD systems and uses signatures to search for the +which is provided for systems and uses signatures to search for the presence of viruses on the filesystem. Due to McAfee Endpoint Security for Linux (ENSL) being 3rd party software, automated remediation is not available for this configuration check. - CCI-001263 - CCI-000366 SI-2(2) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 Virus scanning software can be used to detect if a system has been compromised by computer viruses, as well as to limit their spread to other systems. @@ -6780,6 +7566,8 @@ Detailed information on encrypting partitions using LUKS or LUKS ciphers can be the Oracle Linux 9 Documentation web site: https://docs.oracle.com/en/operating-systems/oracle-linux/9/install/install-InstallingOracleLinuxManually.html#system-options . + Due to different needs, possibilities, and passphrase requirement automated remediation is +not available for this configuration check. 13 14 APO01.06 @@ -6792,9 +7580,6 @@ the Oracle Linux 9 Documentation web site: DSS06.02 DSS06.06 3.13.16 - CCI-002476 - CCI-001199 - CCI-002475 164.308(a)(1)(ii)(D) 164.308(b)(1) 164.310(d) @@ -6831,8 +7616,8 @@ the Oracle Linux 9 Documentation web site: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4.2 - CIP-007-3 R5.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 CM-6(a) SC-28 SC-28(1) @@ -6840,17 +7625,20 @@ the Oracle Linux 9 Documentation web site: AU-9(3) PR.DS-1 PR.DS-5 - SRG-OS-000405-GPOS-00184 - SRG-OS-000185-GPOS-00079 - SRG-OS-000404-GPOS-00183 + SRG-OS-000405-GPOS-00184 + SRG-OS-000185-GPOS-00079 + SRG-OS-000404-GPOS-00183 A.25.SEC-OL1 - OL09-00-000001 - OL09-00-002418 - SV-271431r1092616_rule - SV-271756r1091980_rule + OL09-00-000001 + OL09-00-002418 + SV-271431r1092616_rule + SV-271756r1091980_rule The risk of a system's physical compromise, particularly mobile systems such as laptops, places its data at risk of compromise. Encrypting this data mitigates the risk of its loss if the system is lost. + + + @@ -6861,7 +7649,7 @@ the risk of its loss if the system is lost. One program will create a memory portion, which other processes (if permitted) can access. If /dev/shm is not configured, tmpfs will be mounted to /dev/shm by systemd. - This rule does not have a remedation. + This rule does not have a remediation. It is expected that this will be managed by systemd and will be a tmpfs partition. Any user can upload and execute files inside the /dev/shm similar to the /tmp partition. Configuring /dev/shm allows an administrator @@ -6890,7 +7678,6 @@ mountpoint can instead be configured later. 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -6907,10 +7694,10 @@ mountpoint can instead be configured later. CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000003 - SV-271433r1091011_rule + OL09-00-000003 + SV-271433r1091011_rule Ensuring that /home is mounted on its own partition enables the setting of more restrictive mount options, and also helps ensure that users cannot trivially fill partitions used for log or audit data storage. @@ -6956,7 +7743,6 @@ logical volume at installation time, or migrate it using LVM.8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -6973,9 +7759,9 @@ logical volume at installation time, or migrate it using LVM.CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000004 - SV-271434r1091014_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000004 + SV-271434r1091014_rule The /tmp partition is used as temporary storage by many programs. Placing /tmp in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it. @@ -6999,7 +7785,6 @@ or logical volume at installation time, or migrate it using LVM.8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -7016,10 +7801,10 @@ or logical volume at installation time, or migrate it using LVM.CM-6(a) SC-5(2) PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000005 - SV-271435r1091017_rule + OL09-00-000005 + SV-271435r1091017_rule Ensuring that /var is mounted on its own partition enables the setting of more restrictive mount options. This helps protect system services such as daemons or other programs which use it. @@ -7057,7 +7842,6 @@ volume at installation time, or migrate it using LVM. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -7087,16 +7871,16 @@ volume at installation time, or migrate it using LVM. A.13.1.1 A.13.2.1 A.14.1.3 - CIP-007-3 R6.5 + CIP-007-3 R6.5 CM-6(a) AU-4 SC-5(2) PR.PT-1 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000006 - SV-271436r1091020_rule + OL09-00-000006 + SV-271436r1091020_rule Placing /var/log in its own partition enables better separation between log files and other files in /var/. @@ -7137,8 +7921,6 @@ audit logs that will be created by the auditing daemon. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-001849 164.312(a)(2)(ii) 4.3.3.3.9 4.3.3.5.8 @@ -7172,7 +7954,7 @@ audit logs that will be created by the auditing daemon. A.13.2.1 A.14.1.3 A.17.2.1 - CIP-007-3 R6.5 + CIP-007-3 R6.5 CM-6(a) AU-4 SC-5(2) @@ -7180,12 +7962,12 @@ audit logs that will be created by the auditing daemon. PR.PT-1 PR.PT-4 FMT_SMF_EXT.1 - SRG-OS-000341-GPOS-00132 - SRG-OS-000480-GPOS-00227 - SRG-APP-000357-CTR-000800 + SRG-OS-000341-GPOS-00132 + SRG-OS-000480-GPOS-00227 + SRG-APP-000357-CTR-000800 R71 - OL09-00-000002 - SV-271432r1091008_rule + OL09-00-000002 + SV-271432r1091008_rule Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that @@ -7206,11 +7988,10 @@ part /var/log/audit The /var/tmp directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or logical volume at installation time, or migrate it using LVM. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-000007 - SV-271437r1091023_rule + OL09-00-000007 + SV-271437r1091023_rule The /var/tmp partition is used as temporary storage by many programs. Placing /var/tmp in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it. @@ -7236,7 +8017,7 @@ restrictive mount options, which can help protect programs which use it. The tmp.mount unit configures the tmpfs filesystem and ensures the /tmp directory is wiped during reboot. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'tmp.mount' @@ -7268,8 +8049,8 @@ fi masked: 'false' when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - enable_strategy - low_complexity @@ -7314,16 +8095,15 @@ in the following directories: /etc/dconf/db/local.d /etc/dconf/db/local.d - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(5)(ii)(A) Req-6.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 reload_dconf_db 8.2.8 8.2 - OL09-00-002162 - SV-271692r1091788_rule + OL09-00-002162 + SV-271692r1091788_rule Unlike text-based keyfiles, the binary database is impossible to check by OVAL. Therefore, in order to evaluate dconf configuration, both have to be true at the same time - configuration files have to be compliant, and the database needs to be more recent than those keyfiles, @@ -7353,12 +8133,55 @@ fi - no_reboot_needed - unknown_strategy -- name: Run dconf update +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Get database modification time for local + ansible.builtin.stat: + path: /etc/dconf/db/local + register: local_db + when: + - '"gdm" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002162 + - PCI-DSS-Req-6.2 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_db_up_to_date + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - unknown_strategy + +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Get keyfiles for local + ansible.builtin.find: + paths: /etc/dconf/db/local.d/ + register: local_keyfiles + when: + - '"gdm" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002162 + - PCI-DSS-Req-6.2 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_db_up_to_date + - high_severity + - low_complexity + - medium_disruption + - no_reboot_needed + - unknown_strategy + +- name: Make sure that the dconf databases are up-to-date with regards to respective + keyfiles - Run dconf update for local ansible.builtin.command: cmd: dconf update when: - '"gdm" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not local_db.stat.exists or local_keyfiles.files | length > 0 and local_keyfiles.files + | map(attribute='mtime') | max > local_db.stat.mtime tags: - DISA-STIG-OL09-00-002162 - PCI-DSS-Req-6.2 @@ -7395,6 +8218,8 @@ system-db:site system-db:distro + 8.2.8 + 8.2 Failure to have a functional DConf profile prevents GNOME3 configuration settings from being enforced for all users and allows various security risks. @@ -7448,7 +8273,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.02 3.1.2 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -7480,17 +8304,16 @@ After the settings have been set, run dconf update.CM-7(b) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002127 - OL09-00-002128 - SV-271685r1091767_rule - SV-271686r1091770_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002127 + OL09-00-002128 + SV-271685r1091767_rule + SV-271686r1091770_rule A user who is at the console can reboot the system at the login screen. If restart or shutdown buttons are pressed at the login screen, this can create the risk of short-term loss of availability of systems due to reboot. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7567,16 +8390,15 @@ fi - unknown_strategy - name: Disable the GNOME3 Login Restart and Shutdown Buttons - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-restart-buttons value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7593,14 +8415,13 @@ fi - name: Prevent user modification of GNOME disablement of Login Restart and Shutdown Buttons - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-restart-buttons line: /org/gnome/login-screen/disable-restart-buttons create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7616,10 +8437,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002127 - DISA-STIG-OL09-00-002128 @@ -7658,19 +8479,17 @@ Once the setting has been added, add a lock to user modification. For example: /org/gnome/login-screen/disable-user-list After the settings have been set, run dconf update. - CCI-000366 CM-6(a) AC-23 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL9 - OL09-00-002102 - SV-271672r1092631_rule + OL09-00-002102 + SV-271672r1092631_rule Leaving the user list enabled is a security risk since it allows anyone with physical access to the system to quickly enumerate known user accounts without logging in. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7744,16 +8563,15 @@ fi - unknown_strategy - name: Disable the GNOME3 Login User List - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: disable-user-list value: 'true' no_extra_spaces: true create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7766,14 +8584,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 disablement of Login User List - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/disable-user-list$ line: /org/gnome/login-screen/disable-user-list create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7786,10 +8603,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002102 - NIST-800-53-AC-23 @@ -7824,19 +8641,16 @@ Once the setting has been added, add a lock to For example: /org/gnome/settings-daemon/peripherals/smartcard/removal-action After the settings have been set, run dconf update. - CCI-000057 - CCI-000056 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 - OL09-00-002160 - OL09-00-002126 - SV-271690r1092634_rule - SV-271684r1091764_rule + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 + OL09-00-002160 + OL09-00-002126 + SV-271690r1092634_rule + SV-271684r1091764_rule Locking the screen automatically when removing the smartcard can prevent undesired access to system. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -7909,13 +8723,11 @@ fi - unknown_strategy - name: Detect if removal-action can be found on /etc/dconf/db/local.d/ - find: + ansible.builtin.find: path: /etc/dconf/db/local.d/ contains: ^\s*removal-action register: dconf_gnome_lock_screen_on_smartcard_removal_config_files - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7927,7 +8739,7 @@ fi - unknown_strategy - name: Configure removal-action - default file - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d//00-security-settings section: org/gnome/settings-daemon/peripherals/smartcard option: removal-action @@ -7935,9 +8747,9 @@ fi create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched == 0 + register: default_file tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7949,7 +8761,7 @@ fi - unknown_strategy - name: Configure removal-action - existing files - ini_file: + community.general.ini_file: dest: '{{ item.path }}' section: org/gnome/settings-daemon/peripherals/smartcard option: removal-action @@ -7959,9 +8771,9 @@ fi }}' when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_config_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_config_files.matched > 0 + register: existing_files tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7973,13 +8785,11 @@ fi - unknown_strategy - name: Detect if lock for removal-action can be found on /etc/dconf/db/local.d/ - find: + ansible.builtin.find: path: /etc/dconf/db/local.d/locks contains: ^\s*removal-action register: dconf_gnome_lock_screen_on_smartcard_removal_lock_files - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -7991,14 +8801,13 @@ fi - unknown_strategy - name: Prevent user modification removal-action - default file - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ line: /org/gnome/settings-daemon/peripherals/smartcard/removal-action create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched == 0 tags: @@ -8012,7 +8821,7 @@ fi - unknown_strategy - name: Prevent user modification removal-action - existing files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^/org/gnome/settings-daemon/peripherals/smartcard/removal-action$ line: /org/gnome/settings-daemon/peripherals/smartcard/removal-action @@ -8020,7 +8829,6 @@ fi with_items: '{{ dconf_gnome_lock_screen_on_smartcard_removal_lock_files.files }}' when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - dconf_gnome_lock_screen_on_smartcard_removal_lock_files is defined and dconf_gnome_lock_screen_on_smartcard_removal_lock_files.matched > 0 tags: @@ -8034,10 +8842,10 @@ fi - unknown_strategy - name: Dconf Update - removal-action - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - default_file is changed or existing_files is changed tags: - DISA-STIG-OL09-00-002126 - DISA-STIG-OL09-00-002160 @@ -8073,7 +8881,6 @@ AutomaticLoginEnable=false BAI10.03 BAI10.05 3.1.1 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -8087,16 +8894,15 @@ AutomaticLoginEnable=false AC-6(1) CM-7(b) PR.IP-1 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 8.3.1 8.3 - OL09-00-002161 - SV-271691r1091785_rule + OL09-00-002161 + SV-271691r1091785_rule Failure to restrict system access to authenticated users negatively impacts operating system security. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then if rpm --quiet -q gdm then @@ -8132,16 +8938,14 @@ fi - unknown_strategy - name: Disable GDM Automatic Login - ini_file: + community.general.ini_file: dest: /etc/gdm/custom.conf section: daemon option: AutomaticLoginEnable value: 'false' no_extra_spaces: true create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002161 - NIST-800-171-3.1.1 @@ -8214,7 +9018,7 @@ fi - unknown_strategy - name: Disable XDMCP in GDM - ini_file: + community.general.ini_file: path: /etc/gdm/custom.conf section: xdmcp option: Enable @@ -8265,9 +9069,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000366 - CCI-000778 - CCI-001958 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8293,9 +9094,9 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 3.4.2 3.4 @@ -8303,9 +9104,8 @@ After the settings have been set, run dconf update. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8382,16 +9182,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - automount - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: automount value: 'false' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8407,14 +9206,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - automount - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/automount$ line: /org/gnome/desktop/media-handling/automount create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8430,10 +9228,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.7 - NIST-800-53-CM-6(a) @@ -8479,9 +9277,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000778 - CCI-000366 - CCI-001958 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8507,24 +9302,23 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 3.4.2 3.4 - OL09-00-002100 - OL09-00-002120 - SV-271670r1091722_rule - SV-271678r1091746_rule + OL09-00-002100 + OL09-00-002120 + SV-271670r1091722_rule + SV-271678r1091746_rule Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mounting in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8603,16 +9397,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - automount-open - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: automount-open value: 'false' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8630,14 +9423,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - automount-open - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/automount-open$ line: /org/gnome/desktop/media-handling/automount-open create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8655,10 +9447,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002100 - DISA-STIG-OL09-00-002120 @@ -8706,10 +9498,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.03 3.1.7 - CCI-000366 - CCI-001764 - CCI-001958 - CCI-000778 4.3.3.2.2 4.3.3.5.2 4.3.3.6.6 @@ -8735,22 +9523,21 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-3 PR.AC-6 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 A.11.SEC-OL12 - OL09-00-002101 - OL09-00-002121 - SV-271671r1091725_rule - SV-271679r1091749_rule + OL09-00-002101 + OL09-00-002121 + SV-271671r1091725_rule + SV-271679r1091749_rule Automatically mounting file systems permits easy introduction of unknown devices, thereby facilitating malicious activity. Disabling automatic mount running in GNOME3 can prevent the introduction of malware via removable media. It will, however, also prevent desktop users from legitimate use of removable media. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -8827,16 +9614,15 @@ fi - unknown_strategy - name: Disable GNOME3 Automounting - autorun-never - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/media-handling option: autorun-never value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8852,14 +9638,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Automounting - autorun-never - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/media-handling/autorun-never$ line: /org/gnome/desktop/media-handling/autorun-never create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8875,10 +9660,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002101 - DISA-STIG-OL09-00-002121 @@ -8927,9 +9712,8 @@ After the settings have been set, run dconf update.164.312(e)(2)(ii) Username and password prompting is required for remote access. Otherwise, non-authorized and nefarious users can access the system freely. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9001,16 +9785,15 @@ fi - unknown_strategy - name: Require Credential Prompting for Remote Access in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/Vino option: authentication-methods value: '[''vnc'']' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9021,14 +9804,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Credential Prompting for Remote Access - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/Vino/authentication-methods$ line: /org/gnome/Vino/authentication-methods create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9039,10 +9821,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.12 - dconf_gnome_remote_access_credential_prompt @@ -9093,7 +9875,6 @@ After the settings have been set, run dconf update.BAI10.05 DSS03.01 3.1.13 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -9120,12 +9901,11 @@ After the settings have been set, run dconf update.DE.AE-1 PR.DS-7 PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Open X displays allow an attacker to capture keystrokes and to execute commands remotely. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9200,16 +9980,15 @@ fi - unknown_strategy - name: Require Encryption for Remote Access in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/Vino option: require-encryption value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9223,14 +10002,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME3 Encryption for Remote Access - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/Vino/require-encryption$ line: /org/gnome/Vino/require-encryption create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9244,10 +10022,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - NIST-800-171-3.1.13 - NIST-800-53-AC-17(2) @@ -9330,7 +10108,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9357,7 +10134,7 @@ After the settings have been set, run dconf update.AC-11(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 + SRG-OS-000029-GPOS-00010 8.2.8 8.2 A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate @@ -9372,9 +10149,8 @@ be activated after the idle delay. Applications requiring continuous, real-time screen display (such as network management products) require the login session does not have administrator rights and the display station is located in a controlled-access area. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -9452,16 +10228,15 @@ fi - unknown_strategy - name: Enable GNOME3 Screensaver Idle Activation - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: idle-activation-enabled value: 'true' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9478,14 +10253,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME idle-activation-enabled - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/idle-activation-enabled$ line: /org/gnome/desktop/screensaver/idle-activation-enabled create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9502,10 +10276,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - CJIS-5.5.5 - NIST-800-171-3.1.10 @@ -9549,8 +10323,6 @@ idle-delay=uint32 900 DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9577,21 +10349,20 @@ idle-delay=uint32 900 CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 A.11.SEC-OL7 8.2.8 8.2 - OL09-00-002104 - SV-271674r1091734_rule + OL09-00-002104 + SV-271674r1091734_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME3 can be configured to identify when a user's session has idled and take action to initiate a session lock. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then inactivity_timeout_value='' @@ -9660,16 +10431,15 @@ fi - always - name: Set GNOME3 Screensaver Inactivity Timeout - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/session option: idle-delay value: uint32 {{ inactivity_timeout_value }} create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002104 @@ -9687,10 +10457,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002104 @@ -9733,7 +10503,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9760,18 +10529,17 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 A.11.SEC-OL7 8.2.8 8.2 - OL09-00-002103 - SV-271673r1091731_rule + OL09-00-002103 + SV-271673r1091731_rule A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - +of the information system but does not want to logout because of the temporary nature of the absence. # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then var_screensaver_lock_delay='' @@ -9839,16 +10607,15 @@ fi - always - name: Set GNOME3 Screensaver Lock Delay After Activation Period - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: lock-delay value: uint32 {{ var_screensaver_lock_delay }} create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 @@ -9865,10 +10632,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed tags: - DISA-STIG-OL09-00-002103 - NIST-800-171-3.1.10 @@ -9915,8 +10682,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000056 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -9942,17 +10707,16 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000028-GPOS-00009 - SRG-OS-000030-GPOS-00011 + SRG-OS-000028-GPOS-00009 + SRG-OS-000030-GPOS-00011 8.2.8 8.2 - OL09-00-002123 - SV-271681r1091755_rule + OL09-00-002123 + SV-271681r1091755_rule A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity -of the information system but does not want to logout because of the temporary nature of the absense. - +of the information system but does not want to logout because of the temporary nature of the absence. # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10029,29 +10793,9 @@ fi - no_reboot_needed - unknown_strategy -- name: Dconf Update - command: dconf update - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - ansible_distribution == 'SLES' - tags: - - CJIS-5.5.5 - - DISA-STIG-OL09-00-002123 - - NIST-800-171-3.1.10 - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-8.1.8 - - PCI-DSSv4-8.2 - - PCI-DSSv4-8.2.8 - - dconf_gnome_screensaver_lock_enabled - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - - unknown_strategy - -- name: Enable GNOME3 Screensaver Lock After Idle Period - ini_file: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Enable GNOME3 Screensaver + Lock After Idle Period + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: lock-enabled @@ -10060,8 +10804,8 @@ fi no_extra_spaces: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution != 'SLES' + register: screensaver_config tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10077,16 +10821,17 @@ fi - no_reboot_needed - unknown_strategy -- name: Prevent user modification of GNOME lock-enabled - lineinfile: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Prevent user modification + of GNOME lock-enabled + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/lock-enabled$ line: /org/gnome/desktop/screensaver/lock-enabled create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution != 'SLES' + register: screensaver_lock tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10102,8 +10847,9 @@ fi - no_reboot_needed - unknown_strategy -- name: Enable GNOME3 Screensaver Lock After Idle Period - ini_file: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Enable GNOME3 Screensaver + Lock After Idle Period + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/lockdown option: disable-lock-screen @@ -10112,8 +10858,8 @@ fi no_extra_spaces: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + register: lockdown_config tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10129,16 +10875,17 @@ fi - no_reboot_needed - unknown_strategy -- name: Prevent user modification of GNOME disable-lock-screen - lineinfile: +- name: Enable GNOME3 Screensaver Lock After Idle Period - Prevent user modification + of GNOME disable-lock-screen + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/lockdown/disable-lock-screen$ line: /org/gnome/desktop/lockdown/disable-lock-screen create: true when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + register: lockdown_lock tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10154,13 +10901,14 @@ fi - no_reboot_needed - unknown_strategy -- name: Check GNOME3 screenserver disable-lock-screen false - command: gsettings get org.gnome.desktop.lockdown disable-lock-screen +- name: Enable GNOME3 Screensaver Lock After Idle Period - Check GNOME3 screenserver + disable-lock-screen false + ansible.builtin.command: gsettings get org.gnome.desktop.lockdown disable-lock-screen register: cmd_out when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + changed_when: false tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10176,12 +10924,14 @@ fi - no_reboot_needed - unknown_strategy -- name: Update GNOME3 screenserver disable-lock-screen false - command: gsettings set org.gnome.desktop.lockdown disable-lock-screen false +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update GNOME3 screenserver + disable-lock-screen false + ansible.builtin.command: gsettings set org.gnome.desktop.lockdown disable-lock-screen + false when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - ansible_distribution == 'SLES' + - cmd_out.stdout != 'false' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10197,11 +10947,35 @@ fi - no_reboot_needed - unknown_strategy -- name: Dconf Update - command: dconf update +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update dconf database for + non-SLES systems + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution != 'SLES' + - (screensaver_config is changed or screensaver_lock is changed) + tags: + - CJIS-5.5.5 + - DISA-STIG-OL09-00-002123 + - NIST-800-171-3.1.10 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - dconf_gnome_screensaver_lock_enabled + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Enable GNOME3 Screensaver Lock After Idle Period - Update dconf database for + SLES systems + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - ansible_distribution == 'SLES' + - (lockdown_config is changed or lockdown_lock is changed) tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002123 @@ -10249,7 +11023,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10277,16 +11050,15 @@ After the settings have been set, run dconf update.AC-11(1).1 PR.AC-7 Req-8.1.8 - SRG-OS-000031-GPOS-00012 + SRG-OS-000031-GPOS-00012 8.2.8 8.2 - OL09-00-002106 - SV-271676r1091740_rule + OL09-00-002106 + SV-271676r1091740_rule Setting the screensaver mode to blank-only conceals the contents of the display from passersby. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10366,16 +11138,15 @@ fi - unknown_strategy - name: Implement Blank Screensaver - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/desktop/screensaver option: picture-uri value: string '' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10394,14 +11165,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME picture-uri - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/picture-uri$ line: /org/gnome/desktop/screensaver/picture-uri create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10420,10 +11190,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - CJIS-5.5.5 - DISA-STIG-OL09-00-002106 @@ -10464,7 +11234,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10489,18 +11258,17 @@ After the settings have been set, run dconf update.A.9.4.3 CM-6(a) PR.AC-7 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 - OL09-00-002125 - SV-271683r1091761_rule + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 + OL09-00-002125 + SV-271683r1091761_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/lock-delay$" "/etc/dconf/db/" \ @@ -10540,14 +11308,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME lock-delay - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/screensaver/lock-delay$ line: /org/gnome/desktop/screensaver/lock-delay create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 @@ -10560,10 +11327,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_lineinfile is changed tags: - DISA-STIG-OL09-00-002125 - NIST-800-171-3.1.10 @@ -10598,8 +11365,6 @@ After the settings have been set, run dconf update.DSS05.10 DSS06.10 3.1.10 - CCI-000057 - CCI-000060 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -10625,20 +11390,19 @@ After the settings have been set, run dconf update.CM-6(a) PR.AC-7 Req-8.1.8 - SRG-OS-000029-GPOS-00010 - SRG-OS-000031-GPOS-00012 + SRG-OS-000029-GPOS-00010 + SRG-OS-000031-GPOS-00012 8.2.8 8.2 - OL09-00-002124 - SV-271682r1091758_rule + OL09-00-002124 + SV-271682r1091758_rule A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME desktops can be configured to identify when a user's session has idled and take action to initiate the session lock. As such, users should not be allowed to change session settings. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories LOCKFILES=$(grep -r "^/org/gnome/desktop/session/idle-delay$" "/etc/dconf/db/" \ @@ -10681,14 +11445,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME Session idle-delay - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/desktop/session/idle-delay$ line: /org/gnome/desktop/session/idle-delay create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 @@ -10704,10 +11467,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_lineinfile is changed tags: - DISA-STIG-OL09-00-002124 - NIST-800-171-3.1.10 @@ -10733,10 +11496,10 @@ fi GNOME System Settings GNOME provides configuration and functionality to a graphical desktop environment -that changes grahical configurations or allow a user to perform +that changes graphical configurations or allow a user to perform actions that users normally would not be able to do in non-graphical mode such as remote access configuration, power policies, Geo-location, etc. -Configuring such settings in GNOME will prevent accidential graphical configuration +Configuring such settings in GNOME will prevent accidental graphical configuration changes by users from taking place. Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 @@ -10768,7 +11531,6 @@ After the settings have been set, run dconf update.DSS05.07 DSS06.02 3.1.2 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -10800,18 +11562,17 @@ After the settings have been set, run dconf update.CM-7(b) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002107 - OL09-00-002129 - SV-271677r1091743_rule - SV-271687r1091773_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002107 + OL09-00-002129 + SV-271677r1091743_rule + SV-271687r1091773_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term loss of availability of systems due to unintentional reboot. - # Remediation is applicable only in certain platforms -if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then +if rpm --quiet -q gdm; then # Check for setting in any of the DConf db directories # If files contain ibus or distro, ignore them. @@ -10888,16 +11649,15 @@ fi - unknown_strategy - name: Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/settings-daemon/plugins/media-keys option: logout value: '['''']' create: true no_extra_spaces: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_ini + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10913,14 +11673,13 @@ fi - unknown_strategy - name: Prevent user modification of GNOME disablement of Ctrl-Alt-Del - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/settings-daemon/plugins/media-keys/logout$ line: /org/gnome/settings-daemon/plugins/media-keys/logout create: true - when: - - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + register: result_lineinfile + when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10936,10 +11695,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update + ansible.builtin.command: dconf update when: - '"gdm" in ansible_facts.packages' - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002107 - DISA-STIG-OL09-00-002129 @@ -10973,6 +11732,7 @@ that normally only root is allowed to execute. For more information on Sudo and addition Sudo configuration options, see https://www.sudo.ws. + Group name dedicated to the use of sudo Specify the name of the group that should own /usr/bin/sudo. @@ -11017,23 +11777,19 @@ running a command. $ sudo yum install sudo - CCI-002235 - 1382 - 1384 - 1386 CM-6(a) FMT_MOF_EXT.1 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 R33 + 1386 2.2.6 2.2 - OL09-00-000230 - SV-271474r1091134_rule + OL09-00-000230 + SV-271474r1091134_rule sudo is a program designed to allow a system administrator to give limited root privileges to users and log root activity. The basic philosophy is to give as few privileges as possible but still allow system users to get their work done. - # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -11061,7 +11817,7 @@ fi - package_sudo_installed - name: Ensure sudo is installed - package: + ansible.builtin.package: name: sudo state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -11102,20 +11858,81 @@ version = "*" Verify Group Who Owns /etc/sudoers.d Directory - To properly set the group owner of /etc/sudoers.d, run the command: $ sudo chgrp root /etc/sudoers.d + To properly set the group owner of /etc/sudoers.d, run the command: +$ sudo chgrp root /etc/sudoers.d R50 The ownership of the /etc/sudoers.d directory by the root group is important because this directory hosts sudo configuration. Protection of this directory is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/sudoers.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure group owner on /etc/sudoers.d/ - file: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_sudoersd_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_sudoersd_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_sudoersd_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/sudoers.d/ + ansible.builtin.file: path: /etc/sudoers.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_sudoersd_newgroup }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_groupowner_etc_sudoersd @@ -11133,20 +11950,63 @@ ensures exclusive control of the sudo configuration. Verify User Who Owns /etc/sudoers.d Directory - To properly set the owner of /etc/sudoers.d, run the command: $ sudo chown root /etc/sudoers.d + To properly set the owner of /etc/sudoers.d, run the command: +$ sudo chown root /etc/sudoers.d R50 The ownership of the /etc/sudoers.d directory by the root user is important because this directory hosts sudo configuration. Protection of this directory is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - find -H /etc/sudoers.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/sudoers.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure owner on directory /etc/sudoers.d/ - file: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_owner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_owner_etc_sudoersd_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_sudoersd_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /etc/sudoers.d/ + ansible.builtin.file: path: /etc/sudoers.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_sudoersd_newown }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_owner_etc_sudoersd @@ -11171,18 +12031,34 @@ ensures exclusive control of the sudo configuration. because this directory hosts sudo configuration. Protection of this directory is critical for system security. Restricting the permissions ensures exclusive control of the sudo configuration. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +find -H /etc/sudoers.d/ -maxdepth 0 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u-s,g-ws,o-xwrt {} \; - -find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u-s,g-ws,o-xwrt {} \; +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ file(s) - command: 'find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d ' + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - directory_permissions_etc_sudoersd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /etc/sudoers.d/ file(s) + ansible.builtin.command: 'find -P /etc/sudoers.d/ -maxdepth 0 -perm /u+s,g+ws,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_permissions_etc_sudoersd @@ -11192,12 +12068,13 @@ find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u - no_reboot_needed - name: Set permissions for /etc/sudoers.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-xwrt state: directory with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - directory_permissions_etc_sudoersd @@ -11215,19 +12092,38 @@ find -H /etc/sudoers.d/ -maxdepth 1 -perm /u+s,g+ws,o+xwrt -type d -exec chmod u Verify Group Who Owns /etc/sudoers File - To properly set the group owner of /etc/sudoers, run the command: $ sudo chgrp root /etc/sudoers + To properly set the group owner of /etc/sudoers, run the command: +$ sudo chgrp root /etc/sudoers R50 The ownership of the /etc/sudoers file by the root group is important because this file hosts sudo configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - chgrp root /etc/sudoers + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/sudoers" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/sudoers +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: - path: /etc/sudoers - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_etc_sudoers @@ -11236,11 +12132,57 @@ ensures exclusive control of the sudo configuration. - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/sudoers - file: +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_sudoers_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_sudoers_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_sudoers_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers - group: root - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/sudoers + ansible.builtin.file: + path: /etc/sudoers + follow: false + group: '{{ file_groupowner_etc_sudoers_newgroup }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_groupowner_etc_sudoers @@ -11258,19 +12200,38 @@ ensures exclusive control of the sudo configuration. Verify User Who Owns /etc/sudoers File - To properly set the owner of /etc/sudoers, run the command: $ sudo chown root /etc/sudoers + To properly set the owner of /etc/sudoers, run the command: +$ sudo chown root /etc/sudoers R50 The ownership of the /etc/sudoers file by the root user is important because this file hosts sudo configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the sudo configuration. - chown 0 /etc/sudoers + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/sudoers" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/sudoers +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: - path: /etc/sudoers - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_etc_sudoers @@ -11279,11 +12240,39 @@ ensures exclusive control of the sudo configuration. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/sudoers - file: +- name: Set the file_owner_etc_sudoers_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_sudoers_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/sudoers + ansible.builtin.file: + path: /etc/sudoers + follow: false + owner: '{{ file_owner_etc_sudoers_newown }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_owner_etc_sudoers @@ -11308,16 +12297,31 @@ ensures exclusive control of the sudo configuration. because this file hosts sudo configuration. Protection of this file is critical for system security. Restricting the permissions ensures exclusive control of the sudo configuration. - - - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chmod u-xws,g-xws,o-xwrt /etc/sudoers + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/sudoers - stat: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_sudoers + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/sudoers + ansible.builtin.stat: path: /etc/sudoers register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_etc_sudoers @@ -11327,10 +12331,12 @@ chmod u-xws,g-xws,o-xwrt /etc/sudoers - no_reboot_needed - name: Ensure permission u-xws,g-xws,o-xwrt on /etc/sudoers - file: + ansible.builtin.file: path: /etc/sudoers mode: u-xws,g-xws,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_permissions_etc_sudoers @@ -11350,13 +12356,14 @@ chmod u-xws,g-xws,o-xwrt /etc/sudoers Ensure That the sudo Binary Has the Correct Permissions To properly set the permissions of /usr/bin/sudo, run the command: -$ sudo chmod 4111 /usr/bin/sudo - +$ sudo chmod 4110 /usr/bin/sudo +In order to use this rule, the group owner for /usr/bin/sudo needs to be changed to a +group other than root to effectively limit access to sudo. R38 The sudoers program should only be usable by people who have the correct permissions. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then chmod 4110 /usr/bin/sudo @@ -11376,10 +12383,12 @@ fi - no_reboot_needed - name: Test for existence /usr/bin/sudo - stat: + ansible.builtin.stat: path: /usr/bin/sudo register: file_exists - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - configure_strategy - file_permissions_sudo @@ -11389,10 +12398,11 @@ fi - no_reboot_needed - name: Ensure permission 4110 on /usr/bin/sudo - file: + ansible.builtin.file: path: /usr/bin/sudo mode: '4110' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists tags: @@ -11417,10 +12427,12 @@ in /etc/sudoers.d/. R39 Restricting the capability of sudo allowed commands to execute sub-commands prevents users from running programs with privileges they wouldn't have otherwise. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\bnoexec\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\bnoexec.*$' /etc/sudoers; then # sudoers file doesn't define Option noexec echo "Defaults noexec" >> /etc/sudoers fi @@ -11437,13 +12449,29 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure noexec is enabled in /etc/sudoers - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sudo_add_noexec + +- name: Ensure noexec is enabled in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\bnoexec\b.*$ line: Defaults noexec validate: /usr/sbin/visudo -cf %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - high_severity - low_complexity @@ -11469,10 +12497,12 @@ in /etc/sudoers.d/. R39 Restricting the use cases in which a user is allowed to execute sudo commands reduces the attack surface. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\brequiretty\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\brequiretty.*$' /etc/sudoers; then # sudoers file doesn't define Option requiretty echo "Defaults requiretty" >> /etc/sudoers fi @@ -11489,13 +12519,29 @@ else echo "Skipping remediation, /etc/sudoers failed to validate" false fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure requiretty is enabled in /etc/sudoers - lineinfile: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_add_requiretty + +- name: Ensure requiretty is enabled in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\brequiretty\b.*$ line: Defaults requiretty validate: /usr/sbin/visudo -cf %s + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity - low_disruption @@ -11527,11 +12573,11 @@ in /etc/sudoers.d/. access to the user's terminal after the main program has finished executing. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\buse_pty\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\buse_pty.*$' /etc/sudoers; then # sudoers file doesn't define Option use_pty echo "Defaults use_pty" >> /etc/sudoers fi @@ -11568,12 +12614,14 @@ fi - sudo_add_use_pty - name: Ensure use_pty is enabled in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults.*\buse_pty\b.*$ line: Defaults use_pty validate: /usr/sbin/visudo -cf %s - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - PCI-DSSv4-2.2 @@ -11603,14 +12651,14 @@ a sudo custom logfile at the default location suggested by CIS, which uses A sudo log file simplifies auditing of sudo commands. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then var_sudo_logfile='' if /usr/sbin/visudo -qcf /etc/sudoers; then cp /etc/sudoers /etc/sudoers.bak - if ! grep -P '^[\s]*Defaults[\s]*\blogfile\s*=\s*(?:"?([^",\s]+)"?)\b.*$' /etc/sudoers; then + if ! grep -P '^[\s]*Defaults\b[^!\n]*\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$' /etc/sudoers; then # sudoers file doesn't define Option logfile echo "Defaults logfile=${var_sudo_logfile}" >> /etc/sudoers else @@ -11659,14 +12707,16 @@ fi - always - name: Ensure logfile is enabled with the appropriate value in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^[\s]*Defaults\s(.*)\blogfile=[-]?.+\b(.*)$ line: Defaults \1logfile={{ var_sudo_logfile }}\2 validate: /usr/sbin/visudo -cf %s backrefs: true register: edit_sudoers_logfile_option - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - PCI-DSS-Req-10.2.5 - PCI-DSSv4-2.2 @@ -11679,11 +12729,12 @@ fi - sudo_custom_logfile - name: Enable logfile option with appropriate value in /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers line: Defaults logfile={{ var_sudo_logfile }} validate: /usr/sbin/visudo -cf %s when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - edit_sudoers_logfile_option is defined and not edit_sudoers_logfile_option.changed tags: @@ -11738,7 +12789,6 @@ any sudo configuration snippets in /etc/sudoers.d/.DSS05.10 DSS06.03 DSS06.10 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -11771,18 +12821,21 @@ any sudo configuration snippets in /etc/sudoers.d/.CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002362 - SV-271724r1091884_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + 1546 + OL09-00-002362 + SV-271724r1091884_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -11797,12 +12850,31 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002362 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_remove_no_authenticate + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) @@ -11823,6 +12895,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002362 - NIST-800-53-CM-6(a) @@ -11857,7 +12930,6 @@ in /etc/sudoers.d/. DSS05.10 DSS06.03 DSS06.10 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -11890,18 +12962,21 @@ in /etc/sudoers.d/. CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002363 - SV-271725r1091887_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + 1546 + OL09-00-002363 + SV-271725r1091887_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -11916,12 +12991,31 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002363 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_remove_nopasswd + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) @@ -11942,6 +13036,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002363 - NIST-800-53-CM-6(a) @@ -11977,8 +13072,6 @@ in /etc/sudoers.d/." DSS05.10 DSS06.03 DSS06.10 - CCI-002038 - CCI-004895 4.3.3.5.1 4.3.3.6.1 4.3.3.6.2 @@ -12011,8 +13104,9 @@ in /etc/sudoers.d/." CM-6(a) PR.AC-1 PR.AC-7 - SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00156 A.5.SEC-OL2 + 1546 2.2.6 2.2 Without re-authentication, users may access resources or perform tasks for which they @@ -12021,7 +13115,9 @@ do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for f in /etc/sudoers /etc/sudoers.d/* ; do if [ ! -e "$f" ] ; then continue @@ -12051,12 +13147,32 @@ for f in /etc/sudoers /etc/sudoers.d/* ; do /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo" fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /etc/sudoers.d/ files + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-11 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sudo_require_authentication + +- name: Find /etc/sudoers.d/ files ansible.builtin.find: paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12078,6 +13194,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12095,6 +13212,7 @@ done paths: - /etc/sudoers.d/ register: sudoers + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12116,6 +13234,7 @@ done with_items: - path: /etc/sudoers - '{{ sudoers.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-11 @@ -12145,16 +13264,15 @@ The timestamp_timeout should be configured by making sure that the in /etc/sudoers.d/. If the value is set to an integer less than 0, the user's time stamp will not expire and the user will not have to re-authenticate for privileged actions until the user's session is terminated. - CCI-004895 IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 A.5.SEC-OL2 2.2.6 2.2 - OL09-00-002360 - SV-271722r1091878_rule + OL09-00-002360 + SV-271722r1091878_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. @@ -12163,7 +13281,7 @@ When operating systems provide the capability to escalate a functional capabilit is critical that the user re-authenticate. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then var_sudo_timestamp_timeout='' @@ -12228,7 +13346,9 @@ fi patterns: '*' contains: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* register: sudoers_d_defaults_timestamp_timeout - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12248,7 +13368,9 @@ fi regexp: ^[\s]*Defaults\s.*\btimestamp_timeout[\s]*=.* state: absent with_items: '{{ sudoers_d_defaults_timestamp_timeout.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12270,7 +13392,9 @@ fi validate: /usr/sbin/visudo -cf %s backrefs: true register: edit_sudoers_timestamp_timeout_option - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12290,6 +13414,7 @@ fi line: Defaults timestamp_timeout={{ var_sudo_timestamp_timeout }} validate: /usr/sbin/visudo -cf %s when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - | edit_sudoers_timestamp_timeout_option is defined and not edit_sudoers_timestamp_timeout_option.changed @@ -12313,7 +13438,9 @@ fi }}\b)[-]?\w+\b.*$ state: absent validate: /usr/sbin/visudo -cf %s - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002360 - NIST-800-53-IA-11 @@ -12345,12 +13472,11 @@ Restrict privileged actions by removing the following entries from the sudoers f This rule doesn't come with a remediation, as the exact requirement allows exceptions, and removing lines from the sudoers file can make the system non-administrable. - CCI-000366 CM-6(b) CM-6(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-000232 - SV-271476r1091140_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000232 + SV-271476r1091140_rule If the "sudoers" file is not configured correctly, any user defined on the system can initiate privileged actions on the target system. @@ -12461,17 +13587,16 @@ or if cvtsudoers not supported: /etc/sudoers:Defaults !rootpw /etc/sudoers:Defaults !runaspw - CCI-000366 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-000231 - SV-271475r1091137_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000231 + SV-271475r1091137_rule If the rootpw, targetpw, or runaspw flags are defined and not disabled, by default the operating system will prompt the invoking user for the "root" user password. # Remediation is applicable only in certain platforms -if rpm --quiet -q sudo; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q sudo; }; then if grep -x '^Defaults targetpw$' /etc/sudoers; then sed -i "/Defaults targetpw/d" /etc/sudoers \; @@ -12554,12 +13679,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults targetpw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults targetpw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12572,12 +13699,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults targetpw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults targetpw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12590,12 +13719,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults rootpw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults rootpw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12608,12 +13739,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults rootpw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults rootpw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12626,12 +13759,14 @@ fi - sudoers_validate_passwd - name: Find out if /etc/sudoers.d/* files contain Defaults runaspw to be deduplicated - find: + ansible.builtin.find: path: /etc/sudoers.d patterns: '*' contains: ^Defaults runaspw$ register: sudoers_d_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12644,12 +13779,14 @@ fi - sudoers_validate_passwd - name: Remove found occurrences of Defaults runaspw from /etc/sudoers.d/* files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' regexp: ^Defaults runaspw$ state: absent with_items: '{{ sudoers_d_defaults.files }}' - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12661,14 +13798,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults targetpw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults targetpw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults targetpw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12680,14 +13819,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults rootpw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults rootpw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults rootpw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12699,14 +13840,16 @@ fi - restrict_strategy - sudoers_validate_passwd -- name: Remove any ocurrences of Defaults runaspw in /etc/sudoers - lineinfile: +- name: Remove any occurrences of Defaults runaspw in /etc/sudoers + ansible.builtin.lineinfile: path: /etc/sudoers regexp: ^Defaults runaspw$ validate: /usr/sbin/visudo -cf %s state: absent register: sudoers_file_defaults - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12719,7 +13862,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ @@ -12727,7 +13870,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12740,12 +13885,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12760,13 +13906,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !targetpw$ line: Defaults !targetpw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12779,7 +13927,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ @@ -12787,7 +13935,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12800,12 +13950,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12820,13 +13971,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !rootpw$ line: Defaults !rootpw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12839,7 +13992,7 @@ fi - sudoers_validate_passwd - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ @@ -12847,7 +14000,9 @@ fi check_mode: true changed_when: false register: dupes - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12860,12 +14015,13 @@ fi - sudoers_validate_passwd - name: Deduplicate values from /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ state: absent when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"sudo" in ansible_facts.packages' - dupes.found is defined and dupes.found > 1 tags: @@ -12880,13 +14036,15 @@ fi - sudoers_validate_passwd - name: Insert correct line into /etc/sudoers - lineinfile: + ansible.builtin.lineinfile: path: /etc/sudoers create: false regexp: ^Defaults !runaspw$ line: Defaults !runaspw state: present - when: '"sudo" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"sudo" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000231 - NIST-800-53-CM-6(b) @@ -12926,15 +14084,37 @@ provide secure management of multiple user passwords. In contrast to existing so LUKS stores all necessary setup information in the partition header, enabling the user to transport or migrate their data seamlessly. LUKS for dm-crypt is implemented in cryptsetup. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if ! rpm -q --quiet "cryptsetup" ; then yum install -y "cryptsetup" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure cryptsetup is installed - package: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSSv4-3.5 + - PCI-DSSv4-3.5.1 + - PCI-DSSv4-3.5.1.2 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_cryptsetup-luks_installed + +- name: Ensure cryptsetup is installed + ansible.builtin.package: name: cryptsetup state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-3.5 - PCI-DSSv4-3.5.1 @@ -12975,13 +14155,12 @@ version = "*" $ sudo yum install gnutls-utils - CCI-000366 FIA_X509_EXT.1 FIA_X509_EXT.1.1 FIA_X509_EXT.2 - SRG-OS-000480-GPOS-00227 - OL09-00-000430 - SV-271518r1091266_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000430 + SV-271518r1091266_rule GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them. It provides a simple C language application programming interface (API) to access the secure communications @@ -12995,7 +14174,7 @@ if ! rpm -q --quiet "gnutls-utils" ; then fi - name: Ensure gnutls-utils is installed - package: + ansible.builtin.package: name: gnutls-utils state: present tags: @@ -13036,11 +14215,10 @@ version = "*" $ sudo yum install nss-tools - CCI-000366 FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-000380 - SV-271513r1091251_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000380 + SV-271513r1091251_rule Network Security Services (NSS) is a set of libraries designed to support cross-platform development of security-enabled client and server applications. Install the nss-tools package @@ -13052,7 +14230,7 @@ if ! rpm -q --quiet "nss-tools" ; then fi - name: Ensure nss-tools is installed - package: + ansible.builtin.package: name: nss-tools state: present tags: @@ -13095,8 +14273,8 @@ $ sudo yum install openscap-scanner AGD_PRE.1 AGD_OPE.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000191-GPOS-00080 + SRG-OS-000480-GPOS-00227 + SRG-OS-000191-GPOS-00080 openscap-scanner contains the oscap command line tool. This tool is a configuration and vulnerability scanner, capable of performing compliance checking using SCAP content. @@ -13106,7 +14284,7 @@ if ! rpm -q --quiet "openscap-scanner" ; then fi - name: Ensure openscap-scanner is installed - package: + ansible.builtin.package: name: openscap-scanner state: present tags: @@ -13146,6 +14324,7 @@ version = "*" $ sudo yum install rear + 1409 rear contains the Relax-and-Recover (ReaR) utility. ReaR produces a bootable image of a system and restores from backup using this image. @@ -13161,7 +14340,7 @@ else fi - name: Ensure rear is installed - package: + ansible.builtin.package: name: rear state: present when: not ( ( ( ansible_architecture == "aarch64" and ansible_distribution == 'OracleLinux' @@ -13206,10 +14385,9 @@ version = "*" $ sudo yum install rng-tools - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-000370 - SV-271512r1091248_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000370 + SV-271512r1091248_rule rng-tools provides hardware random number generator tools, such as those used in the formation of x509/PKI certificates. @@ -13237,7 +14415,7 @@ fi - package_rng-tools_installed - name: Ensure rng-tools is installed - package: + ansible.builtin.package: name: rng-tools state: present when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -13282,7 +14460,7 @@ $ sudo yum install scap-security-guide AGD_PRE.1 AGD_OPE.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 The scap-security-guide package provides a guide for configuration of the system from the final system's security point of view. The guidance is specified in the Security Content Automation Protocol (SCAP) format and constitutes a catalog of practical hardening @@ -13291,14 +14469,14 @@ bridges the gap between generalized policy requirements and specific implementat A system administrator can use the oscap CLI tool from the openscap-scanner package, or the SCAP Workbench GUI tool from the scap-workbench package, to verify that the system conforms to provided guidelines. Refer to the scap-security-guide(8) manual -page for futher information. +page for further information. if ! rpm -q --quiet "scap-security-guide" ; then yum install -y "scap-security-guide" fi - name: Ensure scap-security-guide is installed - package: + ansible.builtin.package: name: scap-security-guide state: present tags: @@ -13338,28 +14516,27 @@ version = "*" $ sudo yum erase gssproxy - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000115 - SV-271459r1091089_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000115 + SV-271459r1091089_rule gssproxy is a proxy for GSS API credential handling. Kerberos relies on some key derivation functions that may not be compatible with some site policies such as FIPS 140. # CAUTION: This remediation script will remove gssproxy -# from the system, and may remove any packages -# that depend on gssproxy. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on gssproxy. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "gssproxy" ; then yum remove -y "gssproxy" fi - - name: Ensure gssproxy is removed - package: + - name: 'Uninstall gssproxy Package: Ensure gssproxy is removed' + ansible.builtin.package: name: gssproxy state: absent tags: @@ -13371,7 +14548,8 @@ fi - no_reboot_needed - package_gssproxy_removed - include remove_gssproxy + +include remove_gssproxy class remove_gssproxy { package { 'gssproxy': @@ -13392,27 +14570,26 @@ class remove_gssproxy { $ sudo yum erase iprutils - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000120 - SV-271460r1091092_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000120 + SV-271460r1091092_rule iprutils provides a suite of utlilities to manage and configure SCSI devices supported by the ipr SCSI storage device driver. # CAUTION: This remediation script will remove iprutils -# from the system, and may remove any packages -# that depend on iprutils. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on iprutils. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "iprutils" ; then yum remove -y "iprutils" fi - - name: Ensure iprutils is removed - package: + - name: 'Uninstall iprutils Package: Ensure iprutils is removed' + ansible.builtin.package: name: iprutils state: absent tags: @@ -13424,7 +14601,8 @@ fi - no_reboot_needed - package_iprutils_removed - include remove_iprutils + +include remove_iprutils class remove_iprutils { package { 'iprutils': @@ -13433,6 +14611,7 @@ class remove_iprutils { } + package --remove=iprutils @@ -13448,29 +14627,28 @@ package --remove=iprutils $ sudo yum erase tuned - CCI-000366 - CCI-000381 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000125 - SV-271461r1091095_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000125 + SV-271461r1091095_rule tuned contains a daemon that tunes the system settings dynamically. It does so by monitoring the usage of several system components periodically. Based on that information, components will then be put into lower or higher power savings modes to adapt to the current usage. # CAUTION: This remediation script will remove tuned -# from the system, and may remove any packages -# that depend on tuned. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tuned. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tuned" ; then yum remove -y "tuned" fi - - name: Ensure tuned is removed - package: + - name: 'Uninstall tuned Package: Ensure tuned is removed' + ansible.builtin.package: name: tuned state: absent tags: @@ -13482,7 +14660,8 @@ fi - no_reboot_needed - package_tuned_removed - include remove_tuned + +include remove_tuned class remove_tuned { package { 'tuned': @@ -13491,6 +14670,7 @@ class remove_tuned { } + package --remove=tuned @@ -13524,13 +14704,13 @@ $ sudo yum install dnf-automatic FPT_TUD_EXT.1 FPT_TUD_EXT.2 - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 dnf-automatic is an alternative command line interface (CLI) to dnf upgrade suitable for automatic, regular execution. - + # 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 ;} ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then if ! rpm -q --quiet "dnf-automatic" ; then yum install -y "dnf-automatic" @@ -13552,12 +14732,13 @@ fi - package_dnf-automatic_installed - name: Ensure dnf-automatic is installed - package: + ansible.builtin.package: name: dnf-automatic state: present - when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "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 ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - enable_strategy - low_complexity @@ -13609,7 +14790,6 @@ to 1 in /etc/yum.conf.DSS05.01 DSS05.02 3.4.8 - CCI-002617 4.2.3 4.2.3.12 4.2.3.7 @@ -13625,14 +14805,14 @@ to 1 in /etc/yum.conf.CM-6(a) ID.RA-1 PR.IP-12 - SRG-OS-000437-GPOS-00194 - OL09-00-000495 - SV-271522r1091278_rule + SRG-OS-000437-GPOS-00194 + OL09-00-000495 + SV-271522r1091278_rule Previous versions of software components that are not removed from the information system after updates have been installed may be exploited by some adversaries. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q yum; then +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 ]) ) && rpm --quiet -q yum ); then if grep --silent ^clean_requirements_on_remove /etc/yum.conf ; then sed -i "s/^clean_requirements_on_remove.*/clean_requirements_on_remove=1/g" /etc/yum.conf @@ -13670,7 +14850,9 @@ fi line: clean_requirements_on_remove=1 insertafter: \[main\] create: true - when: '"yum" in ansible_facts.packages' + when: ( not ( "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 ) and "yum" in ansible_facts.packages ) tags: - DISA-STIG-OL09-00-000495 - NIST-800-171-3.4.8 @@ -13695,20 +14877,15 @@ fi Configure dnf-automatic to Install Available Updates Automatically To ensure that the packages comprising the available updates will be automatically installed by dnf-automatic, set apply_updates to yes under [commands] section in /etc/dnf/automatic.conf. - 0940 - 1144 - 1467 - 1472 - 1483 - 1493 - 1494 - 1495 SI-2(5) CM-6(a) SI-2(c) FMT_SMF_EXT.1 - SRG-OS-000805-GPOS-00260 + SRG-OS-000805-GPOS-00260 R61 + 1467 + 1483 + 1493 Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized @@ -13716,9 +14893,9 @@ users may take advantage of weaknesses in the unpatched software. The lack of prompt attention to patching could result in a system compromise. The automated installation of updates ensures that recent security patches are applied in a timely manner. - + # 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 ;} ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then found=false @@ -13730,10 +14907,13 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*apply_updates" "$f"; then + if ! grep -qPz "apply_updates=yes" "$f"; then sed -i "s/apply_updates[^(\n)]*/apply_updates=yes/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then @@ -13772,14 +14952,15 @@ automatically, set upgrade_type to securitySI-2(5) CM-6(a) SI-2(c) - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 + 1493 By default, dnf-automatic installs all available updates. Reducing the amount of updated packages only to updates that were issued as a part of a security advisory increases the system stability. - + # 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 ;} ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then found=false @@ -13791,10 +14972,13 @@ for f in $(echo -n "/etc/dnf/automatic.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[commands\]([^\n\[]*\n+)+?[[:space:]]*upgrade_type" "$f"; then + if ! grep -qPz "upgrade_type=security" "$f"; then sed -i "s/upgrade_type[^(\n)]*/upgrade_type=security/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[commands\]" "$f"; then @@ -13825,6 +15009,155 @@ fi + + Ensure EPEL Repository is Disabled + The system must not have the EPEL (Extra Packages for Enterprise Linux) repository enabled. +EPEL provides additional packages that are not part of the official RHEL distribution and +may not meet enterprise security requirements. + +Check if any repository files in /etc/yum.repos.d/ contain enabled EPEL repositories +by running: +$ grep -r "^\[.*epel.*\]" /etc/yum.repos.d/ + +If EPEL repositories are found, ensure they are disabled by setting enabled=0 in +the repository configuration file. + CCI-000381 + SRG-OS-000095-GPOS-00049 + OL09-00-000105 + SV-271457r1134853_rule + The EPEL repository is not officially supported by Red Hat and may contain packages that have +not been vetted for security in an enterprise environment. Using unsupported repositories can +introduce vulnerabilities, compatibility issues, or packages that do not meet DoD security +requirements. Only packages from authorized repositories should be installed to maintain +system integrity and security. + + # Remediation is applicable only in certain platforms +if rpm --quiet -q yum; then + +# Ensure dnf-plugins-core is available for dnf config-manager +if ! command -v dnf &> /dev/null; then + # System uses yum instead of dnf + if command -v yum-config-manager &> /dev/null; then + CONFIG_MANAGER="yum-config-manager" + else + echo "Neither dnf nor yum-config-manager found, cannot disable repositories" >&2 + exit 1 + fi +else + # System uses dnf + if ! command -v dnf config-manager &> /dev/null 2>&1; then + dnf install -y dnf-plugins-core + fi + CONFIG_MANAGER="dnf config-manager" +fi + +# Find all EPEL repository IDs by name pattern +for repo_file in /etc/yum.repos.d/*.repo; do + [ -f "$repo_file" ] || continue + + # Extract repository IDs that contain "epel" (case-insensitive) + while IFS= read -r repo_id; do + $CONFIG_MANAGER --set-disabled "$repo_id" + done < <(grep -ioP '^\[\K[^\]]*epel[^\]]*(?=\])' "$repo_file") +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure dnf-plugins-core is installed + package: + name: dnf-plugins-core + state: present + when: + - '"yum" in ansible_facts.packages' + - ansible_pkg_mgr == "dnf" + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find all repository files + find: + paths: /etc/yum.repos.d/ + patterns: '*.repo' + register: repo_files + when: '"yum" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find EPEL repository IDs by name + shell: | + set -o pipefail + # Find repository IDs by name (case-insensitive) + grep -ioP '^\[\K[^\]]*epel[^\]]*(?=\])' "{{ item.path }}" || true + register: epel_repo_ids + loop: '{{ repo_files.files }}' + changed_when: false + when: + - '"yum" in ansible_facts.packages' + - repo_files.files is defined + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Disable EPEL repositories using dnf/yum config-manager + command: '{% if ansible_pkg_mgr == "dnf" %} dnf config-manager --set-disabled {{ + item.1 }} {% else %} yum-config-manager --set-disabled {{ item.1 }} {% endif %}' + loop: '{{ epel_repo_ids.results | subelements(''stdout_lines'', skip_missing=True) + }}' + when: + - '"yum" in ansible_facts.packages' + - epel_repo_ids.results is defined + - item.1 | length > 0 + loop_control: + label: '{{ item.1 }}' + register: disable_result + changed_when: disable_result.rc == 0 + failed_when: false + tags: + - DISA-STIG-OL09-00-000105 + - disable_strategy + - ensure_epel_repos_disabled + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + + + + + + + + Ensure gpgcheck Enabled In Main yum Configuration The gpgcheck option controls whether @@ -13848,7 +15181,6 @@ the [main] section: BAI10.05 DSS06.02 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -13887,12 +15219,13 @@ the [main] section: FPT_TUD_EXT.1 FPT_TUD_EXT.2 Req-6.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 + 1493 6.3.3 6.3 - OL09-00-000497 - SV-271524r1091284_rule + OL09-00-000497 + SV-271524r1091284_rule Changes to any software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a @@ -13962,7 +15295,7 @@ fi - no_reboot_needed - name: Ensure GPG check is globally activated - ini_file: + community.general.ini_file: dest: /etc/yum.conf section: main option: gpgcheck @@ -14013,7 +15346,6 @@ packages, set the localpkg_gpgcheck to 1BAI10.03 BAI10.05 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -14037,10 +15369,11 @@ packages, set the localpkg_gpgcheck to 1PR.IP-1 FPT_TUD_EXT.1 FPT_TUD_EXT.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 - OL09-00-000496 - SV-271523r1091281_rule + 1493 + OL09-00-000496 + SV-271523r1091281_rule Changes to any software components can have significant effects to the overall security of the operating system. This requirement ensures the software has not been tampered and has been provided by a trusted vendor. @@ -14099,7 +15432,7 @@ fi block: - name: Check stats of yum - stat: + ansible.builtin.stat: path: /etc/yum.conf register: pkg @@ -14110,7 +15443,7 @@ fi when: pkg.stat.lnk_target is defined - name: Ensure GPG check Enabled for Local Packages (yum) - ini_file: + community.general.ini_file: dest: '{{ pkg_config_file_symlink | default("/etc/yum.conf") }}' section: main option: localpkg_gpgcheck @@ -14161,7 +15494,6 @@ any repos, remove any lines from files in /etc/yum.repos.dBAI10.05 DSS06.02 3.4.8 - CCI-003992 164.308(a)(1)(ii)(D) 164.312(b) 164.312(c)(1) @@ -14200,12 +15532,13 @@ any repos, remove any lines from files in /etc/yum.repos.dFPT_TUD_EXT.1 FPT_TUD_EXT.2 Req-6.2 - SRG-OS-000366-GPOS-00153 + SRG-OS-000366-GPOS-00153 R59 + 1493 6.3.3 6.3 - OL09-00-000498 - SV-271525r1091287_rule + OL09-00-000498 + SV-271525r1091287_rule Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a @@ -14216,7 +15549,7 @@ approved Certificate Authority (CA)." sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - name: Grep for yum repo section names - shell: | + ansible.builtin.shell: | set -o pipefail grep -HEr '^\[.+\]' -r /etc/yum.repos.d/ register: repo_grep_results @@ -14246,7 +15579,7 @@ sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/* - no_reboot_needed - name: Set gpgcheck=1 for each yum repo - ini_file: + community.general.ini_file: path: '{{ item[0] }}' section: '{{ item[1] }}' option: gpgcheck @@ -14315,7 +15648,6 @@ such cases, the key can be installed by running the following command: BAI10.03 BAI10.05 DSS06.02 - CCI-001749 4.3.4.3.2 4.3.4.3.3 4.3.4.4.4 @@ -14346,8 +15678,8 @@ such cases, the key can be installed by running the following command: PR.IP-1 Req-6.2 R59 - OL09-00-000499 - SV-271526r1092460_rule + OL09-00-000499 + SV-271526r1092460_rule Changes to software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided @@ -14536,7 +15868,6 @@ dictates. BAI03.10 DSS05.01 DSS05.02 - CCI-000366 4.2.3 4.2.3.12 4.2.3.7 @@ -14553,12 +15884,13 @@ dictates. PR.IP-12 FMT_MOF_EXT.1 Req-6.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R61 + 1409 6.3.3 6.3 - OL09-00-000015 - SV-271439r1091029_rule + OL09-00-000015 + SV-271439r1091029_rule Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized @@ -14569,7 +15901,7 @@ lack of prompt attention to patching could result in a system compromise. - name: Security patches are up to date - package: + ansible.builtin.package: name: '*' state: latest tags: @@ -14603,13 +15935,13 @@ The dnf-automatic timer can be enabled with the following CM-6(a) SI-2(c) FMT_SMF_EXT.1 - SRG-OS-000191-GPOS-00080 + SRG-OS-000191-GPOS-00080 R61 The dnf-automatic is an alternative command line interface (CLI) to dnf upgrade with specific facilities to make it suitable to be executed automatically and regularly from systemd timers, cron jobs and similar. The tool is controlled by dnf-automatic.timer SystemD timer. - + # 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 ;} ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' if [[ $("$SYSTEMCTL_EXEC" is-system-running) != "offline" ]]; then @@ -14639,19 +15971,20 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable timer dnf-automatic - systemd: + ansible.builtin.systemd: name: dnf-automatic.timer enabled: 'yes' state: started when: - '"dnf-automatic" in ansible_facts.packages' - when: not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + when: ( not ( "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 ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(a) - NIST-800-53-SI-2(5) @@ -14663,6 +15996,10 @@ fi - no_reboot_needed - timer_dnf-automatic_enabled + + + + @@ -14685,6 +16022,7 @@ Oracle Linux 9. Authselect profile Specify the authselect profile to select + local minimal minimal sssd @@ -14698,7 +16036,6 @@ profile cannot be selected, it is probably because PAM files have already been m the administrator. If this is the case, in order to not overwrite the desired changes made by the administrator, the current PAM settings should be investigated before forcing the selection of the chosen authselect profile. - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -14713,26 +16050,34 @@ selection of the chosen authselect profile. AC-3 FIA_UAU.1 FIA_AFL.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R31 enable_authselect + 1409 8.3.4 8.3 - needed_rules + needed_rules Authselect is a successor to authconfig. It is a tool to select system authentication and identity sources from a list of supported profiles instead of letting the administrator manually build the PAM stack. That way, it avoids potential breakage of configuration, as it ships several tested profiles that are well tested and supported to solve different use-cases. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_authselect_profile='' authselect current if test "$?" -ne 0; then - authselect select "$var_authselect_profile" + if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then + authselect select --force "$var_authselect_profile" + else + authselect select "$var_authselect_profile" + fi if test "$?" -ne 0; then if rpm --quiet --verify pam; then @@ -14742,8 +16087,26 @@ if test "$?" -ne 0; then fi fi fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_authselect_profile # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-needed_rules + - NIST-800-53-AC-3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.4 + - configure_strategy + - enable_authselect + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_authselect_profile # promote to variable set_fact: var_authselect_profile: !!str tags: @@ -14755,6 +16118,7 @@ fi register: result_authselect_current changed_when: false failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14773,7 +16137,9 @@ fi register: result_authselect_select changed_when: result_authselect_select.rc == 0 failed_when: false - when: result_authselect_current.rc != 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_current.rc != 0 tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14793,6 +16159,7 @@ fi changed_when: false failed_when: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_authselect_select is not skipped - result_authselect_select.rc != 0 tags: @@ -14815,6 +16182,7 @@ fi fail_msg: - authselect is not used but files from the 'pam' package have been altered, so the authselect configuration won't be forced. + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-needed_rules - NIST-800-53-AC-3 @@ -14831,6 +16199,7 @@ fi ansible.builtin.command: cmd: authselect select --force "{{ var_authselect_profile }}" when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_authselect_current.rc != 0 - result_authselect_select.rc != 0 - result_altered_authselect.rc == 0 @@ -14958,12 +16327,6 @@ OR: DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -14989,11 +16352,11 @@ OR: AC-8(a) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-000090 - SV-271455r1091077_rule + OL09-00-000090 + SV-271455r1091077_rule Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, @@ -15009,7 +16372,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then login_banner_text='' - # Multiple regexes transform the banner regex into a usable banner # 0 - Remove anchors around the banner text login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g') @@ -15020,7 +16382,7 @@ login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g') formatted=$(echo "$login_banner_text" | fold -sw 80) cat <<EOF >/etc/issue @@ -15052,7 +16414,7 @@ fi - always - name: Modify the System Login Banner - Ensure Correct Banner - copy: + ansible.builtin.copy: dest: /etc/issue content: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15114,14 +16476,8 @@ OR: I've read & consent to terms in IS user agreem't. - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification @@ -15149,7 +16505,7 @@ remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/^(\(.*\.\)| remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). remote_login_banner_text=$(echo "$remote_login_banner_text" | sed 's/\\//g') formatted=$(echo "$remote_login_banner_text" | fold -sw 80) @@ -15178,7 +16534,7 @@ fi - always - name: Modify the System Login Banner for Remote Connections - ensure correct banner - copy: + ansible.builtin.copy: dest: /etc/issue.net content: '{{ remote_login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15263,7 +16619,7 @@ motd_banner_text=$(echo "$motd_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') motd_banner_text=$(echo "$motd_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n") motd_banner_text=$(echo "$motd_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/\n/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). motd_banner_text=$(echo "$motd_banner_text" | sed 's/\\//g') formatted=$(echo "$motd_banner_text" | fold -sw 80) @@ -15292,7 +16648,7 @@ fi - always - name: Modify the System Message of the Day Banner - ensure correct banner - copy: + ansible.builtin.copy: dest: /etc/motd content: '{{ motd_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*\.)\|.*\)$", "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)", @@ -15318,7 +16674,8 @@ fi Verify Group Ownership of System Login Banner for Remote Connections To properly set the group owner of /etc/issue.net, run the command: -$ sudo chgrp root /etc/issue.net + + $ sudo chgrp root /etc/issue.net 1.2.8 1.2 @@ -15327,10 +16684,37 @@ access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. Proper group ownership will ensure that only root user can modify the banner. - chgrp 0 /etc/issue.net + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/issue.net" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/issue.net +fi + +fi - - name: Test for existence /etc/issue.net - stat: + - name: Set the file_groupowner_etc_issue_net_newgroup variable if represented by + gid + ansible.builtin.set_fact: + file_groupowner_etc_issue_net_newgroup: '0' + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_groupowner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/issue.net + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15343,10 +16727,11 @@ Proper group ownership will ensure that only root user can modify the banner.Verify ownership of System Login Banner for Remote Connections To properly set the owner of /etc/issue.net, run the command: -$ sudo chown root /etc/issue.net + + $ sudo chown root /etc/issue.net 1.2.8 1.2 @@ -15378,10 +16764,36 @@ access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. Proper ownership will ensure that only root user can modify the banner. - chown 0 /etc/issue.net + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/issue.net" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/issue.net +fi + +fi - - name: Test for existence /etc/issue.net - stat: + - name: Set the file_owner_etc_issue_net_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_issue_net_newown: '0' + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - configure_strategy + - file_owner_etc_issue_net + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/issue.net + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15394,10 +16806,11 @@ Proper ownership will ensure that only root user can modify the banner. - name: Test for existence /etc/issue.net - stat: + ansible.builtin.stat: path: /etc/issue.net register: file_exists tags: @@ -15450,7 +16863,7 @@ chmod u-xs,g-xws,o-xwt /etc/issue.net - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/issue.net - file: + ansible.builtin.file: path: /etc/issue.net mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -15505,12 +16918,6 @@ The banner text must also be set. DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -15537,13 +16944,13 @@ The banner text must also be set. AC-8(b) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-002150 - OL09-00-002122 - SV-271688r1091776_rule - SV-271680r1091752_rule + OL09-00-002150 + OL09-00-002122 + SV-271688r1091776_rule + SV-271680r1091752_rule Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance. @@ -15629,13 +17036,14 @@ fi - unknown_strategy - name: Enable GNOME3 Login Warning Banner - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-enable value: 'true' create: true no_extra_spaces: true + register: result_ini when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002122 @@ -15652,11 +17060,12 @@ fi - unknown_strategy - name: Prevent user modification of GNOME banner-message-enabled - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-enable$ line: /org/gnome/login-screen/banner-message-enable create: true + register: result_lineinfile when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002122 @@ -15673,8 +17082,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update - when: '"gdm" in ansible_facts.packages' + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002122 - DISA-STIG-OL09-00-002150 @@ -15725,12 +17136,6 @@ to begin and end the string with ' and use \n< DSS05.10 DSS06.10 3.1.9 - CCI-000048 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -15756,11 +17161,11 @@ to begin and end the string with ' and use \n< AC-8(a) AC-8(c) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 - OL09-00-002151 - SV-271689r1091779_rule + OL09-00-002151 + SV-271689r1091779_rule An appropriate warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. # Remediation is applicable only in certain platforms @@ -15768,7 +17173,6 @@ if rpm --quiet -q gdm; then login_banner_text='' - # Multiple regexes transform the banner regex into a usable banner # 0 - Remove anchors around the banner text login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g') @@ -15779,7 +17183,7 @@ login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\.\)|.*)$/\1/g') login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g') # 3 - Adds newline "tokens". (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "(n)*") login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\\\n)+)/(n)*/g') -# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example). +# 4 - Remove any leftover backslash. (From any parenthesis in the banner, for example). login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g') # 5 - Removes the newline "token." (Transforms them into newline escape sequences "\n"). # ( Needs to be done after 4, otherwise the escapce sequence will become just "n". @@ -15863,7 +17267,7 @@ fi - always - name: Set the GNOME3 Login Warning Banner Text - file: + ansible.builtin.file: path: /etc/dconf/db/{{ item }} owner: root group: root @@ -15886,7 +17290,7 @@ fi - unknown_strategy - name: Set the GNOME3 Login Warning Banner Text - file: + ansible.builtin.file: path: /etc/dconf/db/local.d/{{ item }} owner: root group: root @@ -15909,7 +17313,7 @@ fi - unknown_strategy - name: Set the GNOME3 Login Warning Banner Text - ini_file: + community.general.ini_file: dest: /etc/dconf/db/local.d/00-security-settings section: org/gnome/login-screen option: banner-message-text @@ -15918,6 +17322,7 @@ fi "(n)*") | regex_replace("\\", "") | regex_replace("\(n\)\*", "\\n") }}''' create: true no_extra_spaces: true + register: result_ini when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002151 @@ -15932,12 +17337,13 @@ fi - unknown_strategy - name: Prevent user modification of the GNOME3 Login Warning Banner Text - lineinfile: + ansible.builtin.lineinfile: path: /etc/dconf/db/local.d/locks/00-security-settings-lock regexp: ^/org/gnome/login-screen/banner-message-text$ line: /org/gnome/login-screen/banner-message-text create: true state: present + register: result_lineinfile when: '"gdm" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002151 @@ -15952,8 +17358,10 @@ fi - unknown_strategy - name: Dconf Update - command: dconf update - when: '"gdm" in ansible_facts.packages' + ansible.builtin.command: dconf update + when: + - '"gdm" in ansible_facts.packages' + - result_ini is changed or result_lineinfile is changed tags: - DISA-STIG-OL09-00-002151 - NIST-800-171-3.1.9 @@ -16028,6 +17436,7 @@ Defines the value set as ENCRYPT_METHOD in /etc/login.defs.SHA512 SHA256 YESCRYPT + SHA512|YESCRYPT SHA512|YESCRYPT @@ -16058,19 +17467,18 @@ frequently. escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: $ sudo grep pam_succeed_if /etc/pam.d/sudo If any occurrences of "pam_succeed_if" is returned from the command, this is a finding. - CCI-004895 IA-11 - SRG-OS-000373-GPOS-00156 - SRG-OS-000373-GPOS-00157 - SRG-OS-000373-GPOS-00158 - OL09-00-002364 - SV-271726r1091890_rule + SRG-OS-000373-GPOS-00156 + SRG-OS-000373-GPOS-00157 + SRG-OS-000373-GPOS-00158 + OL09-00-002364 + SV-271726r1091890_rule Without re-authentication, users may access resources or perform tasks for which they do not have authorization. When operating systems provide the capability to escalate a functional capability, it is critical the user re-authenticate. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then sed -i '/pam_succeed_if/d' /etc/pam.d/sudo @@ -16097,7 +17505,8 @@ fi create: false regexp: pam_succeed_if state: absent - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-002364 - NIST-800-53-IA-11 @@ -16140,7 +17549,6 @@ should be recreated or manually updated. DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -16157,12 +17565,6 @@ should be recreated or manually updated. SR 1.7 SR 1.8 SR 1.9 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.18.1.4 A.9.2.1 A.9.2.4 @@ -16173,7 +17575,7 @@ should be recreated or manually updated. AC-9(1) PR.AC-7 Req-10.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 10.2.1.4 10.2.1 10.2 @@ -16181,9 +17583,9 @@ should be recreated or manually updated. 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. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if [ -f /usr/bin/authselect ]; then if authselect list-features sssd | grep -q with-silent-lastlog; then @@ -16338,7 +17740,7 @@ if [ -f /usr/bin/authselect ]; then fi if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16454,7 +17856,7 @@ else fi if grep -qP "^\s*session\s+required\s+pam_lastlog.so\s.*\bsilent\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*session.*required.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -16492,7 +17894,8 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2 - NIST-800-53-AC-9 @@ -16514,8 +17917,10 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_authselect_present.stat.exists tags: - CJIS-5.5.2 @@ -16542,13 +17947,14 @@ fi 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: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -16566,6 +17972,7 @@ fi 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 @@ -16586,7 +17993,8 @@ fi - result_authselect_disable_feature_cmd is not skipped - result_authselect_disable_feature_cmd is success when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-silent-lastlog") tags: @@ -16629,13 +18037,14 @@ fi 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: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -16680,6 +18089,7 @@ fi 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/") @@ -16691,6 +18101,7 @@ fi 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 @@ -16699,6 +18110,7 @@ fi 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 @@ -16708,6 +18120,7 @@ fi 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 @@ -16758,6 +18171,8 @@ fi 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 @@ -16850,6 +18265,7 @@ fi 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 @@ -16857,6 +18273,12 @@ fi ansible.builtin.set_fact: pam_module_control: required + - 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_lastlog.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -16864,7 +18286,9 @@ fi regexp: (.*session.*{{ pam_module_control | regex_escape() }}.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal - when: '"pam" in ansible_facts.packages' + when: result_pam_file_present.stat.exists + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2 - NIST-800-53-AC-9 @@ -16901,6 +18325,7 @@ risk of a denial-of-service attack. The lockout policy must weigh whether the risk of such a denial-of-service attack outweighs the benefits of thwarting password guessing attacks. + fail_deny Number of failed login attempts before account lockout @@ -16956,7 +18381,7 @@ password guessing attacks. pwhistory_remember - Prevent password re-use using password history lookup + Prevent password reuse using password history lookup 0 1 2 @@ -16998,14 +18423,15 @@ for remediations the first value will be taken' Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. The pam_faillock.so module must be loaded in preauth in /etc/pam.d/password-auth. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003012 - SV-271838r1092226_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003012 + SV-271838r1092226_rule If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent password guessing attacks. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17032,12 +18458,30 @@ do done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003012 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_password_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17058,13 +18502,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -17082,6 +18527,7 @@ fi 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 @@ -17101,7 +18547,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17164,7 +18612,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003012 - NIST-800-53-AC-7 (a) @@ -17185,14 +18635,15 @@ fi Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. The pam_faillock.so module must be loaded in preauth in /etc/pam.d/system-auth. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003011 - SV-271837r1092223_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003011 + SV-271837r1092223_rule If the pam_faillock.so module is not loaded the system will not correctly lockout accounts to prevent password guessing attacks. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17219,12 +18670,30 @@ do done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003011 + - NIST-800-53-AC-7 (a) + - account_password_pam_faillock_system_auth + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17245,13 +18714,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -17269,6 +18739,7 @@ fi 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 @@ -17288,7 +18759,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17351,7 +18824,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003011 - NIST-800-53-AC-7 (a) @@ -17373,30 +18848,33 @@ fi An SELinux Context must be configured for the pam_faillock.so records directory The dir configuration option in PAM pam_faillock.so module defines where the lockout records is stored. The configured directory must have the correct SELinux context. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003010 - SV-271836r1092637_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003010 + SV-271836r1092637_rule Not having the correct SELinux context on the pam_faillock.so records directory may lead to unauthorized access to the directory. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -FAILLOCK_CONF_FILES="/etc/security/faillock.conf /etc/pam.d/system-auth /etc/pam.d/password-auth" +FAILLOCK_CONF_FILES="/etc/security/faillock.conf" + faillock_dirs=$(grep -oP "^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)" $FAILLOCK_CONF_FILES \ | sed -r 's/.*=\s*(\S+)/\1/') +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to semanage and restorecon commands to avoid the issue with the command +# not being found. if [ -n "$faillock_dirs" ]; then for dir in $faillock_dirs; do - if ! semanage fcontext -a -t faillog_t "$dir(/.*)?"; then - semanage fcontext -m -t faillog_t "$dir(/.*)?" + if ! /usr/sbin/semanage fcontext -a -t faillog_t "$dir(/.*)?"; then + /usr/sbin/semanage fcontext -m -t faillog_t "$dir(/.*)?" fi if [ ! -e $dir ]; then mkdir -p $dir fi - restorecon -R -v $dir + /usr/sbin/restorecon -R -v $dir done else echo " @@ -17426,10 +18904,10 @@ fi ansible.builtin.shell: grep -oP '^\s*(?:auth.*pam_faillock.so.*)?dir\s*=\s*(\S+)' "{{ item }}" | sed -r 's/.*=\s*(\S+)/\1/' register: faillock_output + changed_when: false + check_mode: false with_items: - /etc/security/faillock.conf - - /etc/pam.d/system-auth - - /etc/pam.d/password-auth when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003010 @@ -17477,11 +18955,11 @@ fi - restrict_strategy - name: An SELinux Context must be configured for the pam_faillock.so records directory - - Set up SELinux context for faillock - ansible.builtin.shell: |- - if ! semanage fcontext -a -t faillog_t "{{ item }}(/.*)?"; then - semanage fcontext -m -t faillog_t "{{ item }}(/.*)?" - fi + - Get SELinux context for faillock directories + ansible.builtin.command: ls -dZ "{{ item }}" + register: faillock_selinux_context + changed_when: false + check_mode: false with_items: '{{ list_faillock_dir }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -17497,12 +18975,36 @@ fi - restrict_strategy - name: An SELinux Context must be configured for the pam_faillock.so records directory - - Restore SELinux context - ansible.builtin.command: restorecon -R -v "{{ item }}" - with_items: '{{ list_faillock_dir }}' + - Set up SELinux context for faillock + ansible.builtin.shell: |- + if ! semanage fcontext -a -t faillog_t "{{ item.item }}(/.*)?"; then + semanage fcontext -m -t faillog_t "{{ item.item }}(/.*)?" + fi + with_items: '{{ faillock_selinux_context.results }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - item != "" + - item.item != "" + - item.stdout is defined + - '"faillog_t" not in item.stdout' + tags: + - DISA-STIG-OL09-00-003010 + - NIST-800-53-AC-7 (a) + - account_password_selinux_faillock_dir + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: An SELinux Context must be configured for the pam_faillock.so records directory + - Restore SELinux context + ansible.builtin.command: restorecon -R -v "{{ item.item }}" + with_items: '{{ faillock_selinux_context.results }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.item != "" + - item.stdout is defined + - '"faillog_t" not in item.stdout' tags: - DISA-STIG-OL09-00-003010 - NIST-800-53-AC-7 (a) @@ -17544,10 +19046,11 @@ fi PAM faillock locks an account due to excessive password failures, this event must be logged. This rule is deprecated in favor of the accounts_passwords_pam_faillock_audit rule.Please consider replacing this rule in your files as it is not expected to receive updates as of version 0.1.65. - CCI-000044 AC-7 (a) Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -17642,16 +19145,33 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*audit' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ audit/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*audit' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ audit/' "$pam_file" fi done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-7 (a) + - account_passwords_pam_faillock_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17670,13 +19190,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -17693,6 +19214,7 @@ fi 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 @@ -17711,7 +19233,9 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_authselect_present.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17772,7 +19296,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_authselect_present.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17787,6 +19313,7 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17803,7 +19330,9 @@ fi regexp: ^\s*audit line: audit state: present - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -17847,13 +19376,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -17897,6 +19427,7 @@ fi 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/") @@ -17908,6 +19439,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -17916,6 +19448,7 @@ fi 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 @@ -17925,6 +19458,7 @@ fi 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 @@ -17973,6 +19507,8 @@ fi 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 @@ -17981,6 +19517,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -17988,6 +19530,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -18028,13 +19571,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -18078,6 +19622,7 @@ fi 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/") @@ -18089,6 +19634,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -18097,6 +19643,7 @@ fi 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 @@ -18106,6 +19653,7 @@ fi 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 @@ -18154,6 +19702,8 @@ fi 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 @@ -18162,6 +19712,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -18169,6 +19725,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -18178,7 +19735,9 @@ fi - result_pam_option_removal is changed when: - result_pam_file_present.stat.exists - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -18215,7 +19774,9 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_audit_parameter_is_present.found == 0 - when: not result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_faillock_conf_check.stat.exists tags: - NIST-800-53-AC-7 (a) - account_passwords_pam_faillock_audit @@ -18237,7 +19798,6 @@ fi By setting a `dir` in the faillock configuration account lockouts will persist across reboots. This rule is deprecated in favor of the accounts_passwords_pam_faillock_dir rule.Please consider replacing this rule in your files as it is not expected to receive updates as of version 0.1.65. - CCI-000044 AC-7 (ia) Having lockouts persist across reboots ensures that account is only unlocked by an administrator. If the lockouts did not persist across reboots an attack could simply reboot the system to continue brute force attacks against the accounts on the system. @@ -18293,7 +19853,6 @@ updated. DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -18334,14 +19893,14 @@ updated. PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_pam_remember='' var_password_pam_remember_control_flag='' @@ -18544,7 +20103,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -18589,7 +20148,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -18610,7 +20171,9 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -18638,13 +20201,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -18661,6 +20225,7 @@ fi 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 @@ -18680,6 +20245,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") @@ -18723,13 +20289,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -18773,6 +20340,7 @@ fi 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/") @@ -18784,6 +20352,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile @@ -18792,6 +20361,7 @@ fi 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 @@ -18801,6 +20371,7 @@ fi 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 @@ -18849,6 +20420,8 @@ fi 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 @@ -18916,6 +20489,7 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined @@ -18939,7 +20513,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -19002,13 +20578,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -19052,6 +20629,7 @@ fi 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/") @@ -19063,6 +20641,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom @@ -19071,6 +20650,7 @@ fi 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 @@ -19080,6 +20660,7 @@ fi 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 @@ -19130,6 +20711,8 @@ fi 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 @@ -19138,6 +20721,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: 'Limit Password Reuse: password-auth - Check if {{ pam_file_path }} + file is present' + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: 'Limit Password Reuse: password-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -19145,6 +20734,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied' @@ -19156,6 +20746,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: @@ -19198,13 +20789,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: password-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -19248,6 +20840,7 @@ fi 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/") @@ -19259,6 +20852,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile @@ -19267,6 +20861,7 @@ fi 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 @@ -19276,6 +20871,7 @@ fi 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 @@ -19324,6 +20920,8 @@ fi 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 @@ -19414,6 +21012,8 @@ fi state: present register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_add when: + - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_pwhistory_remember_password_auth_option_present.found == 0 @@ -19422,7 +21022,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 register: result_pam_accounts_password_pam_pwhistory_remember_password_auth_edit when: @@ -19437,6 +21037,7 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: @@ -19506,7 +21107,6 @@ system, an authselect custom profile must be used to avoid integrity issues in P DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -19547,14 +21147,14 @@ system, an authselect custom profile must be used to avoid integrity issues in P PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_pam_remember='' var_password_pam_remember_control_flag='' @@ -19757,7 +21357,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -19802,7 +21402,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -19823,7 +21425,9 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -19851,13 +21455,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -19874,6 +21479,7 @@ fi 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 @@ -19893,6 +21499,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") @@ -19936,13 +21543,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -19986,6 +21594,7 @@ fi 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/") @@ -19997,6 +21606,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20005,6 +21615,7 @@ fi 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 @@ -20014,6 +21625,7 @@ fi 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 @@ -20062,6 +21674,8 @@ fi 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 @@ -20129,6 +21743,7 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined @@ -20152,7 +21767,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -20215,13 +21832,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -20265,6 +21883,7 @@ fi 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/") @@ -20276,6 +21895,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20284,6 +21904,7 @@ fi 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 @@ -20293,6 +21914,7 @@ fi 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 @@ -20343,6 +21965,8 @@ fi 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 @@ -20351,6 +21975,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: 'Limit Password Reuse: system-auth - Check if {{ pam_file_path }} file + is present' + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: 'Limit Password Reuse: system-auth - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }}' ansible.builtin.replace: @@ -20358,6 +21988,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: 'Limit Password Reuse: system-auth - Ensure authselect changes are applied' ansible.builtin.command: @@ -20368,6 +21999,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: @@ -20410,13 +22042,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: 'Limit Password Reuse: system-auth - Informative message based on the authselect integrity check result' ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -20460,6 +22093,7 @@ fi 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/") @@ -20471,6 +22105,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: 'Limit Password Reuse: system-auth - Create an authselect custom profile @@ -20479,6 +22114,7 @@ fi 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 @@ -20488,6 +22124,7 @@ fi 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 @@ -20536,6 +22173,8 @@ fi 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 @@ -20626,6 +22265,8 @@ fi state: present register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_add when: + - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_pwhistory_remember_system_auth_option_present.found == 0 @@ -20634,7 +22275,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_remember }} \3 register: result_pam_accounts_password_pam_pwhistory_remember_system_auth_edit when: @@ -20649,6 +22290,7 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: @@ -20700,7 +22342,6 @@ system, an authselect custom profile must be used to avoid integrity issues in P DSS06.03 DSS06.10 3.5.8 - CCI-000200 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -20741,15 +22382,15 @@ system, an authselect custom profile must be used to avoid integrity issues in P PR.AC-6 PR.AC-7 Req-8.2.5 - SRG-OS-000077-GPOS-00045 + SRG-OS-000077-GPOS-00045 R31 8.3.7 8.3 - Preventing re-use of previous passwords helps ensure that a compromised password is not -re-used by a user. - + Preventing reuse of previous passwords helps ensure that a compromised password is not +reused by a user. + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_unix_remember='' @@ -20953,7 +22594,7 @@ else if ! grep -qP "^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwhistory.so.*/ s/$/ remember=$var_password_pam_unix_remember/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_remember \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_remember \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -20992,7 +22633,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -21013,8 +22656,10 @@ fi cmd: authselect list-features sssd register: result_authselect_available_features changed_when: false + check_mode: false when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_authselect_present.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21039,13 +22684,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -21062,6 +22708,7 @@ fi 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 @@ -21081,7 +22728,8 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_authselect_present.stat.exists - result_authselect_available_features.stdout is search("with-pwhistory") tags: @@ -21120,13 +22768,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -21170,6 +22819,7 @@ fi 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/") @@ -21181,6 +22831,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on the @@ -21189,6 +22840,7 @@ fi 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 @@ -21198,6 +22850,7 @@ fi 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 @@ -21244,6 +22897,8 @@ fi 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 @@ -21310,7 +22965,8 @@ fi - result_pam_line_present.found is defined - result_pam_line_present.found == 0 when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - | (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined tags: @@ -21333,7 +22989,9 @@ fi ansible.builtin.stat: path: /etc/security/pwhistory.conf register: result_pwhistory_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - NIST-800-171-3.5.8 @@ -21391,13 +23049,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -21441,6 +23100,7 @@ fi 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/") @@ -21452,6 +23112,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on @@ -21460,6 +23121,7 @@ fi 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 @@ -21469,6 +23131,7 @@ fi 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 @@ -21516,6 +23179,8 @@ fi 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 @@ -21524,6 +23189,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Limit Password Reuse - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Limit Password Reuse - Ensure the "remember" option from "pam_pwhistory.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -21531,6 +23201,7 @@ fi regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Limit Password Reuse - Ensure authselect changes are applied ansible.builtin.command: @@ -21541,7 +23212,8 @@ fi when: - result_pam_file_present.stat.exists when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pwhistory_conf_check.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21579,13 +23251,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Limit Password Reuse - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -21629,6 +23302,7 @@ fi 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/") @@ -21640,6 +23314,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Limit Password Reuse - Create an authselect custom profile based on the @@ -21648,6 +23323,7 @@ fi 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 @@ -21657,6 +23333,7 @@ fi 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 @@ -21703,6 +23380,8 @@ fi 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 @@ -21793,6 +23472,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_remember_add when: + - result_pam_module_accounts_password_pam_unix_remember_option_present.found is + defined - result_pam_module_accounts_password_pam_unix_remember_option_present.found == 0 @@ -21801,7 +23482,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_remember }} \3 register: result_pam_accounts_password_pam_unix_remember_edit when: @@ -21816,7 +23497,8 @@ fi - (result_pam_remember_add is defined and result_pam_remember_add.changed) or (result_pam_remember_edit is defined and result_pam_remember_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - not result_pwhistory_conf_check.stat.exists tags: - CJIS-5.6.2.1.1 @@ -21844,13 +23526,15 @@ fi Account Lockouts Must Be Logged PAM faillock locks an account due to excessive password failures, this event must be logged. - CCI-000044 AC-7 (a) - SRG-OS-000021-GPOS-00005 - OL09-00-003022 - SV-271841r1092235_rule + SRG-OS-000021-GPOS-00005 + OL09-00-003022 + SV-271841r1092235_rule Without auditing of these events it may be harder or impossible to identify what an attacker did after an attack. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then + if [ -f /usr/bin/authselect ]; then if ! authselect check; then echo " @@ -21945,16 +23629,36 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*audit' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ audit/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*audit' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ audit/' "$pam_file" fi done fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Account Lockouts Must Be Logged - Check if system relies on authselect tool + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003022 + - NIST-800-53-AC-7 (a) + - accounts_passwords_pam_faillock_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Account Lockouts Must Be Logged - Check if system relies on authselect tool ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -21974,13 +23678,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -21997,6 +23702,7 @@ fi 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 @@ -22015,7 +23721,10 @@ fi when: - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success - when: result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22077,7 +23786,10 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_is_enabled.found == 0 - when: not result_authselect_present.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not result_authselect_present.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22093,6 +23805,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22110,7 +23825,10 @@ fi regexp: ^\s*audit line: audit state: present - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22155,13 +23873,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -22205,6 +23924,7 @@ fi 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/") @@ -22216,6 +23936,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -22224,6 +23945,7 @@ fi 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 @@ -22233,6 +23955,7 @@ fi 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 @@ -22281,6 +24004,8 @@ fi 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 @@ -22289,6 +24014,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22296,6 +24027,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -22336,13 +24068,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Account Lockouts Must Be Logged - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -22386,6 +24119,7 @@ fi 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/") @@ -22397,6 +24131,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Account Lockouts Must Be Logged - Create an authselect custom profile @@ -22405,6 +24140,7 @@ fi 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 @@ -22414,6 +24150,7 @@ fi 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 @@ -22462,6 +24199,8 @@ fi 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 @@ -22470,6 +24209,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Account Lockouts Must Be Logged - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Account Lockouts Must Be Logged - Ensure the "audit" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -22477,6 +24222,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\baudit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Account Lockouts Must Be Logged - Ensure authselect changes are applied ansible.builtin.command: @@ -22486,7 +24232,10 @@ fi - result_pam_option_removal is changed when: - result_pam_file_present.stat.exists - when: result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22524,7 +24273,10 @@ fi - /etc/pam.d/password-auth when: - result_pam_faillock_audit_parameter_is_present.found == 0 - when: not result_faillock_conf_check.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not result_faillock_conf_check.stat.exists tags: - DISA-STIG-OL09-00-003022 - NIST-800-53-AC-7 (a) @@ -22572,8 +24324,6 @@ parameters should be defined in faillock.conf file.DSS05.10 DSS06.10 3.1.8 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -22590,20 +24340,6 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.9.2.1 A.9.2.4 @@ -22615,20 +24351,33 @@ parameters should be defined in faillock.conf file.PR.AC-7 FIA_AFL.1 Req-8.1.6 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 R31 A.30.SEC-OL1 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.4 8.3 - OL09-00-003020 - SV-271839r1092229_rule + OL09-00-003020 + SV-271839r1092229_rule By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_deny='' @@ -22729,12 +24478,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*deny' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*deny' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ deny='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"deny"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"deny"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"deny"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_deny"'\3/' "$pam_file" fi done fi @@ -22767,7 +24516,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-003020 @@ -22794,13 +24545,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -22817,6 +24569,7 @@ fi 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 @@ -22837,6 +24590,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -22908,6 +24662,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -22936,7 +24691,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-003020 @@ -22961,6 +24718,7 @@ fi line: deny = {{ var_accounts_passwords_pam_faillock_deny }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23014,13 +24772,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -23065,6 +24824,7 @@ fi 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/") @@ -23076,6 +24836,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts After Failed Password Attempts - Create an authselect @@ -23084,6 +24845,7 @@ fi 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 @@ -23093,6 +24855,7 @@ fi 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 @@ -23143,6 +24906,8 @@ fi 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 @@ -23151,6 +24916,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23158,6 +24929,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes are applied @@ -23200,13 +24972,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts After Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -23251,6 +25024,7 @@ fi 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/") @@ -23262,6 +25036,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts After Failed Password Attempts - Create an authselect @@ -23270,6 +25045,7 @@ fi 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 @@ -23279,6 +25055,7 @@ fi 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 @@ -23329,6 +25106,8 @@ fi 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 @@ -23337,6 +25116,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts After Failed Password Attempts - Ensure the "deny" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -23344,6 +25129,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts After Failed Password Attempts - Ensure authselect changes are applied @@ -23355,6 +25141,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23443,6 +25230,7 @@ fi when: - result_pam_faillock_deny_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -23492,8 +25280,6 @@ parameters should be defined in faillock.conf file.DSS05.04 DSS05.10 DSS06.10 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -23510,9 +25296,21 @@ parameters should be defined in faillock.conf file.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 + CM-6(a) + AC-7(b) + IA-5(c) + PR.AC-7 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 0421 0422 - 0431 0974 1173 1401 @@ -23524,27 +25322,14 @@ parameters should be defined in faillock.conf file.1559 1560 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(b) - IA-5(c) - PR.AC-7 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - R31 - OL09-00-003021 - SV-271840r1092232_rule + OL09-00-003021 + SV-271840r1092232_rule By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, also known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then if [ -f /usr/bin/authselect ]; then if ! authselect check; then @@ -23640,8 +25425,8 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*even_deny_root' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ even_deny_root/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*even_deny_root' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ even_deny_root/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ even_deny_root/' "$pam_file" fi done @@ -23671,7 +25456,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) @@ -23694,13 +25481,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -23718,6 +25506,7 @@ fi 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 @@ -23738,6 +25527,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -23805,6 +25595,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -23824,7 +25615,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003021 - NIST-800-53-AC-7(b) @@ -23845,6 +25638,7 @@ fi line: even_deny_root state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -23894,13 +25688,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -23945,6 +25740,7 @@ fi 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/") @@ -23956,6 +25752,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Configure the root Account for Failed Password Attempts - Create an @@ -23964,6 +25761,7 @@ fi 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 @@ -23973,6 +25771,7 @@ fi 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 @@ -24023,6 +25822,8 @@ fi 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 @@ -24031,6 +25832,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24038,6 +25845,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect changes are applied @@ -24080,13 +25888,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Configure the root Account for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -24131,6 +25940,7 @@ fi 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/") @@ -24142,6 +25952,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Configure the root Account for Failed Password Attempts - Create an @@ -24150,6 +25961,7 @@ fi 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 @@ -24159,6 +25971,7 @@ fi 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 @@ -24209,6 +26022,8 @@ fi 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 @@ -24217,6 +26032,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Configure the root Account for Failed Password Attempts - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24224,6 +26045,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Configure the root Account for Failed Password Attempts - Ensure authselect changes are applied @@ -24235,6 +26057,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -24291,6 +26114,7 @@ fi when: - result_pam_faillock_even_deny_root_parameter_is_present.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -24317,7 +26141,7 @@ fi This rule ensures that the system lock out accounts using pam_faillock.so persist after system reboot. From "pam_faillock" man pages: Note that the default directory that "pam_faillock" uses is usually cleared on system -boot so the access will be reenabled after system reboot. If that is undesirable, a different +boot so the access will be re-enabled after system reboot. If that is undesirable, a different tally directory must be set with the "dir" option. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully @@ -24325,7 +26149,12 @@ defined to work as expected. In order to avoid errors when manually editing thes recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version. -The chosen profile expects the directory to be . +The chosen profile expects the directory to be . + +To configure the tally directory, add the following line to /etc/security/faillock.conf: +dir = + + 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 @@ -24333,20 +26162,19 @@ aborted in order to preserve intentional changes. In this case, an informative m be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock parameters should be defined in faillock.conf file. - CCI-000044 AC-7(b) AC-7(a) AC-7.1(ii) - SRG-OS-000021-GPOS-00005 - SRG-OS-000329-GPOS-00128 - OL09-00-003023 - SV-271842r1092238_rule + SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + OL09-00-003023 + SV-271842r1092238_rule Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. In combination with the silent option, user enumeration attacks are also mitigated. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_dir='' @@ -24447,12 +26275,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*dir' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*dir' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ dir='"$var_accounts_passwords_pam_faillock_dir"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"dir"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"dir"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"dir"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"dir"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_dir"'\3/' "$pam_file" fi done fi @@ -24468,8 +26296,11 @@ if ! rpm -q --quiet "policycoreutils-python-utils" ; then fi mkdir -p "$var_accounts_passwords_pam_faillock_dir" -semanage fcontext -a -t faillog_t "$var_accounts_passwords_pam_faillock_dir(/.*)?" -restorecon -R -v "$var_accounts_passwords_pam_faillock_dir" +# Workaround for https://github.com/OpenSCAP/openscap/issues/2242: Use full +# path to semanage and restorecon commands to avoid the issue with the command +# not being found. +/usr/sbin/semanage fcontext -a -t faillog_t "$var_accounts_passwords_pam_faillock_dir(/.*)?" +/usr/sbin/restorecon -R -v "$var_accounts_passwords_pam_faillock_dir" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -24494,7 +26325,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -24515,13 +26348,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -24538,6 +26372,7 @@ fi 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 @@ -24557,6 +26392,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -24622,6 +26458,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -24646,7 +26483,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -24666,6 +26505,7 @@ fi line: dir = {{ var_accounts_passwords_pam_faillock_dir }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -24711,13 +26551,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -24761,6 +26602,7 @@ fi 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/") @@ -24772,6 +26614,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts Must Persist - Create an authselect custom profile based @@ -24780,6 +26623,7 @@ fi 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 @@ -24789,6 +26633,7 @@ fi 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 @@ -24837,6 +26682,8 @@ fi 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 @@ -24845,6 +26692,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts Must Persist - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -24852,6 +26704,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdir\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied ansible.builtin.command: @@ -24889,13 +26742,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Lock Accounts Must Persist - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -24939,6 +26793,7 @@ fi 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/") @@ -24950,6 +26805,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Lock Accounts Must Persist - Create an authselect custom profile based @@ -24958,6 +26814,7 @@ fi 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 @@ -24967,6 +26824,7 @@ fi 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 @@ -25015,6 +26873,8 @@ fi 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 @@ -25023,6 +26883,11 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Lock Accounts Must Persist - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Lock Accounts Must Persist - Ensure the "dir" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25030,6 +26895,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bdir\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Lock Accounts Must Persist - Ensure authselect changes are applied ansible.builtin.command: @@ -25040,6 +26906,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -25124,6 +26991,7 @@ fi when: - result_pam_faillock_dir_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -25146,7 +27014,9 @@ fi - python3-libselinux - python3-policycoreutils - policycoreutils-python-utils - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25159,12 +27029,37 @@ fi - medium_severity - no_reboot_needed -- name: Lock Accounts Must Persist - Create the tally directory if it does not exist +- name: Lock Accounts Must Persist - Create the faillock directory if it does not + exist ansible.builtin.file: path: '{{ var_accounts_passwords_pam_faillock_dir }}' state: directory setype: faillog_t - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-003023 + - NIST-800-53-AC-7(a) + - NIST-800-53-AC-7(b) + - NIST-800-53-AC-7.1(ii) + - accounts_passwords_pam_faillock_dir + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Lock Accounts Must Persist - Get SELinux context for faillock directory + ansible.builtin.command: + cmd: ls -dZ {{ var_accounts_passwords_pam_faillock_dir }} + register: faillock_selinux_context + changed_when: false + check_mode: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25185,7 +27080,10 @@ fi failed_when: false changed_when: - result_accounts_passwords_pam_faillock_dir_semanage.rc == 0 - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - '"faillog_t" not in faillock_selinux_context.stdout' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25202,7 +27100,10 @@ fi ansible.builtin.command: cmd: restorecon -R "{{ var_accounts_passwords_pam_faillock_dir }}" register: result_accounts_passwords_pam_faillock_dir_restorecon - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - '"faillog_t" not in faillock_selinux_context.stdout' tags: - DISA-STIG-OL09-00-003023 - NIST-800-53-AC-7(a) @@ -25249,8 +27150,6 @@ parameters should be defined in faillock.conf file.DSS05.04 DSS05.10 DSS06.10 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -25267,9 +27166,21 @@ parameters should be defined in faillock.conf file.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 + CM-6(a) + AC-7(a) + PR.AC-7 + FIA_AFL.1 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 + R31 0421 0422 - 0431 0974 1173 1401 @@ -25281,27 +27192,14 @@ parameters should be defined in faillock.conf file.1559 1560 1561 - A.18.1.4 - A.9.2.1 - A.9.2.4 - A.9.3.1 - A.9.4.2 - A.9.4.3 - CM-6(a) - AC-7(a) - PR.AC-7 - FIA_AFL.1 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 - R31 - OL09-00-002416 - SV-271754r1091974_rule + OL09-00-002416 + SV-271754r1091974_rule By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_fail_interval='' @@ -25402,12 +27300,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*fail_interval' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*fail_interval' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ fail_interval='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"fail_interval"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"fail_interval"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"fail_interval"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"fail_interval"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'\3/' "$pam_file" fi done fi @@ -25435,7 +27333,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) @@ -25457,13 +27357,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -25481,6 +27382,7 @@ fi 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 @@ -25501,6 +27403,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -25567,6 +27470,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -25590,7 +27494,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002416 - NIST-800-53-AC-7(a) @@ -25610,6 +27516,7 @@ fi line: fail_interval = {{ var_accounts_passwords_pam_faillock_fail_interval }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -25658,13 +27565,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -25709,6 +27617,7 @@ fi 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/") @@ -25720,6 +27629,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Interval For Counting Failed Password Attempts - Create an authselect @@ -25728,6 +27638,7 @@ fi 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 @@ -25737,6 +27648,7 @@ fi 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 @@ -25787,6 +27699,8 @@ fi 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 @@ -25795,6 +27709,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25802,6 +27722,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect changes are applied @@ -25844,13 +27765,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Interval For Counting Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -25895,6 +27817,7 @@ fi 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/") @@ -25906,6 +27829,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Interval For Counting Failed Password Attempts - Create an authselect @@ -25914,6 +27838,7 @@ fi 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 @@ -25923,6 +27848,7 @@ fi 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 @@ -25973,6 +27899,8 @@ fi 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 @@ -25981,6 +27909,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -25988,6 +27922,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Interval For Counting Failed Password Attempts - Ensure authselect changes are applied @@ -25999,6 +27934,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -26084,6 +28020,7 @@ fi when: - result_pam_faillock_fail_interval_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -26143,8 +28080,6 @@ parameters should be defined in faillock.conf file.DSS05.10 DSS06.10 3.1.8 - CCI-000044 - CCI-002238 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -26161,20 +28096,6 @@ parameters should be defined in faillock.conf file.SR 1.7 SR 1.8 SR 1.9 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.9.2.1 A.9.2.4 @@ -26186,20 +28107,33 @@ parameters should be defined in faillock.conf file.PR.AC-7 FIA_AFL.1 Req-8.1.7 - SRG-OS-000329-GPOS-00128 - SRG-OS-000021-GPOS-00005 + SRG-OS-000329-GPOS-00128 + SRG-OS-000021-GPOS-00005 R31 A.30.SEC-OL1 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.4 8.3 - OL09-00-002417 - SV-271755r1091977_rule + OL09-00-002417 + SV-271755r1091977_rule By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_accounts_passwords_pam_faillock_unlock_time='' @@ -26300,12 +28234,12 @@ if [ -f $FAILLOCK_CONF ] || [ "$SKIP_FAILLOCK_CHECK" = "true" ]; then else for pam_file in "${AUTH_FILES[@]}" do - if ! grep -qE '^\s*auth.*pam_faillock\.so (preauth|authfail).*unlock_time' "$pam_file"; then - sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*silent.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" + if ! grep -qE '^\s*auth.*pam_faillock\.so\s+(preauth|authfail).*unlock_time' "$pam_file"; then + sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*preauth.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" sed -i --follow-symlinks '/^auth.*required.*pam_faillock\.so.*authfail.*/ s/$/ unlock_time='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file" else - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*silent.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" - sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"unlock_time"'=\)[0-9]\+\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*preauth.*\)\('"unlock_time"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" + sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock\.so.*authfail.*\)\('"unlock_time"'=\)\S\+\b\(.*\)/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'\3/' "$pam_file" fi done fi @@ -26338,7 +28272,9 @@ fi ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-002417 @@ -26365,13 +28301,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -26388,6 +28325,7 @@ fi 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 @@ -26408,6 +28346,7 @@ fi - result_authselect_enable_feature_cmd is not skipped - result_authselect_enable_feature_cmd is success when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_authselect_present.stat.exists tags: @@ -26479,6 +28418,7 @@ fi when: - result_pam_faillock_is_enabled.found == 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_authselect_present.stat.exists tags: @@ -26507,7 +28447,9 @@ fi ansible.builtin.stat: path: /etc/security/faillock.conf register: result_faillock_conf_check - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.5.3 - DISA-STIG-OL09-00-002417 @@ -26532,6 +28474,7 @@ fi line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }} state: present when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -26585,13 +28528,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -26636,6 +28580,7 @@ fi 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/") @@ -26647,6 +28592,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Lockout Time for Failed Password Attempts - Create an authselect @@ -26655,6 +28601,7 @@ fi 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 @@ -26664,6 +28611,7 @@ fi 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 @@ -26714,6 +28662,8 @@ fi 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 @@ -26722,6 +28672,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -26729,6 +28685,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes are applied @@ -26771,13 +28728,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Lockout Time for Failed Password Attempts - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -26822,6 +28780,7 @@ fi 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/") @@ -26833,6 +28792,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Lockout Time for Failed Password Attempts - Create an authselect @@ -26841,6 +28801,7 @@ fi 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 @@ -26850,6 +28811,7 @@ fi 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 @@ -26900,6 +28862,8 @@ fi 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 @@ -26908,6 +28872,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -26915,6 +28885,7 @@ fi regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Lockout Time for Failed Password Attempts - Ensure authselect changes are applied @@ -26926,6 +28897,7 @@ fi when: - result_pam_file_present.stat.exists when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_faillock_conf_check.stat.exists tags: @@ -27016,6 +28988,7 @@ fi when: - result_pam_faillock_unlock_time_parameter_is_present.found > 0 when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - not result_faillock_conf_check.stat.exists tags: @@ -27058,6 +29031,7 @@ password requirements. The man pages pam_pwquality(8) provide information on the capabilities and configuration of each. + Set Password Quality Requirements with pam_pwquality The pam_pwquality PAM module can be configured to meet @@ -27202,7 +29176,6 @@ length credit for each digit. Modify the dcredit setting DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -27227,20 +29200,6 @@ length credit for each digit. Modify the dcredit setting SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -27260,12 +29219,25 @@ length credit for each digit. Modify the dcredit setting PR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000071-GPOS-00039 + SRG-OS-000071-GPOS-00039 R31 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 - OL09-00-001020 - SV-271616r1091560_rule + OL09-00-001020 + SV-271616r1091560_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -27277,14 +29249,18 @@ to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring digits makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_dcredit='' +if grep -sq dcredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/dcredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -27336,6 +29312,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdcredit\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/password-auth was not found" >&2 +fi @@ -27388,12 +29413,65 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Find + pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + dcredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdcredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) @@ -27435,13 +29513,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -27486,6 +29565,7 @@ fi 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/") @@ -27497,6 +29577,7 @@ fi 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 Enforces Password Requirements - Minimum Digit Characters - @@ -27505,6 +29586,7 @@ fi 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 @@ -27514,6 +29596,7 @@ fi 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 @@ -27564,6 +29647,8 @@ fi 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 @@ -27572,6 +29657,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -27580,6 +29671,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure authselect changes are applied @@ -27589,7 +29681,244 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001020 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_dcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Define + the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - + 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 Enforces Password Requirements - Minimum Digit Characters - Define + a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check + if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure + authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001020 @@ -27614,7 +29943,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*dcredit line: dcredit = {{ var_password_pam_dcredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001020 - NIST-800-53-CM-6(a) @@ -27643,15 +29974,14 @@ fi Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words The pam_pwquality module's dictcheck check if passwords contains dictionary words. When dictcheck is set to 1 passwords will be checked for dictionary words. - CCI-000366 IA-5(c) IA-5(1)(a) CM-6(a) IA-5(4) - SRG-OS-000480-GPOS-00225 - SRG-OS-000072-GPOS-00040 - OL09-00-001125 - SV-271637r1091623_rule + SRG-OS-000480-GPOS-00225 + SRG-OS-000072-GPOS-00040 + OL09-00-001125 + SV-271637r1091623_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -27663,14 +29993,18 @@ password is compromised. Passwords with dictionary words may be more vulnerable to password-guessing attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_dictcheck='' +if grep -sq dictcheck /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/dictcheck/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -27722,6 +30056,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdictcheck\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdictcheck\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/password-auth was not found" >&2 +fi @@ -27771,12 +30154,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure dictcheck is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdictcheck\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) @@ -27815,13 +30245,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -27867,6 +30298,7 @@ fi 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/") @@ -27878,6 +30310,7 @@ fi 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 Enforces Password Requirements - Prevent the Use of Dictionary @@ -27886,6 +30319,7 @@ fi 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 @@ -27895,6 +30329,7 @@ fi 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 @@ -27946,6 +30381,8 @@ fi 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 @@ -27954,6 +30391,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Ensure the "dictcheck" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -27962,6 +30405,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdictcheck\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - Ensure authselect changes are applied @@ -27971,7 +30415,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001125 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_dictcheck + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - 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 Enforces Password Requirements - Prevent the Use of Dictionary + Words - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure the "dictcheck" option from "pam_pwquality.so" is not present + in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdictcheck\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary + Words - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001125 @@ -27993,7 +30670,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*dictcheck line: dictcheck = {{ var_password_pam_dictcheck }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001125 - NIST-800-53-CM-6(a) @@ -28036,7 +30715,6 @@ when changing passwords. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -28078,9 +30756,9 @@ when changing passwords. PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - OL09-00-001025 - SV-271617r1091563_rule + SRG-OS-000072-GPOS-00040 + OL09-00-001025 + SV-271617r1091563_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts @@ -28096,14 +30774,18 @@ before the password is compromised. Requiring a minimum number of different characters during password changes ensures that newly changed passwords should not resemble previously compromised ones. Note that passwords which are changed on compromised systems will still be compromised, however. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_difok='' +if grep -sq difok /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/difok/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -28155,6 +30837,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bdifok\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bdifok\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/password-auth was not found" >&2 +fi @@ -28205,12 +30936,61 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Ensure difok is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bdifok\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-001025 @@ -28250,13 +31030,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -28301,6 +31082,7 @@ fi 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/") @@ -28312,6 +31094,7 @@ fi 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 Enforces Password Requirements - Minimum Different Characters @@ -28320,6 +31103,7 @@ fi 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 @@ -28329,6 +31113,7 @@ fi 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 @@ -28379,6 +31164,8 @@ fi 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 @@ -28387,6 +31174,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Ensure the "difok" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -28395,6 +31188,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bdifok\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - Ensure authselect changes are applied @@ -28404,7 +31198,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001025 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(b) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_difok + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - 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 Enforces Password Requirements - Minimum Different Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure the "difok" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bdifok\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.1.1 @@ -28427,7 +31454,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*difok line: difok = {{ var_password_pam_difok }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-001025 @@ -28456,20 +31485,19 @@ fi enforcing password complexity for the root user. Enable the enforce_for_root setting in /etc/security/pwquality.conf to require the root user to use complex passwords. - CCI-004066 IA-5(c) IA-5(1)(a) CM-6(a) IA-5(4) - SRG-OS-000072-GPOS-00040 - SRG-OS-000071-GPOS-00039 - SRG-OS-000070-GPOS-00038 - SRG-OS-000266-GPOS-00101 - SRG-OS-000078-GPOS-00046 - SRG-OS-000480-GPOS-00225 - SRG-OS-000069-GPOS-00037 - OL09-00-001045 - SV-271621r1091575_rule + SRG-OS-000072-GPOS-00040 + SRG-OS-000071-GPOS-00039 + SRG-OS-000070-GPOS-00038 + SRG-OS-000266-GPOS-00101 + SRG-OS-000078-GPOS-00046 + SRG-OS-000480-GPOS-00225 + SRG-OS-000069-GPOS-00037 + OL09-00-001045 + SV-271621r1091575_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -28477,9 +31505,9 @@ password in resisting attempts at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/security/pwquality.conf" ] ; then @@ -28517,13 +31545,15 @@ fi - restrict_strategy - name: Ensure PAM Enforces Password Requirements - Enforce for root User - lineinfile: + ansible.builtin.lineinfile: path: /etc/security/pwquality.conf create: true regexp: '' line: enforce_for_root state: present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001045 - NIST-800-53-CM-6(a) @@ -28562,7 +31592,6 @@ length credit for each lowercase character. Modify the lcreditDSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -28587,20 +31616,6 @@ length credit for each lowercase character. Modify the lcreditSR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -28620,12 +31635,25 @@ length credit for each lowercase character. Modify the lcreditPR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000070-GPOS-00038 + SRG-OS-000070-GPOS-00038 R31 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 - OL09-00-001015 - SV-271615r1091557_rule + OL09-00-001015 + SV-271615r1091557_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -28633,17 +31661,21 @@ attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of -possble combinations that need to be tested before the password is compromised. +possible combinations that need to be tested before the password is compromised. Requiring a minimum number of lowercase characters makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_lcredit='' +if grep -sq lcredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/lcredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -28695,6 +31727,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\blcredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\blcredit\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/password-auth was not found" >&2 +fi @@ -28747,12 +31828,65 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Ensure lcredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\blcredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) @@ -28794,13 +31928,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -28845,6 +31980,7 @@ fi 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/") @@ -28856,6 +31992,7 @@ fi 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 Enforces Password Requirements - Minimum Lowercase Characters @@ -28864,6 +32001,7 @@ fi 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 @@ -28873,6 +32011,7 @@ fi 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 @@ -28923,6 +32062,8 @@ fi 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 @@ -28931,6 +32072,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -28939,6 +32086,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - Ensure authselect changes are applied @@ -28948,7 +32096,244 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001015 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_lcredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - 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 Enforces Password Requirements - Minimum Lowercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001015 @@ -28973,7 +32358,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*lcredit line: lcredit = {{ var_password_pam_lcredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001015 - NIST-800-53-CM-6(a) @@ -29016,7 +32403,6 @@ to prevent a run of (DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29058,10 +32444,10 @@ to prevent a run of (PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - SRG-OS-000730-GPOS-00190 - OL09-00-001030 - SV-271618r1091566_rule + SRG-OS-000072-GPOS-00040 + SRG-OS-000730-GPOS-00190 + OL09-00-001030 + SV-271618r1091566_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29069,14 +32455,18 @@ attempts at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex a password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_maxclassrepeat='' +if grep -sq maxclassrepeat /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/maxclassrepeat/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -29128,6 +32518,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxclassrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxclassrepeat\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/password-auth was not found" >&2 +fi @@ -29177,13 +32616,60 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure maxclassrepeat is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bmaxclassrepeat\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) @@ -29226,6 +32712,7 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating @@ -29233,7 +32720,7 @@ fi integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -29281,6 +32768,7 @@ fi 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/") @@ -29293,6 +32781,7 @@ fi 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 Enforces Password Requirements - Maximum Consecutive Repeating @@ -29302,6 +32791,7 @@ fi 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 @@ -29312,6 +32802,7 @@ fi 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 @@ -29365,6 +32856,8 @@ fi 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 @@ -29374,6 +32867,13 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Ensure the "maxclassrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -29382,6 +32882,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - Ensure authselect changes are applied @@ -29391,7 +32892,255 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if /etc/pam.d/password-auth file + is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001030 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxclassrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define the PAM file to be edited as a + local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if system relies on authselect + tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect custom profile is used + if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - 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 Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Define a fact for control already filtered + in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Check if {{ pam_file_path }} file is + present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure the "maxclassrepeat" option from + "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bmaxclassrepeat\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating + Characters from Same Character Class - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001030 @@ -29414,7 +33163,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*maxclassrepeat line: maxclassrepeat = {{ var_password_pam_maxclassrepeat }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001030 - NIST-800-53-CM-6(a) @@ -29454,7 +33205,6 @@ run of (DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29495,9 +33245,9 @@ run of (PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 - OL09-00-001035 - SV-271619r1091569_rule + SRG-OS-000072-GPOS-00040 + OL09-00-001035 + SV-271619r1091569_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29509,14 +33259,18 @@ password is compromised. Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_maxrepeat='' +if grep -sq maxrepeat /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/maxrepeat/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -29568,6 +33322,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bmaxrepeat\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bmaxrepeat\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/password-auth was not found" >&2 +fi @@ -29616,12 +33419,57 @@ fi tags: - always +- name: Set Password Maximum Consecutive Repeating Characters - Find pwquality.conf.d + files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Ensure maxrepeat is + not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bmaxrepeat\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Set Password Maximum Consecutive Repeating Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) @@ -29659,13 +33507,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set Password Maximum Consecutive Repeating Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -29710,6 +33559,7 @@ fi 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/") @@ -29721,6 +33571,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set Password Maximum Consecutive Repeating Characters - Create an authselect @@ -29729,6 +33580,7 @@ fi 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 @@ -29738,6 +33590,7 @@ fi 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 @@ -29788,6 +33641,8 @@ fi 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 @@ -29796,6 +33651,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Set Password Maximum Consecutive Repeating Characters - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the "maxrepeat" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -29803,6 +33664,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect changes are applied @@ -29812,7 +33674,235 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001035 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_maxrepeat + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Password Maximum Consecutive Repeating Characters - Check the proper remediation + for the system + block: + + - name: Set Password Maximum Consecutive Repeating Characters - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Set Password Maximum Consecutive Repeating Characters - Check if system + relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + custom profile is used if authselect is present + block: + + - name: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - 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: Set Password Maximum Consecutive Repeating Characters - Define a fact for + control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Set Password Maximum Consecutive Repeating Characters - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure the "maxrepeat" + option from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bmaxrepeat\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Set Password Maximum Consecutive Repeating Characters - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001035 @@ -29833,7 +33923,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*maxrepeat line: maxrepeat = {{ var_password_pam_maxrepeat }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001035 - NIST-800-53-CM-6(a) @@ -29883,7 +33975,6 @@ differing categories of characters when changing passwords.DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -29908,20 +33999,6 @@ differing categories of characters when changing passwords.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -29939,11 +34016,24 @@ differing categories of characters when changing passwords.PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000072-GPOS-00040 + SRG-OS-000072-GPOS-00040 R68 A.11.SEC-OL3 - OL09-00-001040 - SV-271620r1091572_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001040 + SV-271620r1091572_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -29956,14 +34046,18 @@ the password is compromised. Requiring a minimum number of character categories makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_minclass='' +if grep -sq minclass /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/minclass/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30015,6 +34109,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminclass\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminclass\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/password-auth was not found" >&2 +fi @@ -30064,12 +34207,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Ensure minclass is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bminclass\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) @@ -30108,13 +34298,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -30159,6 +34350,7 @@ fi 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/") @@ -30170,6 +34362,7 @@ fi 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 Enforces Password Requirements - Minimum Different Categories @@ -30178,6 +34371,7 @@ fi 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 @@ -30187,6 +34381,7 @@ fi 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 @@ -30237,6 +34432,8 @@ fi 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 @@ -30245,6 +34442,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Ensure the "minclass" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -30253,6 +34456,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - Ensure authselect changes are applied @@ -30262,7 +34466,238 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001040 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_minclass + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - 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 Enforces Password Requirements - Minimum Different Categories + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure the "minclass" option from "pam_pwquality.so" is not present in {{ + pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Different Categories + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001040 @@ -30284,7 +34719,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*minclass line: minclass = {{ var_password_pam_minclass }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001040 - NIST-800-53-CM-6(a) @@ -30324,7 +34761,6 @@ after pam_pwquality to set minimum password length requirements.DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -30349,20 +34785,6 @@ after pam_pwquality to set minimum password length requirements.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -30382,12 +34804,27 @@ after pam_pwquality to set minimum password length requirements.PR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000078-GPOS-00046 + SRG-OS-000078-GPOS-00046 R31 R68 A.11.SEC-OL3 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.6 8.3 + OL09-00-001105 + SV-271633r1091611_rule The shorter the password, the lower the number of possible combinations that need to be tested before the password is compromised. @@ -30397,14 +34834,18 @@ Password length is one factor of several that helps to determine strength and how long it takes to crack a password. Use of more characters in a password helps to exponentially increase the time and/or resources required to compromise the password. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_minlen='' +if grep -sq minlen /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/minlen/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30456,6 +34897,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bminlen\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bminlen\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/password-auth was not found" >&2 +fi @@ -30489,6 +34979,7 @@ fi manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30508,14 +34999,70 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Find pwquality.conf.d + files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure minlen + is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bminlen\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30555,13 +35102,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Length - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -30606,6 +35154,7 @@ fi 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/") @@ -30617,6 +35166,7 @@ fi 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 Enforces Password Requirements - Minimum Length - Create an @@ -30625,6 +35175,7 @@ fi 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 @@ -30634,6 +35185,7 @@ fi 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 @@ -30684,6 +35236,8 @@ fi 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 @@ -30692,6 +35246,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the "minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path }} ansible.builtin.replace: @@ -30699,6 +35259,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect changes are applied @@ -30708,10 +35269,249 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.6 + - accounts_password_pam_minlen + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check the proper + remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the + PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if system + relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - Define a fact + for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if {{ + pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the + "minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect + changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30733,9 +35533,12 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*minlen line: minlen = {{ var_password_pam_minlen }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001105 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) - NIST-800-53-IA-5(4) @@ -30778,7 +35581,6 @@ to require use of a special character in passwords. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -30803,20 +35605,6 @@ to require use of a special character in passwords. SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -30835,10 +35623,23 @@ to require use of a special character in passwords. PR.AC-6 PR.AC-7 FMT_SMF_EXT.1 - SRG-OS-000266-GPOS-00101 + SRG-OS-000266-GPOS-00101 R31 - OL09-00-001120 - SV-271636r1091620_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001120 + SV-271636r1091620_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force @@ -30850,14 +35651,18 @@ to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring a minimum number of special characters makes password guessing attacks more difficult by ensuring a larger search space. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_ocredit='' +if grep -sq ocredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/ocredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -30909,6 +35714,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bocredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bocredit\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/password-auth was not found" >&2 +fi @@ -30958,12 +35812,59 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Find + pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure + ocredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bocredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) @@ -31002,13 +35903,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -31053,6 +35955,7 @@ fi 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/") @@ -31064,6 +35967,7 @@ fi 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 Enforces Password Requirements - Minimum Special Characters @@ -31072,6 +35976,7 @@ fi 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 @@ -31081,6 +35986,7 @@ fi 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 @@ -31131,6 +36037,8 @@ fi 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 @@ -31139,6 +36047,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -31147,6 +36061,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Ensure authselect changes are applied @@ -31156,7 +36071,238 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check + if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001120 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - accounts_password_pam_ocredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - Check + the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters + - 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 Enforces Password Requirements - Minimum Special Characters - + Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Special Characters - + Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001120 @@ -31178,7 +36324,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*ocredit line: ocredit = {{ var_password_pam_ocredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001120 - NIST-800-53-CM-6(a) @@ -31206,17 +36354,16 @@ fi Edit the password section in /etc/pam.d/password-auth to show password requisite pam_pwquality.so. - CCI-004066 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 - SRG-OS-000480-GPOS-00227 - OL09-00-001010 - SV-271614r1091554_rule + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 + SRG-OS-000480-GPOS-00227 + OL09-00-001010 + SV-271614r1091554_rule Enabling PAM password complexity permits to enforce strong passwords and consequently makes the system less prone to dictionary attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/pam.d/password-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/password-auth" @@ -31300,7 +36447,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001010 - accounts_password_pam_pwquality_password_auth @@ -31335,13 +36484,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM password complexity module is enabled in password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -31386,6 +36536,7 @@ fi 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/") @@ -31397,6 +36548,7 @@ fi 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 password complexity module is enabled in password-auth - Create @@ -31405,6 +36557,7 @@ fi 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 @@ -31414,6 +36567,7 @@ fi 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 @@ -31464,6 +36618,8 @@ fi 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 @@ -31542,7 +36698,8 @@ fi (result_pam_accounts_password_pam_pwquality_password_auth_add is defined and result_pam_accounts_password_pam_pwquality_password_auth_add.changed) or (result_pam_accounts_password_pam_pwquality_password_auth_edit is defined and result_pam_accounts_password_pam_pwquality_password_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001010 @@ -31560,21 +36717,733 @@ fi + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + To configure the number of retry prompts that are permitted per-session: +Edit the /etc/security/pwquality.conf to include +retry= + , or a lower value if site +policy is more restrictive. The profile requirement is a maximum of retry= + prompts +per session. + SRG-OS-000069-GPOS-00037 + OL09-00-001001 + SV-271612r1091548_rule + Setting the password retry prompts that are permitted on a per-session basis to a low value +requires some software, such as SSH, to re-connect. This can slow down and +draw additional attention to some types of password-guessing attacks. Note that this +is different from account lockout, which is provided by the pam_faillock module. + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_password_pam_retry='' + + + +if grep -sq retry /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/retry/d" /etc/security/pwquality.conf.d/*.conf +fi + + + +if [ -e "/etc/pam.d/system-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/system-auth" + 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/system-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\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/system-auth was not found" >&2 +fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\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/password-auth was not found" >&2 +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' <<< "^retry") + +# shellcheck disable=SC2059 +printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_retry" + +# 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 "^retry\\>" "/etc/security/pwquality.conf"; then + escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") + LC_ALL=C sed -i --follow-symlinks "s/^retry\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf" +else + if [[ -s "/etc/security/pwquality.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/security/pwquality.conf" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/security/pwquality.conf" + fi + printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf" +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_password_pam_retry # promote to variable + set_fact: + var_password_pam_retry: !!str + tags: + - always + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Ensure retry is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bretry\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check if /etc/pam.d/system-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/system-auth + register: result_pam_file_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check the proper remediation for + the system + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/system-auth + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if system relies + on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect custom + profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the "retry" option + from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect changes + are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check if /etc/pam.d/password-auth + file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Check the proper remediation for + the system + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define the PAM file + to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if system relies + on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect custom + profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - 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 Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Define a fact for control + already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Check if {{ pam_file_path + }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure the "retry" option + from "pam_pwquality.so" is not present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session in /etc/security/pwquality.conf - Ensure authselect changes + are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session in /etc/security/pwquality.conf - Ensure PAM variable retry is set + accordingly + ansible.builtin.lineinfile: + create: true + dest: /etc/security/pwquality.conf + regexp: ^#?\s*retry + line: retry = {{ var_password_pam_retry }} + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-001001 + - accounts_password_pam_pwquality_retry + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + Ensure PAM password complexity module is enabled in system-auth To enable PAM password complexity in system-auth file: Edit the password section in /etc/pam.d/system-auth to show password requisite pam_pwquality.so. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-001000 - SV-271611r1091545_rule + SRG-OS-000480-GPOS-00227 + OL09-00-001000 + SV-271611r1091545_rule Enabling PAM password complexity permits to enforce strong passwords and consequently makes the system less prone to dictionary attacks. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then if [ -e "/etc/pam.d/system-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/system-auth" @@ -31658,7 +37527,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001000 - accounts_password_pam_pwquality_system_auth @@ -31693,13 +37564,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM password complexity module is enabled in system-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -31744,6 +37616,7 @@ fi 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/") @@ -31755,6 +37628,7 @@ fi 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 password complexity module is enabled in system-auth - Create @@ -31763,6 +37637,7 @@ fi 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 @@ -31772,6 +37647,7 @@ fi 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 @@ -31822,6 +37698,8 @@ fi 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 @@ -31900,7 +37778,8 @@ fi (result_pam_accounts_password_pam_pwquality_system_auth_add is defined and result_pam_accounts_password_pam_pwquality_system_auth_add.changed) or (result_pam_accounts_password_pam_pwquality_system_auth_edit is defined and result_pam_accounts_password_pam_pwquality_system_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001000 @@ -31926,7 +37805,8 @@ Edit the /etc/security/pwquality.conf to include retry= , or a lower value if site -policy is more restrictive. The DoD requirement is a maximum of 3 prompts +policy is more restrictive. The profile requirement is a maximum of retry= + prompts per session. 1 11 @@ -31947,7 +37827,6 @@ per session. DSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -31998,42 +37877,22 @@ per session. PR.AC-6 PR.AC-7 PR.IP-1 - SRG-OS-000069-GPOS-00037 - SRG-OS-000480-GPOS-00227 + SRG-OS-000069-GPOS-00037 + SRG-OS-000480-GPOS-00227 R68 A.11.SEC-OL3 - OL09-00-001001 - SV-271612r1091548_rule Setting the password retry prompts that are permitted on a per-session basis to a low value requires some software, such as SSH, to re-connect. This can slow down and draw additional attention to some types of password-guessing attacks. Note that this is different from account lockout, which is provided by the pam_faillock module. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_retry='' -# 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' <<< "^retry") -# shellcheck disable=SC2059 -printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_retry" - -# 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 "^retry\\>" "/etc/security/pwquality.conf"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^retry\\>.*/$escaped_formatted_output/gi" "/etc/security/pwquality.conf" -else - if [[ -s "/etc/security/pwquality.conf" ]] && [[ -n "$(tail -c 1 -- "/etc/security/pwquality.conf" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/security/pwquality.conf" - fi - printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf" -fi if [ -e "/etc/pam.d/password-auth" ] ; then PAM_FILE_PATH="/etc/pam.d/password-auth" @@ -32074,9 +37933,27 @@ fi authselect apply-changes -b fi -if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" -fi + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.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*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*account" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" + else + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*\sretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwquality.so.*/ s/$/ retry=$var_password_pam_retry/" "$PAM_FILE_PATH" + else + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwquality.so\s+.*)(retry=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_retry \3/" "$PAM_FILE_PATH" + fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b @@ -32124,9 +38001,27 @@ fi authselect apply-changes -b fi -if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bretry\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bretry\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" -fi + + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*" "$PAM_FILE_PATH"; then + # Line matching group + control + module was not found. Check group + module. + if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwquality.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*password\s+).*(\bpam_pwquality.so.*)/\1requisite \2/" "$PAM_FILE_PATH" + else + LAST_MATCH_LINE=$(grep -nP "^\s*account" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1) + if [ ! -z $LAST_MATCH_LINE ]; then + sed -i --follow-symlinks $LAST_MATCH_LINE" a password requisite pam_pwquality.so" "$PAM_FILE_PATH" + else + echo "password requisite pam_pwquality.so" >> "$PAM_FILE_PATH" + fi + fi + fi + # Check the option + if ! grep -qP "^\s*password\s+requisite\s+pam_pwquality.so\s*.*\sretry\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "/\s*password\s+requisite\s+pam_pwquality.so.*/ s/$/ retry=$var_password_pam_retry/" "$PAM_FILE_PATH" + else + sed -i -E --follow-symlinks "s/(\s*password\s+requisite\s+pam_pwquality.so\s+.*)(retry=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_retry \3/" "$PAM_FILE_PATH" + fi if [ -f /usr/bin/authselect ]; then authselect apply-changes -b @@ -32144,7 +38039,6 @@ fi manager: auto tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32160,35 +38054,39 @@ fi tags: - always -- name: Ensure PAM variable retry is set accordingly +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if expected PAM module line is present in /etc/pam.d/password-auth ansible.builtin.lineinfile: - create: true - dest: /etc/security/pwquality.conf - regexp: ^\s*retry - line: retry = {{ var_password_pam_retry }} - when: '"pam" in ansible_facts.packages' - tags: - - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - - NIST-800-53-AC-7(a) - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(4) - - accounts_password_pam_retry - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check if /etc/pam.d/password-auth file is present - ansible.builtin.stat: path: /etc/pam.d/password-auth - register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32200,198 +38098,59 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check the proper remediation for the system + Per-Session - Include or update the PAM module line in /etc/pam.d/password-auth block: - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the PAM file to be edited as a local fact - ansible.builtin.set_fact: - pam_file_path: /etc/pam.d/password-auth + Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/password-auth + with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + regexp: ^\s*password\s+.*\s+pam_pwquality.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if system relies on authselect tool - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect custom profile is used if authselect - is present - block: - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Informative message based on the authselect integrity - check result - ansible.builtin.assert: - that: - - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 - when: - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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: - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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_check_cmd is success - - authselect_current_profile is not match("^(custom/|local)") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on sssd - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - when: - - result_authselect_check_cmd is success - - authselect_current_profile is match("local") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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: - - result_authselect_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define a fact for control already filtered in case filters - are used - ansible.builtin.set_fact: - pam_module_control: '' - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is - not present in {{ pam_file_path }} + Permitted Per-Session - Ensure the correct control for the required PAM module + line in /etc/pam.d/password-auth ansible.builtin.replace: - dest: '{{ pam_file_path }}' - regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) - replace: \1\2 - register: result_pam_option_removal + dest: /etc/pam.d/password-auth + regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Ensure the required PAM module line is included in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/password-auth + insertafter: ^\s*account + line: password {{ pam_module_control }} pam_pwquality.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 Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - 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_option_removal is changed + - |- + (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: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32403,14 +38162,133 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check if /etc/pam.d/system-auth file is present - ansible.builtin.stat: + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if the required PAM module option is present in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_accounts_password_pam_retry_option_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so" is included + in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*) + line: \1 retry={{ var_password_pam_retry }} + state: present + register: result_pam_accounts_password_pam_retry_add + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found is defined + - result_pam_module_accounts_password_pam_retry_option_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the required value for "retry" PAM option from "pam_pwquality.so" + in /etc/pam.d/password-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/password-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*) + line: \1\2={{ var_password_pam_retry }} \3 + register: result_pam_accounts_password_pam_retry_edit + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found > 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if expected PAM module line is present in /etc/pam.d/system-auth + ansible.builtin.lineinfile: path: /etc/pam.d/system-auth - register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32422,198 +38300,154 @@ fi - no_reboot_needed - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted - Per-Session - Check the proper remediation for the system + Per-Session - Include or update the PAM module line in /etc/pam.d/system-auth block: - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define the PAM file to be edited as a local fact - ansible.builtin.set_fact: - pam_file_path: /etc/pam.d/system-auth + Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/system-auth + with different control + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*password\s+.*\s+pam_pwquality.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check if system relies on authselect tool - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure authselect custom profile is used if authselect - is present - block: - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - failed_when: false - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Informative message based on the authselect integrity - check result - ansible.builtin.assert: - that: - - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 - when: - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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: - - authselect_current_profile is not match("custom/") - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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_check_cmd is success - - authselect_current_profile is not match("^(custom/|local)") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Create an authselect custom profile based on sssd - profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - when: - - result_authselect_check_cmd is success - - authselect_current_profile is match("local") - - not result_authselect_custom_profile_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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 Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - 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: - - result_authselect_present.stat.exists - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Define a fact for control already filtered in case filters - are used - ansible.builtin.set_fact: - pam_module_control: '' - - - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts - Permitted Per-Session - Ensure the "retry" option from "pam_pwquality.so" is - not present in {{ pam_file_path }} + Permitted Per-Session - Ensure the correct control for the required PAM module + line in /etc/pam.d/system-auth ansible.builtin.replace: - dest: '{{ pam_file_path }}' - regexp: (.*password.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*) - replace: \1\2 - register: result_pam_option_removal + dest: /etc/pam.d/system-auth + regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*) + replace: \1{{ pam_module_control }} \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + + - name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts + Permitted Per-Session - Ensure the required PAM module line is included in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + dest: /etc/pam.d/system-auth + insertafter: ^\s*account + line: password {{ pam_module_control }} pam_pwquality.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 Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session - 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_option_removal is changed + - |- + (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: - - '"pam" in ansible_facts.packages' - - result_pam_file_present.stat.exists + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: requisite + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Check if the required PAM module option is present in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_accounts_password_pam_retry_option_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so" is included + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*) + line: \1 retry={{ var_password_pam_retry }} + state: present + register: result_pam_accounts_password_pam_retry_add + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found is defined + - result_pam_module_accounts_password_pam_retry_option_present.found == 0 + tags: + - CJIS-5.5.3 + - NIST-800-53-AC-7(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(4) + - accounts_password_pam_retry + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted + Per-Session - Ensure the required value for "retry" PAM option from "pam_pwquality.so" + in /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + backrefs: true + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*) + line: \1\2={{ var_password_pam_retry }} \3 + register: result_pam_accounts_password_pam_retry_edit + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_module_accounts_password_pam_retry_option_present.found > 0 tags: - CJIS-5.5.3 - - DISA-STIG-OL09-00-001001 - NIST-800-53-AC-7(a) - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(4) @@ -32650,7 +38484,6 @@ length credit for each uppercase character. Modify the ucreditDSS05.10 DSS06.03 DSS06.10 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -32675,20 +38508,6 @@ length credit for each uppercase character. Modify the ucreditSR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -32708,11 +38527,24 @@ length credit for each uppercase character. Modify the ucreditPR.AC-7 FMT_SMF_EXT.1 Req-8.2.3 - SRG-OS-000069-GPOS-00037 - SRG-OS-000070-GPOS-00038 + SRG-OS-000069-GPOS-00037 + SRG-OS-000070-GPOS-00038 R31 - OL09-00-001005 - SV-271613r1091551_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-001005 + SV-271613r1091551_rule Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. @@ -32721,14 +38553,18 @@ at guessing and brute-force attacks. Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libpwquality; }; then var_password_pam_ucredit='' +if grep -sq ucredit /etc/security/pwquality.conf.d/*.conf ; then + sed -i "/ucredit/d" /etc/security/pwquality.conf.d/*.conf +fi + if [ -e "/etc/pam.d/system-auth" ] ; then @@ -32780,6 +38616,55 @@ fi else echo "/etc/pam.d/system-auth was not found" >&2 fi +if [ -e "/etc/pam.d/password-auth" ] ; then + PAM_FILE_PATH="/etc/pam.d/password-auth" + 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/password-auth") + PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME" + + authselect apply-changes -b + fi + +if grep -qP "^\s*password\s.*\bpam_pwquality.so\s.*\bucredit\b" "$PAM_FILE_PATH"; then + sed -i -E --follow-symlinks "s/(.*password.*pam_pwquality.so.*)\bucredit\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/password-auth was not found" >&2 +fi @@ -32830,12 +38715,61 @@ fi tags: - always +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Find pwquality.conf.d files + ansible.builtin.find: + paths: /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: pwquality_conf_d_files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Ensure ucredit is not set in pwquality.conf.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + regexp: ^\s*\bucredit\b.* + state: absent + with_items: '{{ pwquality_conf_d_files.files }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Check if /etc/pam.d/system-auth file is present ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) @@ -32875,13 +38809,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -32926,6 +38861,7 @@ fi 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/") @@ -32937,6 +38873,7 @@ fi 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 Enforces Password Requirements - Minimum Uppercase Characters @@ -32945,6 +38882,7 @@ fi 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 @@ -32954,6 +38892,7 @@ fi 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 @@ -33004,6 +38943,8 @@ fi 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 @@ -33012,6 +38953,12 @@ fi ansible.builtin.set_fact: pam_module_control: '' + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{ pam_file_path }} @@ -33020,6 +38967,7 @@ fi regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*) replace: \1\2 register: result_pam_option_removal + when: result_pam_file_present.stat.exists - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - Ensure authselect changes are applied @@ -33029,7 +38977,240 @@ fi - result_authselect_present.stat.exists - result_pam_option_removal is changed when: - - '"pam" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + - result_pam_file_present.stat.exists + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-001005 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(a) + - NIST-800-53-IA-5(4) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.3 + - accounts_password_pam_ucredit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - + Check the proper remediation for the system + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/password-auth + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if system relies on authselect tool + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect custom profile is used if authselect is present + block: + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - 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 Enforces Password Requirements - Minimum Uppercase Characters + - Define a fact for control already filtered in case filters are used + ansible.builtin.set_fact: + pam_module_control: '' + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Check if {{ pam_file_path }} file is present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: result_pam_file_present + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{ pam_file_path + }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + when: result_pam_file_present.stat.exists + + - name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters + - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - result_pam_option_removal is changed + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001005 @@ -33052,7 +39233,9 @@ fi dest: /etc/security/pwquality.conf regexp: ^#?\s*ucredit line: ucredit = {{ var_password_pam_ucredit }} - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libpwquality" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-001005 - NIST-800-53-CM-6(a) @@ -33082,6 +39265,7 @@ fi The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several locations. + Minimum number of password hashing rounds configured through /etc/login.defs Minimum number of password hashing rounds configured through /etc/login.defs @@ -33110,7 +39294,6 @@ algorithm for password hashing: DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33135,9 +39318,6 @@ algorithm for password hashing: SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33155,11 +39335,14 @@ algorithm for password hashing: PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 + 0418 + 1055 + 1402 8.3.2 8.3 - OL09-00-001050 - SV-271622r1091578_rule + OL09-00-001050 + SV-271622r1091578_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33172,7 +39355,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q libuser; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q libuser; }; then var_password_hashing_algorithm_pam='' @@ -33227,7 +39410,9 @@ fi line: crypt_style = {{ var_password_hashing_algorithm_pam }} state: present create: true - when: '"libuser" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"libuser" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001050 @@ -33273,7 +39458,6 @@ fi DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33298,9 +39482,6 @@ fi SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33318,12 +39499,15 @@ fi PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 A.19.SEC-OL3 + 0418 + 1055 + 1402 8.3.2 8.3 - OL09-00-001055 - SV-271623r1091581_rule + OL09-00-001055 + SV-271623r1091581_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33333,7 +39517,7 @@ are no more protected than if they are kept in plain text. Using a stronger hashing algorithm makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_password_hashing_algorithm='' @@ -33392,13 +39576,15 @@ fi - always - name: Set Password Hashing Algorithm in /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^#?ENCRYPT_METHOD line: ENCRYPT_METHOD {{ var_password_hashing_algorithm.split('|')[0] }} state: present create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001055 @@ -33461,7 +39647,6 @@ option. DSS06.03 DSS06.10 3.13.11 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -33486,9 +39671,6 @@ option. SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -33506,11 +39688,14 @@ option. PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 A.19.SEC-OL3 - OL09-00-001060 - SV-271624r1091584_rule + 0418 + 1055 + 1402 + OL09-00-001060 + SV-271624r1091584_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm @@ -33523,7 +39708,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_hashing_algorithm_pam='' @@ -33636,7 +39821,7 @@ for hash_option in "${HASHING_ALGORITHMS_OPTIONS[@]}"; do fi if grep -qP "^\s*password\s+.*\s+pam_unix.so\s.*\b$hash_option\b" "$PAM_FILE_PATH"; then - sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\s$hash_option=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(.*password.*.*.*pam_unix.so.*)\b$hash_option\b=?[[:alnum:]]*(.*)/\1\2/g" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -33681,7 +39866,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001060 @@ -33722,13 +39909,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -33773,6 +39961,7 @@ fi 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/") @@ -33784,6 +39973,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect @@ -33792,6 +39982,7 @@ fi 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 @@ -33801,6 +39992,7 @@ fi 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 @@ -33851,6 +40043,8 @@ fi 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 @@ -33943,6 +40137,8 @@ fi state: present register: result_pam_set_password_hashing_algorithm_passwordauth_add when: + - result_pam_module_set_password_hashing_algorithm_passwordauth_option_present.found + is defined - result_pam_module_set_password_hashing_algorithm_passwordauth_option_present.found == 0 @@ -33956,6 +40152,7 @@ fi (result_pam_set_password_hashing_algorithm_passwordauth_add is defined and result_pam_set_password_hashing_algorithm_passwordauth_add.changed) or (result_pam_set_password_hashing_algorithm_passwordauth_edit is defined and result_pam_set_password_hashing_algorithm_passwordauth_edit.changed) when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: @@ -33978,7 +40175,9 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' tags: - CJIS-5.6.2.2 - DISA-STIG-OL09-00-001060 @@ -34019,13 +40218,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set PAM's Password Hashing Algorithm - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -34070,6 +40270,7 @@ fi 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/") @@ -34081,6 +40282,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set PAM's Password Hashing Algorithm - password-auth - Create an authselect @@ -34089,6 +40291,7 @@ fi 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 @@ -34098,6 +40301,7 @@ fi 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 @@ -34148,16 +40352,27 @@ fi 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: Set PAM's Password Hashing Algorithm - password-auth - Check if "{{ pam_file_path + }}" File is Present + ansible.builtin.stat: + path: '{{ pam_file_path }}' + register: pam_file_path_present + - name: Set PAM's Password Hashing Algorithm - password-auth - Ensure That Only - the Correct Hashing Algorithm Option For pam_unix.so Is Used in /etc/pam.d/password-auth + the Correct Hashing Algorithm Option For pam_unix.so Is Used in {{ pam_file_path + }} ansible.builtin.replace: dest: '{{ pam_file_path }}' regexp: (^\s*password.*pam_unix\.so.*)\b{{ item }}\b\s*(.*) replace: \1\2 - when: item != var_password_hashing_algorithm_pam + when: + - item != var_password_hashing_algorithm_pam + - pam_file_path_present.stat.exists loop: - sha512 - yescrypt @@ -34176,6 +40391,7 @@ fi - result_authselect_present.stat.exists - result_pam_hashing_options_removal is changed when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"pam" in ansible_facts.packages' - result_pam_file_present.stat.exists tags: @@ -34238,9 +40454,6 @@ option. DSS06.03 DSS06.10 3.13.11 - CCI-000196 - CCI-000803 - CCI-004062 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -34265,9 +40478,6 @@ option. SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -34285,10 +40495,13 @@ option. PR.AC-6 PR.AC-7 Req-8.2.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 R68 A.19.SEC-OL3 + 0418 + 1055 + 1402 8.3.2 8.3 Passwords need to be protected at all times, and encryption is the standard method for @@ -34303,7 +40516,7 @@ configuration option in /etc/libuser.conf ensures the use algorithm that makes password cracking attacks more difficult. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then var_password_hashing_algorithm_pam='' @@ -34311,6 +40524,63 @@ var_password_hashing_algorithm_pam='. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - OL09-00-001075 - SV-271627r1091593_rule - Passwords need to be protected at all times, and encryption is the standard -method for protecting passwords. If passwords are not encrypted, they can + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001075 + SV-271627r1091593_rule + Passwords need to be protected at all times, and hashing is the standard +method for protecting passwords. If passwords are not hashed, they can be plainly read (i.e., clear text) and easily compromised. Passwords -that are encrypted with a weak algorithm are no more protected than if +that are hashed with a weak algorithm are no more protected than if they are kept in plain text. Using more hashing rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_password_hashing_min_rounds_login_defs='' -config_file="/etc/login.defs" +config_file=/etc/login.defs current_min_rounds=$(grep -Po '^\s*SHA_CRYPT_MIN_ROUNDS\s+\K\d+' "$config_file") current_max_rounds=$(grep -Po '^\s*SHA_CRYPT_MAX_ROUNDS\s+\K\d+' "$config_file") @@ -35046,8 +41287,23 @@ if [[ -n "$current_max_rounds" && "$current_max_rounds" -le "$var_passwo # Clean up after ourselves. rm "/etc/login.defs.bak" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_password_hashing_min_rounds_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001075 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_min_rounds_logindefs +- name: XCCDF Value var_password_hashing_min_rounds_login_defs # promote to variable set_fact: var_password_hashing_min_rounds_login_defs: !!str tags: @@ -35058,6 +41314,7 @@ fi ansible.builtin.slurp: src: /etc/login.defs register: etc_login_defs + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35073,6 +41330,7 @@ fi etc_login_defs_sha_crypt_min_rounds: '{{ etc_login_defs[''content''] | b64decode | regex_search(''^\s*SHA_CRYPT_MIN_ROUNDS\s+(\d+)'', ''\1'', multiline=True) | default([], true) }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35088,6 +41346,7 @@ fi etc_login_defs_sha_crypt_max_rounds: '{{ etc_login_defs[''content''] | b64decode | regex_search(''^\s*SHA_CRYPT_MAX_ROUNDS\s+(\d+)'', ''\1'', multiline=True) | default([], true) }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35104,7 +41363,9 @@ fi regexp: (^\s*SHA_CRYPT_MIN_ROUNDS\s+)(?:\d+)(.*$) replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false - when: etc_login_defs_sha_crypt_min_rounds is defined and etc_login_defs_sha_crypt_min_rounds + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_min_rounds is defined and etc_login_defs_sha_crypt_min_rounds | length > 0 and etc_login_defs_sha_crypt_min_rounds | first | int < var_password_hashing_min_rounds_login_defs | int tags: @@ -35123,7 +41384,9 @@ fi regexp: (^\s*SHA_CRYPT_MAX_ROUNDS\s+)(?:\d+)(.*$) replace: \g<1>{{ var_password_hashing_min_rounds_login_defs }}\g<2> backup: false - when: etc_login_defs_sha_crypt_max_rounds is defined and etc_login_defs_sha_crypt_max_rounds + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_max_rounds is defined and etc_login_defs_sha_crypt_max_rounds | length > 0 and etc_login_defs_sha_crypt_max_rounds | first | int < var_password_hashing_min_rounds_login_defs | int tags: @@ -35141,7 +41404,9 @@ fi line: SHA_CRYPT_MIN_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} path: /etc/login.defs state: present - when: etc_login_defs_sha_crypt_min_rounds | length == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_min_rounds | length == 0 tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35157,7 +41422,9 @@ fi line: SHA_CRYPT_MAX_ROUNDS {{ var_password_hashing_min_rounds_login_defs }} path: /etc/login.defs state: present - when: etc_login_defs_sha_crypt_max_rounds | length == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - etc_login_defs_sha_crypt_max_rounds | length == 0 tags: - DISA-STIG-OL09-00-001075 - low_complexity @@ -35214,8 +41481,6 @@ The debug-shell service can be disabled with the followin $ sudo systemctl mask --now debug-shell.service 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35229,10 +41494,10 @@ The debug-shell service can be disabled with the followin 164.310(d)(2)(iii) CM-6 FIA_UAU.1 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002403 - SV-271742r1091938_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002403 + SV-271742r1091938_rule This prevents attackers with physical access from trivially bypassing security on the machine through valid troubleshooting configurations and gaining root access when the system is rebooted. @@ -35275,82 +41540,51 @@ fi - no_reboot_needed - service_debug-shell_disabled -- name: Disable debug-shell SystemD Service - Collect systemd Services Present in - the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable debug-shell SystemD Service - Disable service debug-shell + block: + + - name: Disable debug-shell SystemD Service - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable debug-shell SystemD Service - Ensure debug-shell.service is Masked + ansible.builtin.systemd: + name: debug-shell.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("debug-shell.service", multiline=True) + + - name: Unit Socket Exists - debug-shell.socket + ansible.builtin.command: systemctl -q list-unit-files debug-shell.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable debug-shell SystemD Service - Disable Socket debug-shell + ansible.builtin.systemd: + name: debug-shell.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("debug-shell.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002403 + - NIST-800-171-3.4.5 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_debug-shell_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Disable debug-shell SystemD Service - Ensure debug-shell.service is Masked - ansible.builtin.systemd: - name: debug-shell.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("debug-shell.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Unit Socket Exists - debug-shell.socket - ansible.builtin.command: systemctl -q list-unit-files debug-shell.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled - -- name: Disable debug-shell SystemD Service - Disable Socket debug-shell - ansible.builtin.systemd: - name: debug-shell.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("debug-shell.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002403 - - NIST-800-171-3.4.5 - - NIST-800-53-CM-6 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_debug-shell_disabled include disable_debug-shell @@ -35365,6 +41599,10 @@ class disable_debug-shell { [customizations.services] masked = ["debug-shell"] + + + + @@ -35401,8 +41639,6 @@ the non-graphical runlevel 3. DSS05.07 DSS06.02 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35440,25 +41676,25 @@ the non-graphical runlevel 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 + 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 CM-6(a) AC-6(1) CM-6(a) PR.AC-4 PR.DS-5 FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002412 - SV-271751r1091965_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002412 + SV-271751r1091965_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term @@ -35508,7 +41744,7 @@ fi - no_reboot_needed - name: Disable Ctrl-Alt-Del Burst Action - lineinfile: + ansible.builtin.lineinfile: dest: /etc/systemd/system.conf state: present regexp: ^CtrlAltDelBurstAction @@ -35566,8 +41802,6 @@ as this file may be restored during future system updates.DSS05.07 DSS06.02 3.4.5 - CCI-000366 - CCI-002235 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35605,24 +41839,24 @@ as this file may be restored during future system updates.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 FAU_GEN.1.2 - SRG-OS-000324-GPOS-00125 - SRG-OS-000480-GPOS-00227 - OL09-00-002413 - SV-271752r1091968_rule + SRG-OS-000324-GPOS-00125 + SRG-OS-000480-GPOS-00227 + OL09-00-002413 + SV-271752r1091968_rule A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term @@ -35630,7 +41864,7 @@ loss of availability of systems due to unintentional reboot.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then systemctl disable ctrl-alt-del.target systemctl mask ctrl-alt-del.target else @@ -35658,7 +41892,7 @@ fi - no_reboot_needed - name: Disable Ctrl-Alt-Del Reboot Activation - systemd: + ansible.builtin.systemd: name: ctrl-alt-del.target force: true masked: true @@ -35715,7 +41949,6 @@ It is also required to change the runtime configuration, run: DSS06.06 3.1.2 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -35782,9 +42015,9 @@ It is also required to change the runtime configuration, run: PR.AC-4 PR.AC-6 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002392 - SV-271736r1091920_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002392 + SV-271736r1091920_rule Using interactive or recovery boot, the console user could disable auditing, firewalls, or other services, weakening system security. @@ -35838,12 +42071,13 @@ fi - reboot_required - restrict_strategy -- name: Verify GRUB_DISABLE_RECOVERY=true - lineinfile: +- name: Verify that Interactive Boot is Disabled - Verify GRUB_DISABLE_RECOVERY=true + ansible.builtin.lineinfile: path: /etc/default/grub regexp: ^GRUB_DISABLE_RECOVERY=.* line: GRUB_DISABLE_RECOVERY=true state: present + register: grub_disable_recovery_changed when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -35860,11 +42094,13 @@ fi - reboot_required - restrict_strategy -- name: Verify that Interactive Boot is Disabled in /etc/default/grub - replace: +- name: Verify that Interactive Boot is Disabled - Verify that Interactive Boot is + Disabled in /etc/default/grub + ansible.builtin.replace: dest: /etc/default/grub regexp: systemd.confirm_spawn(=(1|yes|true|on)|\b) replace: systemd.confirm_spawn=no + register: grub_confirm_spawn_changed when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -35881,11 +42117,13 @@ fi - reboot_required - restrict_strategy -- name: Verify that Interactive Boot is Disabled (runtime) - command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" +- name: Verify that Interactive Boot is Disabled - Verify that Interactive Boot is + Disabled (runtime) + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn" when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' + - grub_confirm_spawn_changed is changed tags: - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 @@ -35899,11 +42137,13 @@ fi - reboot_required - restrict_strategy -- name: Regen grub.cfg handle updated GRUB_DISABLE_RECOVERY and confirm_spawn - command: grub2-mkconfig -o /boot/grub2/grub.cfg +- name: Verify that Interactive Boot is Disabled - Regen grub.cfg handle updated GRUB_DISABLE_RECOVERY + and confirm_spawn + ansible.builtin.command: grub2-mkconfig -o /boot/grub2/grub.cfg when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' + - grub_disable_recovery_changed is changed or grub_confirm_spawn_changed is changed tags: - DISA-STIG-OL09-00-002392 - NIST-800-171-3.1.2 @@ -35957,7 +42197,6 @@ after DSS06.03 DSS06.10 3.1.11 - CCI-001133 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -36006,12 +42245,12 @@ after A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 CM-6(a) AC-17(a) AC-2(5) @@ -36028,7 +42267,7 @@ after PR.IP-2 FMT_SMF_EXT.1.1 Req-8.1.8 - SRG-OS-000163-GPOS-00072 + SRG-OS-000163-GPOS-00072 R32 Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management @@ -36089,7 +42328,7 @@ fi - name: Set 'StopIdleSessionSec' to '{{ var_logind_session_timeout }}' in the [Login] section of '/etc/systemd/logind.conf' - ini_file: + community.general.ini_file: path: /etc/systemd/logind.conf section: Login option: StopIdleSessionSec @@ -36156,7 +42395,6 @@ in /usr/lib/systemd/system/emergency.service.DSS06.10 3.1.1 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -36210,20 +42448,6 @@ in /usr/lib/systemd/system/emergency.service.SR 2.5 SR 2.6 SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.6.1.2 A.7.1.1 @@ -36247,26 +42471,38 @@ in /usr/lib/systemd/system/emergency.service.PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 - OL09-00-000025 - SV-271441r1091035_rule + SRG-OS-000080-GPOS-00048 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-000025 + SV-271441r1117265_rule This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -service_file="/usr/lib/systemd/system/emergency.service" +service_dropin_cfg_dir="/etc/systemd/system/emergency.service.d" +service_dropin_file="${service_dropin_cfg_dir}/10-oscap.conf" sulogin="/usr/lib/systemd/systemd-sulogin-shell emergency" -if grep "^ExecStart=.*" "$service_file" ; then - sed -i "s%^ExecStart=.*%ExecStart=-$sulogin%" "$service_file" -else - echo "ExecStart=-$sulogin" >> "$service_file" -fi +mkdir -p "${service_dropin_cfg_dir}" +echo "[Service]" >> "${service_dropin_file}" +echo "ExecStart=-$sulogin" >> "${service_dropin_file}" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -36290,11 +42526,12 @@ fi - restrict_strategy - name: Require emergency mode password - lineinfile: + ansible.builtin.blockinfile: create: true - dest: /usr/lib/systemd/system/emergency.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + dest: /etc/systemd/system/emergency.service.d/10-oscap.conf + block: |- + [Service] + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000025 @@ -36345,7 +42582,6 @@ in /usr/lib/systemd/system/rescue.service.DSS06.10 3.1.1 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -36399,20 +42635,6 @@ in /usr/lib/systemd/system/rescue.service.SR 2.5 SR 2.6 SR 2.7 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.6.1.2 A.7.1.1 @@ -36428,16 +42650,16 @@ in /usr/lib/systemd/system/rescue.service.A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 AC-3 CM-6(a) @@ -36447,9 +42669,22 @@ in /usr/lib/systemd/system/rescue.service.PR.AC-7 PR.PT-3 FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - OL09-00-000030 - SV-271442r1091038_rule + SRG-OS-000080-GPOS-00048 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-000030 + SV-271442r1117265_rule This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password. @@ -36466,10 +42701,13 @@ for f in $(echo -n "/etc/systemd/system/rescue.service.d/10-oscap.conf /etc/syst # find key in section and change value if grep -qzosP "[[:space:]]*\[Service\]([^\n\[]*\n+)+?[[:space:]]*ExecStart" "$f"; then + if ! grep -qPz "ExecStart=\nExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue" "$f"; then sed -i "s/ExecStart[^(\n)]*/ExecStart=\nExecStart=-\/usr\/lib\/systemd\/systemd-sulogin-shell rescue/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Service\]" "$f"; then @@ -36510,12 +42748,84 @@ fi - require_singleuser_auth - restrict_strategy -- name: Require Authentication for Single User Mode - Require single user mode password - lineinfile: - create: true - dest: /usr/lib/systemd/system/rescue.service - regexp: ^#?ExecStart= - line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue +- name: Require Authentication for Single User Mode - find files which already override + Execstart of rescue.service + ansible.builtin.find: + paths: /etc/systemd/system/rescue.service.d + patterns: '*.conf' + contains: ^\s*ExecStart=.*$ + register: rescue_service_overrides_found + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - set files containing ExecStart + overrides as target + ansible.builtin.set_fact: + rescue_service_remediation_target_file: '{{ rescue_service_overrides_found.files + | map(attribute=''path'') | list }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rescue_service_overrides_found.matched is defined and rescue_service_overrides_found.matched + > 0 + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - set default target for rescue.service + override + ansible.builtin.set_fact: + rescue_service_remediation_target_file: + - /etc/systemd/system/rescue.service.d/10-oscap.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - rescue_service_overrides_found.matched is defined and rescue_service_overrides_found.matched + == 0 + tags: + - DISA-STIG-OL09-00-000030 + - NIST-800-171-3.1.1 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - require_singleuser_auth + - restrict_strategy + +- name: Require Authentication for Single User Mode - Require emergency user mode + password + community.general.ini_file: + path: '{{ item }}' + section: Service + option: ExecStart + values: + - '' + - -/usr/lib/systemd/systemd-sulogin-shell rescue + loop: '{{ rescue_service_remediation_target_file }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000030 @@ -36611,16 +42921,12 @@ The opensc package can be installed with the following co $ sudo yum install opensc - CCI-001953 - CCI-004046 - 1382 - 1384 - 1386 CM-6(a) - SRG-OS-000375-GPOS-00160 - SRG-OS-000376-GPOS-00161 - OL09-00-000400 - SV-271515r1091257_rule + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + 1386 + OL09-00-000400 + SV-271515r1091257_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36629,9 +42935,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -36657,7 +42962,7 @@ fi - package_opensc_installed - name: Ensure opensc is installed - package: + ansible.builtin.package: name: opensc state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -36700,14 +43005,11 @@ version = "*" $ sudo yum install pcsc-lite - CCI-004046 - 1382 - 1384 - 1386 CM-6(a) - SRG-OS-000375-GPOS-00160 - OL09-00-000390 - SV-271514r1091254_rule + SRG-OS-000375-GPOS-00160 + 1386 + OL09-00-000390 + SV-271514r1091254_rule The pcsc-lite package must be installed if it is to be available for multifactor authentication using smartcards. # Remediation is applicable only in certain platforms @@ -36735,7 +43037,7 @@ fi - package_pcsc-lite_installed - name: Ensure pcsc-lite is installed - package: + ansible.builtin.package: name: pcsc-lite state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -36781,18 +43083,14 @@ The openssl-pkcs11 package can be installed with the foll $ sudo yum install openssl-pkcs11 - CCI-000765 - CCI-001953 - CCI-001954 - CCI-004046 CM-6(a) Req-8.3 - SRG-OS-000105-GPOS-00052 - SRG-OS-000375-GPOS-00160 - SRG-OS-000375-GPOS-00161 - SRG-OS-000377-GPOS-00162 - OL09-00-000270 - SV-271491r1091185_rule + SRG-OS-000105-GPOS-00052 + SRG-OS-000375-GPOS-00160 + SRG-OS-000375-GPOS-00161 + SRG-OS-000377-GPOS-00162 + OL09-00-000270 + SV-271491r1091185_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36801,9 +43099,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ); }; then @@ -36831,7 +43128,7 @@ fi - no_reboot_needed - name: Ensure openssl-pkcs11 is installed - package: + ansible.builtin.package: name: openssl-pkcs11 state: present when: @@ -36877,10 +43174,6 @@ version = "*" The pcscd service can be enabled with the following command: $ sudo systemctl enable pcscd.service - CCI-004046 - 1382 - 1384 - 1386 IA-2(1) IA-2(2) IA-2(3) @@ -36890,9 +43183,10 @@ The pcscd service can be enabled with the following comma IA-2(11) CM-6(a) Req-8.3 - SRG-OS-000375-GPOS-00160 - OL09-00-000401 - SV-271516r1091260_rule + SRG-OS-000375-GPOS-00160 + 1386 + OL09-00-000401 + SV-271516r1091260_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -36901,9 +43195,8 @@ authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -36939,27 +43232,21 @@ fi - no_reboot_needed - service_pcscd_enabled -- name: Enable service pcscd +- name: Enable the pcscd Service - Enable service pcscd block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - - name: Start service pcscd - systemd: + - name: Enable the pcscd Service - Enable Service pcscd + ansible.builtin.systemd: name: pcscd + enabled: true state: started - masked: 'no' + masked: false when: - '"pcsc-lite" in ansible_facts.packages' - - - name: Enable service pcscd - ansible.builtin.command: - cmd: systemctl enable pcscd - when: - - '"pcsc-lite" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000401 - NIST-800-53-CM-6(a) @@ -36977,6 +43264,8 @@ fi - medium_severity - no_reboot_needed - service_pcscd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_pcscd @@ -36991,6 +43280,10 @@ class enable_pcscd { [customizations.services] enabled = ["pcscd"] + + + + @@ -37026,11 +43319,6 @@ app default { DSS05.10 DSS06.03 DSS06.10 - CCI-001941 - CCI-004045 - CCI-000765 - CCI-000766 - CCI-000764 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37055,9 +43343,6 @@ app default { SR 1.8 SR 1.9 SR 2.1 - 1382 - 1384 - 1386 A.18.1.4 A.7.1.1 A.9.2.1 @@ -37080,15 +43365,16 @@ app default { PR.AC-6 PR.AC-7 Req-8.3 - SRG-OS-000104-GPOS-00051 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000109-GPOS-00056 - SRG-OS-000108-GPOS-00055 - SRG-OS-000108-GPOS-00057 - SRG-OS-000108-GPOS-00058 - OL09-00-000940 - SV-271610r1091542_rule + SRG-OS-000104-GPOS-00051 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000109-GPOS-00056 + SRG-OS-000108-GPOS-00055 + SRG-OS-000108-GPOS-00057 + SRG-OS-000108-GPOS-00058 + 1386 + OL09-00-000940 + SV-271610r1091542_rule Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. @@ -37137,7 +43423,7 @@ fi - always - name: Check existence of opensc conf - stat: + ansible.builtin.stat: path: /etc/opensc-{{ ansible_architecture }}.conf register: opensc_conf_cd when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -37163,12 +43449,12 @@ fi block: - name: Check if card_drivers is defined - command: /usr/bin/opensc-tool -G app:default:card_drivers + ansible.builtin.command: /usr/bin/opensc-tool -G app:default:card_drivers changed_when: false register: card_drivers - name: Configure opensc Smart Card Drivers - command: | + ansible.builtin.command: | /usr/bin/opensc-tool -S app:default:card_drivers:{{ var_smartcard_drivers }} when: - card_drivers.stdout != var_smartcard_drivers @@ -37218,7 +43504,7 @@ operationally necessary. Accounts Authorized Local Users on the Operating System List the user accounts that are authorized locally on the operating system. This list -includes both users requried by the operating system and by the installed applications. +includes both users required by the operating system and by the installed applications. Depending on the Operating System distribution, version, software groups and applications, the user list is different and can be customized with scap-workbench. OVAL regular expression is used for the user list. @@ -37236,6 +43522,7 @@ in OVAL that is always allowed on the operating system. ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty|salt|cockpit-ws|cockpit-wsinstance)$ + ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|pegasus|systemd-bus-proxy|systemd-network|dbus|polkitd|abrt|unbound|tss|libstoragemgmt|rpc|colord|usbmuxd$|pcp|saslauth|geoclue|setroubleshoot|rtkit|chrony|qemu|radvd|rpcuser|nfsnobody|pulse|gdm|gnome-initial-setup|postfix|avahi|ntp|sshd|tcpdump|oprofile|uuidd|systemd-resolve|systemd-coredump|sssd|rngd|man|systemd-timesync|scard|hacluster|statd|at|dockremap|vnc|messagebus|nscd|flatpak|srvGeoClue|tftp|wsdd|dnsmasq|usbmux|brltty|salt|cockpit-ws|cockpit-wsinstance)$ ^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|tss|systemd-coredump|dbus|polkitd|avahi|colord|rtkit|pipewire|clevis|sssd|geoclue|flatpak|setroubleshoot|libstoragemgmt|systemd-oom|gdm|cockpit-ws|cockpit-wsinstance|gnome-initial-setup|sshd|chrony|dnsmasq|tcpdump|admin)$ @@ -37243,16 +43530,13 @@ in OVAL that is always allowed on the operating system. Change user IDs (UIDs), or delete accounts, so each has a unique name. Automatic remediation of this control is not available due to unique requirements of each system. - CCI-000135 - CCI-000764 - CCI-000804 Req-8.1.1 - SRG-OS-000104-GPOS-00051 - SRG-OS-000121-GPOS-00062 + SRG-OS-000104-GPOS-00051 + SRG-OS-000121-GPOS-00062 8.2.1 8.2 - OL09-00-003001 - SV-271832r1092208_rule + OL09-00-003001 + SV-271832r1092208_rule To assure accountability and prevent unauthenticated access, interactive users must be identified and authenticated to prevent potential misuse and compromise of the system. @@ -37279,14 +43563,14 @@ To remove unauthorized system accounts, use the following command: Automatic remediation of this control is not available due to the unique requirements of each system. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002501 - SV-271770r1092022_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002501 + SV-271770r1092022_rule Accounts providing no operational purpose provide additional opportunities for system compromise. Unnecessary accounts include user accounts for individuals not requiring access to the system and application accounts for applications not installed on the system. + @@ -37299,13 +43583,13 @@ on the system. Ensure All Groups on the System Have Unique Group ID Change the group name or delete groups, so each has a unique id. Automatic remediation of this control is not available due to the unique requirements of each system. - CCI-000764 - SRG-OS-000104-GPOS-00051 + SRG-OS-000104-GPOS-00051 8.2.1 8.2 - OL09-00-003006 - SV-271835r1092217_rule + OL09-00-003006 + SV-271835r1092217_rule To assure accountability and prevent unauthenticated access, groups must be identified uniquely to prevent potential misuse and compromise of the system. + @@ -37331,6 +43615,7 @@ The file /etc/default/useradd controls default settings for all newly-created accounts created with the system's normal command line utilities. This will only apply to newly created accounts + number of days after the last login of the user when the user will be locked out 'This option is specific for the auth or account phase. It specifies the number of days after @@ -37373,15 +43658,14 @@ will also use authselect tool. However, if any manual mod 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. - CCI-000795 IA-4(e) - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then PAM_FILE_PATH="/etc/pam.d/password-auth" if [ -f /usr/bin/authselect ]; then @@ -37432,7 +43716,7 @@ fi if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]*\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then @@ -37468,7 +43752,7 @@ else fi - + @@ -37491,15 +43775,14 @@ will also use authselect tool. However, if any manual mod 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. - CCI-000795 IA-4(e) - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then PAM_FILE_PATH="/etc/pam.d/system-auth" if [ -f /usr/bin/authselect ]; then @@ -37550,7 +43833,7 @@ fi if ! grep -qP "^\s*auth\s+required\s+pam_lastlog.so\s*.*\sinactive\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*auth\s+required\s+pam_lastlog.so.*/ s/$/ inactive=35/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]+\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*auth\s+required\s+pam_lastlog.so\s+.*)(inactive=)[[:alnum:]]*\s*(.*)/\1\235 \3/" "$PAM_FILE_PATH" fi if ! grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s*.*" "$PAM_FILE_PATH"; then @@ -37586,7 +43869,7 @@ else fi - + @@ -37628,8 +43911,6 @@ elapse until the account would be automatically disabled. See the DSS06.03 DSS06.10 3.5.6 - CCI-003628 - CCI-003627 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37673,14 +43954,14 @@ elapse until the account would be automatically disabled. See the A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 IA-4(e) AC-2(3) CM-6(a) @@ -37691,17 +43972,17 @@ elapse until the account would be automatically disabled. See the PR.AC-6 PR.AC-7 Req-8.1.4 - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 8.2.6 8.2 - OL09-00-003065 - SV-271849r1092259_rule + OL09-00-003065 + SV-271849r1092259_rule Inactive identifiers pose a risk to systems and applications because attackers may exploit an inactive identifier and potentially obtain undetected access to the system. Disabling inactive accounts ensures that accounts which may not have been responsibly removed are not available to attackers who may have compromised their credentials. Owners of inactive accounts will not notice if unauthorized access to their user account has been obtained. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_account_disable_post_pw_expiration='' @@ -37756,12 +44037,14 @@ fi - always - name: Set Account Expiration Following Inactivity - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/default/useradd regexp: ^INACTIVE line: INACTIVE={{ var_account_disable_post_pw_expiration }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 - DISA-STIG-OL09-00-003065 @@ -37818,8 +44101,6 @@ period of 72 hours. DSS05.05 DSS05.07 DSS06.03 - CCI-000016 - CCI-001682 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -37860,10 +44141,10 @@ period of 72 hours. PR.AC-1 PR.AC-4 PR.AC-6 - SRG-OS-000123-GPOS-00064 - SRG-OS-000002-GPOS-00002 - OL09-00-003030 - SV-271843r1094969_rule + SRG-OS-000123-GPOS-00064 + SRG-OS-000002-GPOS-00002 + OL09-00-003030 + SV-271843r1094969_rule If temporary user accounts remain active when no longer needed or for an excessive period, these accounts may be used to gain unauthorized access. To mitigate this risk, automated termination of all temporary accounts @@ -37882,8 +44163,6 @@ To ensure all accounts have unique names, run the following command: $ sudo getent passwd | awk -F: '{ print $1}' | uniq -d If a username is returned, change or delete the username. 5.5.2 - CCI-000770 - CCI-000804 Req-8.1.1 8.2.1 8.2 @@ -37946,6 +44225,7 @@ could be adjusted to a 180 day maximum password age, 7 day minimum password age, and 7 day warning period with the following command: $ sudo chage -M 180 -m 7 -W 7 USER + maximum password age Maximum age of password in days @@ -38008,8 +44288,6 @@ edit the file /etc/login.defs and add or correct the following line: PASS_MAX_DAYS -A value of 180 days is sufficient for many environments. -The DoD requirement is 60. The profile requirement is . 1 12 @@ -38024,7 +44302,6 @@ The profile requirement is DSS06.03 DSS06.10 3.5.6 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38049,9 +44326,6 @@ The profile requirement is SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38069,12 +44343,15 @@ The profile requirement is PR.AC-6 PR.AC-7 Req-8.2.4 - SRG-OS-000076-GPOS-00044 + SRG-OS-000076-GPOS-00044 A.5.SEC-OL5 + 0418 + 1055 + 1402 8.3.9 8.3 - OL09-00-001095 - SV-271631r1091605_rule + OL09-00-001095 + SV-271631r1091605_rule Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the @@ -38087,7 +44364,7 @@ increases the risk of users writing down the password in a convenient location subject to physical compromise. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_maximum_age_login_defs='' @@ -38141,12 +44418,14 @@ fi - always - name: Set Password Maximum Age - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/login.defs regexp: ^#?PASS_MAX_DAYS line: PASS_MAX_DAYS {{ var_accounts_maximum_age_login_defs }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 - DISA-STIG-OL09-00-001095 @@ -38180,7 +44459,7 @@ and add or correct the following line: PASS_MIN_DAYS A value of 1 day is considered sufficient for many -environments. The DoD requirement is 1. +environments. The profile requirement is . 1 12 @@ -38195,7 +44474,6 @@ The profile requirement is DSS06.03 DSS06.10 3.5.8 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38220,9 +44498,6 @@ The profile requirement is SR 1.8 SR 1.9 SR 2.1 - 0418 - 1055 - 1402 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38239,8 +44514,13 @@ The profile requirement is PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000075-GPOS-00043 + SRG-OS-000075-GPOS-00043 A.5.SEC-OL5 + 0418 + 1055 + 1402 + OL09-00-001085 + SV-271629r1091599_rule Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, @@ -38252,7 +44532,7 @@ Setting the minimum password age protects against users cycling back to a favorite password after satisfying the password reuse requirement. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_minimum_age_login_defs='' @@ -38285,6 +44565,7 @@ fi manager: auto tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001085 - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38302,14 +44583,17 @@ fi - always - name: Set Password Minimum Age - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/login.defs regexp: ^#?PASS_MIN_DAYS line: PASS_MIN_DAYS {{ var_accounts_minimum_age_login_defs }} - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1.1 + - DISA-STIG-OL09-00-001085 - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38337,8 +44621,6 @@ fi -The DoD requirement is 15. -The FISMA requirement is 12. The profile requirement is . If a program consults /etc/login.defs and also another PAM module @@ -38358,7 +44640,6 @@ information about enforcing password quality requirements.DSS06.03 DSS06.10 3.5.7 - CCI-004066 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -38383,20 +44664,6 @@ information about enforcing password quality requirements.SR 1.8 SR 1.9 SR 2.1 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.18.1.4 A.7.1.1 A.9.2.1 @@ -38413,10 +44680,21 @@ information about enforcing password quality requirements.PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000078-GPOS-00046 + SRG-OS-000078-GPOS-00046 R31 - OL09-00-001105 - SV-271633r1091611_rule + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 Requiring a minimum password length makes password cracking attacks more difficult by ensuring a larger search space. However, any security benefit from an onerous requirement @@ -38424,7 +44702,7 @@ must be carefully weighed against usability problems, support costs, or counterp behavior that may result. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_password_minlen_login_defs='' @@ -38457,7 +44735,6 @@ fi manager: auto tags: - CJIS-5.6.2.1 - - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -38475,16 +44752,17 @@ fi - always - name: Set Password Minimum Length in login.defs - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^PASS_MIN_LEN *[0-9]* state: present line: PASS_MIN_LEN {{ var_accounts_password_minlen_login_defs }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - CJIS-5.6.2.1 - - DISA-STIG-OL09-00-001105 - NIST-800-171-3.5.7 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(a) @@ -38512,22 +44790,23 @@ restriction by running the following command: USER - CCI-004066 IA-5(f) IA-5(1)(d) CM-6(a) - SRG-OS-000076-GPOS-00044 + SRG-OS-000076-GPOS-00044 A.5.SEC-OL5 8.3.9 8.3 - OL09-00-001100 - SV-271632r1091608_rule + OL09-00-001100 + SV-271632r1091608_rule Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_maximum_age_login_defs='' @@ -38536,8 +44815,28 @@ while IFS= read -r i; do chage -M $var_accounts_maximum_age_login_defs $i done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($5 > var || $5 == "")) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001100 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_max_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_maximum_age_login_defs # promote to variable set_fact: var_accounts_maximum_age_login_defs: !!str tags: @@ -38548,6 +44847,9 @@ done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+ cmd: awk -F':' '(/^[^:]+:[^!*]/ && ($5 > {{ var_accounts_maximum_age_login_defs }} || $5 == "")) {print $1}' /etc/shadow register: user_names + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-001100 - NIST-800-53-CM-6(a) @@ -38567,7 +44869,9 @@ done < <(awk -v var="$var_accounts_maximum_age_login_defs" -F: '(/^[^:]+ user: '{{ item }}' password_expire_max: '{{ var_accounts_maximum_age_login_defs }}' with_items: '{{ user_names.stdout_lines }}' - when: user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names.stdout_lines | length > 0 tags: - DISA-STIG-OL09-00-001100 - NIST-800-53-CM-6(a) @@ -38617,22 +44921,21 @@ lifetime by running the following command: $ sudo chage -m 1 USER - CCI-004066 IA-5(f) IA-5(1)(d) CM-6(a) - SRG-OS-000075-GPOS-00043 + SRG-OS-000075-GPOS-00043 A.5.SEC-OL5 - OL09-00-001090 - OL09-00-001085 - SV-271630r1091602_rule - SV-271629r1091599_rule + OL09-00-001090 + SV-271630r1091602_rule Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_minimum_age_login_defs='' @@ -38641,19 +44944,39 @@ while IFS= read -r i; do chage -m $var_accounts_minimum_age_login_defs $i done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+:[^!*]/ && ($4 < var || $4 == "")) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-001090 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - accounts_password_set_min_life_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_minimum_age_login_defs # promote to variable set_fact: var_accounts_minimum_age_login_defs: !!str tags: - always - name: Collect users with not correct minimum time period between password changes - command: | + ansible.builtin.command: | awk -F':' '(/^[^:]+:[^!*]/ && ($4 < {{ var_accounts_minimum_age_login_defs }} || $4 == "")) {print $1}' /etc/shadow register: user_names + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-001085 - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38666,12 +44989,13 @@ done < <(awk -v var="$var_accounts_minimum_age_login_defs" -F: '(/^[^:]+ - restrict_strategy - name: Change the minimum time period between password changes - command: | + ansible.builtin.command: | chage -m {{ var_accounts_minimum_age_login_defs }} {{ item }} with_items: '{{ user_names.stdout_lines }}' - when: user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names.stdout_lines | length > 0 tags: - - DISA-STIG-OL09-00-001085 - DISA-STIG-OL09-00-001090 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38699,9 +45023,7 @@ users, run the command: $ sudo chage --warndays USER -The DoD requirement is 7, and CIS recommendation is no less than 7 days. This profile requirement is . - CCI-000198 IA-5(f) IA-5(1)(d) CM-6(a) @@ -38711,15 +45033,36 @@ This profile requirement is + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_password_warn_age_login_defs='' while IFS= read -r i; do chage --warndays $var_accounts_password_warn_age_login_defs $i done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(($6 < var || $6 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(d) + - NIST-800-53-IA-5(f) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.9 + - accounts_password_set_warn_age_existing + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed +- name: XCCDF Value var_accounts_password_warn_age_login_defs # promote to variable set_fact: var_accounts_password_warn_age_login_defs: !!str tags: @@ -38732,6 +45075,7 @@ done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(( "") && $2 ~ /^\$/) {print $1}' /etc/shadow register: result_pass_warn_age_user_names changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(d) @@ -38751,7 +45095,9 @@ done < <(awk -v var="$var_accounts_password_warn_age_login_defs" -F: '(( cmd: chage --warndays {{ var_accounts_password_warn_age_login_defs }} {{ item }} with_items: '{{ result_pass_warn_age_user_names.stdout_lines }}' - when: result_pass_warn_age_user_names is not skipped and result_pass_warn_age_user_names.stdout_lines + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_pass_warn_age_user_names is not skipped and result_pass_warn_age_user_names.stdout_lines | length > 0 tags: - NIST-800-53-CM-6(a) @@ -38782,7 +45128,6 @@ edit the file /etc/login.defs and add or correct the following line: PASS_WARN_AGE -The DoD requirement is 7. The profile requirement is . 1 12 @@ -38830,9 +45175,6 @@ The profile requirement is SR 1.9 SR 2.1 SR 6.2 - 0418 - 1055 - 1402 A.12.4.1 A.12.4.3 A.18.1.4 @@ -38861,13 +45203,16 @@ The profile requirement is PR.AC-7 Req-8.2.4 A.5.SEC-OL5 + 0418 + 1055 + 1402 8.3.9 8.3 Setting the password warning age enables users to make the change at a practical time. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_password_warn_age_login_defs='' @@ -38919,13 +45264,15 @@ fi - always - name: Set Password Warning Age - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^PASS_WARN_AGE *[0-9]* state: present line: PASS_WARN_AGE {{ var_accounts_password_warn_age_login_defs }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - NIST-800-171-3.5.8 - NIST-800-53-CM-6(a) @@ -38953,8 +45300,7 @@ fi Set existing passwords a period of inactivity before they been locked Configure user accounts that have been inactive for over a given period of time to be automatically disabled by running the following command: -$ sudo chage --inactive 30USER - +$ sudo chage --inactive 30 USER DSS01.03 DSS03.05 @@ -38965,10 +45311,6 @@ to be automatically disabled by running the following command: DSS06.03 DSS06.10 3.5.6 - CCI-000017 - CCI-000795 - CCI-003627 - CCI-003628 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -39012,14 +45354,14 @@ to be automatically disabled by running the following command: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 IA-4(e) AC-2(3) CM-6(a) @@ -39030,20 +45372,43 @@ to be automatically disabled by running the following command: PR.AC-6 PR.AC-7 Req-8.1.4 - SRG-OS-000118-GPOS-00060 + SRG-OS-000118-GPOS-00060 8.2.6 8.2 Inactive accounts pose a threat to system security since the users are not logging in to notice failed login attempts or other anomalies. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_account_disable_post_pw_expiration='' while IFS= read -r i; do chage --inactive $var_account_disable_post_pw_expiration $i done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 > var || $7 == "") && $2 ~ /^\$/) {print $1}' /etc/shadow) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-171-3.5.6 + - NIST-800-53-AC-2(3) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-4(e) + - PCI-DSS-Req-8.1.4 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.6 + - accounts_set_post_pw_existing + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_account_disable_post_pw_expiration # promote to variable set_fact: var_account_disable_post_pw_expiration: !!str tags: @@ -39055,6 +45420,7 @@ done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 && $2 ~ /^\$/) {print $1}' /etc/shadow register: user_names changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) @@ -39074,7 +45440,9 @@ done < <(awk -v var="$var_account_disable_post_pw_expiration" -F: '(($7 ansible.builtin.command: cmd: chage --inactive {{ var_account_disable_post_pw_expiration }} {{ item }} with_items: '{{ user_names.stdout_lines }}' - when: user_names is not skipped and user_names.stdout_lines | length > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - user_names is not skipped and user_names.stdout_lines | length > 0 tags: - NIST-800-171-3.5.6 - NIST-800-53-AC-2(3) @@ -39169,7 +45537,6 @@ properly stored, or the account should be deleted entirely.SR 1.8 SR 1.9 SR 2.1 - 1410 A.18.1.4 A.7.1.1 A.9.2.1 @@ -39186,6 +45553,7 @@ properly stored, or the account should be deleted entirely.PR.AC-6 PR.AC-7 Req-8.2.1 + 1402 8.3.2 8.3 The hashes for all user account passwords should be stored in @@ -39212,16 +45580,14 @@ Password hashes ! or * indicate in available for logon and are not evaluated. If any interactive user password hash does not begin with $6, this is a finding. - CCI-000803 - CCI-004062 IA-5(1)(c) IA-5(1).1(v) IA-7 IA-7.1 - SRG-OS-000073-GPOS-00041 - SRG-OS-000120-GPOS-00061 - OL09-00-001080 - SV-271628r1091596_rule + SRG-OS-000073-GPOS-00041 + SRG-OS-000120-GPOS-00061 + OL09-00-001080 + SV-271628r1091596_rule Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. @@ -39264,16 +45630,14 @@ to the pam_unix.so entry, as shown below: The system's default number of rounds is 5000. Setting a high number of hashing rounds makes it more difficult to brute force the password, but requires more CPU resources to authenticate users. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 R68 - OL09-00-001065 - SV-271625r1091587_rule + OL09-00-001065 + SV-271625r1091587_rule Using a higher number of rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_password_pam_unix_rounds='' @@ -39332,7 +45696,7 @@ if [ -e "/etc/pam.d/password-auth" ] ; then if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -39368,7 +45732,8 @@ fi ansible.builtin.stat: path: /etc/pam.d/password-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-001065 - accounts_password_pam_unix_rounds_password_auth @@ -39403,13 +45768,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set number of Password Hashing Rounds - password-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -39454,6 +45820,7 @@ fi 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/") @@ -39465,6 +45832,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set number of Password Hashing Rounds - password-auth - Create an authselect @@ -39473,6 +45841,7 @@ fi 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 @@ -39482,6 +45851,7 @@ fi 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 @@ -39532,6 +45902,8 @@ fi 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 @@ -39623,6 +45995,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_rounds_password_auth_add when: + - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found == 0 @@ -39631,7 +46005,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 register: result_pam_accounts_password_pam_unix_rounds_password_auth_edit when: @@ -39648,7 +46022,8 @@ fi (result_pam_accounts_password_pam_unix_rounds_password_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_add.changed) or (result_pam_accounts_password_pam_unix_rounds_password_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001065 @@ -39681,16 +46056,14 @@ to the pam_unix.so entry, as shown below: The system's default number of rounds is 5000. Setting a high number of hashing rounds makes it more difficult to brute force the password, but requires more CPU resources to authenticate users. - CCI-000803 - CCI-004062 - SRG-OS-000073-GPOS-00041 + SRG-OS-000073-GPOS-00041 R68 - OL09-00-001070 - SV-271626r1091590_rule + OL09-00-001070 + SV-271626r1091590_rule Using a higher number of rounds makes password cracking attacks more difficult. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_password_pam_unix_rounds='' @@ -39748,7 +46121,7 @@ if [ -e "/etc/pam.d/system-auth" ] ; then if ! grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b" "$PAM_FILE_PATH"; then sed -i -E --follow-symlinks "/\s*password\s+sufficient\s+pam_unix.so.*/ s/$/ rounds=$var_password_pam_unix_rounds/" "$PAM_FILE_PATH" else - sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]+\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" + sed -i -E --follow-symlinks "s/(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds=)[[:alnum:]]*\s*(.*)/\1\2$var_password_pam_unix_rounds \3/" "$PAM_FILE_PATH" fi if [ -f /usr/bin/authselect ]; then @@ -39784,7 +46157,8 @@ fi ansible.builtin.stat: path: /etc/pam.d/system-auth register: result_pam_file_present - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-001070 - accounts_password_pam_unix_rounds_system_auth @@ -39819,13 +46193,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Set number of Password Hashing Rounds - system-auth - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -39870,6 +46245,7 @@ fi 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/") @@ -39881,6 +46257,7 @@ fi register: result_authselect_custom_profile_present changed_when: false when: + - result_authselect_profile is not skipped - authselect_current_profile is not match("custom/") - name: Set number of Password Hashing Rounds - system-auth - Create an authselect @@ -39889,6 +46266,7 @@ fi 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 @@ -39898,6 +46276,7 @@ fi 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 @@ -39948,6 +46327,8 @@ fi 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 @@ -40039,6 +46420,8 @@ fi state: present register: result_pam_accounts_password_pam_unix_rounds_system_auth_add when: + - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found + is defined - result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found == 0 @@ -40047,7 +46430,7 @@ fi ansible.builtin.lineinfile: path: '{{ pam_file_path }}' backrefs: true - regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*) + regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*) line: \1\2={{ var_password_pam_unix_rounds }} \3 register: result_pam_accounts_password_pam_unix_rounds_system_auth_edit when: @@ -40064,7 +46447,8 @@ fi (result_pam_accounts_password_pam_unix_rounds_system_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_add.changed) or (result_pam_accounts_password_pam_unix_rounds_system_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_edit.changed) when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - result_pam_file_present.stat.exists tags: - DISA-STIG-OL09-00-001070 @@ -40098,7 +46482,6 @@ fi DSS05.10 DSS06.03 DSS06.10 - CCI-000764 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40133,27 +46516,27 @@ fi A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 CM-6(a) PR.AC-1 PR.AC-6 PR.AC-7 Req-8.5.a - SRG-OS-000104-GPOS-00051 + SRG-OS-000104-GPOS-00051 8.2.2 8.2 - OL09-00-003005 - SV-271834r1092214_rule + OL09-00-003005 + SV-271834r1092214_rule If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group with the Group Identifier (GID) is subsequently created, the user may have unintended rights to any files associated with the group. @@ -40204,7 +46587,6 @@ a container anyway. DSS06.10 3.1.1 3.1.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -40283,11 +46665,12 @@ a container anyway. PR.DS-5 FIA_UAU.1 Req-8.2.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 8.3.1 8.3 - OL09-00-001110 - SV-271634r1091614_rule + OL09-00-001110 + SV-271634r1091614_rule If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments. @@ -40310,19 +46693,19 @@ authselect apply-changes -b else if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/system-auth"; then - sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/system-auth" fi if grep -qP "^\s*auth\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" + sed -i -E --follow-symlinks "s/(.*auth.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi if grep -qP "^\s*password\s+sufficient\s+pam_unix.so\s.*\bnullok\b" "/etc/pam.d/password-auth"; then - sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\snullok=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" + sed -i -E --follow-symlinks "s/(.*password.*sufficient.*pam_unix.so.*)\bnullok\b=?[[:alnum:]]*(.*)/\1\2/g" "/etc/pam.d/password-auth" fi fi @@ -40384,13 +46767,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Prevent Login to Accounts With Empty Password - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -40407,6 +46791,7 @@ fi 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 @@ -40517,15 +46902,14 @@ Lock an account: $ sudo passwd -l [username] Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway. - CCI-000366 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.6.SEC-OL4 2.2.2 2.2 - OL09-00-001130 - SV-271638r1091626_rule + OL09-00-001130 + SV-271638r1091626_rule If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments. @@ -40561,7 +46945,7 @@ fi - restrict_strategy - name: Collect users with no password - command: | + ansible.builtin.command: | awk -F: '!$2 {print $1}' /etc/shadow register: users_nopasswd changed_when: false @@ -40580,7 +46964,7 @@ fi - restrict_strategy - name: Lock users with no password - command: | + ansible.builtin.command: | passwd -l {{ item }} with_items: '{{ users_nopasswd.stdout_lines }}' when: @@ -40630,7 +47014,6 @@ users and should not be used. Any .netrc files should be DSS06.03 DSS06.06 DSS06.10 - CCI-000196 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40688,21 +47071,21 @@ users and should not be used. Any .netrc files should be A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-5(h) IA-5(1)(c) CM-6(a) @@ -40714,6 +47097,7 @@ users and should not be used. Any .netrc files should be PR.PT-3 Unencrypted passwords for remote FTP servers may be stored in .netrc files. + @@ -40780,7 +47164,6 @@ assigned. DSS06.10 3.1.1 3.1.5 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -40838,16 +47221,16 @@ assigned. A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 AC-6(5) IA-4(b) @@ -40857,22 +47240,52 @@ assigned. PR.AC-7 PR.DS-5 Req-8.5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 8.2.1 8.2 - OL09-00-003000 - SV-271831r1092205_rule + OL09-00-003000 + SV-271831r1092205_rule An account has root authority if it has a UID of 0. Multiple accounts with a UID of 0 afford more opportunity for potential intruders to guess a password for a privileged account. Proper configuration of sudo is recommended to afford multiple system administrators access to root privileges in an accountable manner. - awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --no-run-if-empty --max-lines=1 passwd -l + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all /etc/passwd file entries - getent: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003000 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-6(5) + - NIST-800-53-IA-2 + - NIST-800-53-IA-4(b) + - PCI-DSS-Req-8.5 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.1 + - accounts_no_uid_except_zero + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + +- name: Get all /etc/passwd file entries + ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 @@ -40891,10 +47304,12 @@ access to root privileges in an accountable manner. - restrict_strategy - name: Lock the password of the user accounts other than root with uid 0 - command: passwd -l {{ item.key }} + ansible.builtin.command: passwd -l {{ item.key }} loop: '{{ getent_passwd | dict2items | rejectattr(''key'', ''search'', ''root'') | list }}' - when: item.value.1 == '0' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value.1 == '0' tags: - DISA-STIG-OL09-00-003000 - NIST-800-171-3.1.1 @@ -40926,6 +47341,7 @@ access to root privileges in an accountable manner. 8.2.1 8.2 To help ensure that root-owned files are not inadvertently exposed to other users. + @@ -40948,7 +47364,7 @@ accomplished by use_pam_wheel_group_for_su rule.The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice. - + @@ -41053,16 +47469,16 @@ the pam_securetty.so PAM module is properly enabled in re A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-2 CM-6(a) PR.AC-1 @@ -41103,7 +47519,7 @@ fi - restrict_strategy - name: Direct root Logins Not Allowed - copy: + ansible.builtin.copy: dest: /etc/securetty content: '' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -41140,15 +47556,15 @@ and nfsnobody has an unlocked password, disable it with t $ sudo usermod -L account - 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 + 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) A.6.SEC-OL3 @@ -41156,7 +47572,10 @@ and nfsnobody has an unlocked password, disable it with t 8.2 Disabling authentication for default system accounts makes it more difficult for attackers to make use of them to compromise a system. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t systemaccounts < <(awk -F: \ '($3 < 1000 && $3 != root && $3 != halt && $3 != sync && $3 != shutdown \ && $3 != nfsnobody) { print $1 }' /etc/passwd) @@ -41164,11 +47583,31 @@ readarray -t systemaccounts < <(awk -F: \ for systemaccount in "${systemaccounts[@]}"; do usermod -L "$systemaccount" done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.2 + - low_complexity + - medium_disruption + - medium_severity + - no_password_auth_for_systemaccounts + - no_reboot_needed + - restrict_strategy + +- name: Ensure that System Accounts Are Locked - Get All Local Users From /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) @@ -41185,6 +47624,7 @@ done getent_passwd Facts ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd | dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6 - NIST-800-53-CM-6(a) @@ -41203,6 +47643,7 @@ done password_lock: true loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int < 1000 - item.key not in ['root', 'halt', 'sync', 'shutdown', 'nfsnobody'] tags: @@ -41257,7 +47698,6 @@ system to become inaccessible. DSS05.05 DSS05.07 DSS06.03 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -41274,7 +47714,6 @@ system to become inaccessible. SR 1.9 SR 2.1 SR 6.2 - 1491 A.12.4.1 A.12.4.3 A.6.1.2 @@ -41300,15 +47739,19 @@ system to become inaccessible. PR.AC-1 PR.AC-4 PR.AC-6 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.6.SEC-OL3 + 1491 8.2.2 8.2 - OL09-00-003051 - SV-271845r1092247_rule + OL09-00-003051 + SV-271845r1092247_rule Ensuring shells are not given to system accounts upon login makes it more difficult for attackers to make use of system accounts. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != root \ && $7 != "\/sbin\/shutdown" && $7 != "\/sbin\/halt" && $7 != "\/bin\/sync") \ { print $1 }' /etc/passwd) @@ -41316,12 +47759,35 @@ readarray -t systemaccounts < <(awk -F: '($3 < 1000 && $3 != ro for systemaccount in "${systemaccounts[@]}"; do usermod -s /sbin/nologin "$systemaccount" done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure that System Accounts Do Not Run a Shell Upon Login - Get All Local + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003051 + - 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 @@ -41341,6 +47807,7 @@ done Variable From getent_passwd Facts ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd | dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003051 - NIST-800-53-AC-6 @@ -41363,6 +47830,7 @@ done shell: /sbin/nologin loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" 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'] @@ -41409,7 +47877,6 @@ ttyS1 DSS06.02 3.1.1 3.1.5 - CCI-000770 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -41447,15 +47914,15 @@ ttyS1 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 + 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 @@ -41463,13 +47930,37 @@ ttyS1 Preventing direct root login to serial port interfaces helps ensure accountability for actions taken on the systems using the root account. - sed -i '/ttyS/d' /etc/securetty + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sed -i '/ttyS/d' /etc/securetty + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Restrict Serial Port Root Logins - lineinfile: + - 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 @@ -41512,7 +48003,6 @@ vc/4 DSS06.02 3.1.1 3.1.5 - CCI-000770 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -41550,32 +48040,58 @@ vc/4 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 + 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 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 8.6.1 8.6 Preventing direct root login to virtual console devices helps ensure accountability for actions taken on the system using the root account. - sed -i '/^vc\/[0-9]/d' /etc/securetty + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +sed -i '/^vc\/[0-9]/d' /etc/securetty + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Restrict Virtual Console Root Logins - lineinfile: + - 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) + - PCI-DSSv4-8.6 + - PCI-DSSv4-8.6.1 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - securetty_root_login_console_only + +- name: Restrict Virtual Console Root Logins + ansible.builtin.lineinfile: dest: /etc/securetty regexp: ^vc/[0-9] state: absent + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.1 - NIST-800-171-3.1.5 @@ -41607,14 +48123,12 @@ sure that the following line exists in the file /etc/pam.d/suMembers of "wheel" or GID 0 groups are checked by default if the group option is not set for pam_wheel.so module. Therefore, members of these groups should be manually checked or a different group should be informed according to the site policy. - CCI-002165 - CCI-004895 FMT_SMF_EXT.1.1 - SRG-OS-000373-GPOS-00156 - SRG-OS-000312-GPOS-00123 + SRG-OS-000373-GPOS-00156 + SRG-OS-000312-GPOS-00123 A.5.SEC-OL1 - OL09-00-002361 - SV-271723r1091881_rule + OL09-00-002361 + SV-271723r1091881_rule The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice. @@ -41642,7 +48156,7 @@ fi - use_pam_wheel_for_su - name: Restrict usage of su command only to members of wheel group - replace: + ansible.builtin.replace: path: /etc/pam.d/su regexp: ^[\s]*#[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+use_uid$ replace: auth required pam_wheel.so use_uid @@ -41752,15 +48266,14 @@ parameter in /etc/login.defs to yes CREATE_HOME yes - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003052 - SV-271846r1092250_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003052 + SV-271846r1092250_rule If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if ( rpm --quiet -q shadow-utils && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if [ -e "/etc/login.defs" ] ; then @@ -41806,7 +48319,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ @@ -41816,7 +48329,7 @@ fi register: dupes - name: Deduplicate values from /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ @@ -41824,13 +48337,14 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/login.defs - lineinfile: + ansible.builtin.lineinfile: path: /etc/login.defs create: true regexp: (?i)^\s*CREATE_HOME\s+ line: CREATE_HOME yes state: present - when: '"shadow-utils" in ansible_facts.packages' + when: ( "shadow-utils" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-003052 - accounts_have_homedir_login_defs @@ -41861,7 +48375,6 @@ add or correct the FAIL_DELAY setting in /etc/ BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -41874,14 +48387,14 @@ add or correct the FAIL_DELAY setting in /etc/ AC-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00226 - OL09-00-003070 - SV-271850r1092262_rule + SRG-OS-000480-GPOS-00226 + OL09-00-003070 + SV-271850r1092262_rule Increasing the time between a failed authentication attempt and re-prompting to enter credentials helps to slow a single-threaded brute force attack. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if ( rpm --quiet -q shadow-utils && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_accounts_fail_delay='' @@ -41930,12 +48443,13 @@ fi - always - name: Set accounts logon fail delay - lineinfile: + ansible.builtin.lineinfile: dest: /etc/login.defs regexp: ^FAIL_DELAY line: FAIL_DELAY {{ var_accounts_fail_delay }} create: true - when: '"shadow-utils" in ansible_facts.packages' + when: ( "shadow-utils" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-003070 - NIST-800-53-AC-7(b) @@ -41972,7 +48486,6 @@ a file under /etc/security/limits.d/: 5.5.2.2 DSS01.05 DSS05.02 - CCI-000054 4.3.3.4 SR 3.1 SR 3.8 @@ -41981,20 +48494,20 @@ a file under /etc/security/limits.d/: A.13.2.1 A.14.1.2 A.14.1.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 AC-10 CM-6(a) PR.AC-5 - SRG-OS-000027-GPOS-00008 - OL09-00-002415 - SV-271753r1091971_rule + SRG-OS-000027-GPOS-00008 + OL09-00-002415 + SV-271753r1091971_rule Limiting simultaneous user logins can insulate the system from denial of service problems caused by excessive logins. Automated login processes operating improperly or maliciously may result in an exceptional number of simultaneous login sessions. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if ( rpm --quiet -q pam && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then var_accounts_max_concurrent_login_sessions='' @@ -42032,12 +48545,13 @@ fi - always - name: Find /etc/security/limits.d files containing maxlogins configuration - find: + ansible.builtin.find: paths: /etc/security/limits.d contains: ^[\s]*\*[\s]+(?:(?:hard)|(?:-))[\s]+maxlogins patterns: '*.conf' register: maxlogins - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 - DISA-STIG-OL09-00-002415 @@ -42052,14 +48566,15 @@ fi - name: Limit the Number of Concurrent Login Sessions Allowed Per User in files from limits.d - replace: + ansible.builtin.replace: dest: '{{ item.path }}' regexp: ^#?\*.*maxlogins.* replace: '* hard maxlogins {{ var_accounts_max_concurrent_login_sessions }}' with_items: - '{{ maxlogins.files }}' - when: '"pam" in ansible_facts.packages' + when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 - DISA-STIG-OL09-00-002415 @@ -42073,7 +48588,7 @@ fi - restrict_strategy - name: Limit the Number of Concurrent Login Sessions Allowed Per User - lineinfile: + ansible.builtin.lineinfile: state: present dest: /etc/security/limits.conf insertbefore: ^# End of file @@ -42082,7 +48597,8 @@ fi }}' create: true when: - - '"pam" in ansible_facts.packages' + - ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) - maxlogins.matched == 0 tags: - CJIS-5.5.2.2 @@ -42116,7 +48632,10 @@ Then, add the following entry to /etc/security/namespace.confPolyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /tmp directories being world-writable. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + # shellcheck disable=SC2174 mkdir -p --mode 000 /tmp/tmp-inst chmod 000 /tmp/tmp-inst @@ -42128,6 +48647,10 @@ if ! grep -Eq '^\s*/tmp\s+/tmp/tmp-inst/\s+level\s+root,adm$' /etc/security/name fi echo "/tmp /tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi @@ -42148,7 +48671,10 @@ Then, add the following entry to /etc/security/namespace.confPolyinstantiation of temporary directories is a proactive security measure which reduces chances of attacks that are made possible by /var/tmp directories being world-writable. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + # shellcheck disable=SC2174 mkdir -p --mode 000 /var/tmp/tmp-inst chmod 000 /var/tmp/tmp-inst @@ -42160,6 +48686,10 @@ if ! grep -Eq '^\s*/var/tmp\s+/var/tmp/tmp-inst/\s+level\s+root,adm$' /etc/secur fi echo "/var/tmp /var/tmp/tmp-inst/ level root,adm" >> /etc/security/namespace.conf fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi @@ -42171,8 +48701,9 @@ fi Set Interactive Session Timeout Setting the TMOUT option in /etc/profile ensures that -all user sessions will terminate based on inactivity. -The value of TMOUT should be exported and read only. +all user sessions will terminate based on inactivity. A value of 0 (zero) +disables the automatic logout feature and is therefore not a compliant setting. +The value of TMOUT should be a positive integer, exported, and read only. The TMOUT setting in a file loaded by /etc/profile, e.g. @@ -42191,8 +48722,6 @@ Using the typeset keyword is preferred for wider compatib DSS05.10 DSS06.10 3.1.11 - CCI-000057 - CCI-001133 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -42215,25 +48744,25 @@ Using the typeset keyword is preferred for wider compatib A.9.3.1 A.9.4.2 A.9.4.3 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-12 SC-10 AC-2(5) CM-6(a) PR.AC-7 - SRG-OS-000163-GPOS-00072 - SRG-OS-000029-GPOS-00010 + SRG-OS-000163-GPOS-00072 + SRG-OS-000029-GPOS-00010 R32 A.5.SEC-OL8 8.6.1 8.6 - OL09-00-002411 - SV-271750r1091962_rule + OL09-00-002411 + SV-271750r1091962_rule Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been @@ -42245,7 +48774,7 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_accounts_tmout='' -# if 0, no occurence of tmout found, if 1, occurence found +# if 0, no occurrence of tmout found, if 1, occurrence found tmout_found=0 @@ -42291,7 +48820,7 @@ fi - always - name: Correct any occurrence of TMOUT in /etc/profile - replace: + ansible.builtin.replace: path: /etc/profile regexp: ^[^#].*TMOUT=.* replace: typeset -xr TMOUT={{ var_accounts_tmout }} @@ -42314,7 +48843,7 @@ fi - restrict_strategy - name: Set Interactive Session Timeout - lineinfile: + ansible.builtin.lineinfile: path: /etc/profile.d/tmout.sh create: true regexp: TMOUT= @@ -42358,20 +48887,99 @@ is group-owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of their respective initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 Local initialization files for interactive users are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. - -awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") }' /etc/passwd + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '{if ($4 >= 1000 && $4 != 65534) print $4":"$6}' /etc/passwd | while IFS=: read -r gid home; do find -P "$home" -maxdepth 1 -type f -name "\.[^.]*" -exec chgrp -f --no-dereference -- $gid "{}" \;; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the group-owners of their respective initialization - files - ansible.builtin.command: - cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chgrp -f " $4" "$6"/.[^\.]?*") - }' /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Create + list of interactive users with GID and home directory + ansible.builtin.set_fact: + interactive_users: '{{ interactive_users | default([]) + [{''home'': item.value[4], + ''gid'': item.value[2]}] }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[2] | int >= 1000 | int + - item.value[2] | int != 65534 | int + - item.value[4] != "" + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Find + dot files in interactive user home directories + ansible.builtin.find: + paths: '{{ item.home }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + follow: false + register: user_dotfiles + loop: '{{ interactive_users | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.home != "" + tags: + - accounts_user_dot_group_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Group-Owned By The Primary Group - Set correct + group ownership for user initialization files + ansible.builtin.file: + path: '{{ item.1.path }}' + group: '{{ item.0.item.gid }}' + follow: false + loop: '{{ user_dotfiles.results | subelements(''files'', skip_missing=True) }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.1.path is defined tags: - accounts_user_dot_group_ownership - low_complexity @@ -42394,16 +49002,18 @@ following command: $ sudo chmod o-w FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002427 - SV-271765r1092007_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002427 + SV-271765r1092007_rule If user start-up files execute world-writable programs, especially in unprotected directories, they could be maliciously modified to destroy user files or otherwise compromise the system at the user level. If the system is compromised at the user level, it is easier to elevate privileges to eventually compromise the system at the root and network level. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + readarray -t world_writable_files < <(find / -xdev -type f -perm -0002 2> /dev/null) readarray -t interactive_home_dirs < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6 }' /etc/passwd) @@ -42415,12 +49025,29 @@ for world_writable in "${world_writable_files[@]}"; do fi done done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: User Initialization Files Must Not Run World-Writable Programs - Initialize + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002427 + - accounts_user_dot_no_world_writable_programs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Not Run World-Writable Programs - Initialize variables - set_fact: + ansible.builtin.set_fact: home_user_dirs: [] world_writable_files: [] + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42435,6 +49062,7 @@ done ansible.builtin.getent: database: passwd register: passwd_database + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42445,10 +49073,11 @@ done - restrict_strategy - name: User Initialization Files Must Not Run World-Writable Programs - Fill home_user_dirs - set_fact: + ansible.builtin.set_fact: home_user_dirs: '{{ home_user_dirs + [item.data[4]] }}' - when: item.data[4] is defined and item.data[2]|int >= 1000 and item.data[2]|int - != 65534 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.data[4] is defined and item.data[2]|int >= 1000 and item.data[2]|int != 65534 with_items: '{{ passwd_database.ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' tags: @@ -42465,6 +49094,9 @@ done ansible.builtin.shell: | find / -xdev -type f -perm -0002 2> /dev/null register: world_writable_files + changed_when: false + check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42484,6 +49116,7 @@ done recurse: true with_items: '{{ world_writable_files.stdout_lines }}' register: referenced_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002427 - accounts_user_dot_no_world_writable_programs @@ -42498,7 +49131,9 @@ done ansible.builtin.file: path: '{{ item.item }}' mode: o-w - when: item.matched > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.matched > 0 with_items: '{{ referenced_files.results }}' tags: - DISA-STIG-OL09-00-002427 @@ -42528,20 +49163,102 @@ is owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the ownership of their respective initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. - -awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") }' /etc/passwd + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +awk -F: '{if ($3 >= 1000 && $3 != 65534) print $3":"$6}' /etc/passwd | while IFS=: read -r uid home; do find -P "$home" -maxdepth 1 -type f -name "\.[^.]*" -exec chown -f --no-dereference -- $uid "{}" \;; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the owners of their respective initialization - files - ansible.builtin.command: - cmd: awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$6"/.[^\.]?*") - }' /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Create list + of interactive users with UID and home directory + ansible.builtin.set_fact: + interactive_users: '{{ interactive_users | default([]) + [{''uid'': item.value[1], + ''home'': item.value[4], ''username'': item.key}] }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[1] | int >= 1000 | int + - item.value[1] | int != 65534 | int + - item.value[4] != "" + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Find dot files + in interactive user home directories + ansible.builtin.find: + paths: '{{ item.home }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + follow: false + register: user_dotfiles + loop: '{{ interactive_users | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.home != "" + tags: + - accounts_user_dot_user_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: User Initialization Files Must Be Owned By the Primary User - Set correct + ownership for user initialization files + ansible.builtin.file: + path: '{{ item.1.path }}' + owner: '{{ item.0.item.username }}' + follow: false + loop: '{{ user_dotfiles.results | subelements(''files'', skip_missing=True) }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.0 is not failed + - item.0.item is defined + - item.0.item.username is defined + - item.1.path is defined tags: - accounts_user_dot_user_ownership - low_complexity @@ -42562,10 +49279,9 @@ awk -F':' '{ if ($3 >= 1000 && $3 != 65534) system("chown -f " $3" "$ Ensure that all interactive user initialization files executable search path statements do not contain statements that will reference a working directory other than the users home directory. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003053 - SV-271847r1092253_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003053 + SV-271847r1092253_rule The executable search path (typically the PATH environment variable) contains a list of directories for the shell to search to find executables. If this path includes the current working directory (other than the users home directory), @@ -42575,6 +49291,7 @@ an empty entry, such as a leading or trailing colon or two consecutive colons, this is interpreted as the current working directory. If deviations from the default system search path for the local interactive user are required, they must be documented with the Information System Security Officer (ISSO). + @@ -42588,24 +49305,43 @@ This rule checks if the home directory is properly defined in a folder which has at least one parent folder, like "user" in "/home/user" or "/remote/users/user". Therefore, this rule will report a finding for home directories like /users, /tmp or /. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003002 - SV-271833r1092607_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003002 + SV-271833r1092607_rule If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1 }' /etc/passwd); do # This follows the same logic of evaluation of home directories as used in OVAL. if ! grep -q $user /etc/passwd | cut -d: -f6 | grep '^\/\w*\/\w\{1,\}'; then sed -i "s/\($user:x:[0-9]*:[0-9]*:.*:\).*\(:.*\)$/\1\/home\/$user\2/g" /etc/passwd; fi done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003002 + - accounts_user_interactive_home_directory_defined + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined @@ -42618,6 +49354,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003002 - accounts_user_interactive_home_directory_defined @@ -42634,6 +49371,7 @@ done create_home: false loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[2]|int >= 1000 - item.value[2]|int != 65534 - item.value[2]|int < 61184 or item.value[2]|int > 65519 @@ -42662,24 +49400,43 @@ home directory assigned in /etc/passwd: $ sudo mkdir /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-003050 - SV-271844r1092244_rule + SRG-OS-000480-GPOS-00227 + OL09-00-003050 + SV-271844r1092244_rule If a local interactive user has a home directory defined that does not exist, the user may be given access to the / directory as the current working directory upon logon. This could create a Denial of Service because the user would not be able to access their logon configuration files, and it may give them visibility to system files they normally would not be able to access. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd); do mkhomedir_helper $user 0077; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003050 + - accounts_user_interactive_home_directory_exists + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42692,6 +49449,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42707,8 +49465,9 @@ done create_home: true loop: '{{ local_users }}' when: - - item.value[2]|int >= 1000 - - item.value[2]|int != 65534 + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[1]|int >= 1000 + - item.value[1]|int != 65534 tags: - DISA-STIG-OL09-00-003050 - accounts_user_interactive_home_directory_exists @@ -42738,12 +49497,14 @@ to an interactive user is group-owned by an interactive user.Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of folders or files in their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If a local interactive users files are group-owned by a group of which the user is not a member, unintended users may be able to access them. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do home_dir=$(getent passwd $user | cut -d: -f6) group=$(getent passwd $user | cut -d: -f4) @@ -42752,11 +49513,27 @@ for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $ # check systems that also check inodes timestamps. find $home_dir -not -group $group -exec chgrp -f --no-dereference $group {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_groupownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_groupownership - low_complexity @@ -42768,6 +49545,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_groupownership - low_complexity @@ -42783,6 +49561,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42800,7 +49579,9 @@ done group: '{{ item.0.value[2] }}' recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_groupownership - low_complexity @@ -42830,13 +49611,15 @@ to an interactive user is owned by an interactive user. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the ownership of folders or files in their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If local interactive users do not own the files in their directories, unauthorized users may be able to access them. Additionally, if files are not owned by the user, this could be an indication of system compromise. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $1 }' /etc/passwd); do home_dir=$(getent passwd $user | cut -d: -f6) # Only update the ownership when necessary. This will avoid changing the inode timestamp @@ -42844,11 +49627,27 @@ for user in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $ # check systems that also check inodes timestamps. find $home_dir -not -user $user -exec chown -f --no-dereference $user {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_ownership + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_ownership - low_complexity @@ -42860,6 +49659,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_ownership - low_complexity @@ -42875,6 +49675,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42892,7 +49693,9 @@ done owner: '{{ item.0.value[1] }}' recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_ownership - low_complexity @@ -42915,23 +49718,41 @@ directory with the following command: $ sudo chmod 0750 /home/USER/FILE_DIR Files that begin with a "." are excluded from this requirement. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 If a local interactive user files have excessive permissions, unintended users may be able to access or modify them. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + for home_dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534 && $6 != "/") print $6 }' /etc/passwd); do # Only update the permissions when necessary. This will avoid changing the inode timestamp when # the permission is already defined as expected, therefore not impacting in possible integrity # check systems that also check inodes timestamps. find "$home_dir" -perm /7027 \! -type l -exec chmod u-s,g-w-s,o=- {} \; done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Get all local users from /etc/passwd + - name: Gather the package facts + package_facts: + manager: auto + tags: + - accounts_users_home_files_permissions + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Get all local users from /etc/passwd ansible.builtin.getent: database: passwd split: ':' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_permissions - low_complexity @@ -42943,6 +49764,7 @@ done - name: Create local_users variable from the getent output ansible.builtin.set_fact: local_users: '{{ ansible_facts.getent_passwd|dict2items }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - accounts_users_home_files_permissions - low_complexity @@ -42957,6 +49779,7 @@ done register: path_exists loop: '{{ local_users }}' when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - item.value[1]|int >= 1000 - item.value[1]|int != 65534 - item.value[4] != "/" @@ -42976,7 +49799,9 @@ done follow: false recurse: true loop: '{{ local_users|zip(path_exists.results)|list }}' - when: item.1.stat is defined and item.1.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.1.stat is defined and item.1.stat.exists tags: - accounts_users_home_files_permissions - low_complexity @@ -43006,10 +49831,9 @@ are group-owners of one and only one home directory. Due to OVAL limitation, this rule can report a false negative in a specific situation where two interactive users swap the group-ownership of their respective home directories. - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002514 - SV-271783r1092061_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002514 + SV-271783r1092061_rule If the Group Identifier (GID) of a local interactive users home directory is not the same as the primary GID of the user, this would allow unauthorized access to the users files, and users that share the same group may not be @@ -43090,11 +49914,10 @@ following command: $ sudo chmod 0740 /home/USER/.INIT_FILE - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002513 - SV-271782r1092058_rule + OL09-00-002513 + SV-271782r1092058_rule Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon. @@ -43193,10 +50016,9 @@ following command: $ sudo chmod 0750 /home/USER - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002515 - SV-271784r1092064_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002515 + SV-271784r1092064_rule Excessive permissions on local interactive user home directories may allow unauthorized access to user files by other users. @@ -43304,7 +50126,6 @@ updates as of version 0.1.62. DSS05.04 DSS05.07 DSS06.02 - CCI-000225 4.3.3.7.3 SR 2.1 SR 5.2 @@ -43331,15 +50152,15 @@ updates as of version 0.1.62. 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 + 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 CM-6(a) AC-6(1) CM-6(a) @@ -43475,7 +50296,6 @@ other. BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43492,7 +50312,7 @@ other. execute code provided by unprivileged users, and potentially malicious code. - name: Get root paths which are not symbolic links - stat: + ansible.builtin.stat: path: '{{ item }}' changed_when: false failed_when: false @@ -43509,7 +50329,7 @@ and potentially malicious code. - restrict_strategy - name: Disable writability to root directories - file: + ansible.builtin.file: path: '{{ item.item }}' mode: g-w,o-w with_items: '{{ root_paths.results }}' @@ -43552,7 +50372,6 @@ These empty elements have the same effect as a single . c BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43591,6 +50410,7 @@ a member. + Sensible umask Enter default user umask @@ -43613,36 +50433,35 @@ as follows: BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.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 + 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(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 R36 A.6.SEC-OL5 - OL09-00-002301 - SV-271693r1091791_rule + OL09-00-002301 + SV-271693r1091791_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. # Remediation is applicable only in certain platforms -if rpm --quiet -q bash; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q bash; }; then var_accounts_user_umask='' @@ -43688,7 +50507,9 @@ fi check_mode: true changed_when: false register: umask_replace - when: '"bash" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"bash" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002301 - NIST-800-53-AC-6(1) @@ -43706,6 +50527,7 @@ fi regexp: ^([^#]*\b)umask\s+\d+$ replace: \g<1>umask {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"bash" in ansible_facts.packages' - umask_replace.found > 0 tags: @@ -43725,6 +50547,7 @@ fi path: /etc/bashrc line: umask {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"bash" in ansible_facts.packages' - umask_replace.found == 0 tags: @@ -43758,32 +50581,33 @@ add or correct the umask setting in /etc/csh.c BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.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 + 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(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 - OL09-00-002302 - SV-271694r1091794_rule + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 + OL09-00-002302 + SV-271694r1091794_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_user_umask='' @@ -43792,8 +50616,25 @@ grep -q "^\s*umask" /etc/csh.cshrc && \ if ! [ $? -eq 0 ]; then echo "umask $var_accounts_user_umask" >> /etc/csh.cshrc fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_user_umask # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002302 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - accounts_umask_etc_csh_cshrc + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: var_accounts_user_umask: !!str tags: @@ -43807,6 +50648,7 @@ fi check_mode: true changed_when: false register: umask_replace + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43823,7 +50665,9 @@ fi path: /etc/csh.cshrc regexp: ^(\s*)umask(\s+).* replace: \g<1>umask\g<2>{{ var_accounts_user_umask }} - when: umask_replace.found > 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - umask_replace.found > 0 tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43840,7 +50684,9 @@ fi create: true path: /etc/csh.cshrc line: umask {{ var_accounts_user_umask }} - when: umask_replace.found == 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - umask_replace.found == 0 tags: - DISA-STIG-OL09-00-002302 - NIST-800-53-AC-6(1) @@ -43879,7 +50725,6 @@ add or correct the UMASK setting in /etc/login BAI10.02 BAI10.03 BAI10.05 - CCI-000366 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -43893,30 +50738,30 @@ add or correct the UMASK setting in /etc/login A.14.2.4 A.14.2.5 A.6.1.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 + 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(1) CM-6(a) PR.IP-1 PR.IP-2 - SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00228 R36 A.6.SEC-OL5 - OL09-00-002304 - SV-271696r1091800_rule + OL09-00-002304 + SV-271696r1091800_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read and written to by unauthorized users. # Remediation is applicable only in certain platforms -if rpm --quiet -q shadow-utils; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q shadow-utils; }; then var_accounts_user_umask='' @@ -43972,7 +50817,9 @@ fi check_mode: true changed_when: false register: result_umask_is_set - when: '"shadow-utils" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"shadow-utils" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002304 - NIST-800-53-AC-6(1) @@ -43990,6 +50837,7 @@ fi regexp: ^(\s*)UMASK(\s+).* replace: \g<1>UMASK\g<2>{{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found > 0 tags: @@ -44009,6 +50857,7 @@ fi path: /etc/login.defs line: UMASK {{ var_accounts_user_umask }} when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"shadow-utils" in ansible_facts.packages' - result_umask_is_set.found == 0 tags: @@ -44037,7 +50886,7 @@ add or correct the umask setting in /etc/profi umask -Note that /etc/profile also reads scrips within /etc/profile.d directory. +Note that /etc/profile also reads scripts within /etc/profile.d directory. These scripts are also valid files to set umask value. Therefore, they should also be considered during the check and properly remediated, if necessary. 18 @@ -44045,34 +50894,35 @@ considered during the check and properly remediated, if necessary.BAI03.01 BAI03.02 BAI03.03 - CCI-000366 4.3.4.3.3 A.14.1.1 A.14.2.1 A.14.2.5 A.6.1.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 + 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(1) CM-6(a) PR.IP-2 - SRG-OS-000480-GPOS-00228 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + SRG-OS-000480-GPOS-00227 R36 A.6.SEC-OL5 - OL09-00-002303 - SV-271695r1091797_rule + OL09-00-002303 + SV-271695r1091797_rule The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + var_accounts_user_umask='' @@ -44085,8 +50935,25 @@ done if ! grep -qrE '^[^#]*umask' /etc/profile*; then echo "umask $var_accounts_user_umask" >> /etc/profile fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: XCCDF Value var_accounts_user_umask # promote to variable + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002303 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - accounts_umask_etc_profile + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_accounts_user_umask # promote to variable set_fact: var_accounts_user_umask: !!str tags: @@ -44102,6 +50969,7 @@ fi - '*.sh' contains: ^[\s]*umask\s+\d+ register: result_profile_d_files + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44121,7 +50989,9 @@ fi replace: \1umask {{ var_accounts_user_umask }} loop: '{{ result_profile_d_files.files }}' register: result_umask_replaced_profile_d - when: result_profile_d_files.matched + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - result_profile_d_files.matched tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44140,7 +51010,9 @@ fi mode: 420 path: /etc/profile line: umask {{ var_accounts_user_umask }} - when: not result_profile_d_files.matched + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not result_profile_d_files.matched tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44159,6 +51031,7 @@ fi regexp: ^(\s*)umask\s+\d+ replace: \1umask {{ var_accounts_user_umask }} register: result_umask_replaced_profile + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002303 - NIST-800-53-AC-6(1) @@ -44181,18 +51054,19 @@ fi Ensure the Default Umask is Set Correctly For Interactive Users Remove the UMASK environment variable from all interactive users initialization files. - CCI-000366 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00228 - OL09-00-003060 - SV-271848r1092256_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00228 + OL09-00-003060 + SV-271848r1092256_rule The umask controls the default access mode assigned to newly created files. A umask of 077 limits new files to mode 700 or less permissive. Although umask can be represented as a four-digit number, the first digit representing special access modes is typically ignored or required to be 0. This requirement applies to the globally configured system defaults and the local interactive user defaults for each account on the system. - + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + while IFS= read -r dir; do while IFS= read -r -d '' file; do if [ "$(basename $file)" != ".bash_history" ]; then @@ -44200,18 +51074,96 @@ while IFS= read -r dir; do fi done < <(find $dir -maxdepth 1 -type f -name ".*" -print0) done < <(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6}' /etc/passwd) + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure interactive local users are the owners of their respective initialization - files - ansible.builtin.shell: - cmd: |- - for dir in $(awk -F':' '{ if ($3 >= 1000 && $3 != 65534) print $6}' /etc/passwd); do - for file in $(find $dir -maxdepth 1 -type f -name ".*"); do - if [ "$(basename $file)" != ".bash_history" ]; then - sed -i 's/^\(\s*umask\s*\)/#\1/g' $file - fi - done - done + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Get interactive + users from passwd file + ansible.builtin.getent: + database: passwd + register: passwd_entries + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Filter interactive + users and get home directories + ansible.builtin.set_fact: + interactive_user_homes: '{{ interactive_user_homes | default([]) + [item.value[4]] + }}' + loop: '{{ passwd_entries.ansible_facts.getent_passwd | dict2items }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.value[2] | int >= 1000 | int + - item.value[2] | int != 65534 | int + - item.value[4] != "" + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Find dot + files in interactive user home directories + ansible.builtin.find: + paths: '{{ item }}' + patterns: .* + file_type: file + hidden: true + depth: 1 + register: user_dotfiles + with_items: '{{ interactive_user_homes | default([]) }}' + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item != "" + tags: + - DISA-STIG-OL09-00-003060 + - accounts_umask_interactive_users + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure the Default Umask is Set Correctly For Interactive Users - Comment + out umask statements in user initialization files + ansible.builtin.replace: + path: '{{ item.1.path }}' + regexp: ^\s*umask\s+ + replace: '#\g<0>' + backup: false + with_subelements: + - '{{ user_dotfiles.results }}' + - files + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.0 is not skipped + - item.1.path is defined + - '''.bash_history'' not in item.1.path' tags: - DISA-STIG-OL09-00-003060 - accounts_umask_interactive_users @@ -44318,12 +51270,13 @@ fi - reboot_required - restrict_strategy -- name: Verify GRUB_DISABLE_RECOVERY=true - lineinfile: +- name: Disable Recovery Booting - Verify GRUB_DISABLE_RECOVERY=true + ansible.builtin.lineinfile: path: /etc/default/grub regexp: ^GRUB_DISABLE_RECOVERY=.* line: GRUB_DISABLE_RECOVERY=true state: present + register: grub_config_changed when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44334,10 +51287,12 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL - when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages +- name: Disable Recovery Booting - Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) + - grub_config_changed is changed tags: - grub2_disable_recovery - low_complexity @@ -44371,15 +51326,12 @@ Run the following command to update command line for already installed kernels:< # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="force" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "iommu" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"iommu=[^\"]*\"(.*]\s*)/\1\"iommu=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"iommu=[^\"]*\"(.*]\s*)/\1\"iommu=force\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"iommu=$expected_value\"]" >> "$KARGS_DIR/10-iommu.toml" + echo "kargs = [\"iommu=force\"]" >> "$KARGS_DIR/10-iommu.toml" fi else @@ -44402,8 +51354,10 @@ fi - restrict_strategy - unknown_severity -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="iommu=force" +- name: Check if iommu argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44413,6 +51367,37 @@ fi - reboot_required - restrict_strategy - unknown_severity + +- name: Check if iommu argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="iommu=force" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('iommu=force')) or ((etc_default_grub['content'] + | b64decode) is not search('iommu=force')) + tags: + - grub2_enable_iommu_force + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + - unknown_severity [customizations.kernel] append = "iommu=force" @@ -44443,15 +51428,12 @@ preventing data leaks. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "init_on_alloc" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"init_on_alloc=[^\"]*\"(.*]\s*)/\1\"init_on_alloc=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"init_on_alloc=[^\"]*\"(.*]\s*)/\1\"init_on_alloc=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"init_on_alloc=$expected_value\"]" >> "$KARGS_DIR/10-init_on_alloc.toml" + echo "kargs = [\"init_on_alloc=1\"]" >> "$KARGS_DIR/10-init_on_alloc.toml" fi else @@ -44474,8 +51456,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" +- name: Check if init_on_alloc argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44485,6 +51469,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if init_on_alloc argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('init_on_alloc=1')) or ((etc_default_grub['content'] + | b64decode) is not search('init_on_alloc=1')) + tags: + - grub2_init_on_alloc_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "init_on_alloc=1" @@ -44529,15 +51544,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_l1tf_options='' -expected_value="$var_l1tf_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "l1tf" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"l1tf=[^\"]*\"(.*]\s*)/\1\"l1tf=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"l1tf=[^\"]*\"(.*]\s*)/\1\"l1tf=$var_l1tf_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"l1tf=$expected_value\"]" >> "$KARGS_DIR/10-l1tf.toml" + echo "kargs = [\"l1tf=$var_l1tf_options\"]" >> "$KARGS_DIR/10-l1tf.toml" fi else @@ -44565,8 +51579,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options }}" +- name: Check if l1tf argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44576,6 +51592,38 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if l1tf argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="l1tf={{ var_l1tf_options + }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('l1tf=' ~ var_l1tf_options)) or ((etc_default_grub['content'] + | b64decode) is not search('l1tf=' ~ var_l1tf_options)) + tags: + - grub2_l1tf_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "l1tf=" @@ -44611,15 +51659,12 @@ trying to exploit a vulnerability such as Rowhammer. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="0" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "mce" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mce=[^\"]*\"(.*]\s*)/\1\"mce=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mce=[^\"]*\"(.*]\s*)/\1\"mce=0\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"mce=$expected_value\"]" >> "$KARGS_DIR/10-mce.toml" + echo "kargs = [\"mce=0\"]" >> "$KARGS_DIR/10-mce.toml" fi else @@ -44642,8 +51687,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="mce=0" +- name: Check if mce argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44653,6 +51700,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if mce argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="mce=0" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('mce=0')) or ((etc_default_grub['content'] | + b64decode) is not search('mce=0')) + tags: + - grub2_mce_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "mce=0" @@ -44706,15 +51784,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_mds_options='' -expected_value="$var_mds_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "mds" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mds=[^\"]*\"(.*]\s*)/\1\"mds=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"mds=[^\"]*\"(.*]\s*)/\1\"mds=$var_mds_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"mds=$expected_value\"]" >> "$KARGS_DIR/10-mds.toml" + echo "kargs = [\"mds=$var_mds_options\"]" >> "$KARGS_DIR/10-mds.toml" fi else @@ -44742,8 +51819,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="mds={{ var_mds_options }}" +- name: Check if mds argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44753,6 +51832,38 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if mds argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="mds={{ var_mds_options + }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('mds=' ~ var_mds_options)) or ((etc_default_grub['content'] + | b64decode) is not search('mds=' ~ var_mds_options)) + tags: + - grub2_mds_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "mds=" @@ -44772,7 +51883,7 @@ memory pages in the user space, it is enabled by default since Linux kernel 3.7. But it could be disabled through kernel boot parameters. Ensure that Supervisor Mode Access Prevention (SMAP) is not disabled by -the nosmap boot paramenter option. +the nosmap boot parameter option. Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub doesn't contain the argument nosmap. @@ -44785,7 +51896,7 @@ manipulation of data in the user space. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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*\"nosmap=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"nosmap=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" else @@ -44809,8 +51920,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" +- name: Check if nosmap argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44820,6 +51933,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if nosmap argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="nosmap" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('nosmap')) or ((etc_default_grub['content'] | b64decode) + is search('nosmap')) + tags: + - grub2_nosmap_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -44835,7 +51979,7 @@ it is enabled by default since Linux kernel 3.0. But it could be disabled throug kernel boot parameters. Ensure that Supervisor Mode Execution Prevention (SMEP) is not disabled by -the nosmep boot paramenter option. +the nosmep boot parameter option. Check that the line GRUB_CMDLINE_LINUX="..." within /etc/default/grub doesn't contain the argument nosmep. @@ -44848,7 +51992,7 @@ the kernel to unintentionally execute code in less privileged memory space.# Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 @@ -44872,8 +52016,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" +- name: Check if nosmep argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44883,6 +52029,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if nosmep argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + 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: /sbin/grubby --update-kernel=ALL --remove-args="nosmep" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('nosmep')) or ((etc_default_grub['content'] | b64decode) + is search('nosmep')) + tags: + - grub2_nosmep_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -44917,15 +52094,12 @@ architecture. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "page_alloc.shuffle" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_alloc.shuffle=[^\"]*\"(.*]\s*)/\1\"page_alloc.shuffle=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_alloc.shuffle=[^\"]*\"(.*]\s*)/\1\"page_alloc.shuffle=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"page_alloc.shuffle=$expected_value\"]" >> "$KARGS_DIR/10-page_alloc_shuffle.toml" + echo "kargs = [\"page_alloc.shuffle=1\"]" >> "$KARGS_DIR/10-page_alloc_shuffle.toml" fi else @@ -44948,8 +52122,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" +- name: Check if page_alloc.shuffle argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -44959,6 +52135,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if page_alloc.shuffle argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('page_alloc.shuffle=1')) or ((etc_default_grub['content'] + | b64decode) is not search('page_alloc.shuffle=1')) + tags: + - grub2_page_alloc_shuffle_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "page_alloc.shuffle=1" @@ -44982,14 +52189,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... pti=on ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="pti=on" - CCI-002824 - CCI-000381 SI-16 - SRG-OS-000433-GPOS-00193 - SRG-OS-000095-GPOS-00049 + SRG-OS-000433-GPOS-00193 + SRG-OS-000095-GPOS-00049 R8 - OL09-00-002391 - SV-271735r1091917_rule + OL09-00-002391 + SV-271735r1091917_rule Kernel page-table isolation is a kernel feature that mitigates the Meltdown security vulnerability and hardens the kernel against attempts to bypass kernel address space layout @@ -44997,15 +52202,12 @@ randomization (KASLR). # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="on" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "pti" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"pti=[^\"]*\"(.*]\s*)/\1\"pti=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"pti=[^\"]*\"(.*]\s*)/\1\"pti=on\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"pti=$expected_value\"]" >> "$KARGS_DIR/10-pti.toml" + echo "kargs = [\"pti=on\"]" >> "$KARGS_DIR/10-pti.toml" fi else @@ -45030,8 +52232,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="pti=on" +- name: Check if pti argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45043,6 +52247,41 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if pti argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="pti=on" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('pti=on')) or ((etc_default_grub['content'] + | b64decode) is not search('pti=on')) + tags: + - DISA-STIG-OL09-00-002391 + - NIST-800-53-SI-16 + - grub2_pti_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "pti=on" @@ -45090,15 +52329,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_rng_core_default_quality='' -expected_value="$var_rng_core_default_quality" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "rng_core.default_quality" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"rng_core.default_quality=[^\"]*\"(.*]\s*)/\1\"rng_core.default_quality=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"rng_core.default_quality=[^\"]*\"(.*]\s*)/\1\"rng_core.default_quality=$var_rng_core_default_quality\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"rng_core.default_quality=$expected_value\"]" >> "$KARGS_DIR/10-rng_core_default_quality.toml" + echo "kargs = [\"rng_core.default_quality=$var_rng_core_default_quality\"]" >> "$KARGS_DIR/10-rng_core_default_quality.toml" fi else @@ -45126,9 +52364,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ var_rng_core_default_quality - }}" +- name: Check if rng_core.default_quality argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45138,6 +52377,39 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if rng_core.default_quality argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="rng_core.default_quality={{ + var_rng_core_default_quality }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('rng_core.default_quality=' ~ var_rng_core_default_quality)) + or ((etc_default_grub['content'] | b64decode) is not search('rng_core.default_quality=' + ~ var_rng_core_default_quality)) + tags: + - grub2_rng_core_default_quality_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "rng_core.default_quality=" @@ -45176,15 +52448,12 @@ Overall, this reduces the kernel attack surface area by isolating slabs from eac # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="yes" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "slab_nomerge" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slab_nomerge=[^\"]*\"(.*]\s*)/\1\"slab_nomerge=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slab_nomerge=[^\"]*\"(.*]\s*)/\1\"slab_nomerge=yes\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"slab_nomerge=$expected_value\"]" >> "$KARGS_DIR/10-slab_nomerge.toml" + echo "kargs = [\"slab_nomerge=yes\"]" >> "$KARGS_DIR/10-slab_nomerge.toml" fi else @@ -45207,8 +52476,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" +- name: Check if slab_nomerge argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45218,6 +52489,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if slab_nomerge argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="slab_nomerge=yes" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('slab_nomerge=yes')) or ((etc_default_grub['content'] + | b64decode) is not search('slab_nomerge=yes')) + tags: + - grub2_slab_nomerge_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "slab_nomerge=yes" @@ -45257,7 +52559,7 @@ Run the following command to update command line for already installed kernels:< Disabling Speculative Store Bypass may impact performance of the system. R8 - In vulnerable processsors, the speculatively forwarded store can be used in a cache side channel + In vulnerable processors, the speculatively forwarded store can be used in a cache side channel attack. An example of this is reading memory to which the attacker does not directly have access, for example inside the sandboxed code. # Remediation is applicable only in certain platforms @@ -45265,15 +52567,14 @@ if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet var_spec_store_bypass_disable_options='' -expected_value="$var_spec_store_bypass_disable_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "spec_store_bypass_disable" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spec_store_bypass_disable=[^\"]*\"(.*]\s*)/\1\"spec_store_bypass_disable=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spec_store_bypass_disable=[^\"]*\"(.*]\s*)/\1\"spec_store_bypass_disable=$var_spec_store_bypass_disable_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"spec_store_bypass_disable=$expected_value\"]" >> "$KARGS_DIR/10-spec_store_bypass_disable.toml" + echo "kargs = [\"spec_store_bypass_disable=$var_spec_store_bypass_disable_options\"]" >> "$KARGS_DIR/10-spec_store_bypass_disable.toml" fi else @@ -45301,9 +52602,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ var_spec_store_bypass_disable_options - }}" +- name: Check if spec_store_bypass_disable argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45313,6 +52615,39 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if spec_store_bypass_disable argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="spec_store_bypass_disable={{ + var_spec_store_bypass_disable_options }}" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('spec_store_bypass_disable=' ~ var_spec_store_bypass_disable_options)) + or ((etc_default_grub['content'] | b64decode) is not search('spec_store_bypass_disable=' + ~ var_spec_store_bypass_disable_options)) + tags: + - grub2_spec_store_bypass_disable_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "spec_store_bypass_disable=" @@ -45351,15 +52686,12 @@ access to. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -expected_value="on" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"spectre_v2=[^\"]*\"(.*]\s*)/\1\"spectre_v2=on\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"spectre_v2=$expected_value\"]" >> "$KARGS_DIR/10-spectre_v2.toml" + echo "kargs = [\"spectre_v2=on\"]" >> "$KARGS_DIR/10-spectre_v2.toml" fi else @@ -45382,8 +52714,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" +- name: Check if spectre_v2 argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45393,6 +52727,37 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if spectre_v2 argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + 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: /sbin/grubby --update-kernel=ALL --args="spectre_v2=on" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is not search('spectre_v2=on')) or ((etc_default_grub['content'] + | b64decode) is not search('spectre_v2=on')) + tags: + - grub2_spectre_v2_argument + - high_severity + - low_disruption + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] append = "spectre_v2=on" @@ -45431,7 +52796,7 @@ access when the system is rebooted. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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*\"systemd.debug-shell=[^\"]*\"\s*]/{:a;N;/^\n$/ba;N;/match-architectures.*/d;}" "$KARGS_DIR/*.toml" sed -i -E -e "s/^(\s*kargs\s*=\s*\[.*)\"systemd.debug-shell=[^\"]*\"[,[:space:]]*(.*]\s*)/\1\2/" -e "s/^(\s*kargs.*),\s*\]$/\1\]/" "$KARGS_DIR/*.toml" else @@ -45455,8 +52820,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" +- name: Check if systemd.debug-shell argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: @@ -45466,6 +52833,37 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if systemd.debug-shell argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.debug-shell" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - (grubby_info.stdout is search('systemd.debug-shell')) or ((etc_default_grub['content'] + | b64decode) is search('systemd.debug-shell')) + tags: + - grub2_systemd_debug-shell_argument_absent + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy @@ -45489,29 +52887,24 @@ Run the following command to update command line for already installed kernels:< The vsyscall emulation is only available on x86_64 architecture (CONFIG_X86_VSYSCALL_EMULATION) making this rule not applicable to other CPU architectures. - CCI-000366 - CCI-001084 CM-7(a) FPT_ASLR_EXT.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - OL09-00-002393 - SV-271737r1094967_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-002393 + SV-271737r1094967_rule Virtual Syscalls provide an opportunity of attack for a user who has control of the return instruction pointer. # Remediation is applicable only in certain platforms if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ( grep -sqE "^.*\.x86_64$" /proc/sys/kernel/osrelease || grep -sqE "^x86_64$" /proc/sys/kernel/arch; ); }; then -expected_value="none" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "vsyscall" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"vsyscall=[^\"]*\"(.*]\s*)/\1\"vsyscall=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"vsyscall=[^\"]*\"(.*]\s*)/\1\"vsyscall=none\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"vsyscall=$expected_value\"]" >> "$KARGS_DIR/10-vsyscall.toml" + echo "kargs = [\"vsyscall=none\"]" >> "$KARGS_DIR/10-vsyscall.toml" fi else @@ -45536,8 +52929,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" +- name: Check if vsyscall argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) @@ -45551,6 +52946,44 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if vsyscall argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - ansible_architecture == "x86_64" + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none" + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - ansible_architecture == "x86_64" + - (grubby_info.stdout is not search('vsyscall=none')) or ((etc_default_grub['content'] + | b64decode) is not search('vsyscall=none')) + tags: + - DISA-STIG-OL09-00-002393 + - NIST-800-53-CM-7(a) + - grub2_vsyscall_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "vsyscall=none" @@ -45565,7 +52998,6 @@ append = "vsyscall=none" Non-UEFI GRUB2 bootloader configuration Non-UEFI GRUB2 bootloader configuration - Verify /boot/grub2/grub.cfg Group Ownership The file /boot/grub2/grub.cfg should @@ -45573,7 +53005,8 @@ be group-owned by the root group to prevent destruction or modification of the file. To properly set the group owner of /boot/grub2/grub.cfg, run the command: -$ sudo chgrp root /boot/grub2/grub.cfg + + $ sudo chgrp root /boot/grub2/grub.cfg 12 13 @@ -45589,7 +53022,6 @@ To properly set the group owner of /boot/grub2/grub.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45632,20 +53064,32 @@ To properly set the group owner of /boot/grub2/grub.cfg, PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 2.2 - OL09-00-002530 - SV-271792r1094968_rule + OL09-00-002530 + SV-271792r1094968_rule The root group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chgrp 0 /boot/grub2/grub.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/grub.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/grub.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45670,16 +53114,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists +- name: Set the file_groupowner_grub2_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_grub2_cfg_newgroup: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -45697,16 +53138,40 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/grub.cfg - file: +- name: Test for existence /boot/grub2/grub.cfg + ansible.builtin.stat: path: /boot/grub2/grub.cfg - group: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002530 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/grub.cfg + ansible.builtin.file: + path: /boot/grub2/grub.cfg + follow: false + group: '{{ file_groupowner_grub2_cfg_newgroup }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -45738,7 +53203,8 @@ fi group to prevent reading or modification of the file. To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg + + $ sudo chgrp root /boot/grub2/user.cfg 12 13 @@ -45754,7 +53220,6 @@ To properly set the group owner of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45797,7 +53262,7 @@ To properly set the group owner of /boot/grub2/user.cfg, PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 @@ -45805,11 +53270,23 @@ To properly set the group owner of /boot/grub2/user.cfg, The root group is a highly-privileged group. Furthermore, the group-owner of this file should not have any access privileges anyway. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chgrp 0 /boot/grub2/user.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45833,16 +53310,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists +- name: Set the file_groupowner_user_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_user_cfg_newgroup: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -45859,16 +53333,39 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - group: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + group: '{{ file_groupowner_user_cfg_newgroup }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -45900,7 +53397,8 @@ be owned by the root user to prevent destruction or modification of the file. To properly set the owner of /boot/grub2/grub.cfg, run the command: -$ sudo chown root /boot/grub2/grub.cfg + + $ sudo chown root /boot/grub2/grub.cfg 12 13 @@ -45916,7 +53414,6 @@ To properly set the owner of /boot/grub2/grub.cfg, run th DSS05.07 DSS06.02 3.4.5 - CCI-000366 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -45959,19 +53456,31 @@ To properly set the owner of /boot/grub2/grub.cfg, run th PR.AC-4 PR.DS-5 Req-7.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R29 A.6.SEC-OL2 2.2.6 2.2 - OL09-00-002531 - SV-271793r1092605_rule + OL09-00-002531 + SV-271793r1092605_rule Only root should be able to modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chown 0 /boot/grub2/grub.cfg +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/boot/grub2/grub.cfg" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /boot/grub2/grub.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -45996,16 +53505,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists +- name: Set the file_owner_grub2_cfg_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_grub2_cfg_newown: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -46023,16 +53529,40 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /boot/grub2/grub.cfg - file: +- name: Test for existence /boot/grub2/grub.cfg + ansible.builtin.stat: path: /boot/grub2/grub.cfg - owner: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002531 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_grub2_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /boot/grub2/grub.cfg + ansible.builtin.file: + path: /boot/grub2/grub.cfg + follow: false + owner: '{{ file_owner_grub2_cfg_newown }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46064,7 +53594,8 @@ fi user to prevent reading or modification of the file. To properly set the owner of /boot/grub2/user.cfg, run the command: -$ sudo chown root /boot/grub2/user.cfg + + $ sudo chown root /boot/grub2/user.cfg 12 13 @@ -46080,7 +53611,6 @@ To properly set the owner of /boot/grub2/user.cfg, run th DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46130,11 +53660,23 @@ To properly set the owner of /boot/grub2/user.cfg, run th Only root should be able to modify important boot parameters. Also, non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then -chown 0 /boot/grub2/user.cfg +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -46158,16 +53700,13 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists +- name: Set the file_owner_user_cfg_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_user_cfg_newown: '0' when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - CJIS-5.5.2.2 @@ -46184,16 +53723,39 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - owner: '0' + register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + owner: '{{ file_owner_user_cfg_newown }}' + when: + - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46238,7 +53800,6 @@ To properly set the permissions of /boot/grub2/grub.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46286,9 +53847,9 @@ To properly set the permissions of /boot/grub2/grub.cfg, 2.2 Proper permissions ensure that only the root user can modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then chmod u-xs,g-xwrs,o-xwrt /boot/grub2/grub.cfg @@ -46313,15 +53874,13 @@ fi - no_reboot_needed - name: Test for existence /boot/grub2/grub.cfg - stat: + ansible.builtin.stat: path: /boot/grub2/grub.cfg register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - NIST-800-171-3.4.5 @@ -46337,15 +53896,13 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/grub.cfg - file: + ansible.builtin.file: path: /boot/grub2/grub.cfg mode: u-xs,g-xwrs,o-xwrt when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46388,7 +53945,6 @@ To properly set the permissions of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46436,9 +53992,9 @@ To properly set the permissions of /boot/grub2/user.cfg, 2.2 Proper permissions ensure that only the root user can read or modify important boot parameters. - + # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ ! -d /sys/firmware/efi ] && { ! ( { rpm --quiet -q kernel ;} && { rpm --quiet -q rpm-ostree ;} && { rpm --quiet -q bootc ;} && { ! rpm --quiet -q openshift-kubelet ;} ); }; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ); }; then chmod u-xs,g-xwrs,o-xwrt /boot/grub2/user.cfg @@ -46463,15 +54019,13 @@ fi - no_reboot_needed - name: Test for existence /boot/grub2/user.cfg - stat: + ansible.builtin.stat: path: /boot/grub2/user.cfg register: file_exists when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) tags: - NIST-800-171-3.4.5 @@ -46487,15 +54041,13 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /boot/grub2/user.cfg - file: + ansible.builtin.file: path: /boot/grub2/user.cfg mode: u-xs,g-xwrs,o-xwrt when: - - '"/boot/efi" not in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - - not ( "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 + - not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] ) - file_exists.stat is defined and file_exists.stat.exists tags: @@ -46534,7 +54086,10 @@ admin, or administrator for the grub2 superuser account. Change the superuser to a different username (The default is 'root'). $ sed -i 's/\(set superusers=\).*/\1"<unique user ID>"/g' /etc/grub.d/01_users - +The line mentioned above must be followed by the line +export superusers +so that the superusers is honored. + Once the superuser account has been added, update the @@ -46564,7 +54119,6 @@ Also, do NOT manually add the superuser account and password to the DSS06.06 DSS06.10 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46639,9 +54193,9 @@ Also, do NOT manually add the superuser account and password to the PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 - OL09-00-000050 - SV-271451r1091065_rule + SRG-OS-000080-GPOS-00048 + OL09-00-000050 + SV-271451r1117265_rule Having a non-default grub superuser username makes password-guessing attacks less effective. @@ -46688,7 +54242,6 @@ Also, do NOT manually add the superuser account and password to the DSS06.06 DSS06.10 3.4.5 - CCI-000213 164.308(a)(1)(ii)(B) 164.308(a)(7)(i) 164.308(a)(7)(ii)(A) @@ -46763,15 +54316,17 @@ Also, do NOT manually add the superuser account and password to the PR.AC-6 PR.AC-7 PR.PT-3 - SRG-OS-000080-GPOS-00048 + FIA_UAU.1 + SRG-OS-000080-GPOS-00048 R5 A.8.SEC-OL7 - OL09-00-001115 - SV-271635r1091617_rule + OL09-00-001115 + SV-271635r1117265_rule Password protection on the boot loader configuration ensures users with physical access cannot trivially alter important bootloader settings. These include which kernel to use, and whether to enter single-user mode. + @@ -46787,147 +54342,14 @@ and whether to enter single-user mode. managed by chmod command. In this case, in order to change file permissions for files within /boot/efi it is necessary to update the mount options in /etc/fstab file and reboot the system. - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - The file /boot/grub2/grub.cfg should -be group-owned by the root group to prevent -destruction or modification of the file. - -To properly set the group owner of /boot/grub2/grub.cfg, run the command: -$ sudo chgrp root /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 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 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - The root group is a highly-privileged group. Furthermore, the group-owner of this -file should not have any access privileges anyway. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chgrp 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure group owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - group: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_groupowner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - Verify /boot/grub2/user.cfg Group Ownership The file /boot/grub2/user.cfg should be group-owned by the root group to prevent reading or modification of the file. To properly set the group owner of /boot/grub2/user.cfg, run the command: -$ sudo chgrp root /boot/grub2/user.cfg + + $ sudo chgrp root /boot/grub2/user.cfg 12 13 @@ -46943,7 +54365,6 @@ To properly set the group owner of /boot/grub2/user.cfg, DSS05.07 DSS06.02 3.4.5 - CCI-000225 4.3.3.7.3 SR 2.1 SR 5.2 @@ -46980,9 +54401,21 @@ To properly set the group owner of /boot/grub2/user.cfg, file should not have any access privileges anyway. Non-root users who read the boot parameters may be able to identify weaknesses in security upon boot and be able to exploit them. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then +if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then -chgrp 0 /boot/grub2/user.cfg +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/boot/grub2/user.cfg" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /boot/grub2/user.cfg +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -47004,13 +54437,10 @@ fi - medium_severity - no_reboot_needed -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages +- name: Set the file_groupowner_efi_user_cfg_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_efi_user_cfg_newgroup: '0' + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) tags: - CJIS-5.5.2.2 @@ -47025,12 +54455,31 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /boot/grub2/user.cfg - file: +- name: Test for existence /boot/grub2/user.cfg + ansible.builtin.stat: path: /boot/grub2/user.cfg - group: '0' + register: file_exists + when: ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) + tags: + - CJIS-5.5.2.2 + - NIST-800-171-3.4.5 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-7.1 + - configure_strategy + - file_groupowner_efi_user_cfg + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /boot/grub2/user.cfg + ansible.builtin.file: + path: /boot/grub2/user.cfg + follow: false + group: '{{ file_groupowner_efi_user_cfg_newgroup }}' when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - file_exists.stat is defined and file_exists.stat.exists @@ -47054,632 +54503,6 @@ fi - - Verify the UEFI Boot Loader grub.cfg User Ownership - The file /boot/grub2/grub.cfg should -be owned by the root user to prevent destruction -or modification of the file. - -To properly set the owner of /boot/grub2/grub.cfg, run the command: -$ sudo chown root /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 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 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - Only root should be able to modify important boot parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chown 0 /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - owner: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - The file /boot/grub2/user.cfg should be owned by the root -user to prevent reading or modification of the file. - -To properly set the owner of /boot/grub2/user.cfg, run the command: -$ sudo chown root /boot/grub2/user.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 5.5.2.2 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 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 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - Req-7.1 - R29 - Only root should be able to modify important boot parameters. Also, non-root users who read -the boot parameters may be able to identify weaknesses in security upon boot and be able to -exploit them. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chown 0 /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure owner 0 on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - owner: '0' - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - CJIS-5.5.2.2 - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-7.1 - - configure_strategy - - file_owner_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify the UEFI Boot Loader grub.cfg Permissions - File permissions for /boot/grub2/grub.cfg should be set to 700. - -To properly set the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo chmod 700 /boot/grub2/grub.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 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 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - R29 - Proper permissions ensure that only the root user can modify important boot -parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chmod u-s,g-xwrs,o-xwrt /boot/grub2/grub.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/grub.cfg - stat: - path: /boot/grub2/grub.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/grub.cfg - file: - path: /boot/grub2/grub.cfg - mode: u-s,g-xwrs,o-xwrt - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_grub2_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Verify /boot/grub2/user.cfg Permissions - File permissions for /boot/grub2/user.cfg should be set to 600. - -To properly set the permissions of /boot/grub2/user.cfg, run the command: -$ sudo chmod 600 /boot/grub2/user.cfg - - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - APO01.06 - DSS05.04 - DSS05.07 - DSS06.02 - 3.4.5 - CCI-000225 - 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 - CM-6(a) - AC-6(1) - PR.AC-4 - PR.DS-5 - R29 - Proper permissions ensure that only the root user can read or modify important boot -parameters. - # Remediation is applicable only in certain platforms -if ( rpm --quiet -q grub2-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && [ -d /sys/firmware/efi ]; then - -chmod u-s,g-xwrs,o-xwrt /boot/grub2/user.cfg - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Test for existence /boot/grub2/user.cfg - stat: - path: /boot/grub2/user.cfg - register: file_exists - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure permission u-s,g-xwrs,o-xwrt on /boot/grub2/user.cfg - file: - path: /boot/grub2/user.cfg - mode: u-s,g-xwrs,o-xwrt - when: - - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - - ( "grub2-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - file_exists.stat is defined and file_exists.stat.exists - tags: - - NIST-800-171-3.4.5 - - NIST-800-53-AC-6(1) - - NIST-800-53-CM-6(a) - - configure_strategy - - file_permissions_efi_user_cfg - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - - - - - - - - - Set the UEFI Boot Loader Password - The grub2 boot loader should have a superuser account and password -protection enabled to protect boot-time settings. - - -Since plaintext passwords are a security risk, generate a hash for the password -by running the following command: - -# grub2-setpassword - -When prompted, enter the password that was selected. - - - - To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation -must be automated as a component of machine provisioning, or followed manually as outlined above. - -Also, do NOT manually add the superuser account and password to the -grub.cfg file as the grub2-mkconfig command overwrites this file. - 11 - 12 - 14 - 15 - 16 - 18 - 3 - 5 - DSS05.02 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.03 - DSS06.06 - 3.4.5 - CCI-000213 - 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.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 - A.6.1.2 - A.7.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) - PR.AC-4 - PR.AC-6 - PR.PT-3 - FIA_UAU.1 - SRG-OS-000080-GPOS-00048 - R5 - Password protection on the boot loader configuration ensures -users with physical access cannot trivially alter -important bootloader settings. These include which kernel to use, -and whether to enter single-user mode. - - - - - - - @@ -47774,7 +54597,7 @@ The configuration that was used to build kernel is available at /boot There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. R27 The Privileged Access Never (PAN) is the ARM equivalent of the x86 Supervisor Mode Access -Prevention (SMAP), and it prevents privileged acccess to user data unless explicitly enabled. +Prevention (SMAP), and it prevents privileged access to user data unless explicitly enabled. @@ -47881,7 +54704,7 @@ The configuration that was used to build kernel is available at /boot Certain buggy versions of glibc (2.3.3) will crash if they are presented with a 32-bit vDSO that is not mapped at the address indicated in its segment table. Setting CONFIG_COMPAT_VDSO to y turns off the 32-bit VDSO and works -aroud the glibc bug. +around the glibc bug. The configuration that was used to build kernel is available at /boot/config-*. To check the configuration value for CONFIG_COMPAT_VDSO, run the following command: @@ -47960,7 +54783,7 @@ The configuration that was used to build kernel is available at /boot There is no remediation for this besides re-compiling the kernel with the appropriate value for the config. R16 This add sanity checks to manipulation of linked lists structures in the kernel and may -prevent exploits such as CVE-2017-1661, where a race condition and simultaneos operations +prevent exploits such as CVE-2017-1661, where a race condition and simultaneous operations caused a list to corrupt. @@ -49002,7 +55825,7 @@ allocated when they are released. - Stack Protector buffer overlow detection + Stack Protector buffer overflow detection This feature puts, at the beginning of functions, a canary value on the stack just before the return address, and validates the value just before actually returning. This configuration is available from kernel 4.18. @@ -49348,13 +56171,11 @@ The rsyslog-gnutls package can be installed with the foll $ sudo yum install rsyslog-gnutls - CCI-000366 - CCI-000803 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 R71 - OL09-00-000355 - SV-271510r1091242_rule + OL09-00-000355 + SV-271510r1091242_rule The rsyslog-gnutls package provides Transport Layer Security (TLS) support for the rsyslog daemon, which enables secure remote logging. # Remediation is applicable only in certain platforms @@ -49381,7 +56202,7 @@ fi - package_rsyslog-gnutls_installed - name: Ensure rsyslog-gnutls is installed - package: + ansible.builtin.package: name: rsyslog-gnutls state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49433,9 +56254,6 @@ version = "*" DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-000154 - CCI-001851 164.312(a)(2)(ii) 4.3.3.3.9 4.3.3.5.8 @@ -49455,11 +56273,12 @@ version = "*" A.12.7.1 CM-6(a) PR.PT-1 - SRG-OS-000479-GPOS-00224 - SRG-OS-000051-GPOS-00024 - SRG-OS-000480-GPOS-00227 - OL09-00-000350 - SV-271508r1091236_rule + SRG-OS-000479-GPOS-00224 + SRG-OS-000051-GPOS-00024 + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-000350 + SV-271508r1091236_rule The rsyslog package provides the rsyslog daemon, which provides system logging services. # Remediation is applicable only in certain platforms @@ -49487,7 +56306,7 @@ fi - package_rsyslog_installed - name: Ensure rsyslog is installed - package: + ansible.builtin.package: name: rsyslog state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49564,7 +56383,6 @@ The rsyslog service can be enabled with the following com MEA01.04 MEA01.05 MEA02.01 - CCI-000366 164.312(a)(2)(ii) 4.3.2.6.7 4.3.3.3.9 @@ -49600,9 +56418,10 @@ The rsyslog service can be enabled with the following com ID.SC-4 PR.DS-4 PR.PT-1 - SRG-OS-000480-GPOS-00227 - OL09-00-000351 - SV-271509r1091239_rule + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-000351 + SV-271509r1091239_rule The rsyslog service must be running in order to provide logging services, which are essential to system administration. # Remediation is applicable only in certain platforms @@ -49637,7 +56456,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable rsyslog Service - Enable Service rsyslog @@ -49648,7 +56467,6 @@ fi masked: false when: - '"rsyslog" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000351 - NIST-800-53-AU-4(1) @@ -49659,6 +56477,8 @@ fi - medium_severity - no_reboot_needed - service_rsyslog_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_rsyslog @@ -49673,6 +56493,10 @@ class enable_rsyslog { [customizations.services] enabled = ["rsyslog"] + + + + @@ -49735,7 +56559,6 @@ If the modern syntax (RainerScript) is used: MEA01.04 MEA01.05 MEA02.01 - CCI-000366 4.3.2.6.7 4.3.3.3.9 4.3.3.5.8 @@ -49749,8 +56572,6 @@ If the modern syntax (RainerScript) is used: SR 2.8 SR 2.9 SR 6.1 - 0988 - 1405 A.12.4.1 A.12.4.2 A.12.4.3 @@ -49761,22 +56582,34 @@ If the modern syntax (RainerScript) is used: CM-6(a) ID.SC-4 PR.PT-1 - SRG-OS-000480-GPOS-00227 - OL09-00-005010 - SV-271853r1092271_rule + SRG-OS-000480-GPOS-00227 + 0988 + 1405 + OL09-00-005010 + SV-271853r1092271_rule Cron logging can be used to trace the successful or unsuccessful execution of cron jobs. It can also be used to spot intrusions into the use of the cron facility by unauthorized and malicious users. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if ! grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' /etc/rsyslog.conf /etc/rsyslog.d/*.conf; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove all multilined cron.* entries +sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' {} + +# remove all legacy format and one line cron.* entries +sed -i '/^\s*\*\.\*\s+/var/log/cron\s*$/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^\s*\*\.\*\s+/var/log/cron\s*$/d' {} + +sed -i '/^[[:space:]]*cron\.\*/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*/d' {} + - mkdir -p /etc/rsyslog.d - echo "cron.* /var/log/cron" >> /etc/rsyslog.d/cron.conf -fi +echo "cron.* /var/log/cron" >> $RSYSLOG_D_CONF -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then systemctl restart rsyslog.service fi @@ -49797,11 +56630,12 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Search if cron configuration exists - ansible.builtin.command: grep -Pzo '(?m)^\s*(cron|\*)\.\*\s*(/var/log/(cron|messages)|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/(cron|messages)"\s*\))\s*$' - /etc/rsyslog.conf /etc/rsyslog.d/*.conf - register: cron_log_config_exists - failed_when: false +- name: Ensure cron Is Logging To Rsyslog - Ensure /etc/rsyslog.conf exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -49815,7 +56649,7 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Ensure the /etc/rsyslog.d directory exists +- name: Ensure cron Is Logging To Rsyslog - Ensure /etc/rsyslog.d directory exists ansible.builtin.file: path: /etc/rsyslog.d state: directory @@ -49832,15 +56666,163 @@ fi - no_reboot_needed - rsyslog_cron_logging -- name: Ensure cron Is Logging To Rsyslog - Add cron log configuration line - ansible.builtin.lineinfile: - path: /etc/rsyslog.d/cron.conf - line: cron.* /var/log/cron - create: true +- name: Ensure cron Is Logging To Rsyslog - Remove multilined cron.* action() entries + from rsyslog.conf + ansible.builtin.shell: sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' /etc/rsyslog.conf + changed_when: true when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - cron_log_config_exists.stdout_lines | length == 0 + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Remove multilined cron.* action() entries + from rsyslog.d/*.conf + ansible.builtin.shell: find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*cron\.\*.*action(/,/)/d' + {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Remove *.* entries pointing to /var/log/cron from rsyslog.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: (?i)^\s*\*\.\*\s+/var/log/cron\s*$ + state: absent + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Remove *.* entries pointing to /var/log/cron + from rsyslog.d/*.conf + ansible.builtin.shell: find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '\|^\s*\*\.\*\s\+/var/log/cron\s*$|d' + {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Check if the parameter cron.* is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "cron.*"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog - Check if the parameter cron.* is configured + correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "cron.*"| regex_escape }}/var/log/cron$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005010 + - NIST-800-53-CM-6(a) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_cron_logging + +- name: Ensure cron Is Logging To Rsyslog + block: + + - name: Deduplicate values from /etc/rsyslog.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.conf + create: false + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + state: absent + + - name: Check if /etc/rsyslog.d exists + ansible.builtin.stat: + path: /etc/rsyslog.d + register: _etc_rsyslog_d_exists + + - name: Check if the parameter cron.* is present in /etc/rsyslog.d + ansible.builtin.find: + paths: /etc/rsyslog.d + recurse: 'yes' + follow: 'no' + contains: ^\s*{{ "cron.*"| regex_escape }} + register: _etc_rsyslog_d_has_parameter + when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/rsyslog.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + state: absent + with_items: '{{ _etc_rsyslog_d_has_parameter.files }}' + when: _etc_rsyslog_d_has_parameter.matched + + - name: Insert correct line to /etc/rsyslog.d/cron.conf + ansible.builtin.lineinfile: + path: /etc/rsyslog.d/cron.conf + create: true + regexp: (?i)^\s*{{ "cron.*"| regex_escape }} + line: cron.* /var/log/cron + state: present + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005010 - NIST-800-53-CM-6(a) @@ -49890,34 +56872,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: action(type="omfwd" Target="some.example.com" StreamDriverAuthMode="x509/name") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005015 - SV-271854r1092274_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005015 + SV-271854r1092274_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -sed -i '/^.*\$ActionSendStreamDriverAuthMode.*/d' /etc/rsyslog.conf /etc/rsyslog.d/*.conf 2> /dev/null +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove legacy entries +sed -i '/^[[:space:]]*\$ActionSendStreamDriverAuthMode/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$ActionSendStreamDriverAuthMode/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' {} + -if [ -e "/etc/rsyslog.d/stream_driver_auth.conf" ] ; then +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "/etc/rsyslog.d/stream_driver_auth.conf" + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverAuthMode /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/stream_driver_auth.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/stream_driver_auth.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/stream_driver_auth.conf" "/etc/rsyslog.d/stream_driver_auth.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "/etc/rsyslog.d/stream_driver_auth.conf" +printf '%s\n' "\$ActionSendStreamDriverAuthMode x509/name" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/stream_driver_auth.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -49936,23 +56927,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_actionsendstreamdriverauthmode +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Ensure /etc/rsyslog.d + directory exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Remove RainerScript + action() entries with StreamDriverAuthMode from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Remove RainerScript + action() entries with StreamDriverAuthMode from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverAuthMode/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverAuthMode is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + +- name: Ensure Rsyslog Authenticates Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverAuthMode is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\sx509/name$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005015 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdriverauthmode + - name: Ensure Rsyslog Authenticates Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $ActionSendStreamDriverAuthMode is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -49961,7 +57068,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s @@ -49970,7 +57077,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: (?i)^\s*{{ "$ActionSendStreamDriverAuthMode"| regex_escape }}\s @@ -49979,6 +57086,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005015 - NIST-800-53-AU-4(1) @@ -50004,7 +57112,7 @@ and remote logging. Couple this utility with gnutls (whi library implementing the SSL, TLS and DTLS protocols), and you have a method to securely encrypt and off-load auditing. -When using rsyslogd to off-load logs off a encrpytion system must be used. +When using rsyslogd to off-load logs off a encryption system must be used. Set the following configuration option in /etc/rsyslog.conf or in a file in /etc/rsyslog.d (using legacy syntax): $ActionSendStreamDriverMode 1 @@ -50012,32 +57120,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: action(type="omfwd" ... StreamDriverMode="1") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005020 - SV-271855r1092277_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005020 + SV-271855r1092277_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove ActionSendStreamDriverMode entries +sed -i '/^[[:space:]]*\$ActionSendStreamDriverMode/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$ActionSendStreamDriverMode/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' {} + + +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "/etc/rsyslog.d/encrypt.conf" + LC_ALL=C sed -i "/^\s*\$ActionSendStreamDriverMode /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/encrypt.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "/etc/rsyslog.d/encrypt.conf" +printf '%s\n' "\$ActionSendStreamDriverMode 1" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -50056,23 +57175,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_actionsendstreamdrivermode +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.d directory + exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript action() + entries with StreamDriverMode from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript action() + entries with StreamDriverMode from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*action(/ { :a; N; /)/!ba; /StreamDriverMode/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverMode is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $ActionSendStreamDriverMode is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} 1$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005020 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_actionsendstreamdrivermode + - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $ActionSendStreamDriverMode is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -50081,7 +57316,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' @@ -50090,7 +57325,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: '(?i)^\s*{{ "$ActionSendStreamDriverMode"| regex_escape }} ' @@ -50099,6 +57334,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005020 - NIST-800-53-AU-4(1) @@ -50132,32 +57368,43 @@ Set the following configuration option in /etc/rsyslog.conf or in a file in /etc Alternatively, use the RainerScript syntax: global(DefaultNetstreamDriver="gtls") - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-005025 - SV-271856r1092280_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-005025 + SV-271856r1092280_rule The audit records generated by Rsyslog contain valuable information regarding system configuration, user authentication, and other such information. Audit records should be protected from unauthorized access. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && rpm --quiet -q rsyslog; then -if [ -e "/etc/rsyslog.d/encrypt.conf" ] ; then +RSYSLOG_CONF='/etc/rsyslog.conf' +RSYSLOG_D_FOLDER='/etc/rsyslog.d' +RSYSLOG_D_CONF='/etc/rsyslog.d/encrypt.conf' +test -f $RSYSLOG_CONF || touch $RSYSLOG_CONF +mkdir -p $RSYSLOG_D_FOLDER +# remove DefaultNetstreamDriver entries +sed -i '/^[[:space:]]*\$DefaultNetstreamDriver/d' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*\$DefaultNetstreamDriver/d' {} + +# remove all multilined and onelined RainerScript entries +sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' $RSYSLOG_CONF +find $RSYSLOG_D_FOLDER -type f -name "*.conf" -exec sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' {} + + +if [ -e "$RSYSLOG_D_CONF" ] ; then - LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "/etc/rsyslog.d/encrypt.conf" + LC_ALL=C sed -i "/^\s*\$DefaultNetstreamDriver /Id" "$RSYSLOG_D_CONF" else - touch "/etc/rsyslog.d/encrypt.conf" + touch "$RSYSLOG_D_CONF" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/rsyslog.d/encrypt.conf" +sed -i -e '$a\' "$RSYSLOG_D_CONF" -cp "/etc/rsyslog.d/encrypt.conf" "/etc/rsyslog.d/encrypt.conf.bak" +cp "$RSYSLOG_D_CONF" "$RSYSLOG_D_CONF.bak" # Insert at the end of the file -printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "/etc/rsyslog.d/encrypt.conf" +printf '%s\n' "\$DefaultNetstreamDriver gtls" >> "$RSYSLOG_D_CONF" # Clean up after ourselves. -rm "/etc/rsyslog.d/encrypt.conf.bak" +rm "$RSYSLOG_D_CONF.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -50176,23 +57423,139 @@ fi - no_reboot_needed - rsyslog_encrypt_offload_defaultnetstreamdriver +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.conf + exists + ansible.builtin.file: + path: /etc/rsyslog.conf + state: touch + modification_time: preserve + access_time: preserve + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Ensure /etc/rsyslog.d directory + exists + ansible.builtin.file: + path: /etc/rsyslog.d + state: directory + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript global() + entries with DefaultNetstreamDriver from rsyslog.conf + ansible.builtin.shell: | + sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' /etc/rsyslog.conf + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Remove RainerScript global() + entries with DefaultNetstreamDriver from rsyslog.d/*.conf + ansible.builtin.shell: | + find /etc/rsyslog.d -type f -name "*.conf" -exec sed -i '/^[[:space:]]*global(/ { :a; N; /)/!ba; /DefaultNetstreamDriver/d }' {} + + changed_when: true + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $DefaultNetstreamDriver is configured + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} + register: _sshd_config_has_parameter + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + +- name: Ensure Rsyslog Encrypts Off-Loaded Audit Records - Check if the parameter + $DefaultNetstreamDriver is configured correctly + ansible.builtin.find: + paths: + - /etc/rsyslog.conf + - /etc/rsyslog.d + contains: ^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} gtls$ + register: _sshd_config_correctly + when: + - '"rsyslog" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-005025 + - NIST-800-53-AU-4(1) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - rsyslog_encrypt_offload_defaultnetstreamdriver + - name: Ensure Rsyslog Encrypts Off-Loaded Audit Records block: - name: Deduplicate values from /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: false regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' state: absent - name: Check if /etc/rsyslog.d exists - stat: + ansible.builtin.stat: path: /etc/rsyslog.d register: _etc_rsyslog_d_exists - name: Check if the parameter $DefaultNetstreamDriver is present in /etc/rsyslog.d - find: + ansible.builtin.find: paths: /etc/rsyslog.d recurse: 'yes' follow: 'no' @@ -50201,7 +57564,7 @@ fi when: _etc_rsyslog_d_exists.stat.isdir is defined and _etc_rsyslog_d_exists.stat.isdir - name: Remove parameter from files in /etc/rsyslog.d - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.path }}' create: false regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' @@ -50210,7 +57573,7 @@ fi when: _etc_rsyslog_d_has_parameter.matched - name: Insert correct line to /etc/rsyslog.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf create: true regexp: '(?i)^\s*{{ "$DefaultNetstreamDriver"| regex_escape }} ' @@ -50219,6 +57582,7 @@ fi when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 tags: - DISA-STIG-OL09-00-005025 - NIST-800-53-AU-4(1) @@ -50264,12 +57628,9 @@ correct this: DSS05.04 DSS05.07 DSS06.02 - CCI-001314 4.3.3.7.3 SR 2.1 SR 5.2 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -50293,15 +57654,15 @@ correct this: 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 + 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 CM-6(a) AC-6(1) PR.AC-4 @@ -50309,6 +57670,8 @@ correct this: Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.2 10.3 The log files generated by rsyslog contain valuable information regarding system @@ -50694,12 +58057,9 @@ correct this: DSS05.04 DSS05.07 DSS06.02 - CCI-001314 4.3.3.7.3 SR 2.1 SR 5.2 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -50723,15 +58083,15 @@ correct this: 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 + 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 CM-6(a) AC-6(1) PR.AC-4 @@ -50739,6 +58099,8 @@ correct this: Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.2 10.3 The log files generated by rsyslog contain valuable information regarding system @@ -51103,23 +58465,22 @@ If the permissions are not 640 or more restrictive, run the following command to correct this: $ sudo chmod 640 LOGFILE " - CCI-001314 - 0988 - 1405 - 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 + 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 CM-6(a) AC-6(1) Req-10.5.1 Req-10.5.2 R71 + 0988 + 1405 10.3.1 10.3 Log files can contain valuable information regarding system @@ -51485,11 +58846,10 @@ not, use the following as an example configuration: daemon.* /var/log/messages - CCI-000067 AC-17(1) - SRG-OS-000032-GPOS-00013 - OL09-00-005000 - SV-271851r1092265_rule + SRG-OS-000032-GPOS-00013 + OL09-00-005000 + SV-271851r1092265_rule Logging remote access methods can be used to trace the decrease the risks associated with remote user access management. It can also be used to spot cyber attacks and ensure ongoing compliance with organizational policies @@ -51540,7 +58900,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Set facts' - set_fact: + ansible.builtin.set_fact: conf_files: - /etc/rsyslog.conf remote_methods: @@ -51568,9 +58928,11 @@ fi - name: 'Ensure remote access methods are monitored in Rsyslog: Ensure rsyslog.conf exists' - file: + ansible.builtin.file: path: '{{ conf_files.0 }}' state: touch + access_time: preserve + modification_time: preserve when: - '"rsyslog" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -51585,7 +58947,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Gather conf.d files' - find: + ansible.builtin.find: patterns: - '*.conf' paths: @@ -51605,7 +58967,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Set conf file(s)' - set_fact: + ansible.builtin.set_fact: conf_files: '{{ conf_files + [item.path] }}' loop: '{{ rsyslogd.files }}' when: @@ -51624,7 +58986,7 @@ fi - name: 'Ensure remote access methods are monitored in Rsyslog: Check for existing values' - lineinfile: + ansible.builtin.lineinfile: path: '{{ item.1 }}' regexp: '{{ item.0.regexp }}' state: absent @@ -51646,7 +59008,7 @@ fi - rsyslog_remote_access_monitoring - name: 'Ensure remote access methods are monitored in Rsyslog: Configure' - lineinfile: + ansible.builtin.lineinfile: path: /etc/rsyslog.conf line: '{{ item.item.0.selector }} {{ item.item.0.location }}' insertafter: ^.*\/var\/log\/secure.*$ @@ -51691,11 +59053,10 @@ systemd. The systemd-journald service can be enabled with the following command: $ sudo systemctl enable systemd-journald.service - CCI-001665 SC-24 - SRG-OS-000269-GPOS-00103 - OL09-00-002400 - SV-271739r1091929_rule + SRG-OS-000269-GPOS-00103 + OL09-00-002400 + SV-271739r1091929_rule In the event of a system failure, Oracle Linux 9 must preserve any information necessary to determine cause of failure and any information necessary to return to operations with least disruption to system processes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -51728,7 +59089,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable systemd-journald Service - Enable Service systemd-journald @@ -51739,7 +59100,6 @@ fi masked: false when: - '"systemd" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002400 - NIST-800-53-SC-24 @@ -51749,6 +59109,8 @@ fi - medium_severity - no_reboot_needed - service_systemd-journald_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_systemd-journald @@ -51763,6 +59125,10 @@ class enable_systemd-journald { [customizations.services] enabled = ["systemd-journald"] + + + + @@ -51773,9 +59139,7 @@ enabled = ["systemd-journald"] Ensure All Logs are Rotated by logrotate - -Edit the file /etc/logrotate.d/syslog. Find the first - + Edit the file /etc/logrotate.d/syslog. Find the first line, which should look like this (wrapped for clarity): /var/log/messages /var/log/secure /var/log/maillog /var/log/spooler \ /var/log/boot.log /var/log/cron { @@ -51813,7 +59177,6 @@ used. DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -51864,7 +59227,7 @@ fi - package_logrotate_installed - name: Ensure logrotate is installed - package: + ansible.builtin.package: name: logrotate state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -51924,7 +59287,6 @@ daily DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -51961,7 +59323,7 @@ CRON_DAILY_LOGROTATE_FILE="/etc/cron.daily/logrotate" # daily rotation is configured -grep -q "^daily$" $LOGROTATE_CONF_FILE|| echo "daily" >> $LOGROTATE_CONF_FILE +grep -q "^daily$" $LOGROTATE_CONF_FILE|| sed -i '1i daily' "$LOGROTATE_CONF_FILE" # remove any line configuring weekly, monthly or yearly rotation sed -i '/^\s*\(weekly\|monthly\|yearly\).*$/d' $LOGROTATE_CONF_FILE @@ -51991,11 +59353,13 @@ fi - no_reboot_needed - name: Configure daily log rotation in /etc/logrotate.conf - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/logrotate.conf - regexp: ^daily$ + regexp: ^\s*(weekly|monthly|yearly)$ line: daily + state: present + insertbefore: BOF when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"logrotate" in ansible_facts.packages' @@ -52009,8 +59373,8 @@ fi - medium_severity - no_reboot_needed -- name: Make sure daily log rotation setting is not overriden in /etc/logrotate.conf - lineinfile: +- name: Make sure daily log rotation setting is not overridden in /etc/logrotate.conf + ansible.builtin.lineinfile: create: false dest: /etc/logrotate.conf regexp: ^[\s]*(weekly|monthly|yearly)$ @@ -52032,17 +59396,18 @@ fi block: - name: Add shebang - lineinfile: + ansible.builtin.lineinfile: path: /etc/cron.daily/logrotate line: '#!/bin/sh' insertbefore: BOF create: true - name: Add logrotate call - lineinfile: + ansible.builtin.lineinfile: path: /etc/cron.daily/logrotate line: /usr/sbin/logrotate /etc/logrotate.conf regexp: ^[\s]*/usr/sbin/logrotate[\s\S]*/etc/logrotate.conf$ + create: true when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"logrotate" in ansible_facts.packages' @@ -52081,7 +59446,6 @@ The logrotate timer can be enabled with the following com DSS05.04 DSS05.07 MEA02.01 - CCI-000366 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -52140,11 +59504,11 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable timer logrotate - systemd: + ansible.builtin.systemd: name: logrotate.timer enabled: 'yes' state: started @@ -52166,6 +59530,10 @@ fi - no_reboot_needed - timer_logrotate_enabled + + + + @@ -52204,8 +59572,6 @@ $ sudo yum install syslog-ng-core DSS05.04 DSS05.07 MEA02.01 - CCI-001311 - CCI-001312 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -52250,7 +59616,7 @@ fi - package_syslogng_installed - name: Ensure syslog-ng is installed - package: + ansible.builtin.package: name: syslog-ng state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -52326,10 +59692,6 @@ The syslog-ng service can be enabled with the following c MEA01.04 MEA01.05 MEA02.01 - CCI-001311 - CCI-001312 - CCI-001557 - CCI-001851 4.3.2.6.7 4.3.3.3.9 4.3.3.5.8 @@ -52397,7 +59759,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable syslog-ng Service - Enable Service syslog-ng @@ -52408,7 +59770,6 @@ fi masked: false when: - '"syslog-ng" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-4(1) - NIST-800-53-CM-6(a) @@ -52418,6 +59779,8 @@ fi - medium_severity - no_reboot_needed - service_syslogng_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_syslog-ng @@ -52432,6 +59795,10 @@ class enable_syslog-ng { [customizations.services] enabled = ["syslog-ng"] + + + + @@ -52476,12 +59843,12 @@ $InputTCPServerRun 514 A.12.4.3 A.12.4.4 A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 CM-6(a) AU-6(3) AU-6(4) @@ -52526,12 +59893,12 @@ $UDPServerRun 514 A.12.4.3 A.12.4.4 A.12.7.1 - CIP-004-6 R2.2.2 - CIP-004-6 R3.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R3.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R6.5 CM-6(a) AU-6(3) AU-6(4) @@ -52591,7 +59958,6 @@ input(type="imudp" port="514") DSS05.07 DSS06.02 MEA02.01 - CCI-000366 4.2.3.4 4.3.3.3.9 4.3.3.4 @@ -52618,8 +59984,6 @@ input(type="imudp" port="514") SR 5.3 SR 7.1 SR 7.6 - 0988 - 1405 A.10.1.1 A.11.1.4 A.11.1.5 @@ -52667,9 +60031,11 @@ input(type="imudp" port="514") PR.IP-1 PR.PT-1 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-005030 - SV-271857r1092283_rule + SRG-OS-000480-GPOS-00227 + 0988 + 1405 + OL09-00-005030 + SV-271857r1092283_rule Any process which receives messages from the network incurs some risk of receiving malicious messages. This risk can be eliminated for rsyslog by configuring it not to listen on the network. @@ -52991,14 +60357,23 @@ To use UDP for log message delivery: *.* @ +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="udp") + To use TCP for log message delivery: *.* @@ +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="tcp") + To use RELP for log message delivery: *.* :omrelp: +Or in RainerScript: +*.* action(type="omfwd" ... target="" protocol="relp") + There must be a resolvable DNS CNAME or Alias record set to "" for logs to be sent correctly to the centralized logging utility. It is important to configure queues in case the client is sending log messages to a remote server. If queues are not configured, @@ -53014,6 +60389,8 @@ $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") 1 13 @@ -53031,8 +60408,6 @@ $ActionResumeRetryCount -1 DSS05.04 DSS05.07 MEA02.01 - CCI-000366 - CCI-001851 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(B) 164.308(a)(5)(ii)(C) @@ -53055,8 +60430,6 @@ $ActionResumeRetryCount -1 SR 2.9 SR 7.1 SR 7.2 - 0988 - 1405 A.12.1.3 A.12.4.1 A.12.4.2 @@ -53064,19 +60437,21 @@ $ActionResumeRetryCount -1 A.12.4.4 A.12.7.1 A.17.2.1 - CIP-003-8 R5.2 - CIP-004-6 R3.3 + 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 + SRG-OS-000479-GPOS-00224 + SRG-OS-000480-GPOS-00227 + SRG-OS-000342-GPOS-00133 R71 - OL09-00-005005 - SV-271852r1092608_rule + 0988 + 1405 + OL09-00-005005 + SV-271852r1092608_rule 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 @@ -53133,7 +60508,7 @@ fi - always - name: Set rsyslog remote loghost - lineinfile: + ansible.builtin.lineinfile: dest: /etc/rsyslog.conf regexp: ^\*\.\* line: '*.* @@{{ rsyslog_remote_loghost_address }}' @@ -53168,13 +60543,13 @@ using action. You can use the following command: StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on")' >> /etc/rsyslog.conf Replace the <remote system> in the above command with an IP address or a host name of the remote logging server. - 0988 - 1405 AU-9(3) CM-6(a) - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 R71 + 0988 + 1405 For protection of data being logged, the connection to the remote logging server needs to be authenticated and encrypted. # Remediation is applicable only in certain platforms @@ -53433,10 +60808,10 @@ global option in /etc/rsyslog.conf, for example with the echo 'global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem")' >> /etc/rsyslog.conf Replace the /etc/pki/tls/cert.pem in the above command with the path to the file with CA certificate generated for the purpose of remote logging. Automatic remediation is not available as each organization has unique requirements. + SRG-OS-000480-GPOS-00227 + R71 0988 1405 - SRG-OS-000480-GPOS-00227 - R71 The CA certificate needs to be set or rsyslog.service fails to start with error: ca certificate is not set, cannot continue @@ -53499,7 +60874,6 @@ nameserver 192.168.0.2 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -53516,9 +60890,9 @@ nameserver 192.168.0.2 SC-20(a) CM-6(a) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-006003 - SV-271861r1092295_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006003 + SV-271861r1092295_rule To provide availability for name resolution services, multiple redundant name servers are mandated. A failure in name resolution could lead to the failure of security functions requiring name resolution, which may include @@ -53548,11 +60922,11 @@ ResultActive=auth_admin 3.1.16 + AC-18(4) + CM-6(a) 0418 1055 1402 - AC-18(4) - CM-6(a) 1.2.8 1.2 Allowing non-privileged users to make changes to network settings can allow @@ -53562,6 +60936,9 @@ attack. # Remediation is applicable only in certain platforms if rpm --quiet -q polkit; then +if ! rpm -q --quiet "polkit-pkla-compat" ; then + yum install -y "polkit-pkla-compat" +fi printf "[Disable General User Access to NetworkManager]\nIdentity=default\nAction=org.freedesktop.NetworkManager.*\nResultAny=no\nResultInactive=no\nResultActive=auth_admin\n" > /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla else @@ -53584,8 +60961,28 @@ fi - no_reboot_needed - restrict_strategy -- name: Ensure non-privileged users do not have access to nmcli - ini_file: +- name: Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + - Ensure polkit-pkla-compat is installed + ansible.builtin.package: + name: polkit-pkla-compat + state: present + when: '"polkit" in ansible_facts.packages' + tags: + - NIST-800-171-3.1.16 + - NIST-800-53-AC-18(4) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.8 + - low_complexity + - low_disruption + - medium_severity + - network_nmcli_permissions + - no_reboot_needed + - restrict_strategy + +- name: Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + - Ensure non-privileged users do not have access to nmcli + community.general.ini_file: path: /etc/polkit-1/localauthority/20-org.d/10-nm-harden-access.pkla section: Disable General User Access to NetworkManager option: '{{ item.option }}' @@ -53653,7 +61050,6 @@ Promiscuous mode of an interface can be disabled with the following command: DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.2.3.4 4.3.3.3.7 4.3.3.5.1 @@ -53726,11 +61122,12 @@ Promiscuous mode of an interface can be disabled with the following command: PR.IP-1 PR.MA-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1409 1.4.5 1.4 - OL09-00-006004 - SV-271862r1092298_rule + OL09-00-006004 + SV-271862r1092298_rule Network interfaces in promiscuous mode allow for the capture of all network traffic visible to the system. If unauthorized individuals can access these applications, it may allow them to collect information such as logon IDs, passwords, and key exchanges @@ -53775,11 +61172,12 @@ fi - name: Ensure System is Not Acting as a Network Sniffer - Disable promiscuous mode ansible.builtin.command: - cmd: ip link set dev {{ item.split(':')[1] }} multicast off promisc off + cmd: ip link set dev {{ (item.split(':')[1] | trim).split('@')[0] }} multicast + off promisc off loop: '{{ network_interfaces.stdout_lines }}' when: - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - network_interfaces.stdout_lines is defined and "item.split(':') | length == 3" + - network_interfaces.stdout_lines is defined and item.split(':') | length >= 3 tags: - DISA-STIG-OL09-00-006004 - NIST-800-53-CM-6(a) @@ -53826,12 +61224,11 @@ the firewall has to be reloaded. Configure Firewalld to Use the Nftables Backend Firewalld can be configured with many backends, such as nftables. - CCI-002385 SC-5 - SRG-OS-000420-GPOS-00186 - OL09-00-006000 - SV-271858r1092286_rule - Nftables is modern kernel module for controling network connections coming into a system. + SRG-OS-000420-GPOS-00186 + OL09-00-006000 + SV-271858r1092286_rule + Nftables is modern kernel module for controlling network connections coming into a system. Utilizing the limit statement in "nftables" can help to mitigate DoS attacks. # Remediation is applicable only in certain platforms @@ -53883,7 +61280,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -53893,7 +61290,7 @@ fi register: dupes - name: Deduplicate values from /etc/firewalld/firewalld.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -53901,7 +61298,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/firewalld/firewalld.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/firewalld/firewalld.conf create: true regexp: (?i)^\s*FirewallBackend= @@ -54000,27 +61397,24 @@ service reload, enter the following command as root: $ sudo yum install firewalld - CCI-000382 - CCI-000366 - CCI-002314 - CCI-002322 CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000298-GPOS-00116 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00232 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000298-GPOS-00116 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00232 A.8.SEC-OL3 + 1409 1.2.1 1.2 - OL09-00-000220 - SV-271469r1091119_rule + OL09-00-000220 + SV-271469r1091119_rule "Firewalld" provides an easy and effective way to block/limit remote access to the system via ports, services, and protocols. Remote access services, such as those providing remote access to network devices and information systems, which lack automated control capabilities, increase risk and make remote user access management difficult at best. -Remote access is access to DoD nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. +Remote access is access to nonpublic information systems by an authorized user (or an information system) communicating through an external, non-organization-controlled network. Remote access methods include, for example, dial-up, broadband, and wireless. Oracle Linux 9 functionality (e.g., SSH) must be capable of taking enforcement action if the audit reveals unauthorized activity. Automated control of remote access sessions allows organizations to ensure ongoing compliance with remote access policies by enforcing connection rules of remote access applications on a variety of information system components (e.g., servers, workstations, notebook computers, smartphones, and tablets)." @@ -54051,7 +61445,7 @@ fi - package_firewalld_installed - name: Ensure firewalld is installed - package: + ansible.builtin.package: name: firewalld state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -54105,9 +61499,6 @@ The firewalld service can be enabled with the following c BAI10.05 3.1.3 3.4.7 - CCI-000382 - CCI-000366 - CCI-002314 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -54117,9 +61508,9 @@ The firewalld service can be enabled with the following c A.14.2.2 A.14.2.3 A.14.2.4 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -54127,18 +61518,19 @@ The firewalld service can be enabled with the following c CM-6(a) PR.IP-1 FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 - SRG-OS-000480-GPOS-00227 - SRG-OS-000480-GPOS-00231 - SRG-OS-000480-GPOS-00232 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00231 + SRG-OS-000480-GPOS-00232 SYS.1.6.A5 SYS.1.6.A21 A.8.SEC-OL3 + 1409 1.2.1 1.2 - OL09-00-000221 - SV-271470r1092618_rule + OL09-00-000221 + SV-271470r1092618_rule Access control methods provide the ability to enhance system security posture by restricting services and known good IP addresses and address ranges. This prevents connections from unknown hosts and protocols. @@ -54182,7 +61574,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify firewalld Enabled - Enable Service firewalld @@ -54193,9 +61585,6 @@ fi masked: false when: - '"firewalld" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"firewalld" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000221 - NIST-800-171-3.1.3 @@ -54213,6 +61602,10 @@ fi - medium_severity - no_reboot_needed - service_firewalld_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"firewalld" in ansible_facts.packages' include enable_firewalld @@ -54227,6 +61620,10 @@ class enable_firewalld { [customizations.services] enabled = ["firewalld"] + + + + @@ -54283,8 +61680,6 @@ command: DSS05.03 DSS05.05 DSS06.06 - CCI-000382 - CCI-002314 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -54338,7 +61733,6 @@ command: SR 5.3 SR 7.1 SR 7.6 - 1416 A.11.2.6 A.12.1.2 A.12.5.1 @@ -54361,12 +61755,15 @@ command: PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000096-GPOS-00050 - SRG-OS-000297-GPOS-00115 + SRG-OS-000096-GPOS-00050 + SRG-OS-000297-GPOS-00115 + 1416 1.3.1 1.3 - OL09-00-000223 - SV-271472r1091128_rule + OL09-00-000223 + OL09-00-000222 + SV-271472r1091128_rule + SV-271471r1091125_rule In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information @@ -54394,11 +61791,10 @@ conduct official business. Oracle Linux 9 incorporates the "firewalld" daemon, which allows for many different configurations. One of these configurations is zones. Zones can be utilized to a deny-all, allow-by-exception approach. The default "drop" zone will drop all incoming network packets unless it is explicitly allowed by the configuration file or is related to an outgoing network connection. - CCI-000366 AC-17 (1) - SRG-OS-000297-GPOS-00115 - OL09-00-000224 - SV-271473r1091131_rule + SRG-OS-000297-GPOS-00115 + OL09-00-000224 + SV-271473r1091131_rule Failure to restrict network connectivity only to authorized systems permits inbound connections from malicious systems. It also permits outbound connections that may facilitate exfiltration of data. @@ -54441,7 +61837,7 @@ fi ipv4_rule='rule family=ipv4 source address="127.0.0.1" destination not address="127.0.0.1" drop' ipv6_rule='rule family=ipv6 source address="::1" destination not address="::1" drop' -if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv4_rule}" firewall-offline-cmd --zone=trusted --add-rich-rule="${ipv6_rule}" elif systemctl is-active firewalld; then @@ -54552,7 +61948,7 @@ fi on Service State ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' fail_msg: - firewalld service is not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld service @@ -54604,7 +62000,7 @@ if ! rpm -q --quiet "firewalld" ; then yum install -y "firewalld" fi -if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" || { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then firewall-offline-cmd --zone=trusted --add-interface=lo elif systemctl is-active firewalld; then firewall-cmd --permanent --zone=trusted --add-interface=lo @@ -54654,7 +62050,6 @@ fi - name: Configure Firewalld to Trust Loopback Traffic - Collect Facts About System Services ansible.builtin.service_facts: null - register: result_services_states when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-1.4 @@ -54702,7 +62097,7 @@ fi on Service State ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' fail_msg: - firewalld service is not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld service @@ -54756,7 +62151,6 @@ above. 3.1.3 3.4.7 3.13.6 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -54801,7 +62195,6 @@ above. SR 2.6 SR 2.7 SR 7.6 - 1416 A.12.1.2 A.12.5.1 A.12.6.2 @@ -54816,8 +62209,9 @@ above. PR.IP-1 PR.PT-3 Req-1.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL3 + 1416 1.3.1 1.3 In firewalld the default zone is applied only after all @@ -54857,8 +62251,6 @@ $ sudo yum install libreswan DSS05.02 DSS05.03 DSS05.04 - CCI-000366 - CCI-000803 4.3.3.6.5 4.3.3.6.6 4.3.3.6.7 @@ -54889,22 +62281,44 @@ $ sudo yum install libreswan PR.MA-2 PR.PT-4 Req-4.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000120-GPOS-00061 - OL09-00-000410 - SV-271517r1091263_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000120-GPOS-00061 + OL09-00-000410 + SV-271517r1101885_rule Providing the ability for remote users or systems to initiate a secure VPN connection protects information when it is transmitted over a wide area network. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + if ! rpm -q --quiet "libreswan" ; then yum install -y "libreswan" fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Ensure libreswan is installed - package: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000410 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-4.1 + - enable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - package_libreswan_installed + +- name: Ensure libreswan is installed + ansible.builtin.package: name: libreswan state: present + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000410 - NIST-800-53-CM-6(a) @@ -54941,7 +62355,8 @@ version = "*" Verify Group Who Owns /etc/ipsec.d Directory - To properly set the group owner of /etc/ipsec.d, run the command: $ sudo chgrp root /etc/ipsec.d + To properly set the group owner of /etc/ipsec.d, run the command: +$ sudo chgrp root /etc/ipsec.d R50 The ownership of the /etc/ipsec.d directory by the root group is important @@ -54952,7 +62367,17 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/ipsec.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -54969,11 +62394,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - directory_groupowner_etc_ipsecd_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_ipsecd_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_ipsecd_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/ipsec.d/ - file: + ansible.builtin.file: path: /etc/ipsec.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_ipsecd_newgroup }}' when: '"libreswan" in ansible_facts.packages' tags: - configure_strategy @@ -54992,7 +62448,8 @@ fi Verify User Who Owns /etc/ipsec.d Directory - To properly set the owner of /etc/ipsec.d, run the command: $ sudo chown root /etc/ipsec.d + To properly set the owner of /etc/ipsec.d, run the command: +$ sudo chown root /etc/ipsec.d R50 The ownership of the /etc/ipsec.d directory by the root user is important @@ -55003,7 +62460,17 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/ipsec.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55020,11 +62487,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_ipsecd_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_ipsecd_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_ipsecd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/ipsec.d/ - file: + ansible.builtin.file: path: /etc/ipsec.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_ipsecd_newown }}' when: '"libreswan" in ansible_facts.packages' tags: - configure_strategy @@ -55054,7 +62534,7 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/ipsec.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55072,7 +62552,8 @@ fi - no_reboot_needed - name: Find /etc/ipsec.d/ file(s) - command: 'find -H /etc/ipsec.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/ipsec.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -55087,7 +62568,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/ipsec.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -55111,7 +62592,8 @@ fi Verify Group Who Owns /etc/ipsec.conf File - To properly set the group owner of /etc/ipsec.conf, run the command: $ sudo chgrp root /etc/ipsec.conf + To properly set the group owner of /etc/ipsec.conf, run the command: +$ sudo chgrp root /etc/ipsec.conf R50 The ownership of the /etc/ipsec.conf file by the root group is important @@ -55122,7 +62604,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chgrp root /etc/ipsec.conf +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ipsec.conf" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/ipsec.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55139,8 +62633,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - file_groupowner_etc_ipsec_conf_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_ipsec_conf_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_ipsec_conf_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55152,10 +62676,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/ipsec.conf - file: +- name: Ensure group owner on /etc/ipsec.conf + ansible.builtin.file: path: /etc/ipsec.conf - group: root + follow: false + group: '{{ file_groupowner_etc_ipsec_conf_newgroup }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55176,7 +62701,8 @@ fi Verify Group Who Owns /etc/ipsec.secrets File - To properly set the group owner of /etc/ipsec.secrets, run the command: $ sudo chgrp root /etc/ipsec.secrets + To properly set the group owner of /etc/ipsec.secrets, run the command: +$ sudo chgrp root /etc/ipsec.secrets R50 The ownership of the /etc/ipsec.secrets file by the root group is important @@ -55187,7 +62713,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chgrp root /etc/ipsec.secrets +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ipsec.secrets" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/ipsec.secrets +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55204,8 +62742,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"libreswan" in ansible_facts.packages' + - file_groupowner_etc_ipsec_secrets_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_ipsec_secrets_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_ipsec_secrets_newgroup: root + when: + - '"libreswan" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55217,10 +62785,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/ipsec.secrets - file: +- name: Ensure group owner on /etc/ipsec.secrets + ansible.builtin.file: path: /etc/ipsec.secrets - group: root + follow: false + group: '{{ file_groupowner_etc_ipsec_secrets_newgroup }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55241,7 +62810,8 @@ fi Verify User Who Owns /etc/ipsec.conf File - To properly set the owner of /etc/ipsec.conf, run the command: $ sudo chown root /etc/ipsec.conf + To properly set the owner of /etc/ipsec.conf, run the command: +$ sudo chown root /etc/ipsec.conf R50 The ownership of the /etc/ipsec.conf file by the root user is important @@ -55252,7 +62822,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chown 0 /etc/ipsec.conf +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ipsec.conf" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ipsec.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55269,8 +62851,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_ipsec_conf_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_ipsec_conf_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55282,10 +62876,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ipsec.conf - file: +- name: Ensure owner on /etc/ipsec.conf + ansible.builtin.file: path: /etc/ipsec.conf - owner: '0' + follow: false + owner: '{{ file_owner_etc_ipsec_conf_newown }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55306,7 +62901,8 @@ fi Verify User Who Owns /etc/ipsec.secrets File - To properly set the owner of /etc/ipsec.secrets, run the command: $ sudo chown root /etc/ipsec.secrets + To properly set the owner of /etc/ipsec.secrets, run the command: +$ sudo chown root /etc/ipsec.secrets R50 The ownership of the /etc/ipsec.secrets file by the root user is important @@ -55317,7 +62913,19 @@ ensures exclusive control of the Libreswan configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q libreswan; then -chown 0 /etc/ipsec.secrets +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ipsec.secrets" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ipsec.secrets +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55334,8 +62942,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_ipsec_secrets_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_ipsec_secrets_newown: '0' + when: '"libreswan" in ansible_facts.packages' + tags: + - configure_strategy + - file_owner_etc_ipsec_secrets + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55347,10 +62967,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ipsec.secrets - file: +- name: Ensure owner on /etc/ipsec.secrets + ansible.builtin.file: path: /etc/ipsec.secrets - owner: '0' + follow: false + owner: '{{ file_owner_etc_ipsec_secrets_newown }}' when: - '"libreswan" in ansible_facts.packages' - file_exists.stat is defined and file_exists.stat.exists @@ -55400,7 +63021,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ipsec.conf - stat: + ansible.builtin.stat: path: /etc/ipsec.conf register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55413,7 +63034,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.conf - file: + ansible.builtin.file: path: /etc/ipsec.conf mode: u-xs,g-xws,o-xwt when: @@ -55465,7 +63086,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ipsec.secrets - stat: + ansible.builtin.stat: path: /etc/ipsec.secrets register: file_exists when: '"libreswan" in ansible_facts.packages' @@ -55478,7 +63099,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/ipsec.secrets - file: + ansible.builtin.file: path: /etc/ipsec.secrets mode: u-xs,g-xws,o-xwt when: @@ -55528,7 +63149,6 @@ requirements of each system. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -55585,10 +63205,11 @@ requirements of each system. PR.AC-5 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-006010 - SV-271863r1092639_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006010 + SV-271863r1092639_rule IP tunneling mechanisms can be used to bypass network filtering. + @@ -55618,7 +63239,8 @@ sophisticated ruleset tailored to your environment, please consult the references at the end of this section. Verify Group Who Owns /etc/iptables Directory - To properly set the group owner of /etc/iptables, run the command: $ sudo chgrp root /etc/iptables + To properly set the group owner of /etc/iptables, run the command: +$ sudo chgrp root /etc/iptables R50 The ownership of the /etc/iptables directory by the root group is important @@ -55629,7 +63251,17 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/iptables/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55646,11 +63278,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"iptables" in ansible_facts.packages' + - directory_groupowner_etc_iptables_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_iptables_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_iptables_newgroup: root + when: + - '"iptables" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/iptables/ - file: + ansible.builtin.file: path: /etc/iptables/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_iptables_newgroup }}' when: '"iptables" in ansible_facts.packages' tags: - configure_strategy @@ -55669,7 +63332,8 @@ fi Verify User Who Owns /etc/iptables Directory - To properly set the owner of /etc/iptables, run the command: $ sudo chown root /etc/iptables + To properly set the owner of /etc/iptables, run the command: +$ sudo chown root /etc/iptables R50 The ownership of the /etc/iptables directory by the root user is important @@ -55680,7 +63344,17 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/iptables/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55697,11 +63371,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_iptables_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_iptables_newown: '0' + when: '"iptables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_iptables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/iptables/ - file: + ansible.builtin.file: path: /etc/iptables/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_iptables_newown }}' when: '"iptables" in ansible_facts.packages' tags: - configure_strategy @@ -55731,7 +63418,7 @@ ensures exclusive control of the iptables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q iptables; then -find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/iptables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -55749,7 +63436,8 @@ fi - no_reboot_needed - name: Find /etc/iptables/ file(s) - command: 'find -H /etc/iptables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/iptables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -55764,7 +63452,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/iptables/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -55935,9 +63623,9 @@ The iptables service can be enabled with the following co A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -55954,7 +63642,7 @@ The iptables service can be enabled with the following co capability for IPv4 and ICMP. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q iptables && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then +if ( rpm --quiet -q iptables && ! (systemctl is-active firewalld &>/dev/null) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'iptables.service' @@ -55987,7 +63675,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify iptables Enabled - Enable Service iptables @@ -55998,8 +63686,6 @@ fi masked: false when: - '"iptables" in ansible_facts.packages' - when: ( "iptables" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) tags: - NIST-800-53-AC-4 - NIST-800-53-CA-3(5) @@ -56012,6 +63698,9 @@ fi - medium_severity - no_reboot_needed - service_iptables_enabled + - special_service_block + when: ( "iptables" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_iptables @@ -56026,6 +63715,10 @@ class enable_iptables { [customizations.services] enabled = ["iptables"] + + + + @@ -56107,9 +63800,9 @@ If changes were required, reload the ip6tables rules: A.14.2.3 A.14.2.4 A.9.1.2 - CIP-003-8 R4 - CIP-003-8 R5 - CIP-004-6 R3 + CIP-003-8 R4 + CIP-003-8 R5 + CIP-004-6 R3 AC-4 CM-7(b) CA-3(5) @@ -56134,6 +63827,10 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi + + + + @@ -56177,7 +63874,9 @@ saved configuration file. To set the default policy to DROP (instead of ACCEPT) for the built-in INPUT chain which processes incoming packets, add or correct the following line in + /etc/sysconfig/iptables: + :INPUT DROP [0:0] 11 @@ -56505,7 +64204,7 @@ fi - reboot_required - name: Disable IPv6 Networking kernel module - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/ipv6.conf regexp: ^options\s+ipv6\s+disable=\d @@ -56523,7 +64222,7 @@ fi - reboot_required - name: Ensure disable_ipv6 (all and default) is set to 1 - sysctl: + ansible.posix.sysctl: name: '{{ item }}' value: '1' state: present @@ -56569,7 +64268,6 @@ functionality require the IPv6 stack loaded to work. DSS05.05 DSS06.06 3.1.20 - CCI-001551 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -56660,7 +64358,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv6.conf.all.disable_ipv6 # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv6.conf.all.disable_ipv6="1" fi @@ -56708,16 +64406,12 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.all.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -56731,14 +64425,61 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: Comment out any occurrences of net.ipv6.conf.all.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Find all files that contain + net.ipv6.conf.all.disable_ipv6 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.disable_ipv6\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Find all files that set net.ipv6.conf.all.disable_ipv6 + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.disable_ipv6\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_disable_ipv6 + +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Comment out any occurrences + of net.ipv6.conf.all.disable_ipv6 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv6.conf.all.disable_ipv6 replace: '#net.ipv6.conf.all.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -56751,8 +64492,9 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 -- name: Ensure sysctl net.ipv6.conf.all.disable_ipv6 is set to 1 - sysctl: +- name: Disable IPv6 Addressing on All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.disable_ipv6 + is set to 1 + ansible.posix.sysctl: name: net.ipv6.conf.all.disable_ipv6 value: '1' sysctl_file: /etc/sysctl.conf @@ -56771,6 +64513,10 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_disable_ipv6 + + + + @@ -56797,7 +64543,6 @@ functionality require the IPv6 stack loaded to work. DSS05.05 DSS06.06 3.1.20 - CCI-001551 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -56888,7 +64633,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv6.conf.default.disable_ipv6 # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv6.conf.default.disable_ipv6="1" fi @@ -56936,16 +64681,13 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv6.conf.default.disable_ipv6.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -56959,14 +64701,61 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: Comment out any occurrences of net.ipv6.conf.default.disable_ipv6 from config - files - replace: - path: '{{ item.path }}' +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Find all files that + contain net.ipv6.conf.default.disable_ipv6 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.disable_ipv6\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Find all files that + set net.ipv6.conf.default.disable_ipv6 to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.disable_ipv6\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_disable_ipv6 + +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Comment out any occurrences + of net.ipv6.conf.default.disable_ipv6 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv6.conf.default.disable_ipv6 replace: '#net.ipv6.conf.default.disable_ipv6' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -56979,8 +64768,9 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 -- name: Ensure sysctl net.ipv6.conf.default.disable_ipv6 is set to 1 - sysctl: +- name: Disable IPv6 Addressing on IPv6 Interfaces by Default - Ensure sysctl net.ipv6.conf.default.disable_ipv6 + is set to 1 + ansible.posix.sysctl: name: net.ipv6.conf.default.disable_ipv6 value: '1' sysctl_file: /etc/sysctl.conf @@ -56999,6 +64789,10 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_disable_ipv6 + + + + @@ -57166,7 +64960,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -57223,10 +65016,10 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006040 - SV-271877r1092343_rule + OL09-00-006040 + SV-271877r1092343_rule An illicit router advertisement message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -57262,7 +65055,7 @@ sysctl_net_ipv6_conf_all_accept_ra_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra is set - sysctl: +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Find all + files that contain net.ipv6.conf.all.accept_ra + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Find all + files that set net.ipv6.conf.all.accept_ra to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Comment + out any occurrences of net.ipv6.conf.all.accept_ra from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra + replace: '#net.ipv6.conf.all.accept_ra' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006040 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra + +- name: Configure Accepting Router Advertisements on All IPv6 Interfaces - Ensure + sysctl net.ipv6.conf.all.accept_ra is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}' sysctl_file: /etc/sysctl.conf @@ -57381,6 +65223,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_ra + + + + + @@ -57430,7 +65277,7 @@ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set - sysctl: +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.accept_ra_defrtr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_defrtr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.accept_ra_defrtr to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_defrtr\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.accept_ra_defrtr from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_defrtr + replace: '#net.ipv6.conf.all.accept_ra_defrtr' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.accept_ra_defrtr is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_defrtr value: '{{ sysctl_net_ipv6_conf_all_accept_ra_defrtr_value }}' sysctl_file: /etc/sysctl.conf @@ -57530,6 +65416,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_defrtr - unknown_severity + + + + + @@ -57579,7 +65470,7 @@ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set - sysctl: +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Find all files that contain net.ipv6.conf.all.accept_ra_pinfo + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_pinfo\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Find all files that set net.ipv6.conf.all.accept_ra_pinfo to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_pinfo\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Comment out any occurrences of net.ipv6.conf.all.accept_ra_pinfo + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_pinfo + replace: '#net.ipv6.conf.all.accept_ra_pinfo' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces - Ensure sysctl net.ipv6.conf.all.accept_ra_pinfo is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_pinfo value: '{{ sysctl_net_ipv6_conf_all_accept_ra_pinfo_value }}' sysctl_file: /etc/sysctl.conf @@ -57679,6 +65610,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_pinfo - unknown_severity + + + + + @@ -57728,7 +65664,7 @@ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set - sysctl: +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Find all files that contain net.ipv6.conf.all.accept_ra_rtr_pref + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_rtr_pref\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Find all files that set net.ipv6.conf.all.accept_ra_rtr_pref to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_ra_rtr_pref\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Comment out any occurrences of net.ipv6.conf.all.accept_ra_rtr_pref + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_ra_rtr_pref + replace: '#net.ipv6.conf.all.accept_ra_rtr_pref' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces - Ensure sysctl net.ipv6.conf.all.accept_ra_rtr_pref is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_ra_rtr_pref value: '{{ sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value }}' sysctl_file: /etc/sysctl.conf @@ -57828,6 +65804,11 @@ fi - sysctl_net_ipv6_conf_all_accept_ra_rtr_pref - unknown_severity + + + + + @@ -57853,7 +65834,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -57912,11 +65892,11 @@ To make sure that the setting is persistent, add the following line to a file in CM-6.1(iv) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006041 - SV-271878r1092346_rule + OL09-00-006041 + SV-271878r1092346_rule An illicit ICMP redirect message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -57952,7 +65932,7 @@ sysctl_net_ipv6_conf_all_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set - sysctl: +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Find all files + that contain net.ipv6.conf.all.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Find all files + that set net.ipv6.conf.all.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_redirects\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Comment out any + occurrences of net.ipv6.conf.all.accept_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_redirects + replace: '#net.ipv6.conf.all.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006041 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.accept_redirects + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_redirects value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -58080,6 +66112,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_redirects + + + + + @@ -58113,7 +66150,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -58162,11 +66198,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.AC-5 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006042 - SV-271879r1092349_rule + OL09-00-006042 + SV-271879r1092349_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the @@ -58210,7 +66246,7 @@ sysctl_net_ipv6_conf_all_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.accept_source_route to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.accept_source_route\s*=\s*{{ sysctl_net_ipv6_conf_all_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.accept_source_route from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.accept_source_route + replace: '#net.ipv6.conf.all.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006042 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.accept_source_route is set + ansible.posix.sysctl: name: net.ipv6.conf.all.accept_source_route value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -58330,6 +66415,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_accept_source_route + + + + + @@ -58379,7 +66469,7 @@ sysctl_net_ipv6_conf_all_autoconf_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.autoconf is set - sysctl: +- name: Configure Auto Configuration on All IPv6 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Find all files that + contain net.ipv6.conf.all.autoconf + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.autoconf\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Find all files that + set net.ipv6.conf.all.autoconf to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.autoconf\s*=\s*{{ sysctl_net_ipv6_conf_all_autoconf_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Comment out any occurrences + of net.ipv6.conf.all.autoconf from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.autoconf + replace: '#net.ipv6.conf.all.autoconf' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces - Ensure sysctl net.ipv6.conf.all.autoconf + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.autoconf value: '{{ sysctl_net_ipv6_conf_all_autoconf_value }}' sysctl_file: /etc/sysctl.conf @@ -58478,6 +66607,11 @@ fi - sysctl_net_ipv6_conf_all_autoconf - unknown_severity + + + + + @@ -58515,7 +66649,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS05.07 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -58581,9 +66714,9 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-006043 - SV-271880r1092352_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006043 + SV-271880r1092352_rule IP forwarding permits the kernel to forward packets from one network interface to another. The ability to forward packets between two networks is only appropriate for systems acting as routers. @@ -58621,7 +66754,7 @@ sysctl_net_ipv6_conf_all_forwarding_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.forwarding is set - sysctl: +- name: Disable Kernel Parameter for IPv6 Forwarding - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Find all files that contain + net.ipv6.conf.all.forwarding + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.forwarding\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Find all files that set net.ipv6.conf.all.forwarding + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.forwarding\s*=\s*{{ sysctl_net_ipv6_conf_all_forwarding_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Comment out any occurrences + of net.ipv6.conf.all.forwarding from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.forwarding + replace: '#net.ipv6.conf.all.forwarding' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006043 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv6 Forwarding - Ensure sysctl net.ipv6.conf.all.forwarding + is set + ansible.posix.sysctl: name: net.ipv6.conf.all.forwarding value: '{{ sysctl_net_ipv6_conf_all_forwarding_value }}' sysctl_file: /etc/sysctl.conf @@ -58744,6 +66927,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_all_forwarding + + + + + @@ -58793,7 +66981,7 @@ sysctl_net_ipv6_conf_all_max_addresses_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.max_addresses is set - sysctl: +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Find all files that contain net.ipv6.conf.all.max_addresses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.max_addresses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Find all files that set net.ipv6.conf.all.max_addresses to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.max_addresses\s*=\s*{{ sysctl_net_ipv6_conf_all_max_addresses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.all.max_addresses from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.max_addresses + replace: '#net.ipv6.conf.all.max_addresses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.all.max_addresses is set + ansible.posix.sysctl: name: net.ipv6.conf.all.max_addresses value: '{{ sysctl_net_ipv6_conf_all_max_addresses_value }}' sysctl_file: /etc/sysctl.conf @@ -58893,6 +67119,11 @@ fi - sysctl_net_ipv6_conf_all_max_addresses - unknown_severity + + + + + @@ -58942,7 +67173,7 @@ sysctl_net_ipv6_conf_all_router_solicitations_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.all.router_solicitations is set - sysctl: +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Set fact for + sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Find all files + that contain net.ipv6.conf.all.router_solicitations + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.router_solicitations\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Find all files + that set net.ipv6.conf.all.router_solicitations to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.all.router_solicitations\s*=\s*{{ sysctl_net_ipv6_conf_all_router_solicitations_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Comment out + any occurrences of net.ipv6.conf.all.router_solicitations from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.all.router_solicitations + replace: '#net.ipv6.conf.all.router_solicitations' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_all_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces - Ensure sysctl + net.ipv6.conf.all.router_solicitations is set + ansible.posix.sysctl: name: net.ipv6.conf.all.router_solicitations value: '{{ sysctl_net_ipv6_conf_all_router_solicitations_value }}' sysctl_file: /etc/sysctl.conf @@ -59042,6 +67311,11 @@ fi - sysctl_net_ipv6_conf_all_router_solicitations - unknown_severity + + + + + @@ -59067,7 +67341,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -59124,10 +67397,10 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006044 - SV-271881r1092355_rule + OL09-00-006044 + SV-271881r1092355_rule An illicit router advertisement message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -59163,7 +67436,7 @@ sysctl_net_ipv6_conf_default_accept_ra_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra is set - sysctl: +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Find all files that contain net.ipv6.conf.default.accept_ra + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Find all files that set net.ipv6.conf.default.accept_ra to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Comment out any occurrences of net.ipv6.conf.default.accept_ra from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra + replace: '#net.ipv6.conf.default.accept_ra' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006044 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra + +- name: Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + - Ensure sysctl net.ipv6.conf.default.accept_ra is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}' sysctl_file: /etc/sysctl.conf @@ -59283,6 +67604,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_ra + + + + + @@ -59332,7 +67658,7 @@ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set - sysctl: +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Find all files that contain net.ipv6.conf.default.accept_ra_defrtr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_defrtr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Find all files that set net.ipv6.conf.default.accept_ra_defrtr to + correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_defrtr\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_defrtr + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_defrtr + replace: '#net.ipv6.conf.default.accept_ra_defrtr' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_defrtr + - unknown_severity + +- name: Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_defrtr is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_defrtr value: '{{ sysctl_net_ipv6_conf_default_accept_ra_defrtr_value }}' sysctl_file: /etc/sysctl.conf @@ -59432,6 +67798,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_defrtr - unknown_severity + + + + + @@ -59481,7 +67852,7 @@ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is set - sysctl: +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that contain net.ipv6.conf.default.accept_ra_pinfo + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_pinfo\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that set net.ipv6.conf.default.accept_ra_pinfo + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_pinfo\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_pinfo + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_pinfo + replace: '#net.ipv6.conf.default.accept_ra_pinfo' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_pinfo + - unknown_severity + +- name: Configure Accepting Prefix Information in Router Advertisements on All IPv6 + Interfaces By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_pinfo is + set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_pinfo value: '{{ sysctl_net_ipv6_conf_default_accept_ra_pinfo_value }}' sysctl_file: /etc/sysctl.conf @@ -59581,6 +67993,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_pinfo - unknown_severity + + + + + @@ -59630,7 +68047,7 @@ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref is set - sysctl: +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that contain net.ipv6.conf.default.accept_ra_rtr_pref + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_rtr_pref\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Find all files that set net.ipv6.conf.default.accept_ra_rtr_pref + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_ra_rtr_pref\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Comment out any occurrences of net.ipv6.conf.default.accept_ra_rtr_pref + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_ra_rtr_pref + replace: '#net.ipv6.conf.default.accept_ra_rtr_pref' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref + - unknown_severity + +- name: Configure Accepting Router Preference in Router Advertisements on All IPv6 + Interfaces By Default - Ensure sysctl net.ipv6.conf.default.accept_ra_rtr_pref + is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_ra_rtr_pref value: '{{ sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value }}' sysctl_file: /etc/sysctl.conf @@ -59730,6 +68188,11 @@ fi - sysctl_net_ipv6_conf_default_accept_ra_rtr_pref - unknown_severity + + + + + @@ -59755,7 +68218,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.05 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -59812,11 +68274,11 @@ To make sure that the setting is persistent, add the following line to a file in CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 - OL09-00-006045 - SV-271882r1092358_rule + OL09-00-006045 + SV-271882r1092358_rule An illicit ICMP redirect message could result in a man-in-the-middle attack. # Remediation is applicable only in certain platforms @@ -59852,7 +68314,7 @@ sysctl_net_ipv6_conf_default_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Find all files that contain net.ipv6.conf.default.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Find all files that set net.ipv6.conf.default.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_redirects\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Comment out any occurrences of net.ipv6.conf.default.accept_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_redirects + replace: '#net.ipv6.conf.default.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006045 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + - Ensure sysctl net.ipv6.conf.default.accept_redirects is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_redirects value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -59972,6 +68483,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_redirects + + + + + @@ -60005,7 +68521,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -60057,13 +68572,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R13 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006046 - SV-271883r1092361_rule + OL09-00-006046 + SV-271883r1092361_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the @@ -60106,7 +68621,7 @@ sysctl_net_ipv6_conf_default_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Find all files that contain net.ipv6.conf.default.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Find all files that set net.ipv6.conf.default.accept_source_route + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.accept_source_route\s*=\s*{{ sysctl_net_ipv6_conf_default_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Comment out any occurrences of net.ipv6.conf.default.accept_source_route + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.accept_source_route + replace: '#net.ipv6.conf.default.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006046 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(b) + - NIST-800-53-CM-6.1(iv) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv6_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces + by Default - Ensure sysctl net.ipv6.conf.default.accept_source_route is set + ansible.posix.sysctl: name: net.ipv6.conf.default.accept_source_route value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -60246,6 +68821,11 @@ fi - reboot_required - sysctl_net_ipv6_conf_default_accept_source_route + + + + + @@ -60295,7 +68875,7 @@ sysctl_net_ipv6_conf_default_autoconf_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.autoconf is set - sysctl: +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Find all + files that contain net.ipv6.conf.default.autoconf + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.autoconf\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Find all + files that set net.ipv6.conf.default.autoconf to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.autoconf\s*=\s*{{ sysctl_net_ipv6_conf_default_autoconf_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Comment out + any occurrences of net.ipv6.conf.default.autoconf from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.autoconf + replace: '#net.ipv6.conf.default.autoconf' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_autoconf + - unknown_severity + +- name: Configure Auto Configuration on All IPv6 Interfaces By Default - Ensure sysctl + net.ipv6.conf.default.autoconf is set + ansible.posix.sysctl: name: net.ipv6.conf.default.autoconf value: '{{ sysctl_net_ipv6_conf_default_autoconf_value }}' sysctl_file: /etc/sysctl.conf @@ -60395,6 +69013,11 @@ fi - sysctl_net_ipv6_conf_default_autoconf - unknown_severity + + + + + @@ -60444,7 +69067,7 @@ sysctl_net_ipv6_conf_default_max_addresses_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.max_addresses is set - sysctl: +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Find all files that contain net.ipv6.conf.default.max_addresses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.max_addresses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Find all files that set net.ipv6.conf.default.max_addresses to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.max_addresses\s*=\s*{{ sysctl_net_ipv6_conf_default_max_addresses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Comment out any occurrences of net.ipv6.conf.default.max_addresses + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.max_addresses + replace: '#net.ipv6.conf.default.max_addresses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_max_addresses + - unknown_severity + +- name: Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + By Default - Ensure sysctl net.ipv6.conf.default.max_addresses is set + ansible.posix.sysctl: name: net.ipv6.conf.default.max_addresses value: '{{ sysctl_net_ipv6_conf_default_max_addresses_value }}' sysctl_file: /etc/sysctl.conf @@ -60544,6 +69207,11 @@ fi - sysctl_net_ipv6_conf_default_max_addresses - unknown_severity + + + + + @@ -60593,7 +69261,7 @@ sysctl_net_ipv6_conf_default_router_solicitations_value=' tags: - always -- name: Ensure sysctl net.ipv6.conf.default.router_solicitations is set - sysctl: +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Find all files that contain net.ipv6.conf.default.router_solicitations + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.router_solicitations\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Find all files that set net.ipv6.conf.default.router_solicitations to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv6.conf.default.router_solicitations\s*=\s*{{ sysctl_net_ipv6_conf_default_router_solicitations_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Comment out any occurrences of net.ipv6.conf.default.router_solicitations from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv6.conf.default.router_solicitations + replace: '#net.ipv6.conf.default.router_solicitations' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv6_conf_default_router_solicitations + - unknown_severity + +- name: Configure Denying Router Solicitations on All IPv6 Interfaces By Default - + Ensure sysctl net.ipv6.conf.default.router_solicitations is set + ansible.posix.sysctl: name: net.ipv6.conf.default.router_solicitations value: '{{ sysctl_net_ipv6_conf_default_router_solicitations_value }}' sysctl_file: /etc/sysctl.conf @@ -60693,6 +69401,11 @@ fi - sysctl_net_ipv6_conf_default_router_solicitations - unknown_severity + + + + + @@ -60924,7 +69637,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.accept_local # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.accept_local="0" fi @@ -60968,16 +69681,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Accepting Packets Routed Between Local Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.accept_local.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -60987,14 +69697,53 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: Comment out any occurrences of net.ipv4.conf.all.accept_local from config - files - replace: - path: '{{ item.path }}' +- name: Disable Accepting Packets Routed Between Local Interfaces - Find all files + that contain net.ipv4.conf.all.accept_local + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_local\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Disable Accepting Packets Routed Between Local Interfaces - Find all files + that set net.ipv4.conf.all.accept_local to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_local\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_local + +- name: Disable Accepting Packets Routed Between Local Interfaces - Comment out any + occurrences of net.ipv4.conf.all.accept_local from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.accept_local replace: '#net.ipv4.conf.all.accept_local' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -61003,8 +69752,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local -- name: Ensure sysctl net.ipv4.conf.all.accept_local is set to 0 - sysctl: +- name: Disable Accepting Packets Routed Between Local Interfaces - Ensure sysctl + net.ipv4.conf.all.accept_local is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_local value: '0' sysctl_file: /etc/sysctl.conf @@ -61019,6 +69769,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_local + + + + @@ -61057,7 +69811,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -61122,11 +69875,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006020 - SV-271864r1092304_rule + OL09-00-006020 + SV-271864r1092304_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect @@ -61167,7 +69920,7 @@ sysctl_net_ipv4_conf_all_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set - sysctl: +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Find all files + that contain net.ipv4.conf.all.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Find all files + that set net.ipv4.conf.all.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_redirects\s*=\s*{{ sysctl_net_ipv4_conf_all_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Comment out any + occurrences of net.ipv4.conf.all.accept_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_redirects + replace: '#net.ipv4.conf.all.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006020 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_redirects + +- name: Disable Accepting ICMP Redirects for All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.accept_redirects + is set + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_redirects value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -61295,6 +70100,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_redirects + + + + + @@ -61341,7 +70151,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -61434,10 +70243,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -61452,11 +70261,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006021 - SV-271865r1092307_rule + OL09-00-006021 + SV-271865r1092307_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement @@ -61499,7 +70308,7 @@ sysctl_net_ipv4_conf_all_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.accept_source_route to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.accept_source_route\s*=\s*{{ sysctl_net_ipv4_conf_all_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.accept_source_route from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.accept_source_route + replace: '#net.ipv4.conf.all.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006021 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.accept_source_route is set + ansible.posix.sysctl: name: net.ipv4.conf.all.accept_source_route value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -61627,6 +70489,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_accept_source_route + + + + + @@ -61680,7 +70547,7 @@ sysctl_net_ipv4_conf_all_arp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.arp_filter is set - sysctl: +- name: Configure ARP filtering for All IPv4 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Find all files that contain + net.ipv4.conf.all.arp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Find all files that set + net.ipv4.conf.all.arp_filter to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_filter\s*=\s*{{ sysctl_net_ipv4_conf_all_arp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Comment out any occurrences + of net.ipv4.conf.all.arp_filter from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_filter + replace: '#net.ipv4.conf.all.arp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_filter + +- name: Configure ARP filtering for All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.arp_filter + is set + ansible.posix.sysctl: name: net.ipv4.conf.all.arp_filter value: '{{ sysctl_net_ipv4_conf_all_arp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -61779,6 +70684,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_arp_filter + + + + + @@ -61830,7 +70740,7 @@ sysctl_net_ipv4_conf_all_arp_ignore_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.arp_ignore is set - sysctl: +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Find all + files that contain net.ipv4.conf.all.arp_ignore + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_ignore\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Find all + files that set net.ipv4.conf.all.arp_ignore to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.arp_ignore\s*=\s*{{ sysctl_net_ipv4_conf_all_arp_ignore_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.arp_ignore from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.arp_ignore + replace: '#net.ipv4.conf.all.arp_ignore' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_arp_ignore + +- name: Configure Response Mode of ARP Requests for All IPv4 Interfaces - Ensure sysctl + net.ipv4.conf.all.arp_ignore is set + ansible.posix.sysctl: name: net.ipv4.conf.all.arp_ignore value: '{{ sysctl_net_ipv4_conf_all_arp_ignore_value }}' sysctl_file: /etc/sysctl.conf @@ -61929,6 +70878,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_arp_ignore + + + + + @@ -61938,7 +70892,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces To set the runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.all.drop_gratuitous_arp=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.all.drop_gratuitous_arp = 1 @@ -61976,7 +70930,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.drop_gratuitous_arp # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.drop_gratuitous_arp="1" fi @@ -62020,16 +70974,12 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -62039,14 +70989,53 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: Comment out any occurrences of net.ipv4.conf.all.drop_gratuitous_arp from - config files - replace: - path: '{{ item.path }}' +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Find all files that contain + net.ipv4.conf.all.drop_gratuitous_arp + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.drop_gratuitous_arp\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Find all files that set + net.ipv4.conf.all.drop_gratuitous_arp to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.drop_gratuitous_arp\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Comment out any occurrences + of net.ipv4.conf.all.drop_gratuitous_arp from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.drop_gratuitous_arp replace: '#net.ipv4.conf.all.drop_gratuitous_arp' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -62055,8 +71044,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp -- name: Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp is set to 1 - sysctl: +- name: Drop Gratuitous ARP frames on All IPv4 Interfaces - Ensure sysctl net.ipv4.conf.all.drop_gratuitous_arp + is set to 1 + ansible.posix.sysctl: name: net.ipv4.conf.all.drop_gratuitous_arp value: '1' sysctl_file: /etc/sysctl.conf @@ -62071,6 +71061,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_drop_gratuitous_arp + + + + @@ -62088,11 +71082,10 @@ One such case is Libvirt; a toolkit By default, Libvirt requires IP forwarding to be enabled to facilitate network communication between the virtualization host and guest machines. It enables IP forwarding after every reboot. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-006028 - SV-271872r1092328_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006028 + SV-271872r1092328_rule IP forwarding permits the kernel to forward packets from one network interface to another. The ability to forward packets between two networks is only appropriate for systems acting as routers. @@ -62130,7 +71123,7 @@ sysctl_net_ipv4_conf_all_forwarding_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.forwarding is set - sysctl: +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Find + all files that contain net.ipv4.conf.all.forwarding + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.forwarding\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Find + all files that set net.ipv4.conf.all.forwarding to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.forwarding\s*=\s*{{ sysctl_net_ipv4_conf_all_forwarding_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.forwarding from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.forwarding + replace: '#net.ipv4.conf.all.forwarding' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006028 + - NIST-800-53-CM-6(b) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_forwarding + +- name: Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - Ensure + sysctl net.ipv4.conf.all.forwarding is set + ansible.posix.sysctl: name: net.ipv4.conf.all.forwarding value: '{{ sysctl_net_ipv4_conf_all_forwarding_value }}' sysctl_file: /etc/sysctl.conf @@ -62237,6 +71273,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_forwarding + + + + + @@ -62277,7 +71318,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -62357,10 +71397,10 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006022 - SV-271866r1092310_rule + OL09-00-006022 + SV-271866r1092310_rule The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity @@ -62398,7 +71438,7 @@ sysctl_net_ipv4_conf_all_log_martians_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.log_martians is set - sysctl: +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Find + all files that contain net.ipv4.conf.all.log_martians + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.log_martians\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Find + all files that set net.ipv4.conf.all.log_martians to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.log_martians\s*=\s*{{ sysctl_net_ipv4_conf_all_log_martians_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Comment + out any occurrences of net.ipv4.conf.all.log_martians from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.log_martians + replace: '#net.ipv4.conf.all.log_martians' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006022 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_all_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - Ensure + sysctl net.ipv4.conf.all.log_martians is set + ansible.posix.sysctl: name: net.ipv4.conf.all.log_martians value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}' sysctl_file: /etc/sysctl.conf @@ -62518,6 +71606,11 @@ fi - sysctl_net_ipv4_conf_all_log_martians - unknown_severity + + + + + @@ -62566,7 +71659,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.route_localnet # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.route_localnet="0" fi @@ -62610,16 +71703,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.route_localnet.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -62629,14 +71719,54 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: Comment out any occurrences of net.ipv4.conf.all.route_localnet from config +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.route_localnet + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.route_localnet\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.route_localnet to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.route_localnet\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_route_localnet + +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.route_localnet from config files - replace: - path: '{{ item.path }}' + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.route_localnet replace: '#net.ipv4.conf.all.route_localnet' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -62645,8 +71775,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet -- name: Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 - sysctl: +- name: Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.route_localnet is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.route_localnet value: '0' sysctl_file: /etc/sysctl.conf @@ -62661,6 +71792,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_route_localnet + + + + @@ -62698,7 +71833,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -62755,13 +71889,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006024 - SV-271868r1092316_rule + OL09-00-006024 + SV-271868r1092316_rule Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for @@ -62800,7 +71934,7 @@ sysctl_net_ipv4_conf_all_rp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.rp_filter is set - sysctl: +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.rp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.rp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.rp_filter to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.rp_filter\s*=\s*{{ sysctl_net_ipv4_conf_all_rp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.rp_filter from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.rp_filter + replace: '#net.ipv4.conf.all.rp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006024 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.rp_filter is set + ansible.posix.sysctl: name: net.ipv4.conf.all.rp_filter value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -62935,7 +72126,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_rp_filter + + + + + + @@ -62980,8 +72177,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-001503 - CCI-001551 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63088,7 +72283,7 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 @@ -63129,7 +72324,7 @@ sysctl_net_ipv4_conf_all_secure_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.secure_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.secure_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.secure_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.secure_redirects\s*=\s*{{ sysctl_net_ipv4_conf_all_secure_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.secure_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.secure_redirects + replace: '#net.ipv4.conf.all.secure_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_secure_redirects + +- name: Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.secure_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.all.secure_redirects value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -63261,6 +72511,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_secure_redirects + + + + + @@ -63312,7 +72567,7 @@ sysctl_net_ipv4_conf_all_shared_media_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.all.shared_media is set - sysctl: +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.shared_media + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.shared_media\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.shared_media to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.shared_media\s*=\s*{{ sysctl_net_ipv4_conf_all_shared_media_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.shared_media from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.all.shared_media + replace: '#net.ipv4.conf.all.shared_media' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.shared_media is set + ansible.posix.sysctl: name: net.ipv4.conf.all.shared_media value: '{{ sysctl_net_ipv4_conf_all_shared_media_value }}' sysctl_file: /etc/sysctl.conf @@ -63412,6 +72705,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_shared_media + + + + + @@ -63459,7 +72757,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63566,13 +72863,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006025 - SV-271869r1092319_rule + OL09-00-006025 + SV-271869r1092319_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect @@ -63612,7 +72909,7 @@ sysctl_net_ipv4_conf_default_accept_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set - sysctl: +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Find all files that contain net.ipv4.conf.default.accept_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Find all files that set net.ipv4.conf.default.accept_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_redirects\s*=\s*{{ sysctl_net_ipv4_conf_default_accept_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.default.accept_redirects from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_redirects + replace: '#net.ipv4.conf.default.accept_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006025 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_redirects + +- name: Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.default.accept_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.default.accept_redirects value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -63752,6 +73108,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_accept_redirects + + + + + @@ -63799,7 +73160,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -63892,10 +73252,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -63909,11 +73269,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006026 - SV-271870r1092322_rule + OL09-00-006026 + SV-271870r1092322_rule Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. @@ -63955,7 +73315,7 @@ sysctl_net_ipv4_conf_default_accept_source_route_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set - sysctl: +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.accept_source_route + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_source_route\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.accept_source_route + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.accept_source_route\s*=\s*{{ sysctl_net_ipv4_conf_default_accept_source_route_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.accept_source_route + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.accept_source_route + replace: '#net.ipv4.conf.default.accept_source_route' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006026 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_accept_source_route + +- name: Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.accept_source_route is set + ansible.posix.sysctl: name: net.ipv4.conf.default.accept_source_route value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}' sysctl_file: /etc/sysctl.conf @@ -64083,6 +73497,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_accept_source_route + + + + + @@ -64092,7 +73511,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default To set the runtime status of the net.ipv4.conf.default.log_martians kernel parameter, run the following command: $ sudo sysctl -w net.ipv4.conf.default.log_martians=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.ipv4.conf.default.log_martians = 1 @@ -64123,7 +73542,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -64203,10 +73621,10 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 - OL09-00-006023 - SV-271867r1092313_rule + OL09-00-006023 + SV-271867r1092313_rule The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity @@ -64244,7 +73662,7 @@ sysctl_net_ipv4_conf_default_log_martians_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.log_martians is set - sysctl: +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Find all files that contain net.ipv4.conf.default.log_martians + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.log_martians\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Find all files that set net.ipv4.conf.default.log_martians to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.log_martians\s*=\s*{{ sysctl_net_ipv4_conf_default_log_martians_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Comment out any occurrences of net.ipv4.conf.default.log_martians from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.log_martians + replace: '#net.ipv4.conf.default.log_martians' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006023 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(3)(a) + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_conf_default_log_martians + - unknown_severity + +- name: Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + - Ensure sysctl net.ipv4.conf.default.log_martians is set + ansible.posix.sysctl: name: net.ipv4.conf.default.log_martians value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}' sysctl_file: /etc/sysctl.conf @@ -64364,6 +73831,11 @@ fi - sysctl_net_ipv4_conf_default_log_martians - unknown_severity + + + + + @@ -64402,7 +73874,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.4.3.3 @@ -64458,11 +73929,11 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-4 PR.DS-5 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 - OL09-00-006027 - SV-271871r1092325_rule + OL09-00-006027 + SV-271871r1092325_rule Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for @@ -64501,7 +73972,7 @@ sysctl_net_ipv4_conf_default_rp_filter_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.rp_filter is set - sysctl: +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.rp_filter + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.rp_filter\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.rp_filter to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.rp_filter\s*=\s*{{ sysctl_net_ipv4_conf_default_rp_filter_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.rp_filter from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.rp_filter + replace: '#net.ipv4.conf.default.rp_filter' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006027 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_rp_filter + +- name: Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.rp_filter is set + ansible.posix.sysctl: name: net.ipv4.conf.default.rp_filter value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}' sysctl_file: /etc/sysctl.conf @@ -64625,6 +74148,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_rp_filter + + + + + @@ -64671,7 +74199,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-001551 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -64764,10 +74291,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -64781,7 +74308,7 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 Accepting "secure" ICMP redirects (from those gateways listed as @@ -64820,7 +74347,7 @@ sysctl_net_ipv4_conf_default_secure_redirects_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set - sysctl: +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Find + all files that contain net.ipv4.conf.default.secure_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.secure_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Find + all files that set net.ipv4.conf.default.secure_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.secure_redirects\s*=\s*{{ sysctl_net_ipv4_conf_default_secure_redirects_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Comment + out any occurrences of net.ipv4.conf.default.secure_redirects from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.secure_redirects + replace: '#net.ipv4.conf.default.secure_redirects' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_secure_redirects + +- name: Configure Kernel Parameter for Accepting Secure Redirects By Default - Ensure + sysctl net.ipv4.conf.default.secure_redirects is set + ansible.posix.sysctl: name: net.ipv4.conf.default.secure_redirects value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}' sysctl_file: /etc/sysctl.conf @@ -64940,6 +74515,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_secure_redirects + + + + + @@ -64991,7 +74571,7 @@ sysctl_net_ipv4_conf_default_shared_media_value=' tags: - always -- name: Ensure sysctl net.ipv4.conf.default.shared_media is set - sysctl: +- name: Configure Sending and Accepting Shared Media Redirects by Default - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Find all + files that contain net.ipv4.conf.default.shared_media + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.shared_media\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Find all + files that set net.ipv4.conf.default.shared_media to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.shared_media\s*=\s*{{ sysctl_net_ipv4_conf_default_shared_media_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Comment + out any occurrences of net.ipv4.conf.default.shared_media from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.conf.default.shared_media + replace: '#net.ipv4.conf.default.shared_media' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_shared_media + +- name: Configure Sending and Accepting Shared Media Redirects by Default - Ensure + sysctl net.ipv4.conf.default.shared_media is set + ansible.posix.sysctl: name: net.ipv4.conf.default.shared_media value: '{{ sysctl_net_ipv4_conf_default_shared_media_value }}' sysctl_file: /etc/sysctl.conf @@ -65091,6 +74709,11 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_shared_media + + + + + @@ -65138,7 +74761,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -65231,10 +74853,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -65248,12 +74870,12 @@ To make sure that the setting is persistent, add the following line to a file in PR.PT-3 PR.PT-4 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006030 - SV-271873r1092331_rule + OL09-00-006030 + SV-271873r1092331_rule Responding to broadcast (ICMP) echoes facilitates network mapping and provides a vector for amplification attacks. @@ -65292,7 +74914,7 @@ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value=' tags: - always -- name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set - sysctl: +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Find all files that contain net.ipv4.icmp_echo_ignore_broadcasts + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_echo_ignore_broadcasts\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Find all files that set net.ipv4.icmp_echo_ignore_broadcasts to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_echo_ignore_broadcasts\s*=\s*{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from config + files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts + replace: '#net.ipv4.icmp_echo_ignore_broadcasts' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006030 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + +- name: Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + - Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set + ansible.posix.sysctl: name: net.ipv4.icmp_echo_ignore_broadcasts value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}' sysctl_file: /etc/sysctl.conf @@ -65428,6 +75107,11 @@ fi - reboot_required - sysctl_net_ipv4_icmp_echo_ignore_broadcasts + + + + + @@ -65466,7 +75150,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -65523,10 +75206,10 @@ To make sure that the setting is persistent, add the following line to a file in A.14.2.4 A.17.2.1 A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -65535,13 +75218,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 Req-1.4.3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.2 1.4 - OL09-00-006031 - SV-271874r1092612_rule + OL09-00-006031 + SV-271874r1092612_rule Ignoring bogus ICMP error responses reduces log size, although some activity would not be logged. # Remediation is applicable only in certain platforms @@ -65577,7 +75260,7 @@ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value=' tags: - always -- name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set - sysctl: +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Find all files that contain net.ipv4.icmp_ignore_bogus_error_responses + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_ignore_bogus_error_responses\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Find all files that set net.ipv4.icmp_ignore_bogus_error_responses to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.icmp_ignore_bogus_error_responses\s*=\s*{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses + replace: '#net.ipv4.icmp_ignore_bogus_error_responses' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-006031 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - PCI-DSS-Req-1.4.3 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - disable_strategy + - low_complexity + - medium_disruption + - reboot_required + - sysctl_net_ipv4_icmp_ignore_bogus_error_responses + - unknown_severity + +- name: Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + - Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set + ansible.posix.sysctl: name: net.ipv4.icmp_ignore_bogus_error_responses value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}' sysctl_file: /etc/sysctl.conf @@ -65709,6 +75448,11 @@ fi - sysctl_net_ipv4_icmp_ignore_bogus_error_responses - unknown_severity + + + + + @@ -65757,7 +75501,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.ip_local_port_range # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.ip_local_port_range="32768 65535" fi @@ -65801,16 +75545,12 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Set Kernel Parameter to Increase Local Port Range - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_local_port_range.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -65820,13 +75560,53 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: Comment out any occurrences of net.ipv4.ip_local_port_range from config files - replace: - path: '{{ item.path }}' +- name: Set Kernel Parameter to Increase Local Port Range - Find all files that contain + net.ipv4.ip_local_port_range + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_local_port_range\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Set Kernel Parameter to Increase Local Port Range - Find all files that set + net.ipv4.ip_local_port_range to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_local_port_range\s*=\s*32768 65535$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_local_port_range + +- name: Set Kernel Parameter to Increase Local Port Range - Comment out any occurrences + of net.ipv4.ip_local_port_range from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.ip_local_port_range replace: '#net.ipv4.ip_local_port_range' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -65835,8 +75615,9 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range -- name: Ensure sysctl net.ipv4.ip_local_port_range is set to 32768 65535 - sysctl: +- name: Set Kernel Parameter to Increase Local Port Range - Ensure sysctl net.ipv4.ip_local_port_range + is set to 32768 65535 + ansible.posix.sysctl: name: net.ipv4.ip_local_port_range value: 32768 65535 sysctl_file: /etc/sysctl.conf @@ -65851,6 +75632,10 @@ fi - reboot_required - sysctl_net_ipv4_ip_local_port_range + + + + @@ -65900,7 +75685,7 @@ sysctl_net_ipv4_tcp_rfc1337_value=' tags: - always -- name: Ensure sysctl net.ipv4.tcp_rfc1337 is set - sysctl: +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Find all + files that contain net.ipv4.tcp_rfc1337 + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_rfc1337\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Find all + files that set net.ipv4.tcp_rfc1337 to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_rfc1337\s*=\s*{{ sysctl_net_ipv4_tcp_rfc1337_value }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Comment out + any occurrences of net.ipv4.tcp_rfc1337 from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.tcp_rfc1337 + replace: '#net.ipv4.tcp_rfc1337' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_rfc1337 + +- name: Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - Ensure sysctl + net.ipv4.tcp_rfc1337 is set + ansible.posix.sysctl: name: net.ipv4.tcp_rfc1337 value: '{{ sysctl_net_ipv4_tcp_rfc1337_value }}' sysctl_file: /etc/sysctl.conf @@ -65999,6 +75822,11 @@ fi - reboot_required - sysctl_net_ipv4_tcp_rfc1337 + + + + + @@ -66038,9 +75866,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS05.07 DSS06.02 3.1.20 - CCI-001095 - CCI-000366 - CCI-002385 4.2.3.4 4.3.3.4 4.4.3.3 @@ -66099,15 +75924,15 @@ To make sure that the setting is persistent, add the following line to a file in PR.DS-5 PR.PT-4 Req-1.4.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000420-GPOS-00186 - SRG-OS-000142-GPOS-00071 + SRG-OS-000480-GPOS-00227 + SRG-OS-000420-GPOS-00186 + SRG-OS-000142-GPOS-00071 R12 A.8.SEC-OL6 1.4.3 1.4 - OL09-00-006050 - SV-271884r1092364_rule + OL09-00-006050 + SV-271884r1092364_rule A TCP SYN flood attack can cause a denial of service by filling a system's TCP connection table with connections in the SYN_RCVD state. Syncookies can be used to track a connection when a subsequent ACK is received, @@ -66147,7 +75972,7 @@ sysctl_net_ipv4_tcp_syncookies_value=' tags: - always -- name: Ensure sysctl net.ipv4.tcp_syncookies is set - sysctl: +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Find + all files that contain net.ipv4.tcp_syncookies + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_syncookies\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Find + all files that set net.ipv4.tcp_syncookies to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.tcp_syncookies\s*=\s*{{ sysctl_net_ipv4_tcp_syncookies_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Comment + out any occurrences of net.ipv4.tcp_syncookies from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*net.ipv4.tcp_syncookies + replace: '#net.ipv4.tcp_syncookies' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006050 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5(1) + - NIST-800-53-SC-5(2) + - NIST-800-53-SC-5(3)(a) + - PCI-DSS-Req-1.4.1 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_tcp_syncookies + +- name: Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - Ensure + sysctl net.ipv4.tcp_syncookies is set + ansible.posix.sysctl: name: net.ipv4.tcp_syncookies value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}' sysctl_file: /etc/sysctl.conf @@ -66294,6 +76182,11 @@ fi - reboot_required - sysctl_net_ipv4_tcp_syncookies + + + + + @@ -66348,7 +76241,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -66441,10 +76333,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -66459,13 +76351,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.5 1.4 - OL09-00-006032 - SV-271875r1092337_rule + OL09-00-006032 + SV-271875r1092337_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology. @@ -66502,7 +76394,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.all.send_redirects # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0" fi @@ -66556,16 +76448,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.1 @@ -66585,14 +76474,74 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from config +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Find all files that contain net.ipv4.conf.all.send_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.send_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Find all files that set net.ipv4.conf.all.send_redirects to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.all.send_redirects\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006032 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_all_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Comment out any occurrences of net.ipv4.conf.all.send_redirects from config files - replace: - path: '{{ item.path }}' + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.all.send_redirects replace: '#net.ipv4.conf.all.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - CJIS-5.10.1.1 - DISA-STIG-OL09-00-006032 @@ -66611,8 +76560,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects -- name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 - sysctl: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + - Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.all.send_redirects value: '0' sysctl_file: /etc/sysctl.conf @@ -66637,6 +76587,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_all_send_redirects + + + + @@ -66683,7 +76637,6 @@ To make sure that the setting is persistent, add the following line to a file in DSS06.02 DSS06.06 3.1.20 - CCI-000366 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -66776,10 +76729,10 @@ To make sure that the setting is persistent, add the following line to a file in A.9.4.1 A.9.4.4 A.9.4.5 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -66794,13 +76747,13 @@ To make sure that the setting is persistent, add the following line to a file in PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.5 1.4 - OL09-00-006033 - SV-271876r1092641_rule + OL09-00-006033 + SV-271876r1092641_rule ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology. @@ -66837,7 +76790,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.conf.default.send_redirects # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0" fi @@ -66891,16 +76844,13 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.10.1.1 @@ -66920,14 +76870,75 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from config - files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Find all files that contain net.ipv4.conf.default.send_redirects + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.send_redirects\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Find all files that set net.ipv4.conf.default.send_redirects to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.conf.default.send_redirects\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.10.1.1 + - DISA-STIG-OL09-00-006033 + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.5 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_conf_default_send_redirects + +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Comment out any occurrences of net.ipv4.conf.default.send_redirects + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.conf.default.send_redirects replace: '#net.ipv4.conf.default.send_redirects' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - CJIS-5.10.1.1 - DISA-STIG-OL09-00-006033 @@ -66946,8 +76957,9 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects -- name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 - sysctl: +- name: Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + by Default - Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0 + ansible.posix.sysctl: name: net.ipv4.conf.default.send_redirects value: '0' sysctl_file: /etc/sysctl.conf @@ -66972,6 +76984,10 @@ fi - reboot_required - sysctl_net_ipv4_conf_default_send_redirects + + + + @@ -67012,7 +77028,6 @@ profiles or benchmarks that target usage of IPv4 forwarding. DSS05.07 DSS06.06 3.1.20 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -67080,10 +77095,10 @@ profiles or benchmarks that target usage of IPv4 forwarding. A.14.2.4 A.17.2.1 A.9.1.2 - CIP-007-3 R4 - CIP-007-3 R4.1 - CIP-007-3 R4.2 - CIP-007-3 R5.1 + CIP-007-3 R4 + CIP-007-3 R4.1 + CIP-007-3 R4.2 + CIP-007-3 R5.1 CM-7(a) CM-7(b) SC-5 @@ -67096,7 +77111,7 @@ profiles or benchmarks that target usage of IPv4 forwarding. PR.PT-4 Req-1.3.1 Req-1.3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 A.8.SEC-OL6 1.4.3 @@ -67136,7 +77151,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.ipv4.ip_forward # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.ipv4.ip_forward="0" fi @@ -67190,16 +77205,13 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Set fact for + sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.ipv4.ip_forward.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.20 @@ -67219,13 +77231,73 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: Comment out any occurrences of net.ipv4.ip_forward from config files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Find all files + that contain net.ipv4.ip_forward + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_forward\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Find all files + that set net.ipv4.ip_forward to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.ipv4.ip_forward\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.20 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-SC-5 + - NIST-800-53-SC-7(a) + - PCI-DSS-Req-1.3.1 + - PCI-DSS-Req-1.3.2 + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.3 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_ipv4_ip_forward + +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Comment out + any occurrences of net.ipv4.ip_forward from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.ipv4.ip_forward replace: '#net.ipv4.ip_forward' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-171-3.1.20 - NIST-800-53-CM-6(a) @@ -67244,8 +77316,9 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward -- name: Ensure sysctl net.ipv4.ip_forward is set to 0 - sysctl: +- name: Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - Ensure sysctl + net.ipv4.ip_forward is set to 0 + ansible.posix.sysctl: name: net.ipv4.ip_forward value: '0' sysctl_file: /etc/sysctl.conf @@ -67270,6 +77343,10 @@ fi - reboot_required - sysctl_net_ipv4_ip_forward + + + + @@ -67312,7 +77389,7 @@ originating from within a corporate network to include malicious mobile code and configured software on a host. # Remediation is applicable only in certain platforms -if ( rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then +if ( ! (systemctl is-active iptables &>/dev/null) && ! (systemctl is-active ufw &>/dev/null) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); then if ! rpm -q --quiet "nftables" ; then yum install -y "nftables" @@ -67336,7 +77413,7 @@ fi - package_nftables_installed - name: Ensure nftables is installed - package: + ansible.builtin.package: name: nftables state: present when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -67425,86 +77502,52 @@ fi - no_reboot_needed - service_nftables_disabled -- name: Verify nftables Service is Disabled - Collect systemd Services Present in - the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Verify nftables Service is Disabled - Disable service nftables + block: + + - name: Verify nftables Service is Disabled - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Verify nftables Service is Disabled - Ensure nftables.service is Masked + ansible.builtin.systemd: + name: nftables.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("nftables.service", multiline=True) + + - name: Unit Socket Exists - nftables.socket + ansible.builtin.command: systemctl -q list-unit-files nftables.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Verify nftables Service is Disabled - Disable Socket nftables + ansible.builtin.systemd: + name: nftables.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("nftables.socket", multiline=True) + tags: + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.1 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_nftables_disabled + - special_service_block when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Verify nftables Service is Disabled - Ensure nftables.service is Masked - ansible.builtin.systemd: - name: nftables.service - state: stopped - enabled: false - masked: true - when: - - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - - service_exists.stdout_lines is search("nftables.service", multiline=True) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Unit Socket Exists - nftables.socket - ansible.builtin.command: systemctl -q list-unit-files nftables.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled - -- name: Verify nftables Service is Disabled - Disable Socket nftables - ansible.builtin.systemd: - name: nftables.socket - enabled: false - state: stopped - masked: true - when: - - ( "firewalld" in ansible_facts.packages and "nftables" in ansible_facts.packages - and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ) - - socket_file_exists.stdout_lines is search("nftables.socket", multiline=True) - tags: - - PCI-DSSv4-1.2 - - PCI-DSSv4-1.2.1 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_nftables_disabled include disable_nftables @@ -67519,6 +77562,10 @@ class disable_nftables { [customizations.services] masked = ["nftables"] + + + + @@ -67528,7 +77575,8 @@ masked = ["nftables"] Verify Group Who Owns /etc/nftables Directory - To properly set the group owner of /etc/nftables, run the command: $ sudo chgrp root /etc/nftables + To properly set the group owner of /etc/nftables, run the command: +$ sudo chgrp root /etc/nftables R50 The ownership of the /etc/nftables directory by the root group is important @@ -67539,7 +77587,17 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/nftables/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67556,11 +77614,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - '"nftables" in ansible_facts.packages' + - directory_groupowner_etc_nftables_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_nftables_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_nftables_newgroup: root + when: + - '"nftables" in ansible_facts.packages' + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/nftables/ - file: + ansible.builtin.file: path: /etc/nftables/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_nftables_newgroup }}' when: '"nftables" in ansible_facts.packages' tags: - configure_strategy @@ -67579,7 +77668,8 @@ fi Verify User Who Owns /etc/nftables Directory - To properly set the owner of /etc/nftables, run the command: $ sudo chown root /etc/nftables + To properly set the owner of /etc/nftables, run the command: +$ sudo chown root /etc/nftables R50 The ownership of the /etc/nftables directory by the root user is important @@ -67590,7 +77680,17 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/nftables/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67607,11 +77707,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_nftables_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_nftables_newown: '0' + when: '"nftables" in ansible_facts.packages' + tags: + - configure_strategy + - directory_owner_etc_nftables + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/nftables/ - file: + ansible.builtin.file: path: /etc/nftables/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_nftables_newown }}' when: '"nftables" in ansible_facts.packages' tags: - configure_strategy @@ -67641,7 +77754,7 @@ ensures exclusive control of the nftables configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q nftables; then -find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/nftables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -67659,7 +77772,8 @@ fi - no_reboot_needed - name: Find /etc/nftables/ file(s) - command: 'find -H /etc/nftables/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/nftables/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -67674,7 +77788,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/nftables/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -67725,8 +77839,7 @@ for other distributions and graphical frontends. The ufw service can be enabled with the following command: $ sudo systemctl enable ufw.service - CCI-002314 - SRG-OS-000297-GPOS-00115 + SRG-OS-000297-GPOS-00115 The ufw service must be enabled and running in order for ufw to protect the system # Remediation is applicable only in certain platforms @@ -67758,7 +77871,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Verify ufw Enabled - Enable Service ufw @@ -67769,10 +77882,6 @@ fi masked: false when: - '"ufw" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ( "ufw" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" - in ansible_facts.packages) ) tags: - enable_strategy - low_complexity @@ -67780,6 +77889,11 @@ fi - medium_severity - no_reboot_needed - service_ufw_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ( "ufw" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" + in ansible_facts.packages) ) include enable_ufw @@ -67794,6 +77908,10 @@ class enable_ufw { [customizations.services] enabled = ["ufw"] + + + + @@ -67821,17 +77939,21 @@ and virtual paths. To configure the system to prevent the atm kernel module from being loaded, add the following line to the file /etc/modprobe.d/atm.conf: install atm /bin/false +This entry will cause a non-zero return value during a atm module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install atm /bin/true To configure the system to prevent the atm from being used, add the following line to file /etc/modprobe.d/atm.conf: blacklist atm - CCI-000381 AC-18 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000040 - SV-271443r1092463_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000040 + SV-271443r1092463_rule Disabling ATM protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -67867,7 +77989,7 @@ fi - reboot_required - name: Ensure kernel module 'atm' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/atm.conf regexp: install\s+atm @@ -67884,7 +78006,7 @@ fi - reboot_required - name: Ensure kernel module 'atm' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/atm.conf regexp: ^blacklist atm$ @@ -67916,18 +78038,22 @@ is now also used in marine, industrial, and medical applications. To configure the system to prevent the can kernel module from being loaded, add the following line to the file /etc/modprobe.d/can.conf: install can /bin/false +This entry will cause a non-zero return value during a can module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install can /bin/true To configure the system to prevent the can from being used, add the following line to file /etc/modprobe.d/can.conf: blacklist can - CCI-000381 AC-18 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 - OL09-00-000041 - SV-271444r1091044_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + OL09-00-000041 + SV-271444r1091044_rule Disabling CAN protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -67963,7 +78089,7 @@ fi - reboot_required - name: Ensure kernel module 'can' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/can.conf regexp: install\s+can @@ -67980,7 +78106,7 @@ fi - reboot_required - name: Ensure kernel module 'can' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/can.conf regexp: ^blacklist can$ @@ -68012,6 +78138,11 @@ streaming media and telephony. To configure the system to prevent the dccp kernel module from being loaded, add the following line to the file /etc/modprobe.d/dccp.conf: install dccp /bin/false +This entry will cause a non-zero return value during a dccp module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install dccp /bin/true To configure the system to prevent the dccp from being used, add the following line to file /etc/modprobe.d/dccp.conf: @@ -68030,7 +78161,6 @@ add the following line to file /etc/modprobe.d/dccp.conf: DSS05.05 DSS06.06 3.4.6 - CCI-001958 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68088,8 +78218,8 @@ add the following line to file /etc/modprobe.d/dccp.conf: PR.IP-1 PR.PT-3 Req-1.4.2 - SRG-OS-000096-GPOS-00050 - SRG-OS-000378-GPOS-00163 + SRG-OS-000096-GPOS-00050 + SRG-OS-000378-GPOS-00163 1.4.2 1.4 Disabling DCCP protects @@ -68133,7 +78263,7 @@ fi - reboot_required - name: Ensure kernel module 'dccp' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/dccp.conf regexp: install\s+dccp @@ -68156,7 +78286,7 @@ fi - reboot_required - name: Ensure kernel module 'dccp' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/dccp.conf regexp: ^blacklist dccp$ @@ -68193,16 +78323,20 @@ high-speed real-time communication. To configure the system to prevent the firewire-core kernel module from being loaded, add the following line to the file /etc/modprobe.d/firewire-core.conf: install firewire-core /bin/false +This entry will cause a non-zero return value during a firewire-core module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install firewire-core /bin/true To configure the system to prevent the firewire-core from being used, add the following line to file /etc/modprobe.d/firewire-core.conf: blacklist firewire-core - CCI-000381 AC-18 - SRG-OS-000095-GPOS-00049 - OL09-00-000042 - SV-271445r1091047_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000042 + SV-271445r1091047_rule Disabling FireWire protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68238,7 +78372,7 @@ fi - reboot_required - name: Ensure kernel module 'firewire-core' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/firewire-core.conf regexp: install\s+firewire-core @@ -68255,7 +78389,7 @@ fi - reboot_required - name: Ensure kernel module 'firewire-core' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/firewire-core.conf regexp: ^blacklist firewire-core$ @@ -68287,6 +78421,11 @@ low-latency communications between nodes in a cluster. To configure the system to prevent the rds kernel module from being loaded, add the following line to the file /etc/modprobe.d/rds.conf: install rds /bin/false +This entry will cause a non-zero return value during a rds module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install rds /bin/true To configure the system to prevent the rds from being used, add the following line to file /etc/modprobe.d/rds.conf: @@ -68395,7 +78534,7 @@ fi - reboot_required - name: Ensure kernel module 'rds' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/rds.conf regexp: install\s+rds @@ -68413,7 +78552,7 @@ fi - reboot_required - name: Ensure kernel module 'rds' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/rds.conf regexp: ^blacklist rds$ @@ -68447,6 +78586,11 @@ within one connection. To configure the system to prevent the sctp kernel module from being loaded, add the following line to the file /etc/modprobe.d/sctp.conf: install sctp /bin/false +This entry will cause a non-zero return value during a sctp module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install sctp /bin/true To configure the system to prevent the sctp from being used, add the following line to file /etc/modprobe.d/sctp.conf: @@ -68465,7 +78609,6 @@ add the following line to file /etc/modprobe.d/sctp.conf: DSS05.05 DSS06.06 3.4.6 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68524,12 +78667,12 @@ add the following line to file /etc/modprobe.d/sctp.conf: PR.PT-3 FMT_SMF_EXT.1 Req-1.4.2 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 1.4.2 1.4 - OL09-00-000043 - SV-271446r1091050_rule + OL09-00-000043 + SV-271446r1091050_rule Disabling SCTP protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68572,7 +78715,7 @@ fi - reboot_required - name: Ensure kernel module 'sctp' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/sctp.conf regexp: install\s+sctp @@ -68596,7 +78739,7 @@ fi - reboot_required - name: Ensure kernel module 'sctp' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/sctp.conf regexp: ^blacklist sctp$ @@ -68635,6 +78778,11 @@ cluster. To configure the system to prevent the tipc kernel module from being loaded, add the following line to the file /etc/modprobe.d/tipc.conf: install tipc /bin/false +This entry will cause a non-zero return value during a tipc module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install tipc /bin/true To configure the system to prevent the tipc from being used, add the following line to file /etc/modprobe.d/tipc.conf: @@ -68655,7 +78803,6 @@ the tipc kernel module will be loaded.DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68713,9 +78860,9 @@ the tipc kernel module will be loaded.PR.IP-1 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - OL09-00-000044 - SV-271447r1092464_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000044 + SV-271447r1092464_rule Disabling TIPC protects the system against exploitation of any flaws in its implementation. # Remediation is applicable only in certain platforms @@ -68753,7 +78900,7 @@ fi - reboot_required - name: Ensure kernel module 'tipc' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/tipc.conf regexp: install\s+tipc @@ -68772,7 +78919,7 @@ fi - reboot_required - name: Ensure kernel module 'tipc' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/tipc.conf regexp: ^blacklist tipc$ @@ -68849,8 +78996,6 @@ to prevent the loading of the Bluetooth module: DSS05.05 DSS06.06 3.1.16 - CCI-001443 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -68928,10 +79073,10 @@ to prevent the loading of the Bluetooth module: PR.PT-3 PR.PT-4 FMT_SMF_EXT.1 - SRG-OS-000095-GPOS-00049 - SRG-OS-000300-GPOS-00118 - OL09-00-000046 - SV-271449r1091059_rule + SRG-OS-000095-GPOS-00049 + SRG-OS-000300-GPOS-00118 + OL09-00-000046 + SV-271449r1091059_rule If Bluetooth functionality must be disabled, preventing the kernel from loading the kernel module provides an additional safeguard against its activation. @@ -68976,7 +79121,7 @@ fi - reboot_required - name: Ensure kernel module 'bluetooth' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/bluetooth.conf regexp: install\s+bluetooth @@ -69000,7 +79145,7 @@ fi - reboot_required - name: Ensure kernel module 'bluetooth' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/bluetooth.conf regexp: ^blacklist bluetooth$ @@ -69058,10 +79203,6 @@ Configure the system to disable all wireless network interfaces with the followi DSS05.05 DSS06.06 3.1.16 - CCI-001443 - CCI-001444 - CCI-002421 - CCI-002418 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -69115,8 +79256,6 @@ Configure the system to disable all wireless network interfaces with the followi SR 5.3 SR 7.1 SR 7.6 - 1315 - 1319 A.11.2.6 A.12.1.2 A.12.5.1 @@ -69141,14 +79280,16 @@ Configure the system to disable all wireless network interfaces with the followi PR.PT-3 PR.PT-4 Req-1.3.3 - SRG-OS-000299-GPOS-00117 - SRG-OS-000300-GPOS-00118 - SRG-OS-000424-GPOS-00188 - SRG-OS-000481-GPOS-000481 + SRG-OS-000299-GPOS-00117 + SRG-OS-000300-GPOS-00118 + SRG-OS-000424-GPOS-00188 + SRG-OS-000481-GPOS-00481 + 1315 + 1319 1.3.3 1.3 - OL09-00-006001 - SV-271859r1092289_rule + OL09-00-006001 + SV-271859r1092289_rule The use of wireless networking can introduce many different attack vectors into the organization's network. Common attack vectors such as malicious association and ad hoc networks will allow an attacker to spoof a wireless access point @@ -69156,8 +79297,10 @@ and ad hoc networks will allow an attacker to spoof a wireless access point attacker to monitor and record network traffic. These malicious APs can also serve to create a man-in-the-middle attack or be used to create a denial of service to valid network resources. - - + + # Remediation is applicable only in certain platforms +if ( ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then + if ! rpm -q --quiet "NetworkManager" ; then yum install -y "NetworkManager" fi @@ -69175,6 +79318,10 @@ if command -v wicked >/dev/null 2>&1 && systemctl is-active wi done fi fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - name: Gather the package facts package_facts: @@ -69200,6 +79347,8 @@ fi - name: Service facts ansible.builtin.service_facts: null + when: ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) tags: - DISA-STIG-OL09-00-006001 - NIST-800-171-3.1.16 @@ -69225,6 +79374,8 @@ fi state: present with_items: - NetworkManager + when: ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", + "container"] ) ) tags: - DISA-STIG-OL09-00-006001 - NIST-800-171-3.1.16 @@ -69245,8 +79396,10 @@ fi - wireless_disable_interfaces - name: NetworkManager Deactivate Wireless Network Interfaces - command: nmcli radio wifi off + ansible.builtin.command: nmcli radio wifi off when: + - ( not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + ) ) - '''NetworkManager'' in ansible_facts.packages' - ansible_facts.services['NetworkManager.service'].state == 'running' tags: @@ -69277,6 +79430,37 @@ fi + + Transport Layer Security Support + Support for Transport Layer Security (TLS), and its predecessor, the Secure +Sockets Layer (SSL), is included in Red Hat Enterprise Linux in the OpenSSL software (RPM package +openssl). TLS provides encrypted and authenticated network +communications, and many network services include support for it. TLS or SSL +can be leveraged to avoid any plaintext transmission of sensitive data. + +For information on how to use OpenSSL, see +http://www.openssl.org/docs/. Information on FIPS validation +of OpenSSL is available at http://www.openssl.org/docs/fips.html +and http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/140val-all.htm. + + Only Allow DoD PKI-established CAs + The operating system must only allow the use of DoD PKI-established +certificate authorities for verification of the establishment of +protected sessions. + SRG-OS-000403-GPOS-00182 + OL09-00-900140 + SV-271901r1092415_rule + Untrusted Certificate Authorities (CA) can issue certificates, but they +may be issued by organizations or individuals that seek to compromise +DoD systems or by organizations with insufficient security controls. If +the CA used for verifying the certificate is not a DoD-approved CA, +trust of this CA has not been established. +The DoD will only accept PKI-certificates obtained from a DoD-approved +internal or external certificate authority. Reliance on CAs for the +establishment of secure sessions includes, for example, the use of +SSL/TLS certificates. + + Network Manager The NetworkManager daemon configures a variety of network connections. @@ -69294,96 +79478,163 @@ default - NetworkManager will update /etc/resolv.conf to reflect the nameservers NetworkManager DNS Mode Must Be Must Configured The DNS processing mode in NetworkManager describes how DNS is processed on the system. Depending the mode some changes the system's DNS may not be respected. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-006002 - SV-271860r1092292_rule + SRG-OS-000480-GPOS-00227 + OL09-00-006002 + SV-271860r1092292_rule To ensure that DNS resolver settings are respected, a DNS mode in NetworkManager must be configured. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q NetworkManager; then var_networkmanager_dns_mode='' +found=false - -# Try find '[main]' and 'dns' in '/etc/NetworkManager/NetworkManager.conf', if it exists, set -# to '$var_networkmanager_dns_mode', if it isn't here, add it, if '[main]' doesn't exist, add it there -if grep -qzosP '[[:space:]]*\[main]([^\n\[]*\n+)+?[[:space:]]*dns' '/etc/NetworkManager/NetworkManager.conf'; then - - sed -i "s/dns[^(\n)]*/dns=$var_networkmanager_dns_mode/" '/etc/NetworkManager/NetworkManager.conf' -elif grep -qs '[[:space:]]*\[main]' '/etc/NetworkManager/NetworkManager.conf'; then - sed -i "/[[:space:]]*\[main]/a dns=$var_networkmanager_dns_mode" '/etc/NetworkManager/NetworkManager.conf' -else - if test -d "/etc/NetworkManager"; then - printf '%s\n' '[main]' "dns=$var_networkmanager_dns_mode" >> '/etc/NetworkManager/NetworkManager.conf' - else - echo "Config file directory '/etc/NetworkManager' doesnt exist, not remediating, assuming non-applicability." >&2 +# set value in all files if they contain section or key +for f in $(echo -n "/etc/NetworkManager/conf.d/complianceascode_hardening.conf /etc/NetworkManager/conf.d/*.conf /etc/NetworkManager/NetworkManager.conf"); do + if [ ! -e "$f" ]; then + continue fi -fi -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then - systemctl reload NetworkManager + # find key in section and change value + if grep -qzosP "[[:space:]]*\[main\]([^\n\[]*\n+)+?[[:space:]]*dns" "$f"; then + if ! grep -qPz "dns=$var_networkmanager_dns_mode" "$f"; then + + sed -i "s/dns[^(\n)]*/dns=$var_networkmanager_dns_mode/" "$f" + + fi + + found=true + + # find section and add key = value to it + elif grep -qs "[[:space:]]*\[main\]" "$f"; then + + sed -i "/[[:space:]]*\[main\]/a dns=$var_networkmanager_dns_mode" "$f" + + found=true + fi +done + +# if section not in any file, append section with key = value to FIRST file in files parameter +if ! $found ; then + file=$(echo "/etc/NetworkManager/conf.d/complianceascode_hardening.conf /etc/NetworkManager/conf.d/*.conf /etc/NetworkManager/NetworkManager.conf" | cut -f1 -d ' ') + mkdir -p "$(dirname "$file")" + + echo -e "[main]\ndns=$var_networkmanager_dns_mode" >> "$file" + fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy - name: XCCDF Value var_networkmanager_dns_mode # promote to variable set_fact: var_networkmanager_dns_mode: !!str tags: - always -- name: Set 'dns' to '{{ var_networkmanager_dns_mode }}' in the [main] section of - '/etc/NetworkManager/NetworkManager.conf' - ini_file: - path: /etc/NetworkManager/NetworkManager.conf +- name: NetworkManager DNS Mode Must Be Must Configured - Search for a section in + files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[main\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/NetworkManager/NetworkManager.conf'' | dirname }}' + pattern: '{{ ''/etc/NetworkManager/NetworkManager.conf'' | basename | regex_escape + }}' + - path: /etc/NetworkManager/conf.d + pattern: .*\.conf + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + - restrict_strategy + +- name: NetworkManager DNS Mode Must Be Must Configured - Count number of files which + contain the correct section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: '"NetworkManager" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-006002 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - networkmanager_dns_mode + - no_reboot_needed + - restrict_strategy + +- name: NetworkManager DNS Mode Must Be Must Configured - Add missing configuration + to correct section + community.general.ini_file: + path: '{{item}}' section: main option: dns - value: '{{ var_networkmanager_dns_mode }}' - create: true - mode: 420 + value: '{{var_networkmanager_dns_mode}}' + state: present no_extra_spaces: true - when: '"NetworkManager" in ansible_facts.packages' + when: + - '"NetworkManager" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy -- name: NetworkManager DNS Mode Must Be Must Configured - Ensure Network Manager - ansible.builtin.systemd: - name: NetworkManager - state: reloaded - when: '"NetworkManager" in ansible_facts.packages' +- name: NetworkManager DNS Mode Must Be Must Configured - Add configuration to new + remediation file + community.general.ini_file: + path: /etc/NetworkManager/conf.d/complianceascode_hardening.conf + section: main + option: dns + value: '{{var_networkmanager_dns_mode}}' + state: present + no_extra_spaces: true + create: true + when: + - '"NetworkManager" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-006002 - NIST-800-53-CM-6(b) - - configure_strategy - low_complexity - low_disruption - medium_severity - networkmanager_dns_mode - no_reboot_needed + - restrict_strategy @@ -69429,13 +79680,11 @@ arisen. All directories in local partitions which are world-writable should be owned by root. If any world-writable directories are not owned by root, this should be investigated. Following this, the files should be deleted or assigned to root user. - CCI-000366 - CCI-001090 - SRG-OS-000480-GPOS-00227 - SRG-OS-000138-GPOS-00069 + SRG-OS-000480-GPOS-00227 + SRG-OS-000138-GPOS-00069 R54 - OL09-00-002516 - SV-271785r1092067_rule + OL09-00-002516 + SV-271785r1117267_rule Allowing a user account to own a world-writable directory is undesirable because it allows the owner of that directory to remove or replace any files that may be placed in the directory by other users. @@ -69443,9 +79692,9 @@ other users. # At least under containerized env /proc can have files w/o possilibity to # modify even as root. And touching /proc is not good idea anyways. find / -path /proc -prune -o \ - -not -fstype afs -not -fstype ceph -not -fstype cifs -not -fstype smb3 -not -fstype smbfs \ - -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs -not -fstype nfs4 \ - -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ + -not -fstype afs -not -fstype autofs -not -fstype ceph -not -fstype cifs -not -fstype smb3 \ + -not -fstype smbfs -not -fstype sshfs -not -fstype ncpfs -not -fstype ncp -not -fstype nfs \ + -not -fstype nfs4 -not -fstype gfs -not -fstype gfs2 -not -fstype glusterfs -not -fstype gpfs \ -not -fstype pvfs2 -not -fstype ocfs2 -not -fstype lustre -not -fstype davfs \ -not -fstype fuse.sshfs -type d -perm -0002 -uid +0 -exec chown root {} \; @@ -69454,6 +79703,7 @@ find / -path /proc -prune -o \ ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -69636,6 +79886,11 @@ To set the sticky bit on a world-writable directory DIR, run th amount of resources depending on the number of directories present on the system. It is not a problem in most cases, but especially systems with a large number of directories can be affected. See https://access.redhat.com/articles/6999111. + Please note that there might be cases where the rule remediation cannot fix directory permissions. +This can happen for example when running on a system with some immutable parts. +These immutable parts cannot be remediated because they are read-only. +Example of such directories can be OStree deployments located at /sysroot/ostree/deploy. +In such case, it is needed to make modifications to the underlying ostree snapshot and this is out of scope of regular rule remediation. 12 13 14 @@ -69648,7 +79903,6 @@ be affected. See https://access.redhat.com/articles/6999111DSS05.04 DSS05.07 DSS06.02 - CCI-001090 4.3.3.7.3 SR 2.1 SR 5.2 @@ -69675,25 +79929,26 @@ be affected. See https://access.redhat.com/articles/6999111A.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000138-GPOS-00069 + SRG-OS-000138-GPOS-00069 R54 + 1409 2.2.6 2.2 - OL09-00-002510 - SV-271779r1092049_rule + OL09-00-002510 + SV-271779r1117267_rule Failing to set the sticky bit on public directories allows unauthorized users to delete files in the directory structure. @@ -69712,6 +79967,7 @@ and for directories requiring global read/write access. ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -69929,10 +80185,9 @@ correct its ownership with the following command: $ sudo chgrp root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without @@ -69945,6 +80200,38 @@ Software libraries also include privileged programs which execute with escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. + + +for SYSCMDDIRS in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin +do + find -L $SYSCMDDIRS ! -group root -type d -exec chgrp root '{}' \; +done + + - name: Verify that system commands directories have root as a group owner - Set group + ownership of directories that contain system commands to root + ansible.builtin.file: + path: '{{ item }}' + group: root + recurse: 'yes' + state: directory + follow: 'yes' + with_items: + - /bin + - /sbin + - /usr/bin + - /usr/sbin + - /usr/local/bin + - /usr/local/sbin + tags: + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - dir_system_commands_group_root_owned + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + @@ -69968,10 +80255,9 @@ correct its ownership with the following command: $ sudo chown root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without @@ -69984,6 +80270,37 @@ Software libraries also include privileged programs which execute with escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. + +for SYSCMDDIRS in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin +do + find -L $SYSCMDDIRS \! -user root -type d -exec chown root {} \; +done + + - name: Verify that system commands directories have root ownership - Set ownership + of directories that contain system commands to root + ansible.builtin.file: + path: '{{ item }}' + owner: root + recurse: 'yes' + state: directory + follow: 'yes' + with_items: + - /bin + - /sbin + - /usr/bin + - /usr/sbin + - /usr/local/bin + - /usr/local/sbin + tags: + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - dir_system_commands_root_owned + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + @@ -69993,7 +80310,8 @@ including upgrades and modifications. Verify Group Who Owns /etc/crypttab File - To properly set the group owner of /etc/crypttab, run the command: $ sudo chgrp root /etc/crypttab + To properly set the group owner of /etc/crypttab, run the command: +$ sudo chgrp root /etc/crypttab R50 The ownership of the /etc/crypttab file by the root group is important @@ -70001,12 +80319,31 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - chgrp root /etc/crypttab + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/crypttab" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/crypttab +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: - path: /etc/crypttab - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_etc_crypttab @@ -70015,11 +80352,57 @@ configuration. - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/crypttab - file: +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_crypttab_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_crypttab_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_crypttab_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab - group: root - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupowner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /etc/crypttab + ansible.builtin.file: + path: /etc/crypttab + follow: false + group: '{{ file_groupowner_etc_crypttab_newgroup }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_groupowner_etc_crypttab @@ -70043,22 +80426,82 @@ addresses. These files must be group-owned by root. To properly set the group owner of /boot/System.map*, run the command: -$ sudo chgrp root /boot/System.map* + + $ sudo chgrp root /boot/System.map* R29 The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - -find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -regex '^.*System\.map.*$' -exec chgrp -L root {} \; + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -regex '^.*System\.map.*$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) matching ^.*System\.map.*$ - command: find -H /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended - -regex "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_systemmap_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Set the file_groupowner_systemmap_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_systemmap_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) matching ^.*System\.map.*$ + ansible.builtin.command: find -P /boot/ -maxdepth 1 -type f ! -group root -regextype + posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupowner_systemmap @@ -70068,12 +80511,14 @@ find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -rege - no_reboot_needed - name: Ensure group owner on /boot/ file(s) matching ^.*System\.map.*$ - file: + ansible.builtin.file: path: '{{ item }}' - group: root + follow: false + group: '{{ file_groupowner_systemmap_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_groupowner_systemmap @@ -70091,7 +80536,8 @@ find -L /boot/ -maxdepth 1 -type f ! -group root -regextype posix-extended -rege Verify User Who Owns /etc/crypttab File - To properly set the owner of /etc/crypttab, run the command: $ sudo chown root /etc/crypttab + To properly set the owner of /etc/crypttab, run the command: +$ sudo chown root /etc/crypttab R50 The ownership of the /etc/crypttab file by the root user is important @@ -70099,12 +80545,31 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - chown 0 /etc/crypttab + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/crypttab" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/crypttab +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: - path: /etc/crypttab - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_etc_crypttab @@ -70113,11 +80578,39 @@ configuration. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/crypttab - file: +- name: Set the file_owner_etc_crypttab_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_crypttab_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab - owner: '0' - when: file_exists.stat is defined and file_exists.stat.exists + register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on /etc/crypttab + ansible.builtin.file: + path: /etc/crypttab + follow: false + owner: '{{ file_owner_etc_crypttab_newown }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_owner_etc_crypttab @@ -70141,22 +80634,65 @@ addresses. These files must be owned by root. To properly set the owner of /boot/System.map*, run the command: -$ sudo chown root /boot/System.map* + + $ sudo chown root /boot/System.map* R29 The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - -find -L /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*System\.map.*$' -exec chown -L 0 {} \; + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /boot/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*System\.map.*$' -exec chown --no-dereference "$newown" {} \; + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) matching ^.*System\.map.*$ - command: find -H /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex - "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Set the file_owner_systemmap_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_systemmap_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) matching ^.*System\.map.*$ + ansible.builtin.command: find -P /boot/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_owner_systemmap @@ -70166,12 +80702,14 @@ find -L /boot/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^. - no_reboot_needed - name: Ensure owner on /boot/ file(s) matching ^.*System\.map.*$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_owner_systemmap_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_owner_systemmap @@ -70197,16 +80735,32 @@ because this file hosts encrypted block devices configuration. Protection of this file is critical for system security. Assigning the ownership to root ensures exclusive control of the encrypted block devices configuration. - - - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then chmod u-xs,g-xwrs,o-xwrt /etc/crypttab + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /etc/crypttab - stat: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_etc_crypttab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/crypttab + ansible.builtin.stat: path: /etc/crypttab register: file_exists + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_etc_crypttab @@ -70216,10 +80770,12 @@ chmod u-xs,g-xwrs,o-xwrt /etc/crypttab - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crypttab - file: + ansible.builtin.file: path: /etc/crypttab mode: u-xs,g-xwrs,o-xwrt - when: file_exists.stat is defined and file_exists.stat.exists + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_exists.stat is defined and file_exists.stat.exists tags: - configure_strategy - file_permissions_etc_crypttab @@ -70249,19 +80805,35 @@ To properly set the permissions of /boot/System.map*, run The purpose of System.map files is primarily for debugging and profiling the kernel. Unrestricted access to these files might disclose information useful to attackers and malicious software leading to more sophisticated exploitation. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +find -P /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*System\.map.*$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; - -find -L /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*System\.map.*$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Find /boot/ file(s) - command: find -H /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype - posix-extended -regex "^.*System\.map.*$" + - name: Gather the package facts + package_facts: + manager: auto + tags: + - configure_strategy + - file_permissions_systemmap + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + +- name: Find /boot/ file(s) + ansible.builtin.command: find -P /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type + f -regextype posix-extended -regex "^.*System\.map.*$" register: files_found changed_when: false failed_when: false check_mode: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_systemmap @@ -70271,12 +80843,13 @@ find -L /boot/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-e - no_reboot_needed - name: Set permissions for /boot/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xwrs,o-xwrt state: file with_items: - '{{ files_found.stdout_lines }}' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - file_permissions_systemmap @@ -70349,6 +80922,7 @@ See https://access.redhat.com/articles/6999111.PR.AC-4 PR.DS-5 R56 + 1409 Executable files with the SGID permission run with the privileges of the owner of the file. SGID files of uncertain provenance could allow for unprivileged users to elevate privileges. The presence of these files should be strictly controlled on the system. @@ -70416,6 +80990,7 @@ See https://access.redhat.com/articles/6999111.PR.AC-4 PR.DS-5 R56 + 1409 Executable files with the SUID permission run with the privileges of the owner of the file. SUID files of uncertain provenance could allow for unprivileged users to elevate privileges. The presence of these files should be strictly controlled on the system. @@ -70475,20 +81050,21 @@ See https://access.redhat.com/articles/6999111.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 R54 + 1409 2.2.6 2.2 Data in world-writable files can be modified by any user on the system. In almost all @@ -70558,7 +81134,6 @@ See https://access.redhat.com/articles/6999111.DSS06.03 DSS06.06 DSS06.10 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -70641,12 +81216,12 @@ See https://access.redhat.com/articles/6999111.PR.AC-7 PR.DS-5 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R53 2.2.6 2.2 - OL09-00-002511 - SV-271780r1092052_rule + OL09-00-002511 + SV-271780r1092052_rule 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 @@ -70701,7 +81276,6 @@ See https://access.redhat.com/articles/6999111.DSS06.02 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -70785,12 +81359,12 @@ See https://access.redhat.com/articles/6999111.PR.DS-5 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R53 2.2.6 2.2 - OL09-00-002512 - SV-271781r1092055_rule + OL09-00-002512 + SV-271781r1092055_rule 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 @@ -70848,7 +81422,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_fifos # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_fifos="2" fi @@ -70894,16 +81468,12 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_fifos.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(1) @@ -70915,13 +81485,57 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: Comment out any occurrences of fs.protected_fifos from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Find all files that contain + fs.protected_fifos + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_fifos\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Find all files that set + fs.protected_fifos to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_fifos\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_fifos + +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Comment out any occurrences + of fs.protected_fifos from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_fifos replace: '#fs.protected_fifos' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -70932,8 +81546,9 @@ fi - reboot_required - sysctl_fs_protected_fifos -- name: Ensure sysctl fs.protected_fifos is set to 2 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on FIFOs - Ensure sysctl fs.protected_fifos + is set to 2 + ansible.posix.sysctl: name: fs.protected_fifos value: '2' sysctl_file: /etc/sysctl.conf @@ -70950,6 +81565,10 @@ fi - reboot_required - sysctl_fs_protected_fifos + + + + @@ -70962,25 +81581,23 @@ fi To set the runtime status of the fs.protected_hardlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_hardlinks=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_hardlinks = 1 - CCI-002235 - CCI-002165 - 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 + 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 CM-6(a) AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 R14 - OL09-00-002401 - SV-271740r1091932_rule + OL09-00-002401 + SV-271740r1091932_rule By enabling this kernel parameter, users can no longer create soft or hard links to files which they do not own. Disallowing such hardlinks mitigate vulnerabilities based on insecure file system accessed by privileged programs, avoiding an @@ -71017,7 +81634,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_hardlinks # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_hardlinks="1" fi @@ -71064,16 +81681,13 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_hardlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002401 @@ -71086,13 +81700,59 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: Comment out any occurrences of fs.protected_hardlinks from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Find all files that + contain fs.protected_hardlinks + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_hardlinks\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Find all files that + set fs.protected_hardlinks to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_hardlinks\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002401 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_hardlinks + +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Comment out any occurrences + of fs.protected_hardlinks from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_hardlinks replace: '#fs.protected_hardlinks' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002401 - NIST-800-53-AC-6(1) @@ -71104,8 +81764,9 @@ fi - reboot_required - sysctl_fs_protected_hardlinks -- name: Ensure sysctl fs.protected_hardlinks is set to 1 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Hardlinks - Ensure sysctl fs.protected_hardlinks + is set to 1 + ansible.posix.sysctl: name: fs.protected_hardlinks value: '1' sysctl_file: /etc/sysctl.conf @@ -71123,6 +81784,10 @@ fi - reboot_required - sysctl_fs_protected_hardlinks + + + + @@ -71174,7 +81839,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_regular # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_regular="2" fi @@ -71220,16 +81885,13 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_regular.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-6(1) @@ -71241,13 +81903,57 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: Comment out any occurrences of fs.protected_regular from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Find all files that + contain fs.protected_regular + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_regular\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Find all files that + set fs.protected_regular to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_regular\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_regular + +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Comment out any + occurrences of fs.protected_regular from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_regular replace: '#fs.protected_regular' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-AC-6(1) - NIST-800-53-CM-6(a) @@ -71258,8 +81964,9 @@ fi - reboot_required - sysctl_fs_protected_regular -- name: Ensure sysctl fs.protected_regular is set to 2 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Regular files - Ensure sysctl fs.protected_regular + is set to 2 + ansible.posix.sysctl: name: fs.protected_regular value: '2' sysctl_file: /etc/sysctl.conf @@ -71276,6 +81983,10 @@ fi - reboot_required - sysctl_fs_protected_regular + + + + @@ -71288,25 +81999,23 @@ fi To set the runtime status of the fs.protected_symlinks kernel parameter, run the following command: $ sudo sysctl -w fs.protected_symlinks=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: fs.protected_symlinks = 1 - CCI-002235 - CCI-002165 - 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 + 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 CM-6(a) AC-6(1) - SRG-OS-000312-GPOS-00122 - SRG-OS-000312-GPOS-00123 - SRG-OS-000324-GPOS-00125 + SRG-OS-000312-GPOS-00122 + SRG-OS-000312-GPOS-00123 + SRG-OS-000324-GPOS-00125 R14 - OL09-00-002402 - SV-271741r1091935_rule + OL09-00-002402 + SV-271741r1091935_rule By enabling this kernel parameter, symbolic links are permitted to be followed only when outside a sticky world-writable directory, or when the UID of the link and follower match, or when the directory owner matches the symlink's owner. @@ -71345,7 +82054,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.protected_symlinks # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.protected_symlinks="1" fi @@ -71392,16 +82101,12 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.protected_symlinks.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002402 @@ -71414,13 +82119,59 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: Comment out any occurrences of fs.protected_symlinks from config files - replace: - path: '{{ item.path }}' +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Find all files that contain + fs.protected_symlinks + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_symlinks\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Find all files that set + fs.protected_symlinks to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.protected_symlinks\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002402 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_protected_symlinks + +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Comment out any occurrences + of fs.protected_symlinks from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.protected_symlinks replace: '#fs.protected_symlinks' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002402 - NIST-800-53-AC-6(1) @@ -71432,8 +82183,9 @@ fi - reboot_required - sysctl_fs_protected_symlinks -- name: Ensure sysctl fs.protected_symlinks is set to 1 - sysctl: +- name: Enable Kernel Parameter to Enforce DAC on Symlinks - Ensure sysctl fs.protected_symlinks + is set to 1 + ansible.posix.sysctl: name: fs.protected_symlinks value: '1' sysctl_file: /etc/sysctl.conf @@ -71451,6 +82203,10 @@ fi - reboot_required - sysctl_fs_protected_symlinks + + + + @@ -71468,23 +82224,53 @@ read access to the shadow file allows malicious attacks a passwords, and should never be enabled. Verify Group Who Owns Backup group File - To properly set the group owner of /etc/group-, run the command: $ sudo chgrp root /etc/group- + To properly set the group owner of /etc/group-, run the command: +$ sudo chgrp root /etc/group- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002533 - SV-271795r1092097_rule + OL09-00-002533 + SV-271795r1092097_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chgrp 0 /etc/group- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/group-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/group- +fi + +fi - - name: Test for existence /etc/group- - stat: + - name: Set the file_groupowner_backup_etc_group_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_group_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002533 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group- + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -71500,10 +82286,11 @@ Protection of this file is important for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/group- - file: +- name: Ensure group owner on /etc/group- + ansible.builtin.file: path: /etc/group- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_group_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002533 @@ -71527,20 +82314,48 @@ Protection of this file is important for system security. Verify Group Who Owns Backup gshadow File - To properly set the group owner of /etc/gshadow-, run the command: $ sudo chgrp root /etc/gshadow- + To properly set the group owner of /etc/gshadow-, run the command: +$ sudo chgrp root /etc/gshadow- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 - OL09-00-002539 - SV-271801r1092115_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002539 + SV-271801r1092115_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/gshadow- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/gshadow-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/gshadow- +fi + +fi - - name: Test for existence /etc/gshadow- - stat: + - name: Set the file_groupowner_backup_etc_gshadow_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_gshadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002539 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_groupowner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow- + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -71554,10 +82369,11 @@ it contains group password hashes. Protection of this file is critical for syste - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/gshadow- - file: +- name: Ensure group owner on /etc/gshadow- + ansible.builtin.file: path: /etc/gshadow- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_gshadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002539 @@ -71579,23 +82395,53 @@ it contains group password hashes. Protection of this file is critical for syste Verify Group Who Owns Backup passwd File - To properly set the group owner of /etc/passwd-, run the command: $ sudo chgrp root /etc/passwd- + To properly set the group owner of /etc/passwd-, run the command: +$ sudo chgrp root /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002545 - SV-271807r1092133_rule + OL09-00-002545 + SV-271807r1092133_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. - chgrp 0 /etc/passwd- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/passwd-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/passwd- +fi + +fi - - name: Test for existence /etc/passwd- - stat: + - name: Set the file_groupowner_backup_etc_passwd_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_passwd_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002545 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd- + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -71611,10 +82457,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/passwd- - file: +- name: Ensure group owner on /etc/passwd- + ansible.builtin.file: path: /etc/passwd- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_passwd_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002545 @@ -71638,22 +82485,51 @@ Protection of this file is critical for system security. Verify User Who Owns Backup shadow File - To properly set the group owner of /etc/shadow-, run the command: $ sudo chgrp root /etc/shadow- + To properly set the group owner of /etc/shadow-, run the command: +$ sudo chgrp root /etc/shadow- - CCI-000366 Req-8.7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002551 - SV-271813r1092151_rule + OL09-00-002551 + SV-271813r1092151_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/shadow- + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shadow-" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shadow- +fi + +fi - - name: Test for existence /etc/shadow- - stat: + - name: Set the file_groupowner_backup_etc_shadow_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_backup_etc_shadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002551 + - PCI-DSS-Req-8.7 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow- + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -71668,10 +82544,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/shadow- - file: +- name: Ensure group owner on /etc/shadow- + ansible.builtin.file: path: /etc/shadow- - group: '0' + follow: false + group: '{{ file_groupowner_backup_etc_shadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002551 @@ -71694,7 +82571,8 @@ Protection of this file is critical for system security. Verify Group Who Owns group File - To properly set the group owner of /etc/group, run the command: $ sudo chgrp root /etc/group + To properly set the group owner of /etc/group, run the command: +$ sudo chgrp root /etc/group 12 13 @@ -71709,7 +82587,6 @@ Protection of this file is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71736,32 +82613,63 @@ Protection of this file is critical for system security. 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002532 - SV-271794r1092094_rule + OL09-00-002532 + SV-271794r1092094_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chgrp 0 /etc/group + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/group" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/group +fi + +fi - - name: Test for existence /etc/group - stat: + - name: Set the file_groupowner_etc_group_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_group_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002532 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -71779,10 +82687,11 @@ on the system. Protection of this file is important for system security. Verify Group Who Owns gshadow File - To properly set the group owner of /etc/gshadow, run the command: $ sudo chgrp root /etc/gshadow + To properly set the group owner of /etc/gshadow, run the command: +$ sudo chgrp root /etc/gshadow 12 13 @@ -71822,7 +82732,6 @@ on the system. Protection of this file is important for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71849,29 +82758,56 @@ on the system. Protection of this file is important for system security.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002538 - SV-271800r1092112_rule + OL09-00-002538 + SV-271800r1092112_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/gshadow + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/gshadow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/gshadow +fi + +fi - - name: Test for existence /etc/gshadow - stat: + - name: Set the file_groupowner_etc_gshadow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_gshadow_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002538 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -71885,10 +82821,11 @@ is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/gshadow - file: +- name: Ensure group owner on /etc/gshadow + ansible.builtin.file: path: /etc/gshadow - group: '0' + follow: false + group: '{{ file_groupowner_etc_gshadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002538 @@ -71910,7 +82847,8 @@ is critical for system security. Verify Group Who Owns passwd File - To properly set the group owner of /etc/passwd, run the command: $ sudo chgrp root /etc/passwd + To properly set the group owner of /etc/passwd, run the command: +$ sudo chgrp root /etc/passwd 12 13 @@ -71925,7 +82863,6 @@ is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -71952,32 +82889,63 @@ is critical for system security. 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002544 - SV-271806r1092130_rule + OL09-00-002544 + SV-271806r1092130_rule The /etc/passwd file contains information about the users that are configured on the system. Protection of this file is critical for system security. - chgrp 0 /etc/passwd + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/passwd" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/passwd +fi + +fi - - name: Test for existence /etc/passwd - stat: + - name: Set the file_groupowner_etc_passwd_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_passwd_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002544 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -71995,10 +82963,11 @@ the system. Protection of this file is critical for system security. Verify Group Who Owns shadow File - To properly set the group owner of /etc/shadow, run the command: $ sudo chgrp root /etc/shadow + To properly set the group owner of /etc/shadow, run the command: +$ sudo chgrp root /etc/shadow 12 13 @@ -72039,7 +83009,6 @@ the system. Protection of this file is critical for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72066,32 +83035,63 @@ the system. Protection of this file is critical for system security.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002550 - SV-271812r1092148_rule + OL09-00-002550 + SV-271812r1092148_rule The /etc/shadow file stores password hashes. Protection of this file is critical for system security. - chgrp 0 /etc/shadow + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shadow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shadow +fi + +fi - - name: Test for existence /etc/shadow - stat: + - name: Set the file_groupowner_etc_shadow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_shadow_newgroup: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002550 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -72109,10 +83109,11 @@ critical for system security. - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/shadow - file: +- name: Ensure group owner on /etc/shadow + ansible.builtin.file: path: /etc/shadow - group: '0' + follow: false + group: '{{ file_groupowner_etc_shadow_newgroup }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - CJIS-5.5.2.2 @@ -72140,17 +83141,44 @@ critical for system security. Verify Group Who Owns /etc/shells File To properly set the group owner of /etc/shells, run the command: -$ sudo chgrp root /etc/shells + + $ sudo chgrp root /etc/shells AC-3 MP-2 R50 The /etc/shells file contains the list of full pathnames to shells on the system. Since this file is used by many system programs this file should be protected. - chgrp 0 /etc/shells + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/shells" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/shells +fi + +fi - - name: Test for existence /etc/shells - stat: + - name: Set the file_groupowner_etc_shells_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_etc_shells_newgroup: '0' + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_groupowner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shells + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -72163,10 +83191,11 @@ Since this file is used by many system programs this file should be protected. Verify User Who Owns Backup group File - To properly set the owner of /etc/group-, run the command: $ sudo chown root /etc/group- + To properly set the owner of /etc/group-, run the command: +$ sudo chown root /etc/group- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002535 - SV-271797r1092103_rule + OL09-00-002535 + SV-271797r1092103_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chown 0 /etc/group- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/group-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/group- +fi + +fi - - name: Test for existence /etc/group- - stat: + - name: Set the file_owner_backup_etc_group_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_group_newown: '0' + tags: + - DISA-STIG-OL09-00-002535 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group- + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -72219,10 +83277,11 @@ Protection of this file is important for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/group- - file: +- name: Ensure owner on /etc/group- + ansible.builtin.file: path: /etc/group- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_group_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002535 @@ -72246,20 +83305,47 @@ Protection of this file is important for system security. Verify User Who Owns Backup gshadow File - To properly set the owner of /etc/gshadow-, run the command: $ sudo chown root /etc/gshadow- + To properly set the owner of /etc/gshadow-, run the command: +$ sudo chown root /etc/gshadow- - CCI-000366 AC-6 (1) Req-8.7 - SRG-OS-000480-GPOS-00227 - OL09-00-002541 - SV-271803r1092121_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002541 + SV-271803r1092121_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. - chown 0 /etc/gshadow- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/gshadow-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/gshadow- +fi + +fi - - name: Test for existence /etc/gshadow- - stat: + - name: Set the file_owner_backup_etc_gshadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_gshadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002541 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7 + - configure_strategy + - file_owner_backup_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow- + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -72273,10 +83359,11 @@ it contains group password hashes. Protection of this file is critical for syste - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/gshadow- - file: +- name: Ensure owner on /etc/gshadow- + ansible.builtin.file: path: /etc/gshadow- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_gshadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002541 @@ -72298,23 +83385,52 @@ it contains group password hashes. Protection of this file is critical for syste Verify User Who Owns Backup passwd File - To properly set the owner of /etc/passwd-, run the command: $ sudo chown root /etc/passwd- + To properly set the owner of /etc/passwd-, run the command: +$ sudo chown root /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002547 - SV-271809r1092139_rule + OL09-00-002547 + SV-271809r1092139_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. - chown 0 /etc/passwd- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/passwd-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/passwd- +fi + +fi - - name: Test for existence /etc/passwd- - stat: + - name: Set the file_owner_backup_etc_passwd_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_passwd_newown: '0' + tags: + - DISA-STIG-OL09-00-002547 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd- + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -72330,10 +83446,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/passwd- - file: +- name: Ensure owner on /etc/passwd- + ansible.builtin.file: path: /etc/passwd- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_passwd_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002547 @@ -72357,23 +83474,52 @@ Protection of this file is critical for system security. Verify Group Who Owns Backup shadow File - To properly set the owner of /etc/shadow-, run the command: $ sudo chown root /etc/shadow- + To properly set the owner of /etc/shadow-, run the command: +$ sudo chown root /etc/shadow- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002553 - SV-271815r1092157_rule + OL09-00-002553 + SV-271815r1092157_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. - chown 0 /etc/shadow- + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shadow-" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shadow- +fi + +fi - - name: Test for existence /etc/shadow- - stat: + - name: Set the file_owner_backup_etc_shadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_backup_etc_shadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002553 + - NIST-800-53-AC-6 (1) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_backup_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow- + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -72389,10 +83535,11 @@ Protection of this file is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/shadow- - file: +- name: Ensure owner on /etc/shadow- + ansible.builtin.file: path: /etc/shadow- - owner: '0' + follow: false + owner: '{{ file_owner_backup_etc_shadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002553 @@ -72416,7 +83563,8 @@ Protection of this file is critical for system security. Verify User Who Owns group File - To properly set the owner of /etc/group, run the command: $ sudo chown root /etc/group + To properly set the owner of /etc/group, run the command: +$ sudo chown root /etc/group 12 13 @@ -72431,7 +83579,6 @@ Protection of this file is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72458,32 +83605,63 @@ Protection of this file is critical for system security. 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002534 - SV-271796r1092100_rule + OL09-00-002534 + SV-271796r1092100_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. - chown 0 /etc/group + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/group" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/group +fi + +fi - - name: Test for existence /etc/group - stat: + - name: Set the file_owner_etc_group_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_group_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002534 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_group + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/group + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -72501,10 +83679,11 @@ on the system. Protection of this file is important for system security. Verify User Who Owns gshadow File - To properly set the owner of /etc/gshadow, run the command: $ sudo chown root /etc/gshadow + To properly set the owner of /etc/gshadow, run the command: +$ sudo chown root /etc/gshadow 12 13 @@ -72544,7 +83724,6 @@ on the system. Protection of this file is important for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72571,29 +83750,56 @@ on the system. Protection of this file is important for system security.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002540 - SV-271802r1092118_rule + OL09-00-002540 + SV-271802r1092118_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. - chown 0 /etc/gshadow + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/gshadow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/gshadow +fi + +fi - - name: Test for existence /etc/gshadow - stat: + - name: Set the file_owner_etc_gshadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_gshadow_newown: '0' + tags: + - DISA-STIG-OL09-00-002540 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_etc_gshadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/gshadow + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -72607,10 +83813,11 @@ is critical for system security. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/gshadow - file: +- name: Ensure owner on /etc/gshadow + ansible.builtin.file: path: /etc/gshadow - owner: '0' + follow: false + owner: '{{ file_owner_etc_gshadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002540 @@ -72632,7 +83839,8 @@ is critical for system security. Verify User Who Owns passwd File - To properly set the owner of /etc/passwd, run the command: $ sudo chown root /etc/passwd + To properly set the owner of /etc/passwd, run the command: +$ sudo chown root /etc/passwd 12 13 @@ -72647,7 +83855,6 @@ is critical for system security. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72674,32 +83881,63 @@ is critical for system security. 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002546 - SV-271808r1092136_rule + OL09-00-002546 + SV-271808r1092136_rule The /etc/passwd file contains information about the users that are configured on the system. Protection of this file is critical for system security. - chown 0 /etc/passwd + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/passwd" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/passwd +fi + +fi - - name: Test for existence /etc/passwd - stat: + - name: Set the file_owner_etc_passwd_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_passwd_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002546 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_passwd + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/passwd + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -72717,10 +83955,11 @@ the system. Protection of this file is critical for system security. Verify User Who Owns shadow File - To properly set the owner of /etc/shadow, run the command: $ sudo chown root /etc/shadow + To properly set the owner of /etc/shadow, run the command: +$ sudo chown root /etc/shadow 12 13 @@ -72761,7 +84001,6 @@ the system. Protection of this file is critical for system security.DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -72788,35 +84027,66 @@ the system. Protection of this file is critical for system security.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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002552 - SV-271814r1092154_rule + OL09-00-002552 + SV-271814r1092154_rule The /etc/shadow file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file to root provides the designated owner with access to sensitive information which could weaken the system security posture. - chown 0 /etc/shadow + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shadow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shadow +fi + +fi - - name: Test for existence /etc/shadow - stat: + - name: Set the file_owner_etc_shadow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_shadow_newown: '0' + tags: + - CJIS-5.5.2.2 + - DISA-STIG-OL09-00-002552 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.7.c + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_etc_shadow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shadow + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -72834,10 +84104,11 @@ which could weaken the system security posture. - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/shadow - file: +- name: Ensure owner on /etc/shadow + ansible.builtin.file: path: /etc/shadow - owner: '0' + follow: false + owner: '{{ file_owner_etc_shadow_newown }}' when: file_exists.stat is defined and file_exists.stat.exists tags: - CJIS-5.5.2.2 @@ -72865,17 +84136,44 @@ which could weaken the system security posture. Verify Who Owns /etc/shells File To properly set the owner of /etc/shells, run the command: -$ sudo chown root /etc/shells + + $ sudo chown root /etc/shells AC-3 MP-2 R50 The /etc/shells file contains the list of full pathnames to shells on the system. Since this file is used by many system programs this file should be protected. - chown 0 /etc/shells + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/shells" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/shells +fi + +fi - - name: Test for existence /etc/shells - stat: + - name: Set the file_owner_etc_shells_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_shells_newown: '0' + tags: + - NIST-800-53-AC-3 + - NIST-800-53-MP-2 + - configure_strategy + - file_owner_etc_shells + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /etc/shells + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -72888,10 +84186,11 @@ Since this file is used by many system programs this file should be protected./etc/group-, run the command: $ sudo chmod 0644 /etc/group- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002537 - SV-271799r1092109_rule + OL09-00-002537 + SV-271799r1092109_rule The /etc/group- file is a backup file of /etc/group, and as such, it contains information regarding groups that are configured on the system. Protection of this file is important for system security. @@ -72934,7 +84232,7 @@ Protection of this file is important for system security. chmod u-xs,g-xws,o-xwt /etc/group- - name: Test for existence /etc/group- - stat: + ansible.builtin.stat: path: /etc/group- register: file_exists tags: @@ -72951,7 +84249,7 @@ chmod u-xs,g-xws,o-xwt /etc/group- - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group- - file: + ansible.builtin.file: path: /etc/group- mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -72981,11 +84279,10 @@ chmod u-xs,g-xws,o-xwt /etc/group- To properly set the permissions of /etc/gshadow-, run the command: $ sudo chmod 0000 /etc/gshadow- - CCI-000366 AC-6 (1) - SRG-OS-000480-GPOS-00227 - OL09-00-002543 - SV-271805r1092127_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002543 + SV-271805r1092127_rule The /etc/gshadow- file is a backup of /etc/gshadow, and as such, it contains group password hashes. Protection of this file is critical for system security. @@ -72995,7 +84292,7 @@ it contains group password hashes. Protection of this file is critical for syste chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- - name: Test for existence /etc/gshadow- - stat: + ansible.builtin.stat: path: /etc/gshadow- register: file_exists tags: @@ -73009,7 +84306,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow- - file: + ansible.builtin.file: path: /etc/gshadow- mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73036,14 +84333,13 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow- To properly set the permissions of /etc/passwd-, run the command: $ sudo chmod 0644 /etc/passwd- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002549 - SV-271811r1092145_rule + OL09-00-002549 + SV-271811r1092145_rule The /etc/passwd- file is a backup file of /etc/passwd, and as such, it contains information about the users that are configured on the system. Protection of this file is critical for system security. @@ -73054,7 +84350,7 @@ Protection of this file is critical for system security. chmod u-xs,g-xws,o-xwt /etc/passwd- - name: Test for existence /etc/passwd- - stat: + ansible.builtin.stat: path: /etc/passwd- register: file_exists tags: @@ -73071,7 +84367,7 @@ chmod u-xs,g-xws,o-xwt /etc/passwd- - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd- - file: + ansible.builtin.file: path: /etc/passwd- mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73101,14 +84397,13 @@ chmod u-xs,g-xws,o-xwt /etc/passwd- To properly set the permissions of /etc/shadow-, run the command: $ sudo chmod 0000 /etc/shadow- - CCI-000366 AC-6 (1) Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002554 - SV-271816r1092160_rule + OL09-00-002554 + SV-271816r1092160_rule The /etc/shadow- file is a backup file of /etc/shadow, and as such, it contains the list of local system accounts and password hashes. Protection of this file is critical for system security. @@ -73119,7 +84414,7 @@ Protection of this file is critical for system security. chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- - name: Test for existence /etc/shadow- - stat: + ansible.builtin.stat: path: /etc/shadow- register: file_exists tags: @@ -73136,7 +84431,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow- - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow- - file: + ansible.builtin.file: path: /etc/shadow- mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73179,7 +84474,6 @@ To properly set the permissions of /etc/group, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73206,26 +84500,26 @@ To properly set the permissions of /etc/group, run the co 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002536 - SV-271798r1092106_rule + OL09-00-002536 + SV-271798r1092106_rule The /etc/group file contains information regarding groups that are configured on the system. Protection of this file is important for system security. @@ -73235,7 +84529,7 @@ on the system. Protection of this file is important for system security. - name: Test for existence /etc/group - stat: + ansible.builtin.stat: path: /etc/group register: file_exists tags: @@ -73254,7 +84548,7 @@ chmod u-xs,g-xws,o-xwt /etc/group - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/group - file: + ansible.builtin.file: path: /etc/group mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73298,7 +84592,6 @@ To properly set the permissions of /etc/gshadow, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73325,23 +84618,23 @@ To properly set the permissions of /etc/gshadow, run the 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002542 - SV-271804r1092124_rule + OL09-00-002542 + SV-271804r1092124_rule The /etc/gshadow file contains group password hashes. Protection of this file is critical for system security. @@ -73351,7 +84644,7 @@ is critical for system security. chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow - name: Test for existence /etc/gshadow - stat: + ansible.builtin.stat: path: /etc/gshadow register: file_exists tags: @@ -73366,7 +84659,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/gshadow - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/gshadow - file: + ansible.builtin.file: path: /etc/gshadow mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73407,7 +84700,6 @@ To properly set the permissions of /etc/passwd, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73434,26 +84726,26 @@ To properly set the permissions of /etc/passwd, run the c 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002548 - SV-271810r1092142_rule + OL09-00-002548 + SV-271810r1092142_rule If the /etc/passwd file is writable by a group-owner or the world the risk of its compromise is increased. The file contains the list of accounts on the system and associated information, and protection of this file @@ -73465,7 +84757,7 @@ is critical for system security. chmod u-xs,g-xws,o-xwt /etc/passwd - name: Test for existence /etc/passwd - stat: + ansible.builtin.stat: path: /etc/passwd register: file_exists tags: @@ -73484,7 +84776,7 @@ chmod u-xs,g-xws,o-xwt /etc/passwd - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/passwd - file: + ansible.builtin.file: path: /etc/passwd mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73529,7 +84821,6 @@ To properly set the permissions of /etc/shadow, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -73556,26 +84847,26 @@ To properly set the permissions of /etc/shadow, run the c 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 + 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 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-8.7.c - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002555 - SV-271817r1092163_rule + OL09-00-002555 + SV-271817r1092163_rule The /etc/shadow file contains the list of local system accounts and stores password hashes. Protection of this file is critical for system security. Failure to give ownership of this file @@ -73588,7 +84879,7 @@ which could weaken the system security posture. chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow - name: Test for existence /etc/shadow - stat: + ansible.builtin.stat: path: /etc/shadow register: file_exists tags: @@ -73607,7 +84898,7 @@ chmod u-xwrs,g-xwrs,o-xwrt /etc/shadow - no_reboot_needed - name: Ensure permission u-xwrs,g-xwrs,o-xwrt on /etc/shadow - file: + ansible.builtin.file: path: /etc/shadow mode: u-xwrs,g-xwrs,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -73651,7 +84942,7 @@ Since this file is used by many system programs this file should be protected. - name: Test for existence /etc/shells - stat: + ansible.builtin.stat: path: /etc/shells register: file_exists tags: @@ -73665,7 +84956,7 @@ chmod u-xs,g-xws,o-xwt /etc/shells - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/shells - file: + ansible.builtin.file: path: /etc/shells mode: u-xs,g-xws,o-xwt when: file_exists.stat is defined and file_exists.stat.exists @@ -73694,23 +84985,47 @@ messages in the system and should only be accessed by authorized personnel. Verify Group Who Owns /var/log Directory - To properly set the group owner of /var/log, run the command: $ sudo chgrp root /var/log + To properly set the group owner of /var/log, run the command: +$ sudo chgrp root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002560 - SV-271818r1092166_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002560 + SV-271818r1092166_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /var/log/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi - - name: Ensure group owner on /var/log/ - file: + - name: Set the file_groupowner_var_log_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_var_log_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002560 + - configure_strategy + - file_groupowner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /var/log/ + ansible.builtin.file: path: /var/log/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_var_log_newgroup }}' tags: - DISA-STIG-OL09-00-002560 - configure_strategy @@ -73729,18 +85044,44 @@ personnel. Verify Group Who Owns /var/log/messages File - To properly set the group owner of /var/log/messages, run the command: $ sudo chgrp root /var/log/messages + To properly set the group owner of /var/log/messages, run the command: +$ sudo chgrp root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002563 - SV-271821r1092175_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002563 + SV-271821r1092175_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. - chgrp 0 /var/log/messages + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/var/log/messages" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /var/log/messages +fi + +fi - - name: Test for existence /var/log/messages - stat: + - name: Set the file_groupowner_var_log_messages_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupowner_var_log_messages_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002563 + - configure_strategy + - file_groupowner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /var/log/messages + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -73752,10 +85093,11 @@ the system and should only be accessed by authorized personnel. Verify Group Who Owns /var/log/syslog File - To properly set the group owner of /var/log/syslog, run the command: $ sudo chgrp adm /var/log/syslog + To properly set the group owner of /var/log/syslog, run the command: +$ sudo chgrp adm /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. - chgrp 4 /var/log/syslog + + # Remediation is applicable only in certain platforms +if rpm --quiet -q rsyslog; then + +newgroup="" +if getent group "4" >/dev/null 2>&1; then + newgroup="4" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "4 is not a defined group on the system" +else +if ! stat -c "%g %G" "/var/log/syslog" | grep -E -w -q "4"; then + chgrp --no-dereference "$newgroup" /var/log/syslog +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_groupowner_var_log_syslog @@ -73795,11 +85156,40 @@ the system and should only be accessed by authorized personnel. Verify User Who Owns /var/log Directory - To properly set the owner of /var/log, run the command: $ sudo chown root /var/log + To properly set the owner of /var/log, run the command: +$ sudo chown root /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002561 - SV-271819r1092169_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002561 + SV-271819r1092169_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. - find -H /var/log/ -maxdepth 1 -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /var/log/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /var/log/ - file: + - name: Set the file_owner_var_log_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_var_log_newown: '0' + tags: + - DISA-STIG-OL09-00-002561 + - configure_strategy + - file_owner_var_log + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /var/log/ + ansible.builtin.file: path: /var/log/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_var_log_newown }}' tags: - DISA-STIG-OL09-00-002561 - configure_strategy @@ -73852,18 +85266,43 @@ personnel. Verify User Who Owns /var/log/messages File - To properly set the owner of /var/log/messages, run the command: $ sudo chown root /var/log/messages + To properly set the owner of /var/log/messages, run the command: +$ sudo chown root /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002564 - SV-271822r1092178_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002564 + SV-271822r1092178_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. - chown 0 /var/log/messages + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/var/log/messages" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /var/log/messages +fi + +fi - - name: Test for existence /var/log/messages - stat: + - name: Set the file_owner_var_log_messages_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_var_log_messages_newown: '0' + tags: + - DISA-STIG-OL09-00-002564 + - configure_strategy + - file_owner_var_log_messages + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Test for existence /var/log/messages + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -73875,10 +85314,11 @@ the system and should only be accessed by authorized personnel. Verify User Who Owns /var/log/syslog File - To properly set the owner of /var/log/syslog, run the command: $ sudo chown syslog /var/log/syslog + To properly set the owner of /var/log/syslog, run the command: +$ sudo chown syslog /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. - chown 104 /var/log/syslog + + # Remediation is applicable only in certain platforms +if rpm --quiet -q rsyslog; then + +newown="" +if id "syslog" >/dev/null 2>&1; then + newown="syslog" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "syslog is not a defined user on the system" +else +if ! stat -c "%u %U" "/var/log/syslog" | grep -E -w -q "syslog"; then + chown --no-dereference "$newown" /var/log/syslog +fi + +fi + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Test for existence /var/log/syslog - stat: - path: /var/log/syslog - register: file_exists + - name: Gather the package facts + package_facts: + manager: auto tags: - configure_strategy - file_owner_var_log_syslog @@ -73918,11 +85377,55 @@ the system and should only be accessed by authorized personnel./var/log, run the command: $ sudo chmod 0755 /var/log - CCI-001314 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 - OL09-00-002562 - SV-271820r1092172_rule + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 + OL09-00-002562 + SV-271820r1092172_rule The /var/log directory contains files with logs of error messages in the system and should only be accessed by authorized personnel. @@ -73956,10 +85458,11 @@ personnel. -find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /var/log/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - name: Find /var/log/ file(s) - command: 'find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /var/log/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -73974,7 +85477,7 @@ find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws, - no_reboot_needed - name: Set permissions for /var/log/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74000,22 +85503,21 @@ find -H /var/log/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws, Verify Permissions on /var/log/messages File To properly set the permissions of /var/log/messages, run the command: -$ sudo chmod 0600 /var/log/messages +$ sudo chmod 0640 /var/log/messages - CCI-001314 - SRG-OS-000206-GPOS-00084 - OL09-00-002565 - SV-271823r1092181_rule + SRG-OS-000206-GPOS-00084 + OL09-00-002565 + SV-271823r1092181_rule The /var/log/messages file contains logs of error messages in the system and should only be accessed by authorized personnel. -chmod u-xs,g-xwrs,o-xwrt /var/log/messages +chmod u-xs,g-xws,o-xwrt /var/log/messages - name: Test for existence /var/log/messages - stat: + ansible.builtin.stat: path: /var/log/messages register: file_exists tags: @@ -74027,10 +85529,10 @@ chmod u-xs,g-xwrs,o-xwrt /var/log/messages - medium_severity - no_reboot_needed -- name: Ensure permission u-xs,g-xwrs,o-xwrt on /var/log/messages - file: +- name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/messages + ansible.builtin.file: path: /var/log/messages - mode: u-xs,g-xwrs,o-xwrt + mode: u-xs,g-xws,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists tags: - DISA-STIG-OL09-00-002565 @@ -74054,8 +85556,7 @@ chmod u-xs,g-xwrs,o-xwrt /var/log/messages To properly set the permissions of /var/log/syslog, run the command: $ sudo chmod 0640 /var/log/syslog - CCI-001314 - SRG-OS-000206-GPOS-00084 + SRG-OS-000206-GPOS-00084 The /var/log/syslog file contains logs of error messages in the system and should only be accessed by authorized personnel. @@ -74065,7 +85566,7 @@ the system and should only be accessed by authorized personnel. - name: Test for existence /var/log/syslog - stat: + ansible.builtin.stat: path: /var/log/syslog register: file_exists tags: @@ -74077,7 +85578,7 @@ chmod u-xs,g-xws,o-xwrt /var/log/syslog - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /var/log/syslog - file: + ansible.builtin.file: path: /var/log/syslog mode: u-xs,g-xws,o-xwrt when: file_exists.stat is defined and file_exists.stat.exists @@ -74122,27 +85623,53 @@ ownership with the following command: $ sudo chgrp root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002520 - SV-271786r1092070_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002520 + SV-271786r1092070_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership of library directories is necessary to protect the integrity of the system. - find -H /lib/ -type d -exec chgrp -L 0 {} \; -find -H /lib64/ -type d -exec chgrp -L 0 {} \; -find -H /usr/lib/ -type d -exec chgrp -L 0 {} \; -find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; + +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /lib/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /lib64/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib64/ -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi - - name: Ensure group owner on /lib/ recursively - file: + - name: Set the dir_group_ownership_library_dirs_newgroup variable if represented + by gid + ansible.builtin.set_fact: + dir_group_ownership_library_dirs_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002520 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_group_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure group owner on /lib/ recursively + ansible.builtin.file: path: /lib/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74155,11 +85682,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /lib64/ recursively - file: + ansible.builtin.file: path: /lib64/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74172,11 +85700,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /usr/lib/ recursively - file: + ansible.builtin.file: path: /usr/lib/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74189,11 +85718,12 @@ find -H /usr/lib64/ -type d -exec chgrp -L 0 {} \; - no_reboot_needed - name: Ensure group owner on /usr/lib64/ recursively - file: + ansible.builtin.file: path: /usr/lib64/ + follow: false state: directory recurse: true - group: '0' + group: '{{ dir_group_ownership_library_dirs_newgroup }}' tags: - DISA-STIG-OL09-00-002520 - NIST-800-53-CM-5(6) @@ -74227,24 +85757,46 @@ following command: $ sudo chown root DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 + SRG-OS-000258-GPOS-00099 System binaries are executed by privileged users as well as system services, and restrictive permissions are necessary to ensure that their execution of these programs cannot be co-opted. - find -H /bin/ -type d -exec chown -L 0 {} \; -find -H /sbin/ -type d -exec chown -L 0 {} \; -find -H /usr/bin/ -type d -exec chown -L 0 {} \; -find -H /usr/sbin/ -type d -exec chown -L 0 {} \; -find -H /usr/local/bin/ -type d -exec chown -L 0 {} \; -find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/local/bin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/local/sbin/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /bin/ recursively - file: + - name: Set the dir_ownership_binary_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + dir_ownership_binary_dirs_newown: '0' + tags: + - configure_strategy + - dir_ownership_binary_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /bin/ recursively + ansible.builtin.file: path: /bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74254,11 +85806,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /sbin/ recursively - file: + ansible.builtin.file: path: /sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74268,11 +85821,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/bin/ recursively - file: + ansible.builtin.file: path: /usr/bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74282,11 +85836,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/sbin/ recursively - file: + ansible.builtin.file: path: /usr/sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74296,11 +85851,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/local/bin/ recursively - file: + ansible.builtin.file: path: /usr/local/bin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74310,11 +85866,12 @@ find -H /usr/local/sbin/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/local/sbin/ recursively - file: + ansible.builtin.file: path: /usr/local/sbin/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_binary_dirs_newown }}' tags: - configure_strategy - dir_ownership_binary_dirs @@ -74348,27 +85905,52 @@ ownership with the following command: $ sudo chown root DIR - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002521 - SV-271787r1092073_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002521 + SV-271787r1092073_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership of library directories is necessary to protect the integrity of the system. - find -H /lib/ -type d -exec chown -L 0 {} \; -find -H /lib64/ -type d -exec chown -L 0 {} \; -find -H /usr/lib/ -type d -exec chown -L 0 {} \; -find -H /usr/lib64/ -type d -exec chown -L 0 {} \; + +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /lib/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /lib64/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/lib/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; +find -P /usr/lib64/ -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi - - name: Ensure owner on directory /lib/ recursively - file: + - name: Set the dir_ownership_library_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + dir_ownership_library_dirs_newown: '0' + tags: + - DISA-STIG-OL09-00-002521 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - dir_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Ensure owner on directory /lib/ recursively + ansible.builtin.file: path: /lib/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74381,11 +85963,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /lib64/ recursively - file: + ansible.builtin.file: path: /lib64/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74398,11 +85981,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/lib/ recursively - file: + ansible.builtin.file: path: /usr/lib/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74415,11 +85999,12 @@ find -H /usr/lib64/ -type d -exec chown -L 0 {} \; - no_reboot_needed - name: Ensure owner on directory /usr/lib64/ recursively - file: + ansible.builtin.file: path: /usr/lib64/ + follow: false state: directory recurse: true - owner: '0' + owner: '{{ dir_ownership_library_dirs_newown }}' tags: - DISA-STIG-OL09-00-002521 - NIST-800-53-CM-5(6) @@ -74454,8 +86039,7 @@ following command: $ sudo chmod go-w DIR - CCI-001495 - SRG-OS-000258-GPOS-00099 + SRG-OS-000258-GPOS-00099 System binaries are executed by privileged users, as well as system services, and restrictive permissions are necessary to ensure execution of these programs cannot be co-opted. @@ -74476,7 +86060,7 @@ find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; - name: Find /bin/ file(s) recursively - command: 'find -H /bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74490,7 +86074,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74505,7 +86089,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /sbin/ file(s) recursively - command: 'find -H /sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /sbin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74519,7 +86103,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74534,7 +86118,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/bin/ file(s) recursively - command: 'find -H /usr/bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74548,7 +86132,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74563,7 +86147,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/sbin/ file(s) recursively - command: 'find -H /usr/sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/sbin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74577,7 +86161,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74592,7 +86176,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/local/bin/ file(s) recursively - command: 'find -H /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/local/bin/ -perm /u+s,g+ws,o+wt -type d ' register: files_found changed_when: false failed_when: false @@ -74606,7 +86190,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/local/bin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74621,7 +86205,8 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Find /usr/local/sbin/ file(s) recursively - command: 'find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -74635,7 +86220,7 @@ find -H /usr/local/sbin/ -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt - no_reboot_needed - name: Set permissions for /usr/local/sbin/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -74674,14 +86259,13 @@ its permission with the following command: $ sudo chmod go-w DIR - CCI-001499 - CIP-003-8 R6 + CIP-003-8 R6 CM-5 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002522 - SV-271788r1092076_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002522 + SV-271788r1092076_rule If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management process. @@ -74704,7 +86288,7 @@ find -H /usr/lib/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - name: Find /lib/ file(s) recursively - command: 'find -H /lib/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /lib/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74722,7 +86306,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74741,7 +86325,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /lib64/ file(s) recursively - command: 'find -H /lib64/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /lib64/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74759,7 +86343,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74778,7 +86362,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /usr/lib/ file(s) recursively - command: 'find -H /usr/lib/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /usr/lib/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74796,7 +86380,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /usr/lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74815,7 +86399,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Find /usr/lib64/ file(s) recursively - command: 'find -H /usr/lib64/ -perm /g+w,o+w -type d ' + ansible.builtin.command: 'find -P /usr/lib64/ -perm /g+w,o+w -type d ' register: files_found changed_when: false failed_when: false @@ -74833,7 +86417,7 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; - no_reboot_needed - name: Set permissions for /usr/lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: directory @@ -74860,7 +86444,8 @@ find -H /usr/lib64/ -perm /g+w,o+w -type d -exec chmod g-w,o-w {} \; Verify Group Who Owns /etc/sysctl.d Directory - To properly set the group owner of /etc/sysctl.d, run the command: $ sudo chgrp root /etc/sysctl.d + To properly set the group owner of /etc/sysctl.d, run the command: +$ sudo chgrp root /etc/sysctl.d R50 The ownership of the /etc/sysctl.d directory by the root group is important @@ -74871,7 +86456,17 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/sysctl.d/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74888,11 +86483,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_sysctld_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_sysctld_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_sysctld_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/sysctl.d/ - file: + ansible.builtin.file: path: /etc/sysctl.d/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_sysctld_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -74911,7 +86537,8 @@ fi Verify User Who Owns /etc/sysctl.d Directory - To properly set the owner of /etc/sysctl.d, run the command: $ sudo chown root /etc/sysctl.d + To properly set the owner of /etc/sysctl.d, run the command: +$ sudo chown root /etc/sysctl.d R50 The ownership of the /etc/sysctl.d directory by the root user is important @@ -74922,7 +86549,17 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/sysctl.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74939,11 +86576,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_sysctld_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_sysctld_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_sysctld + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/sysctl.d/ - file: + ansible.builtin.file: path: /etc/sysctl.d/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_sysctld_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -74973,7 +86623,7 @@ ensures exclusive control of the kernel configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /etc/sysctl.d/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -74991,7 +86641,8 @@ fi - no_reboot_needed - name: Find /etc/sysctl.d/ file(s) - command: 'find -H /etc/sysctl.d/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /etc/sysctl.d/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -75006,7 +86657,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/sysctl.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -75046,13 +86697,12 @@ with the following command: $ sudo chgrp root FILE - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002504 - SV-271773r1092031_rule + OL09-00-002504 + SV-271773r1092031_rule If the operating system allows any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management @@ -75064,13 +86714,16 @@ escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. -for SYSCMDFILES in /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -do - find -L $SYSCMDFILES \! -group root -type f -exec chgrp root '{}' \; -done +find -P /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin \! -group root -type f -exec chgrp root '{}' \; || true - - name: Retrieve the system command files and set their group ownership to root - command: find -L {{ item }} ! -group root -type f -exec chgrp root '{}' \; + - name: Verify that system commands files are group owned by root or a system account + - Find system command files with incorrect group ownership + ansible.builtin.find: + paths: '{{ item }}' + file_type: file + follow: false + recurse: false + register: system_command_files_found with_items: - /bin - /sbin @@ -75079,8 +86732,24 @@ done - /usr/local/bin - /usr/local/sbin changed_when: false - failed_when: false - check_mode: false + tags: + - DISA-STIG-OL09-00-002504 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - file_groupownership_system_commands_dirs + - medium_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Verify that system commands files are group owned by root or a system account + - Set group ownership to root for system command files + ansible.builtin.file: + path: '{{ item.path }}' + group: root + with_items: '{{ system_command_files_found.results | map(attribute=''files'') | + flatten | rejectattr(''gr_name'', ''equalto'', ''root'') | list }}' tags: - DISA-STIG-OL09-00-002504 - NIST-800-53-CM-5(6) @@ -75128,7 +86797,6 @@ following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75155,40 +86823,35 @@ following command: 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 + 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 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002505 - SV-271774r1092034_rule + 1409 + OL09-00-002505 + SV-271774r1092034_rule System binaries are executed by privileged users as well as system services, and restrictive permissions are necessary to ensure that their execution of these programs cannot be co-opted. - find /bin/ \ -/usr/bin/ \ -/usr/local/bin/ \ -/sbin/ \ -/usr/sbin/ \ -/usr/local/sbin/ \ -/usr/libexec \ -\! -user root -execdir chown root {} \; + +find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ /usr/libexec \! -user root -execdir chown root {} \; - name: Read list of system executables without root ownership - command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ /usr/local/sbin/ - /usr/libexec \! -user root + ansible.builtin.command: find /bin/ /usr/bin/ /usr/local/bin/ /sbin/ /usr/sbin/ + /usr/local/sbin/ /usr/libexec \! -user root register: no_root_system_executables changed_when: false failed_when: false @@ -75207,7 +86870,7 @@ execution of these programs cannot be co-opted. - restrict_strategy - name: Set ownership to root of system executables - file: + ansible.builtin.file: path: '{{ item }}' owner: root with_items: '{{ no_root_system_executables.stdout_lines }}' @@ -75262,7 +86925,6 @@ ownership with the following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75289,38 +86951,67 @@ ownership with the following command: 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 + 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 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 - OL09-00-002524 - SV-271790r1092082_rule + SRG-OS-000259-GPOS-00100 + 1409 + OL09-00-002524 + SV-271790r1134866_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Proper ownership is necessary to protect the integrity of the system. -find /lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi -find /lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else -find /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +find -P /lib/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; -find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exec chown -L 0 {} \; +find -P /lib64/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +find -P /usr/lib/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +find -P /usr/lib64/ -type f ! -user 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chown --no-dereference "$newown" {} \; + +fi - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" + - name: Set the file_ownership_library_dirs_newown variable if represented by uid + ansible.builtin.set_fact: + file_ownership_library_dirs_newown: '0' + tags: + - DISA-STIG-OL09-00-002524 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - NIST-800-53-CM-6(a) + - configure_strategy + - file_ownership_library_dirs + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Find /lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75338,10 +87029,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /lib/ file(s) matching ^.*$ - file: +- name: Ensure owner on /lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75358,8 +87050,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" +- name: Find /lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib64/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75377,10 +87070,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /lib64/ file(s) matching ^.*$ - file: +- name: Ensure owner on /lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75397,8 +87091,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -uid 0 -regextype posix-extended -regex "^.*$" +- name: Find /usr/lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75416,10 +87111,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /usr/lib/ file(s) matching ^.*$ - file: +- name: Ensure owner on /usr/lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75436,9 +87132,9 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib64/ -type f ! -user 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75456,10 +87152,11 @@ find /usr/lib64/ -type f ! -uid 0 -regextype posix-extended -regex '^.*$' -exe - medium_severity - no_reboot_needed -- name: Ensure owner on /usr/lib64/ file(s) matching ^.*$ - file: +- name: Ensure owner on /usr/lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_library_dirs_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75512,7 +87209,6 @@ following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75539,25 +87235,26 @@ following command: 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 + 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 CM-5(6) CM-5(6).1 CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 + SRG-OS-000259-GPOS-00100 R50 - OL09-00-002506 - SV-271775r1092037_rule + 1409 + OL09-00-002506 + SV-271775r1092037_rule System binaries are executed by privileged users, as well as system services, and restrictive permissions are necessary to ensure execution of these programs cannot be co-opted. @@ -75567,8 +87264,8 @@ for dirPath in $DIRS; do done - name: Read list of world and group writable system executables - ansible.builtin.command: find /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin - /usr/libexec -perm /022 -type f + ansible.builtin.command: find -L /bin /usr/bin /usr/local/bin /sbin /usr/sbin /usr/local/sbin + /usr/libexec -perm /022 \( -type l -o -type f \) register: world_writable_library_files changed_when: false failed_when: false @@ -75643,7 +87340,6 @@ its permission with the following command: DSS05.04 DSS05.07 DSS06.02 - CCI-001499 4.3.3.7.3 SR 2.1 SR 5.2 @@ -75670,24 +87366,25 @@ its permission with the following command: 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 + 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 CM-6(a) CM-5(6) CM-5(6).1 AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000259-GPOS-00100 - OL09-00-002525 - SV-271791r1092085_rule + SRG-OS-000259-GPOS-00100 + 1409 + OL09-00-002525 + SV-271791r1134971_rule Files from shared library directories are loaded into the address space of processes (including privileged ones) or of the kernel itself at runtime. Restrictive permissions are necessary to protect the integrity of the system. @@ -75695,17 +87392,17 @@ runtime. Restrictive permissions are necessary to protect the integrity of the s -find /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; -find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*$' -exec chmod g-w,o-w {} \; +find -P /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.*\.so.*$' -exec chmod g-w,o-w {} \; - name: Find /lib/ file(s) recursively - command: find -H /lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /lib/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75724,7 +87421,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75744,8 +87441,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /lib64/ file(s) recursively - command: find -H /lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /lib64/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75764,7 +87461,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75784,8 +87481,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /usr/lib/ file(s) recursively - command: find -H /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended -regex - "^.*$" + ansible.builtin.command: find -P /usr/lib/ -perm /g+w,o+w -type f -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75804,7 +87501,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /usr/lib/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75824,8 +87521,8 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Find /usr/lib64/ file(s) recursively - command: find -H /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended - -regex "^.*$" + ansible.builtin.command: find -P /usr/lib64/ -perm /g+w,o+w -type f -regextype + posix-extended -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75844,7 +87541,7 @@ find /usr/lib64/ -perm /g+w,o+w -type f -regextype posix-extended -regex '^.* - no_reboot_needed - name: Set permissions for /usr/lib64/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: g-w,o-w state: file @@ -75881,17 +87578,16 @@ by default: /usr/lib64 All system-wide shared library files should be protected from unauthorised -access. If any of these files is not group-owned by root, correct its group-owner with -the following command: +access. If any of these files is not group-owned by root, +correct its group-owner with the following command: $ sudo chgrp root FILE - CCI-001499 CM-5(6) CM-5(6).1 - SRG-OS-000259-GPOS-00100 - OL09-00-002523 - SV-271789r1092079_rule + SRG-OS-000259-GPOS-00100 + OL09-00-002523 + SV-271789r1134863_rule If the operating system were to allow any user to make changes to software libraries, then those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management process. @@ -75902,16 +87598,39 @@ also include privileged programs which execute with escalated privileges. Only q and authorized individuals must be allowed to obtain access to information system components for purposes of initiating changes, including upgrades and modifications. -find /lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi -find /lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*\.so.*$' -exec chgrp --no-dereference "$newgroup" {} \; -find /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; - -find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -exec chgrp -L 0 {} \; +fi - - name: Find /lib/ file(s) matching ^.*$ recursively - command: find -H /lib/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" + - name: Set the root_permissions_syslibrary_files_newgroup variable if represented + by gid + ansible.builtin.set_fact: + root_permissions_syslibrary_files_newgroup: '0' + tags: + - DISA-STIG-OL09-00-002523 + - NIST-800-53-CM-5(6) + - NIST-800-53-CM-5(6).1 + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - root_permissions_syslibrary_files + +- name: Find /lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75927,10 +87646,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /lib/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75945,8 +87665,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /lib64/ file(s) matching ^.*$ recursively - command: find -H /lib64/ -type f ! -group 0 -regextype posix-extended -regex "^.*$" +- name: Find /lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /lib64/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75962,10 +87683,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /lib64/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -75980,9 +87702,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /usr/lib/ file(s) matching ^.*$ recursively - command: find -H /usr/lib/ -type f ! -group 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -75998,10 +87720,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /usr/lib/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /usr/lib/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -76016,9 +87739,9 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Find /usr/lib64/ file(s) matching ^.*$ recursively - command: find -H /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex - "^.*$" +- name: Find /usr/lib64/ file(s) matching ^.*\.so.*$ recursively + ansible.builtin.command: find -P /usr/lib64/ -type f ! -group 0 -regextype posix-extended + -regex "^.*\.so.*$" register: files_found changed_when: false failed_when: false @@ -76034,10 +87757,11 @@ find /usr/lib64/ -type f ! -group 0 -regextype posix-extended -regex '^.*$' -e - no_reboot_needed - root_permissions_syslibrary_files -- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*$ - file: +- name: Ensure group owner on /usr/lib64/ file(s) matching ^.*\.so.*$ + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ root_permissions_syslibrary_files_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -76107,9 +87831,6 @@ The autofs service can be disabled with the following com DSS06.03 DSS06.10 3.4.6 - CCI-000778 - CCI-000366 - CCI-001958 164.308(a)(3)(i) 164.308(a)(3)(ii)(A) 164.310(d)(1) @@ -76166,11 +87887,11 @@ The autofs service can be disabled with the following com PR.AC-3 PR.AC-6 PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - OL09-00-002000 - SV-271639r1091629_rule + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + OL09-00-002000 + SV-271639r1091629_rule Disabling the automounter permits the administrator to statically control filesystem mounting through /etc/fstab. @@ -76220,97 +87941,54 @@ fi - no_reboot_needed - service_autofs_disabled -- name: Disable the Automounter - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable the Automounter - Disable service autofs + block: + + - name: Disable the Automounter - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable the Automounter - Ensure autofs.service is Masked + ansible.builtin.systemd: + name: autofs.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("autofs.service", multiline=True) + + - name: Unit Socket Exists - autofs.socket + ansible.builtin.command: systemctl -q list-unit-files autofs.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable the Automounter - Disable Socket autofs + ansible.builtin.systemd: + name: autofs.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("autofs.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002000 + - NIST-800-171-3.4.6 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_autofs_disabled + - special_service_block when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Disable the Automounter - Ensure autofs.service is Masked - ansible.builtin.systemd: - name: autofs.service - state: stopped - enabled: false - masked: true - when: - - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("autofs.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Unit Socket Exists - autofs.socket - ansible.builtin.command: systemctl -q list-unit-files autofs.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled - -- name: Disable the Automounter - Disable Socket autofs - ansible.builtin.systemd: - name: autofs.socket - enabled: false - state: stopped - masked: true - when: - - ( "autofs" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("autofs.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002000 - - NIST-800-171-3.4.6 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-MP-7 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_autofs_disabled include disable_autofs @@ -76325,6 +88003,10 @@ class disable_autofs { [customizations.services] masked = ["autofs"] + + + + @@ -76338,6 +88020,11 @@ masked = ["autofs"] To configure the system to prevent the cramfs kernel module from being loaded, add the following line to the file /etc/modprobe.d/cramfs.conf: install cramfs /bin/false +This entry will cause a non-zero return value during a cramfs module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install cramfs /bin/true To configure the system to prevent the cramfs from being used, add the following line to file /etc/modprobe.d/cramfs.conf: @@ -76361,7 +88048,6 @@ decompress the image. DSS05.05 DSS06.06 3.4.6 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -76418,9 +88104,9 @@ decompress the image. CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000095-GPOS-00049 - OL09-00-000045 - SV-271448r1091056_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000045 + SV-271448r1091056_rule Removing support for unneeded filesystem types reduces the local attack surface of the server. @@ -76460,7 +88146,7 @@ fi - reboot_required - name: Ensure kernel module 'cramfs' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/cramfs.conf regexp: install\s+cramfs @@ -76480,7 +88166,7 @@ fi - reboot_required - name: Ensure kernel module 'cramfs' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/cramfs.conf regexp: ^blacklist cramfs$ @@ -76512,6 +88198,11 @@ fi To configure the system to prevent the squashfs kernel module from being loaded, add the following line to the file /etc/modprobe.d/squashfs.conf: install squashfs /bin/false +This entry will cause a non-zero return value during a squashfs module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install squashfs /bin/true To configure the system to prevent the squashfs from being used, add the following line to file /etc/modprobe.d/squashfs.conf: @@ -76630,7 +88321,7 @@ fi - reboot_required - name: Ensure kernel module 'squashfs' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/squashfs.conf regexp: install\s+squashfs @@ -76649,7 +88340,7 @@ fi - reboot_required - name: Ensure kernel module 'squashfs' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/squashfs.conf regexp: ^blacklist squashfs$ @@ -76677,6 +88368,11 @@ fi To configure the system to prevent the udf kernel module from being loaded, add the following line to the file /etc/modprobe.d/udf.conf: install udf /bin/false +This entry will cause a non-zero return value during a udf module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install udf /bin/true To configure the system to prevent the udf from being used, add the following line to file /etc/modprobe.d/udf.conf: @@ -76687,7 +88383,7 @@ This effectively prevents usage of this uncommon filesystem. The udf filesystem type is the universal disk format used to implement the ISO/IEC 13346 and ECMA-167 specifications. This is an open vendor filesystem type for data storage on a broad -range of media. This filesystem type is neccessary to support +range of media. This filesystem type is necessary to support writing DVDs and newer optical disc formats. 11 14 @@ -76796,7 +88492,7 @@ fi - reboot_required - name: Ensure kernel module 'udf' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/udf.conf regexp: install\s+udf @@ -76815,7 +88511,7 @@ fi - reboot_required - name: Ensure kernel module 'udf' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/udf.conf regexp: ^blacklist udf$ @@ -76845,6 +88541,11 @@ to prevent automatic loading of the USB storage driver. To configure the system to prevent the usb-storage kernel module from being loaded, add the following line to the file /etc/modprobe.d/usb-storage.conf: install usb-storage /bin/false +This entry will cause a non-zero return value during a usb-storage module installation +and additionally convey the meaning of the entry to the user in form of an error message. +If you would like to omit a non-zero return value and an error message, you may want to add a different line instead +(both /bin/true and /bin/false are allowed by OVAL and will be accepted by the scan): +install usb-storage /bin/true To configure the system to prevent the usb-storage from being used, add the following line to file /etc/modprobe.d/usb-storage.conf: @@ -76868,9 +88569,6 @@ module, but will not prevent an administrator (or another program) from using th DSS06.03 DSS06.10 3.1.21 - CCI-000778 - CCI-001958 - CCI-003959 164.308(a)(3)(i) 164.308(a)(3)(ii)(A) 164.310(d)(1) @@ -76927,17 +88625,15 @@ module, but will not prevent an administrator (or another program) from using th PR.AC-3 PR.AC-6 PR.AC-7 - SRG-OS-000114-GPOS-00059 - SRG-OS-000378-GPOS-00163 - SRG-OS-000480-GPOS-00227 - SRG-APP-000141-CTR-000315 + SRG-OS-000114-GPOS-00059 + SRG-OS-000378-GPOS-00163 + SRG-OS-000480-GPOS-00227 + SRG-APP-000141-CTR-000315 A.15.SEC-OL1 3.4.2 3.4 - OL09-00-000047 - OL09-00-002332 - SV-271450r1092466_rule - SV-271702r1091818_rule + OL09-00-000047 + SV-271450r1092466_rule USB storage devices such as thumb drives can be used to introduce malicious software. @@ -76965,7 +88661,6 @@ fi manager: auto tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -76981,7 +88676,7 @@ fi - reboot_required - name: Ensure kernel module 'usb-storage' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/usb-storage.conf regexp: install\s+usb-storage @@ -76989,7 +88684,6 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -77005,7 +88699,7 @@ fi - reboot_required - name: Ensure kernel module 'usb-storage' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/usb-storage.conf regexp: ^blacklist usb-storage$ @@ -77013,7 +88707,6 @@ fi when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000047 - - DISA-STIG-OL09-00-002332 - NIST-800-171-3.1.21 - NIST-800-53-CM-6(a) - NIST-800-53-CM-7(a) @@ -77043,6 +88736,23 @@ that limit what files on those partitions can do. These options are set in the /etc/fstab configuration file, and can be used to make certain types of malicious behavior more difficult. + + Value for hidepid option + The hidepid mount option is applicable to /proc and is used to control who can access +the information in /proc/[pid] directories. The option can have one of the following +values: +0: Everybody may access all /proc/[pid] directories. +1: Users may not access files and subdirectories inside any /proc/[pid] directories + but their own. The /proc/[pid] directories themselves remain visible. +2: Same as for mode 1, but in addition the /proc/[pid] directories belonging to other + users become invisible. + 0 + noaccess + invisible + 1 + 2 + 2 + Removable Partition This value is used by the checks mount_option_nodev_removable_partitions, mount_option_nodev_removable_partitions, @@ -77060,17 +88770,16 @@ should not be required on the boot partition. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /boot/efi. - CCI-000366 - CCI-001764 CM-6(b) CM-6.1(iv) - SRG-OS-000480-GPOS-00227 - OL09-00-002032 - SV-271649r1091659_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002032 + SV-271649r1091659_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from boot partitions. + # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/boot/efi" > /dev/null || findmnt --fstab "/boot/efi" > /dev/null; }; then function perform_remediation { @@ -77139,10 +88848,13 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false - when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages + check_mode: false + when: + - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002032 - NIST-800-53-CM-6(b) @@ -77163,8 +88875,9 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77194,8 +88907,9 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77218,8 +88932,9 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002032 @@ -77242,8 +88957,9 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + - '"/boot/efi" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77275,16 +88991,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /boot. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -77294,13 +89009,13 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002030 - SV-271647r1091653_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002030 + SV-271647r1091653_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77373,10 +89088,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002030 - NIST-800-53-AC-6 @@ -77401,8 +89117,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77435,8 +89151,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77463,8 +89179,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002030 @@ -77491,8 +89207,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77533,7 +89249,7 @@ Add the noexec option to the fourth column of binaries should be executed from this partition after the booting process finishes. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77599,10 +89315,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - configure_strategy - high_disruption @@ -77620,8 +89337,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77647,8 +89364,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77668,8 +89385,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "noexec" not in mount_info.options tags: - configure_strategy @@ -77689,8 +89406,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77720,17 +89437,15 @@ should not be required on the boot partition. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /boot. - CCI-000366 - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -77740,15 +89455,15 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002031 - SV-271648r1091656_rule + OL09-00-002031 + SV-271648r1091656_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from boot partitions. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -77821,10 +89536,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002031 - NIST-800-53-AC-6 @@ -77849,8 +89565,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -77883,8 +89599,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -77911,8 +89627,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002031 @@ -77939,8 +89655,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" | length == 0) @@ -77992,7 +89708,6 @@ Add the nodev option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78050,15 +89765,15 @@ Add the nodev option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -78068,13 +89783,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002040 - SV-271650r1091662_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002040 + SV-271650r1091662_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78138,10 +89854,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002040 - NIST-800-53-AC-6 @@ -78166,8 +89883,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78200,8 +89917,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78228,8 +89945,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002040 @@ -78256,8 +89973,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78307,7 +90024,6 @@ Add the noexec option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78365,15 +90081,15 @@ Add the noexec option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -78383,13 +90099,14 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002041 - SV-271651r1091665_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002041 + SV-271651r1091665_rule Allowing users to execute binaries from world-writable directories such as /dev/shm can expose the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78453,10 +90170,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002041 - NIST-800-53-AC-6 @@ -78481,8 +90199,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78516,8 +90234,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78544,8 +90262,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "noexec" not in mount_info.options tags: - DISA-STIG-OL09-00-002041 @@ -78572,8 +90290,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78622,7 +90340,6 @@ Add the nosuid option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -78680,15 +90397,15 @@ Add the nosuid option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -78698,13 +90415,14 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002042 - SV-271652r1094966_rule + SRG-OS-000368-GPOS-00154 + 1409 + OL09-00-002042 + SV-271652r1094966_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation { @@ -78768,10 +90486,11 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002042 - NIST-800-53-AC-6 @@ -78796,8 +90515,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) tags: @@ -78831,8 +90550,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - ("" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length == 0) @@ -78859,8 +90578,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined and "nosuid" not in mount_info.options tags: - DISA-STIG-OL09-00-002042 @@ -78887,8 +90606,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("" | length == 0) @@ -78939,7 +90658,7 @@ single user or group can cause for other users (or the wider system) by intentio accidentally filling up the partition. Quotas can also be applied to inodes for filesystems where inode exhaustion is a concern. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79019,8 +90738,8 @@ fi fstab_mount_point_info: [] when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79035,8 +90754,8 @@ fi database: passwd when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79052,8 +90771,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79073,8 +90792,8 @@ fi filter: ansible_mounts when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79112,7 +90831,7 @@ fi - name: Add grpquota Option to /home - Ensure mount option grpquota is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},grpquota' @@ -79125,8 +90844,8 @@ fi - '''grpquota'' not in item.options' when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -79153,30 +90872,27 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /home. - CCI-001764 - SRG-OS-000368-GPOS-00154 - OL09-00-002070 - SV-271666r1091710_rule + OVAL looks for partitions whose mount point is a substring of any interactive user's home +directory and validates that nodev option is there. Because of this, there could be false +negatives when several partitions share a base substring. For example, if there is a home +directory in /var/tmp/user1 and there are partitions mounted in /var and +/var/tmp. The nodev option is only expected in /var/tmp, but OVAL will +check both. +Bash remediation uses the df command to find out the partition where the home +directory is mounted. However, if the directory doesn't exist the remediation won't be +applied. + SRG-OS-000368-GPOS-00154 + OL09-00-002070 + SV-271666r1091710_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/home" > /dev/null || findmnt --fstab "/home" > /dev/null; }; then -function perform_remediation { - - # the mount point /home has to be defined in /etc/fstab - # before this remediation can be executed. In case it is not defined, the - # remediation aborts and no changes regarding the mount point are done. - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" "/home")" +function perform_remediation (){ - grep "$mount_point_match_regexp" -q /etc/fstab \ - || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; - echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; } - - - - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" /home)" + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $1)" # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab if ! grep -q "$mount_point_match_regexp" /etc/fstab; then @@ -79190,22 +90906,34 @@ function perform_remediation { if [ "$fs_type" == "iso9660" ] ; then previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") fi - echo " /home defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab + echo " $1 defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "nodev"; then previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,nodev|" /etc/fstab fi - - if mkdir -p "/home"; then - if mountpoint -q "/home"; then - mount -o remount --target "/home" + if mkdir -p "$1"; then + if mountpoint -q "$1"; then + mount -o remount --target "$1" fi fi } -perform_remediation +readarray -t home_directories < \ + <(awk -F':' '{if ($3>=1000 && $3!= 65534) print $6}' /etc/passwd ) + + +for home_directory in "${home_directories[@]}" +do + if [ -d $home_directory ]; then + fstab_mount_point=$(df $home_directory | awk '/^\/dev/ {print $6}') + if ! grep -qP "^/$|^/lib$|^/opt$|^/usr$|^/bin$|^/sbin$|^/boot$|^/dev$|^/proc$" <<< $fstab_mount_point + then + perform_remediation "$fstab_mount_point" + fi + fi +done else >&2 echo 'Remediation is not applicable, nothing was done' @@ -79223,16 +90951,26 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Check information associated to mountpoint' - command: findmnt --fstab '/home' - register: device_name - failed_when: device_name.rc > 1 - changed_when: false +- name: Add nodev Option to /home - Initialize variables + ansible.builtin.set_fact: + non_allowed_partitions: + - / + - /lib + - /opt + - /usr + - /bin + - /sbin + - /boot + - /dev + - /proc + home_directories: [] + allowed_mount_point: [] + fstab_mount_point_info: [] when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002070 @@ -79243,20 +90981,15 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Create mount_info dictionary variable' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - '{{ device_name.stdout_lines[0].split() | list | lower }}' - - '{{ device_name.stdout_lines[1].split() | list }}' +- name: Add nodev Option to /home - Get home directories from passwd + ansible.builtin.getent: + database: passwd when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length > 0) tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79266,27 +90999,20 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: If /home not mounted, craft mount_info manually' - set_fact: - mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}' - with_together: - - - target - - source - - fstype - - options - - - /home - - '' - - '' - - defaults +- name: Add nodev Option to /home - Filter home directories based on UID range + ansible.builtin.set_fact: + home_directories: '{{ home_directories + [item.data[4]] }}' when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - ("--fstab" | length == 0) - - device_name.stdout is defined and device_name.stdout_lines is defined - - (device_name.stdout | length == 0) + - item.data[4] is defined + - item.data[2]|int >= 1000 + - item.data[2]|int != 65534 + - item.data[4] not in non_allowed_partitions + with_items: '{{ ansible_facts.getent_passwd | dict2items(key_name=''user'', value_name=''data'')}}' tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79296,18 +91022,15 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Make sure nodev option is part of the to /home - options' - set_fact: - mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev'' - }) }}' +- name: Add nodev Option to /home - Gather mount points + ansible.builtin.setup: + filter: ansible_mounts when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - mount_info is defined and "nodev" not in mount_info.options tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79317,22 +91040,51 @@ fi - no_reboot_needed - unknown_severity -- name: 'Add nodev Option to /home: Ensure /home is mounted with nodev option' - mount: - path: /home - src: '{{ mount_info.source }}' - opts: '{{ mount_info.options }}' - state: mounted - fstype: '{{ mount_info.fstype }}' +- name: Add nodev Option to /home - Ensure mount options for home directories + block: + + - name: ' Add nodev Option to /home - Obtain mount point using df and shell' + ansible.builtin.shell: | + df {{ item }} | awk '/^\/dev/ {print $6}' + register: df_output + with_items: '{{ home_directories }}' + + - name: Add nodev Option to /home - Set mount point for each home directory + ansible.builtin.set_fact: + allowed_mount_point: '{{ allowed_mount_point + [item.stdout_lines[0]] }}' + with_items: '{{ df_output.results }}' + when: + - item.stdout_lines is defined + - item.stdout_lines | length > 0 + - item.stdout_lines[0] != "" + + - name: Add nodev Option to /home - Obtain full mount information for allowed mount + point + ansible.builtin.set_fact: + fstab_mount_point_info: '{{ fstab_mount_point_info + [ ansible_mounts | selectattr(''mount'', + ''equalto'', item) | first ]}}' + with_items: '{{ allowed_mount_point }}' + when: allowed_mount_point is defined + + - name: Add nodev Option to /home - Ensure mount option nodev is in fstab for allowed + mount point + ansible.posix.mount: + path: '{{ item.mount }}' + src: '{{ item.device }}' + opts: '{{ item.options }},nodev' + state: mounted + fstype: '{{ item.fstype }}' + with_items: '{{ fstab_mount_point_info }}' + when: + - allowed_mount_point is defined + - item.mount not in non_allowed_partitions + - '''nodev'' not in item.options' when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/home" in ansible_mounts | map(attribute="mount") | list' - - mount_info is defined - - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" - | length == 0) tags: - DISA-STIG-OL09-00-002070 - configure_strategy @@ -79341,9 +91093,6 @@ fi - mount_option_home_nodev - no_reboot_needed - unknown_severity - - -part /home --mountoptions="nodev" @@ -79368,17 +91117,16 @@ check both. Bash remediation uses the df command to find out the partition where the home directory is mounted. However, if the directory doesn't exist the remediation won't be applied. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002072 - SV-271668r1091716_rule + OL09-00-002072 + SV-271668r1091716_rule The /home directory contains data of individual users. Binaries in this directory should not be considered as trusted and users should not be able to execute them. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79459,8 +91207,8 @@ fi fstab_mount_point_info: [] when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79476,8 +91224,8 @@ fi database: passwd when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79494,8 +91242,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79516,8 +91264,8 @@ fi filter: ansible_mounts when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79556,7 +91304,7 @@ fi - name: Add noexec Option to /home - Ensure mount option noexec is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},noexec' @@ -79569,8 +91317,8 @@ fi - '''noexec'' not in item.options' when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002072 - NIST-800-53-CM-6(b) @@ -79620,8 +91368,6 @@ applied. DSS05.05 DSS05.06 DSS06.06 - CCI-000366 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -79679,15 +91425,15 @@ applied. A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -79697,15 +91443,15 @@ applied. PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002071 - SV-271667r1091713_rule + OL09-00-002071 + SV-271667r1091713_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from user home directory partitions. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -79791,8 +91537,8 @@ fi fstab_mount_point_info: [] when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79813,8 +91559,8 @@ fi database: passwd when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79836,8 +91582,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -79863,8 +91609,8 @@ fi filter: ansible_mounts when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79908,7 +91654,7 @@ fi - name: Add nosuid Option to /home - Ensure mount option nosuid is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},nosuid' @@ -79921,8 +91667,8 @@ fi - '''nosuid'' not in item.options' when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002071 - NIST-800-53-AC-6 @@ -79970,7 +91716,7 @@ single user or group can cause for other users (or the wider system) by intentio accidentally filling up the partition. Quotas can also be applied to inodes for filesystems where inode exhaustion is a concern. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then function perform_remediation (){ @@ -80050,8 +91796,8 @@ fi fstab_mount_point_info: [] when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80066,8 +91812,8 @@ fi database: passwd when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80083,8 +91829,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.data[4] is defined - item.data[2]|int >= 1000 - item.data[2]|int != 65534 @@ -80104,8 +91850,8 @@ fi filter: ansible_mounts when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80143,7 +91889,7 @@ fi - name: Add usrquota Option to /home - Ensure mount option usrquota is in fstab for allowed mount point - ansible.builtin.mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},usrquota' @@ -80156,8 +91902,8 @@ fi - '''usrquota'' not in item.options' when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - NIST-800-53-CM-6(b) - configure_strategy @@ -80195,7 +91941,6 @@ Add the nodev option to the fourth column of DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -80247,15 +91992,15 @@ Add the nodev option to the fourth column of A.14.2.3 A.14.2.4 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -80264,18 +92009,18 @@ Add the nodev option to the fourth column of MP-7 PR.IP-1 PR.PT-3 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00227 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00227 R28 - OL09-00-002080 - SV-271669r1091719_rule + OL09-00-002080 + SV-271669r1091719_rule The nodev mount option prevents files from being interpreted as character or block devices. The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails, for which it is not advised to set nodev on these filesystems. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then MOUNT_OPTION="nodev" # Create array of local non-root partitions @@ -80285,38 +92030,73 @@ readarray -t partitions_records < <(findmnt --mtab --raw --evaluate | grep readarray -t polyinstantiated_dirs < \ <(grep -oP "^\s*[^#\s]+\s+\S+" /etc/security/namespace.conf | grep -oP "(?<=\s)\S+?(?=/?\$)") +# Define excluded non-local file systems +excluded_fstypes=( + afs + autofs + ceph + cifs + smb3 + smbfs + sshfs + ncpfs + ncp + nfs + nfs4 + gfs + gfs2 + glusterfs + gpfs + pvfs2 + ocfs2 + lustre + davfs + fuse.sshfs +) for partition_record in "${partitions_records[@]}"; do # Get all important information for fstab - mount_point="$(echo ${partition_record} | cut -d " " -f1)" - device="$(echo ${partition_record} | cut -d " " -f2)" - device_type="$(echo ${partition_record} | cut -d " " -f3)" - if ! printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then - # device and device_type will be used only in case when the device doesn't have fstab record - mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)" + mount_point="$(echo "${partition_record}" | cut -d " " -f1)" + device="$(echo "${partition_record}" | cut -d " " -f2)" + device_type="$(echo "${partition_record}" | cut -d " " -f3)" - # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab - if ! grep -q "$mount_point_match_regexp" /etc/fstab; then - # runtime opts without some automatic kernel/userspace-added defaults - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ - | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") - [ "$previous_mount_opts" ] && previous_mount_opts+="," - # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in - # fstab as "block". The next variable is to satisfy shellcheck SC2050. - fs_type="$device_type" - if [ "$fs_type" == "iso9660" ] ; then - previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") - fi - echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab - # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it - elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "$MOUNT_OPTION"; then - previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') - sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab + # Skip polyinstantiated directories + if printf '%s\0' "${polyinstantiated_dirs[@]}" | grep -qxzF "$mount_point"; then + continue + fi + + # Skip any non-local filesystem + for excluded_fstype in "${excluded_fstypes[@]}"; do + if [[ "$device_type" == "$excluded_fstype" ]]; then + # jump out of both loops and move to next partition_record + continue 2 fi - if mkdir -p "$mount_point"; then - if mountpoint -q "$mount_point"; then - mount -o remount --target "$mount_point" - fi + done + + # If we reach here, it's a local, non-root partition that isn't excluded. + mount_point_match_regexp="$(printf "^[[:space:]]*[^#].*[[:space:]]%s[[:space:]]" $mount_point)" + + # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab + if ! grep -q "$mount_point_match_regexp" /etc/fstab; then + # runtime opts without some automatic kernel/userspace-added defaults + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/mtab | head -1 | awk '{print $4}' \ + | sed -E "s/(rw|defaults|seclabel|$MOUNT_OPTION)(,|$)//g;s/,$//") + [ "$previous_mount_opts" ] && previous_mount_opts+="," + # In iso9660 filesystems mtab could describe a "blocksize" value, this should be reflected in + # fstab as "block". The next variable is to satisfy shellcheck SC2050. + fs_type="$device_type" + if [ "$fs_type" == "iso9660" ] ; then + previous_mount_opts=$(sed 's/blocksize=/block=/' <<< "$previous_mount_opts") + fi + echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab + # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it + elif ! grep "$mount_point_match_regexp" /etc/fstab | grep -q "$MOUNT_OPTION"; then + previous_mount_opts=$(grep "$mount_point_match_regexp" /etc/fstab | awk '{print $4}') + sed -i "s|\(${mount_point_match_regexp}.*${previous_mount_opts}\)|\1,$MOUNT_OPTION|" /etc/fstab + fi + if mkdir -p "$mount_point"; then + if mountpoint -q "$mount_point"; then + mount -o remount --target "$mount_point" fi fi done @@ -80347,12 +92127,55 @@ fi - no_reboot_needed - name: 'Add nodev Option to Non-Root Local Partitions: Refresh facts' - setup: + ansible.builtin.setup: gather_subset: mounts when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) + tags: + - DISA-STIG-OL09-00-002080 + - NIST-800-53-AC-6 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-MP-7 + - configure_strategy + - high_disruption + - low_complexity + - medium_severity + - mount_option_nodev_nonroot_local_partitions + - no_reboot_needed + +- name: 'Add nodev Option to Non-Root Local Partitions: Define excluded (non-local) + file systems' + ansible.builtin.set_fact: + excluded_fstypes: + - afs + - autofs + - ceph + - cifs + - smb3 + - smbfs + - sshfs + - ncpfs + - ncp + - nfs + - nfs4 + - gfs + - gfs2 + - glusterfs + - gpfs + - pvfs2 + - ocfs2 + - lustre + - davfs + - fuse.sshfs + when: ( not ( "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 ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002080 - NIST-800-53-AC-6 @@ -80370,7 +92193,7 @@ fi - name: 'Add nodev Option to Non-Root Local Partitions: Ensure non-root local partitions are mounted with nodev option' - mount: + ansible.posix.mount: path: '{{ item.mount }}' src: '{{ item.device }}' opts: '{{ item.options }},nodev' @@ -80379,10 +92202,11 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - item.mount is match('/\w') - item.options is not search('nodev') + - item.fstype not in excluded_fstypes with_items: - '{{ ansible_facts.mounts }}' tags: @@ -80404,12 +92228,12 @@ fi are present with nodev option in /etc/fstab' ansible.builtin.replace: path: /etc/fstab - regexp: ^\s*(?!#)(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(?!nodev)(\S+)(.*)$ + regexp: ^\s*(?!#)(/dev/\S+|UUID=\S+)\s+(/\w\S*)\s+(\S+)\s+(?!.*\bnodev\b)(\S+)(.*)$ replace: \1 \2 \3 \4,nodev \5 when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002080 - NIST-800-53-AC-6 @@ -80465,7 +92289,6 @@ Add the nodev option to the fourth column of DSS05.07 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80531,15 +92354,15 @@ Add the nodev option to the fourth column of A.8.3.3 A.9.1.2 A.9.2.1 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -80551,15 +92374,15 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002021 - SV-271645r1091647_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002021 + SV-271645r1091647_rule The only legitimate location for device files is the /dev directory located on the root partition. An exception to this is chroot jails, and it is not advised to set nodev on partitions which contain their root filesystems. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -80602,15 +92425,15 @@ fi - always - name: Ensure permission nodev are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,nodev \5 when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002021 - NIST-800-53-AC-6 @@ -80666,7 +92489,6 @@ Add the noexec option to the fourth column of DSS05.07 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80732,15 +92554,15 @@ Add the noexec option to the fourth column of A.8.3.3 A.9.1.2 A.9.2.1 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -80752,13 +92574,13 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002020 - SV-271644r1091644_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002020 + SV-271644r1091644_rule Allowing users to execute binaries from removable media such as USB keys exposes the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -80801,15 +92623,15 @@ fi - always - name: Ensure permission noexec are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,noexec \5 when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002020 - NIST-800-53-AC-6 @@ -80839,7 +92661,7 @@ fi and set-group-identifier (SGID) permissions from taking effect. These permissions allow users to execute binaries with the same permissions as the owner and group of the file respectively. Users should not be allowed to introduce SUID and SGID -files into the system via partitions mounted from removeable media. +files into the system via partitions mounted from removable media. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of @@ -80871,7 +92693,6 @@ Add the nosuid option to the fourth column of DSS06.02 DSS06.03 DSS06.06 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -80955,15 +92776,15 @@ Add the nosuid option to the fourth column of 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -80977,14 +92798,14 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002022 - SV-271646r1091650_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002022 + SV-271646r1091650_rule The presence of SUID and SGID executables should be tightly controlled. Allowing users to introduce SUID or SGID binaries from partitions mounted off of removable media would allow them to introduce their own highly-privileged programs. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ); then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ); then var_removable_partition='' @@ -81027,15 +92848,15 @@ fi - always - name: Ensure permission nosuid are set on var_removable_partition - lineinfile: + ansible.builtin.lineinfile: path: /etc/fstab regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$ backrefs: true line: \1 \2 \3 \4,nosuid \5 when: ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) tags: - DISA-STIG-OL09-00-002022 - NIST-800-53-AC-6 @@ -81073,7 +92894,7 @@ Add the nosuid option to the fourth column of not be able to execute SUID or SGID binaries from this directory. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/opt" > /dev/null || findmnt --fstab "/opt" > /dev/null; }; then function perform_remediation { @@ -81139,11 +92960,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -81162,8 +92984,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81190,8 +93012,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81212,8 +93034,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -81234,8 +93056,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/opt" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81272,7 +93094,7 @@ Add the nosuid option to the fourth column of not be able to execute SUID or SGID binaries from this directory. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/srv" > /dev/null || findmnt --fstab "/srv" > /dev/null; }; then function perform_remediation { @@ -81338,11 +93160,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -81361,8 +93184,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81389,8 +93212,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81411,8 +93234,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -81433,8 +93256,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/srv" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81480,7 +93303,6 @@ Add the nodev option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -81538,15 +93360,15 @@ Add the nodev option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -81556,14 +93378,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002050 - SV-271653r1091671_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002050 + SV-271653r1091671_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -81636,11 +93458,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002050 @@ -81666,8 +93489,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -81701,8 +93524,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -81729,8 +93552,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -81758,8 +93581,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -81811,7 +93634,6 @@ Add the noexec option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -81869,15 +93691,15 @@ Add the noexec option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -81887,16 +93709,16 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002051 - SV-271654r1091674_rule + OL09-00-002051 + SV-271654r1091674_rule Allowing users to execute binaries from world-writable directories such as /tmp should never be necessary in normal operation and can expose the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -81969,11 +93791,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002051 @@ -81999,8 +93822,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82034,8 +93857,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82063,8 +93886,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -82092,8 +93915,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82146,7 +93969,6 @@ Add the nosuid option to the fourth column of DSS05.05 DSS05.06 DSS06.06 - CCI-001764 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -82204,15 +94026,15 @@ Add the nosuid option to the fourth column of A.8.3.1 A.8.3.3 A.9.1.2 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -82222,15 +94044,15 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002052 - SV-271655r1091677_rule + OL09-00-002052 + SV-271655r1091677_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/tmp" > /dev/null || findmnt --fstab "/tmp" > /dev/null; }; then function perform_remediation { @@ -82303,11 +94125,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002052 @@ -82333,8 +94156,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82368,8 +94191,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82397,8 +94220,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -82426,8 +94249,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82467,16 +94290,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -82487,14 +94309,14 @@ Add the nodev option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002064 - SV-271660r1091692_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002064 + SV-271660r1091692_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -82567,11 +94389,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002064 @@ -82597,8 +94420,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82633,8 +94456,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82662,8 +94485,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -82692,8 +94515,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82730,16 +94553,15 @@ from being executed out of /var/log/audit. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -82750,15 +94572,15 @@ Add the noexec option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002065 - SV-271661r1091695_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002065 + SV-271661r1091695_rule Allowing users to execute binaries from directories containing audit log files such as /var/log/audit should never be necessary in normal operation and can expose the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -82831,11 +94653,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002065 @@ -82861,8 +94684,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -82897,8 +94720,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -82926,8 +94749,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -82956,8 +94779,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -82995,16 +94818,15 @@ should not be required in directories containing audit log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -83015,15 +94837,15 @@ Add the nosuid option to the fourth column of PR.PT-2 PR.PT-3 FMT_SMF_EXT.1 - SRG-OS-000368-GPOS-00154 - OL09-00-002066 - SV-271662r1091698_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002066 + SV-271662r1091698_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for audit log files. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log/audit" > /dev/null || findmnt --fstab "/var/log/audit" > /dev/null; }; then function perform_remediation { @@ -83096,11 +94918,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002066 @@ -83126,8 +94949,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83162,8 +94985,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83191,8 +95014,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -83221,8 +95044,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log/audit" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83262,16 +95085,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -83281,14 +95103,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002061 - SV-271657r1091683_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002061 + SV-271657r1091683_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83361,11 +95183,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002061 @@ -83391,8 +95214,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83426,8 +95249,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83455,8 +95278,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -83484,8 +95307,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83522,16 +95345,15 @@ from being executed out of /var/log. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -83541,16 +95363,16 @@ Add the noexec option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002062 - SV-271658r1091686_rule + OL09-00-002062 + SV-271658r1091686_rule Allowing users to execute binaries from directories containing log files such as /var/log should never be necessary in normal operation and can expose the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83623,11 +95445,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002062 @@ -83653,8 +95476,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83689,8 +95512,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83718,8 +95541,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -83747,8 +95570,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -83786,16 +95609,15 @@ should not be required in directories containing log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -83805,16 +95627,16 @@ Add the nosuid option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002063 - SV-271659r1091689_rule + OL09-00-002063 + SV-271659r1091689_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for log files. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/log" > /dev/null || findmnt --fstab "/var/log" > /dev/null; }; then function perform_remediation { @@ -83887,11 +95709,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002063 @@ -83917,8 +95740,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -83953,8 +95776,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -83982,8 +95805,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -84011,8 +95834,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/log" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84052,16 +95875,15 @@ jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var. - CCI-001764 - 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -84071,14 +95893,14 @@ Add the nodev option to the fourth column of PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000368-GPOS-00154 - OL09-00-002060 - SV-271656r1091680_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002060 + SV-271656r1091680_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84151,11 +95973,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002060 @@ -84181,8 +96004,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84216,8 +96039,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84244,8 +96067,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -84273,8 +96096,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84316,7 +96139,7 @@ Add the noexec option to the fourth column of mails and caches. No binaries should be executed from this directory. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84382,11 +96205,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -84405,8 +96229,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84433,8 +96257,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84455,8 +96279,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -84477,8 +96301,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84513,7 +96337,7 @@ Add the nosuid option to the fourth column of The presence of SUID and SGID executables should be tightly controlled. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var" > /dev/null || findmnt --fstab "/var" > /dev/null; }; then function perform_remediation { @@ -84579,11 +96403,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' tags: - configure_strategy @@ -84602,8 +96427,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84630,8 +96455,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84652,8 +96477,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -84674,8 +96499,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84706,15 +96531,14 @@ should not exist within temporary directories like /var/tmpnodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 - OL09-00-002067 - SV-271663r1091701_rule + SRG-OS-000368-GPOS-00154 + OL09-00-002067 + SV-271663r1091701_rule The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -84781,11 +96605,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002067 @@ -84805,8 +96630,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -84834,8 +96659,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -84857,8 +96682,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nodev" not in mount_info.options tags: @@ -84880,8 +96705,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -84912,17 +96737,16 @@ from being executed out of /var/tmp. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002068 - SV-271664r1091704_rule + OL09-00-002068 + SV-271664r1091704_rule Allowing users to execute binaries from world-writable directories such as /var/tmp should never be necessary in normal operation and can expose the system to potential compromise. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -84989,11 +96813,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002068 @@ -85013,8 +96838,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -85043,8 +96868,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -85066,8 +96891,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "noexec" not in mount_info.options tags: @@ -85089,8 +96914,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -85122,16 +96947,15 @@ should not be required in these world-writable directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp. - CCI-001764 - SRG-OS-000368-GPOS-00154 + SRG-OS-000368-GPOS-00154 R28 - OL09-00-002069 - SV-271665r1091707_rule + OL09-00-002069 + SV-271665r1091707_rule The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions. # 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 /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then +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 ]) ) && ! ( [ -f /.dockerenv ] || [ -f /run/.containerenv ] ) ) && { findmnt --kernel "/var/tmp" > /dev/null || findmnt --fstab "/var/tmp" > /dev/null; }; then function perform_remediation { @@ -85198,11 +97022,12 @@ fi register: device_name failed_when: device_name.rc > 1 changed_when: false + check_mode: false when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' tags: - DISA-STIG-OL09-00-002069 @@ -85222,8 +97047,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - device_name.stdout is defined and device_name.stdout_lines is defined - (device_name.stdout | length > 0) @@ -85252,8 +97077,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - ("--fstab" | length == 0) - device_name.stdout is defined and device_name.stdout_lines is defined @@ -85275,8 +97100,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined and "nosuid" not in mount_info.options tags: @@ -85298,8 +97123,8 @@ fi when: - ( not ( "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 not ( ansible_virtualization_type in ["docker", "lxc", "openvz", "podman", - "container"] ) ) + and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type in + ["docker", "lxc", "openvz", "podman", "container"] ) ) - '"/var/tmp" in ansible_mounts | map(attribute="mount") | list' - mount_info is defined - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab" @@ -85342,11 +97167,10 @@ or compromised programs. Disable the uvcvideo module If the device contains a camera it should be covered or disabled when not in use. - CCI-000381 CM-7 (a) CM-7 (5) (b) - SRG-OS-000095-GPOS-00049 - SRG-OS-000370-GPOS-00155 + SRG-OS-000095-GPOS-00049 + SRG-OS-000370-GPOS-00155 Failing to disconnect from collaborative computing devices (i.e., cameras) can result in subsequent compromises of organizational information. Providing easy methods to physically disconnect from such devices after a collaborative computing session helps to ensure participants actually carry out the disconnect activity without having to go through complex and tedious procedures. @@ -85383,7 +97207,7 @@ fi - reboot_required - name: Ensure kernel module 'uvcvideo' is disabled - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/uvcvideo.conf regexp: install\s+uvcvideo @@ -85400,7 +97224,7 @@ fi - reboot_required - name: Ensure kernel module 'uvcvideo' is blacklisted - lineinfile: + ansible.builtin.lineinfile: create: true dest: /etc/modprobe.d/uvcvideo.conf regexp: ^blacklist uvcvideo$ @@ -85428,14 +97252,13 @@ fi To set the runtime status of the kernel.core_pattern kernel parameter, run the following command: $ sudo sysctl -w kernel.core_pattern=|/bin/false To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.core_pattern = |/bin/false - CCI-000366 SC-7(10) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002380 - SV-271728r1091896_rule + OL09-00-002380 + SV-271728r1091896_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. @@ -85471,7 +97294,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.core_pattern # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.core_pattern="|/bin/false" fi @@ -85520,16 +97343,12 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable storing core dumps - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_pattern.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002380 @@ -85544,13 +97363,62 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: Comment out any occurrences of kernel.core_pattern from config files - replace: - path: '{{ item.path }}' +- name: Disable storing core dumps - Find all files that contain kernel.core_pattern + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_pattern\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Disable storing core dumps - Find all files that set kernel.core_pattern to + correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_pattern\s*=\s*\|/bin/false$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002380 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern + +- name: Disable storing core dumps - Comment out any occurrences of kernel.core_pattern + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_pattern replace: '#kernel.core_pattern' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002380 - NIST-800-53-SC-7(10) @@ -85564,8 +97432,8 @@ fi - reboot_required - sysctl_kernel_core_pattern -- name: Ensure sysctl kernel.core_pattern is set to |/bin/false - sysctl: +- name: Disable storing core dumps - Ensure sysctl kernel.core_pattern is set to |/bin/false + ansible.posix.sysctl: name: kernel.core_pattern value: '|/bin/false' sysctl_file: /etc/sysctl.conf @@ -85585,6 +97453,10 @@ fi - reboot_required - sysctl_kernel_core_pattern + + + + @@ -85682,15 +97554,14 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: List /etc/sysctl.d/*.conf files - find: - paths: - - /etc/sysctl.d/ - - /run/sysctl.d/ - contains: ^[\s]*kernel.core_pattern.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d +- name: Disable storing core dumps - Find all files that contain kernel.core_pattern + ansible.builtin.shell: + cmd: find -L /etc/sysctl.conf /etc/sysctl.d/ /run/sysctl.d/ -type f -name '*.conf' + | xargs grep -HP '^\s*kernel.core_pattern\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -85700,14 +97571,35 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf - files - replace: - path: '{{ item.path }}' +- name: Disable storing core dumps - Find all files that set kernel.core_pattern to + correct value + ansible.builtin.shell: + cmd: find -L /etc/sysctl.conf /etc/sysctl.d/ /run/sysctl.d/ -type f -name '*.conf' + | xargs grep -HP '^\s*kernel.core_pattern\s*=\s*$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_pattern_empty_string + +- name: Disable storing core dumps - Comment out any occurrences of kernel.core_pattern + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_pattern replace: '#kernel.core_pattern' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -85716,25 +97608,11 @@ fi - reboot_required - sysctl_kernel_core_pattern_empty_string -- name: Comment out any occurrences of kernel.core_pattern with value from /etc/sysctl.conf - files - replace: - path: /etc/sysctl.conf - regexp: ^[\s]*kernel.core_pattern([ \t]*=[ \t]*\S+) - replace: '#kernel.core_pattern\1' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - disable_strategy - - low_complexity - - medium_disruption - - medium_severity - - reboot_required - - sysctl_kernel_core_pattern_empty_string - -- name: Ensure sysctl kernel.core_pattern is set to empty - sysctl: +- name: Disable storing core dumps - Ensure sysctl kernel.core_pattern is set to empty + ansible.posix.sysctl: name: kernel.core_pattern value: ' ' + sysctl_file: /etc/sysctl.conf state: present reload: true when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -85799,7 +97677,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.core_uses_pid # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.core_uses_pid="0" fi @@ -85843,16 +97721,12 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Configure file name of core dumps - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.core_uses_pid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -85862,13 +97736,52 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: Comment out any occurrences of kernel.core_uses_pid from config files - replace: - path: '{{ item.path }}' +- name: Configure file name of core dumps - Find all files that contain kernel.core_uses_pid + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_uses_pid\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Configure file name of core dumps - Find all files that set kernel.core_uses_pid + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.core_uses_pid\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_core_uses_pid + +- name: Configure file name of core dumps - Comment out any occurrences of kernel.core_uses_pid + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.core_uses_pid replace: '#kernel.core_uses_pid' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -85877,8 +97790,9 @@ fi - reboot_required - sysctl_kernel_core_uses_pid -- name: Ensure sysctl kernel.core_uses_pid is set to 0 - sysctl: +- name: Configure file name of core dumps - Ensure sysctl kernel.core_uses_pid is + set to 0 + ansible.posix.sysctl: name: kernel.core_uses_pid value: '0' sysctl_file: /etc/sysctl.conf @@ -85893,6 +97807,10 @@ fi - reboot_required - sysctl_kernel_core_uses_pid + + + + @@ -85906,8 +97824,6 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.dmesg_restrict = 1 3.1.5 - CCI-001082 - CCI-001090 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -85918,12 +97834,13 @@ To make sure that the setting is persistent, add the following line to a file in SI-11(a) SI-11(b) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 R9 - OL09-00-002406 - SV-271745r1091947_rule + 1546 + OL09-00-002406 + SV-271745r1117266_rule Unprivileged access to the kernel syslog can expose sensitive kernel address information. @@ -85958,7 +97875,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.dmesg_restrict # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.dmesg_restrict="1" fi @@ -86006,16 +97923,12 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Restrict Access to Kernel Message Buffer - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.dmesg_restrict.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002406 @@ -86029,13 +97942,60 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: Comment out any occurrences of kernel.dmesg_restrict from config files - replace: - path: '{{ item.path }}' +- name: Restrict Access to Kernel Message Buffer - Find all files that contain kernel.dmesg_restrict + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.dmesg_restrict\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Restrict Access to Kernel Message Buffer - Find all files that set kernel.dmesg_restrict + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.dmesg_restrict\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002406 + - NIST-800-171-3.1.5 + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_dmesg_restrict + +- name: Restrict Access to Kernel Message Buffer - Comment out any occurrences of + kernel.dmesg_restrict from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.dmesg_restrict replace: '#kernel.dmesg_restrict' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002406 - NIST-800-171-3.1.5 @@ -86048,8 +98008,9 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict -- name: Ensure sysctl kernel.dmesg_restrict is set to 1 - sysctl: +- name: Restrict Access to Kernel Message Buffer - Ensure sysctl kernel.dmesg_restrict + is set to 1 + ansible.posix.sysctl: name: kernel.dmesg_restrict value: '1' sysctl_file: /etc/sysctl.conf @@ -86068,6 +98029,10 @@ fi - reboot_required - sysctl_kernel_dmesg_restrict + + + + @@ -86080,14 +98045,13 @@ fi To set the runtime status of the kernel.kexec_load_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.kexec_load_disabled=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kexec_load_disabled = 1 - CCI-003992 - CCI-000366 CM-6 FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - SRG-OS-000366-GPOS-00153 - OL09-00-002428 - SV-271766r1092010_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000366-GPOS-00153 + 1409 + OL09-00-002428 + SV-271766r1092010_rule Disabling kexec_load allows greater control of the kernel memory. It makes it impossible to load another kernel image after it has been disabled. @@ -86123,7 +98087,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.kexec_load_disabled # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.kexec_load_disabled="1" fi @@ -86169,16 +98133,12 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Kernel Image Loading - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.kexec_load_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002428 @@ -86190,13 +98150,56 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: Comment out any occurrences of kernel.kexec_load_disabled from config files - replace: - path: '{{ item.path }}' +- name: Disable Kernel Image Loading - Find all files that contain kernel.kexec_load_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kexec_load_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Disable Kernel Image Loading - Find all files that set kernel.kexec_load_disabled + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kexec_load_disabled\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002428 + - NIST-800-53-CM-6 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kexec_load_disabled + +- name: Disable Kernel Image Loading - Comment out any occurrences of kernel.kexec_load_disabled + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.kexec_load_disabled replace: '#kernel.kexec_load_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002428 - NIST-800-53-CM-6 @@ -86207,8 +98210,9 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled -- name: Ensure sysctl kernel.kexec_load_disabled is set to 1 - sysctl: +- name: Disable Kernel Image Loading - Ensure sysctl kernel.kexec_load_disabled is + set to 1 + ansible.posix.sysctl: name: kernel.kexec_load_disabled value: '1' sysctl_file: /etc/sysctl.conf @@ -86225,6 +98229,10 @@ fi - reboot_required - sysctl_kernel_kexec_load_disabled + + + + @@ -86245,6 +98253,10 @@ that once this option has been set, it cannot be reverted without doing a system reboot. Make sure that all needed kernel modules are loaded before setting this option. + + + + @@ -86294,7 +98306,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.panic_on_oops # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.panic_on_oops="1" fi @@ -86338,16 +98350,12 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Kernel panic on oops - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.panic_on_oops.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86357,13 +98365,52 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: Comment out any occurrences of kernel.panic_on_oops from config files - replace: - path: '{{ item.path }}' +- name: Kernel panic on oops - Find all files that contain kernel.panic_on_oops + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.panic_on_oops\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Kernel panic on oops - Find all files that set kernel.panic_on_oops to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.panic_on_oops\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_panic_on_oops + +- name: Kernel panic on oops - Comment out any occurrences of kernel.panic_on_oops + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.panic_on_oops replace: '#kernel.panic_on_oops' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86372,8 +98419,8 @@ fi - reboot_required - sysctl_kernel_panic_on_oops -- name: Ensure sysctl kernel.panic_on_oops is set to 1 - sysctl: +- name: Kernel panic on oops - Ensure sysctl kernel.panic_on_oops is set to 1 + ansible.posix.sysctl: name: kernel.panic_on_oops value: '1' sysctl_file: /etc/sysctl.conf @@ -86388,6 +98435,10 @@ fi - reboot_required - sysctl_kernel_panic_on_oops + + + + @@ -86401,7 +98452,7 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_cpu_time_max_percent = 1 R9 - The kernel.perf_cpu_time_max_percent configures a treshold of + The kernel.perf_cpu_time_max_percent configures a threshold of maximum percentile of CPU that can be used by Perf system. Restricting usage of Perf system decreases risk of potential availability problems. @@ -86436,7 +98487,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_cpu_time_max_percent # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_cpu_time_max_percent="1" fi @@ -86480,16 +98531,12 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Limit CPU consumption of the Perf system - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_cpu_time_max_percent.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86499,14 +98546,52 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: Comment out any occurrences of kernel.perf_cpu_time_max_percent from config - files - replace: - path: '{{ item.path }}' +- name: Limit CPU consumption of the Perf system - Find all files that contain kernel.perf_cpu_time_max_percent + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_cpu_time_max_percent\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Limit CPU consumption of the Perf system - Find all files that set kernel.perf_cpu_time_max_percent + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_cpu_time_max_percent\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_cpu_time_max_percent + +- name: Limit CPU consumption of the Perf system - Comment out any occurrences of + kernel.perf_cpu_time_max_percent from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_cpu_time_max_percent replace: '#kernel.perf_cpu_time_max_percent' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86515,8 +98600,9 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent -- name: Ensure sysctl kernel.perf_cpu_time_max_percent is set to 1 - sysctl: +- name: Limit CPU consumption of the Perf system - Ensure sysctl kernel.perf_cpu_time_max_percent + is set to 1 + ansible.posix.sysctl: name: kernel.perf_cpu_time_max_percent value: '1' sysctl_file: /etc/sysctl.conf @@ -86531,6 +98617,10 @@ fi - reboot_required - sysctl_kernel_perf_cpu_time_max_percent + + + + @@ -86580,7 +98670,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_event_max_sample_rate # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_event_max_sample_rate="1" fi @@ -86624,16 +98714,12 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Limit sampling frequency of the Perf system - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_max_sample_rate.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86643,14 +98729,53 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: Comment out any occurrences of kernel.perf_event_max_sample_rate from config - files - replace: - path: '{{ item.path }}' +- name: Limit sampling frequency of the Perf system - Find all files that contain + kernel.perf_event_max_sample_rate + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_max_sample_rate\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Limit sampling frequency of the Perf system - Find all files that set kernel.perf_event_max_sample_rate + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_max_sample_rate\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_perf_event_max_sample_rate + +- name: Limit sampling frequency of the Perf system - Comment out any occurrences + of kernel.perf_event_max_sample_rate from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_event_max_sample_rate replace: '#kernel.perf_event_max_sample_rate' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86659,8 +98784,9 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate -- name: Ensure sysctl kernel.perf_event_max_sample_rate is set to 1 - sysctl: +- name: Limit sampling frequency of the Perf system - Ensure sysctl kernel.perf_event_max_sample_rate + is set to 1 + ansible.posix.sysctl: name: kernel.perf_event_max_sample_rate value: '1' sysctl_file: /etc/sysctl.conf @@ -86675,6 +98801,10 @@ fi - reboot_required - sysctl_kernel_perf_event_max_sample_rate + + + + @@ -86687,16 +98817,14 @@ fi To set the runtime status of the kernel.perf_event_paranoid kernel parameter, run the following command: $ sudo sysctl -w kernel.perf_event_paranoid=2 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.perf_event_paranoid = 2 - CCI-001082 - CCI-001090 AC-6 FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000138-GPOS-00069 - SRG-APP-000243-CTR-000600 + SRG-OS-000132-GPOS-00067 + SRG-OS-000138-GPOS-00069 + SRG-APP-000243-CTR-000600 R9 - OL09-00-002407 - SV-271746r1091950_rule + OL09-00-002407 + SV-271746r1117266_rule Kernel profiling can reveal sensitive information about kernel behaviour. # Remediation is applicable only in certain platforms @@ -86730,7 +98858,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.perf_event_paranoid # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.perf_event_paranoid="2" fi @@ -86776,16 +98904,12 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disallow kernel profiling by unprivileged users - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.perf_event_paranoid.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002407 @@ -86797,13 +98921,57 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: Comment out any occurrences of kernel.perf_event_paranoid from config files - replace: - path: '{{ item.path }}' +- name: Disallow kernel profiling by unprivileged users - Find all files that contain + kernel.perf_event_paranoid + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_paranoid\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Disallow kernel profiling by unprivileged users - Find all files that set + kernel.perf_event_paranoid to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.perf_event_paranoid\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002407 + - NIST-800-53-AC-6 + - disable_strategy + - low_complexity + - low_severity + - medium_disruption + - reboot_required + - sysctl_kernel_perf_event_paranoid + +- name: Disallow kernel profiling by unprivileged users - Comment out any occurrences + of kernel.perf_event_paranoid from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.perf_event_paranoid replace: '#kernel.perf_event_paranoid' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002407 - NIST-800-53-AC-6 @@ -86814,8 +98982,9 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid -- name: Ensure sysctl kernel.perf_event_paranoid is set to 2 - sysctl: +- name: Disallow kernel profiling by unprivileged users - Ensure sysctl kernel.perf_event_paranoid + is set to 2 + ansible.posix.sysctl: name: kernel.perf_event_paranoid value: '2' sysctl_file: /etc/sysctl.conf @@ -86832,6 +99001,10 @@ fi - reboot_required - sysctl_kernel_perf_event_paranoid + + + + @@ -86881,7 +99054,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.pid_max # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.pid_max="65536" fi @@ -86925,16 +99098,12 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Configure maximum number of process identifiers - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.pid_max.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -86944,13 +99113,53 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: Comment out any occurrences of kernel.pid_max from config files - replace: - path: '{{ item.path }}' +- name: Configure maximum number of process identifiers - Find all files that contain + kernel.pid_max + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.pid_max\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Configure maximum number of process identifiers - Find all files that set + kernel.pid_max to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.pid_max\s*=\s*65536$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_pid_max + +- name: Configure maximum number of process identifiers - Comment out any occurrences + of kernel.pid_max from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.pid_max replace: '#kernel.pid_max' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -86959,8 +99168,9 @@ fi - reboot_required - sysctl_kernel_pid_max -- name: Ensure sysctl kernel.pid_max is set to 65536 - sysctl: +- name: Configure maximum number of process identifiers - Ensure sysctl kernel.pid_max + is set to 65536 + ansible.posix.sysctl: name: kernel.pid_max value: '65536' sysctl_file: /etc/sysctl.conf @@ -86975,6 +99185,10 @@ fi - reboot_required - sysctl_kernel_pid_max + + + + @@ -87024,7 +99238,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.sysrq # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.sysrq="0" fi @@ -87068,16 +99282,12 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disallow magic SysRq key - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.sysrq.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -87087,13 +99297,52 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: Comment out any occurrences of kernel.sysrq from config files - replace: - path: '{{ item.path }}' +- name: Disallow magic SysRq key - Find all files that contain kernel.sysrq + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.sysrq\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Disallow magic SysRq key - Find all files that set kernel.sysrq to correct + value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.sysrq\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_sysrq + +- name: Disallow magic SysRq key - Comment out any occurrences of kernel.sysrq from + config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.sysrq replace: '#kernel.sysrq' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -87102,8 +99351,8 @@ fi - reboot_required - sysctl_kernel_sysrq -- name: Ensure sysctl kernel.sysrq is set to 0 - sysctl: +- name: Disallow magic SysRq key - Ensure sysctl kernel.sysrq is set to 0 + ansible.posix.sysctl: name: kernel.sysrq value: '0' sysctl_file: /etc/sysctl.conf @@ -87118,6 +99367,10 @@ fi - reboot_required - sysctl_kernel_sysrq + + + + @@ -87130,15 +99383,14 @@ fi To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, run the following command: $ sudo sysctl -w kernel.unprivileged_bpf_disabled=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 1 - CCI-000366 - CCI-001082 AC-6 SC-7(10) - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 R9 - OL09-00-002409 - SV-271748r1091956_rule + 1409 + OL09-00-002409 + SV-271748r1117266_rule Loading and accessing the packet filters programs and maps using the bpf() syscall has the potential of revealing sensitive information about the kernel state. @@ -87173,7 +99425,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.unprivileged_bpf_disabled # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="1" fi @@ -87220,16 +99472,13 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002409 @@ -87242,14 +99491,59 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from config - files - replace: - path: '{{ item.path }}' +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that contain kernel.unprivileged_bpf_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that set kernel.unprivileged_bpf_disabled to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002409 + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Comment + out any occurrences of kernel.unprivileged_bpf_disabled from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.unprivileged_bpf_disabled replace: '#kernel.unprivileged_bpf_disabled' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002409 - NIST-800-53-AC-6 @@ -87261,8 +99555,9 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled -- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set to 1 - sysctl: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Ensure + sysctl kernel.unprivileged_bpf_disabled is set to 1 + ansible.posix.sysctl: name: kernel.unprivileged_bpf_disabled value: '1' sysctl_file: /etc/sysctl.conf @@ -87280,6 +99575,10 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled + + + + @@ -87317,12 +99616,11 @@ To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.unprivileged_bpf_disabled = 2 - CCI-000366 AC-6 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 Loading and accessing the packet filters programs and maps using the bpf() syscall has the potential of revealing sensitive information about the kernel state. @@ -87359,7 +99657,7 @@ sysctl_kernel_unprivileged_bpf_disabled_value=' tags: - always -- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set - sysctl: +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Set + fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that contain kernel.unprivileged_bpf_disabled + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Find + all files that set kernel.unprivileged_bpf_disabled to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.unprivileged_bpf_disabled\s*=\s*{{ sysctl_kernel_unprivileged_bpf_disabled_value + }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Comment + out any occurrences of kernel.unprivileged_bpf_disabled from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*kernel.unprivileged_bpf_disabled + replace: '#kernel.unprivileged_bpf_disabled' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - NIST-800-53-AC-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_unprivileged_bpf_disabled_accept_default + +- name: Disable Access to Network bpf() Syscall From Unprivileged Processes - Ensure + sysctl kernel.unprivileged_bpf_disabled is set + ansible.posix.sysctl: name: kernel.unprivileged_bpf_disabled value: '{{ sysctl_kernel_unprivileged_bpf_disabled_value }}' sysctl_file: /etc/sysctl.conf @@ -87467,6 +99807,10 @@ fi - reboot_required - sysctl_kernel_unprivileged_bpf_disabled_accept_default + + + + @@ -87479,15 +99823,14 @@ fi To set the runtime status of the kernel.yama.ptrace_scope kernel parameter, run the following command: $ sudo sysctl -w kernel.yama.ptrace_scope=1 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.yama.ptrace_scope = 1 - CCI-000366 - CCI-001082 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000480-GPOS-00227 R11 - OL09-00-002410 - SV-271749r1091959_rule + 1409 + OL09-00-002410 + SV-271749r1117266_rule Unrestricted usage of ptrace allows compromised binaries to run ptrace on another processes of the user. Like this, the attacker can steal sensitive information from the target processes (e.g. SSH sessions, web browser, ...) @@ -87525,7 +99868,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.yama.ptrace_scope # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.yama.ptrace_scope="1" fi @@ -87571,16 +99914,12 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Restrict usage of ptrace to descendant processes - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.yama.ptrace_scope.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002410 @@ -87592,13 +99931,57 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: Comment out any occurrences of kernel.yama.ptrace_scope from config files - replace: - path: '{{ item.path }}' +- name: Restrict usage of ptrace to descendant processes - Find all files that contain + kernel.yama.ptrace_scope + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.yama.ptrace_scope\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Restrict usage of ptrace to descendant processes - Find all files that set + kernel.yama.ptrace_scope to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.yama.ptrace_scope\s*=\s*1$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002410 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_yama_ptrace_scope + +- name: Restrict usage of ptrace to descendant processes - Comment out any occurrences + of kernel.yama.ptrace_scope from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.yama.ptrace_scope replace: '#kernel.yama.ptrace_scope' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002410 - NIST-800-53-SC-7(10) @@ -87609,8 +99992,9 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope -- name: Ensure sysctl kernel.yama.ptrace_scope is set to 1 - sysctl: +- name: Restrict usage of ptrace to descendant processes - Ensure sysctl kernel.yama.ptrace_scope + is set to 1 + ansible.posix.sysctl: name: kernel.yama.ptrace_scope value: '1' sysctl_file: /etc/sysctl.conf @@ -87627,6 +100011,10 @@ fi - reboot_required - sysctl_kernel_yama_ptrace_scope + + + + @@ -87639,13 +100027,13 @@ fi To set the runtime status of the net.core.bpf_jit_harden kernel parameter, run the following command: $ sudo sysctl -w net.core.bpf_jit_harden=2 To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: net.core.bpf_jit_harden = 2 - CCI-000366 CM-6 SC-7(10) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R12 - OL09-00-002430 - SV-271768r1092016_rule + 1409 + OL09-00-002430 + SV-271768r1092016_rule When hardened, the extended Berkeley Packet Filter just-in-time compiler will randomize any kernel addresses in the BPF programs and maps, and will not expose the JIT addresses in /proc/kallsyms. @@ -87681,7 +100069,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for net.core.bpf_jit_harden # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w net.core.bpf_jit_harden="2" fi @@ -87728,16 +100116,13 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Harden the operation of the BPF just-in-time compiler - Set fact for sysctl + paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*net.core.bpf_jit_harden.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002430 @@ -87750,13 +100135,59 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: Comment out any occurrences of net.core.bpf_jit_harden from config files - replace: - path: '{{ item.path }}' +- name: Harden the operation of the BPF just-in-time compiler - Find all files that + contain net.core.bpf_jit_harden + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.core.bpf_jit_harden\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Harden the operation of the BPF just-in-time compiler - Find all files that + set net.core.bpf_jit_harden to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*net.core.bpf_jit_harden\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002430 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_net_core_bpf_jit_harden + +- name: Harden the operation of the BPF just-in-time compiler - Comment out any occurrences + of net.core.bpf_jit_harden from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*net.core.bpf_jit_harden replace: '#net.core.bpf_jit_harden' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002430 - NIST-800-53-CM-6 @@ -87768,8 +100199,9 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden -- name: Ensure sysctl net.core.bpf_jit_harden is set to 2 - sysctl: +- name: Harden the operation of the BPF just-in-time compiler - Ensure sysctl net.core.bpf_jit_harden + is set to 2 + ansible.posix.sysctl: name: net.core.bpf_jit_harden value: '2' sysctl_file: /etc/sysctl.conf @@ -87787,6 +100219,10 @@ fi - reboot_required - sysctl_net_core_bpf_jit_harden + + + + @@ -87805,16 +100241,17 @@ add the following line to a file in the directory /etc/sysctl.duser.max_user_namespaces = 0 When containers are deployed on the machine, the value should be set to large non-zero value. - This configuration baseline was created to deploy the base operating system for general purpose -workloads. When the operating system is configured for certain purposes, such as to host Linux Containers, -it is expected that user.max_user_namespaces will be enabled. - CCI-000366 + Remediation of this rule might impair or prevent functionality of certain applications. +This stands especially for general container usage and for certain desktop applications. +There is an alternative rule which performs the same check but it intentionally lacks the remediation part. +If needed, you can use the rule sysctl_user_max_user_namespaces_no_remediation. +In that case, ensure that such use case is properly documented. SC-39 CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-002370 - SV-271727r1091893_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002370 + SV-271727r1091893_rule It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or system objectives. These unnecessary capabilities or services are often overlooked and therefore may remain unsecured. They increase the risk to the platform by providing additional attack vectors. @@ -87852,7 +100289,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for user.max_user_namespaces # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w user.max_user_namespaces="0" fi @@ -87899,16 +100336,12 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable the use of user namespaces - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*user.max_user_namespaces.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002370 @@ -87921,13 +100354,58 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: Comment out any occurrences of user.max_user_namespaces from config files - replace: - path: '{{ item.path }}' +- name: Disable the use of user namespaces - Find all files that contain user.max_user_namespaces + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*user.max_user_namespaces\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Disable the use of user namespaces - Find all files that set user.max_user_namespaces + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*user.max_user_namespaces\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002370 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_user_max_user_namespaces + +- name: Disable the use of user namespaces - Comment out any occurrences of user.max_user_namespaces + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*user.max_user_namespaces replace: '#user.max_user_namespaces' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002370 - NIST-800-53-CM-6(a) @@ -87939,8 +100417,9 @@ fi - reboot_required - sysctl_user_max_user_namespaces -- name: Ensure sysctl user.max_user_namespaces is set to 0 - sysctl: +- name: Disable the use of user namespaces - Ensure sysctl user.max_user_namespaces + is set to 0 + ansible.posix.sysctl: name: user.max_user_namespaces value: '0' sysctl_file: /etc/sysctl.conf @@ -87958,6 +100437,10 @@ fi - reboot_required - sysctl_user_max_user_namespaces + + + + @@ -88007,7 +100490,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for vm.mmap_min_addr # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w vm.mmap_min_addr="65536" fi @@ -88051,16 +100534,13 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Prevent applications from mapping low portion of virtual memory - Set fact + for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*vm.mmap_min_addr.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy @@ -88070,13 +100550,53 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: Comment out any occurrences of vm.mmap_min_addr from config files - replace: - path: '{{ item.path }}' +- name: Prevent applications from mapping low portion of virtual memory - Find all + files that contain vm.mmap_min_addr + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*vm.mmap_min_addr\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Prevent applications from mapping low portion of virtual memory - Find all + files that set vm.mmap_min_addr to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*vm.mmap_min_addr\s*=\s*65536$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_vm_mmap_min_addr + +- name: Prevent applications from mapping low portion of virtual memory - Comment + out any occurrences of vm.mmap_min_addr from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*vm.mmap_min_addr replace: '#vm.mmap_min_addr' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - disable_strategy - low_complexity @@ -88085,8 +100605,9 @@ fi - reboot_required - sysctl_vm_mmap_min_addr -- name: Ensure sysctl vm.mmap_min_addr is set to 65536 - sysctl: +- name: Prevent applications from mapping low portion of virtual memory - Ensure sysctl + vm.mmap_min_addr is set to 65536 + ansible.posix.sysctl: name: vm.mmap_min_addr value: '65536' sysctl_file: /etc/sysctl.conf @@ -88101,6 +100622,10 @@ fi - reboot_required - sysctl_vm_mmap_min_addr + + + + @@ -88130,17 +100655,17 @@ The core dumps of setuid programs are further protected. The sysctl variable fs.suid_dumpable controls whether the kernel allows core dumps from these programs at all. The default value of 0 is recommended. + Disable acquiring, saving, and processing core dumps The systemd-coredump.socket unit is a socket activation of the systemd-coredump@.service which processes core dumps. By masking the unit, core dump processing is disabled. - CCI-000366 SC-7(10) FMT_SMF_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-002384 - SV-271732r1091908_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002384 + SV-271732r1091908_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. @@ -88181,6 +100706,7 @@ fi cmd: systemctl -q list-unit-files --type socket register: result_systemd_unit_files changed_when: false + check_mode: false when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002384 @@ -88212,6 +100738,10 @@ fi - no_reboot_needed - service_systemd-coredump_disabled + + + + @@ -88222,22 +100752,21 @@ fi Disable core dump backtraces The ProcessSizeMax option in [Coredump] section -of /etc/systemd/coredump.conf -specifies the maximum size in bytes of a core which will be processed. -Core dumps exceeding this size may be stored, but the backtrace will not -be generated. - If the /etc/systemd/coredump.conf file +of /etc/systemd/coredump.conf or in a drop-in file under +/etc/systemd/coredump.conf.d/ specifies the maximum size in bytes +of a core which will be processed. Core dumps exceeding this size may be +stored, but the backtrace will not be generated. + If the /etc/systemd/coredump.conf file or a drop-in file under /etc/systemd/coredump.conf.d/ does not already contain the [Coredump] section, the value will not be configured correctly. - CCI-000366 CM-6 Req-3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002381 - SV-271729r1091899_rule + OL09-00-002381 + SV-271729r1091899_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to @@ -88245,26 +100774,29 @@ debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations +debugging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy. # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q systemd; }; then found=false # set value in all files if they contain section or key -for f in $(echo -n "/etc/systemd/coredump.conf"); do +for f in $(echo -n "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf"); do if [ ! -e "$f" ]; then continue fi # find key in section and change value if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*ProcessSizeMax" "$f"; then + if ! grep -qPz "ProcessSizeMax=0" "$f"; then sed -i "s/ProcessSizeMax[^(\n)]*/ProcessSizeMax=0/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then @@ -88277,7 +100809,7 @@ done # if section not in any file, append section with key = value to FIRST file in files parameter if ! $found ; then - file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + file=$(echo "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" echo -e "[Coredump]\nProcessSizeMax=0" >> "$file" @@ -88305,15 +100837,99 @@ fi - no_reboot_needed - restrict_strategy -- name: Set 'ProcessSizeMax' to '0' in the [Coredump] section of '/etc/systemd/coredump.conf' - ini_file: - path: /etc/systemd/coredump.conf +- name: Disable core dump backtraces - Search for a section in files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[Coredump\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/systemd/coredump.conf'' | dirname }}' + pattern: '{{ ''/etc/systemd/coredump.conf'' | basename | regex_escape }}' + - path: /etc/systemd/coredump.conf.d + pattern: .*\.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Count number of files which contain the correct + section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Add missing configuration to correct section + community.general.ini_file: + path: '{{item}}' section: Coredump option: ProcessSizeMax value: '0' + state: present + no_extra_spaces: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' + tags: + - DISA-STIG-OL09-00-002381 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_backtraces + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable core dump backtraces - Add configuration to new remediation file + community.general.ini_file: + path: /etc/systemd/coredump.conf.d/complianceascode_hardening.conf + section: Coredump + option: ProcessSizeMax + value: '0' + state: present + no_extra_spaces: true create: true - mode: 420 - when: '"systemd" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-002381 - NIST-800-53-CM-6 @@ -88337,45 +100953,49 @@ fi Disable storing core dump - The Storage option in [Coredump] sectionof /etc/systemd/coredump.conf + The Storage option in [Coredump] section +of /etc/systemd/coredump.conf or a drop-in file in +/etc/systemd/coredump.conf.d/*.conf can be set to none to disable storing core dumps permanently. - If the /etc/systemd/coredump.conf file + If the /etc/systemd/coredump.conf file or a drop-in file under /etc/systemd/coredump.conf.d/ does not already contain the [Coredump] section, the value will not be configured correctly. - CCI-000366 CM-6 Req-3.2 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002382 - SV-271730r1091902_rule + OL09-00-002382 + SV-271730r1091902_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced -debuging. Permitting temporary enablement of core dumps during such situations +debugging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy. # Remediation is applicable only in certain platforms -if rpm --quiet -q systemd; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q systemd; }; then found=false # set value in all files if they contain section or key -for f in $(echo -n "/etc/systemd/coredump.conf"); do +for f in $(echo -n "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf"); do if [ ! -e "$f" ]; then continue fi # find key in section and change value if grep -qzosP "[[:space:]]*\[Coredump\]([^\n\[]*\n+)+?[[:space:]]*Storage" "$f"; then + if ! grep -qPz "Storage=none" "$f"; then sed -i "s/Storage[^(\n)]*/Storage=none/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[Coredump\]" "$f"; then @@ -88388,7 +101008,7 @@ done # if section not in any file, append section with key = value to FIRST file in files parameter if ! $found ; then - file=$(echo "/etc/systemd/coredump.conf" | cut -f1 -d ' ') + file=$(echo "/etc/systemd/coredump.conf.d/complianceascode_hardening.conf /etc/systemd/coredump.conf.d/*.conf /etc/systemd/coredump.conf" | cut -f1 -d ' ') mkdir -p "$(dirname "$file")" echo -e "[Coredump]\nStorage=none" >> "$file" @@ -88416,15 +101036,99 @@ fi - no_reboot_needed - restrict_strategy -- name: Set 'Storage' to 'none' in the [Coredump] section of '/etc/systemd/coredump.conf' - ini_file: - path: /etc/systemd/coredump.conf +- name: Disable storing core dump - Search for a section in files + ansible.builtin.find: + paths: '{{item.path}}' + patterns: '{{item.pattern}}' + contains: ^\s*\[Coredump\] + read_whole_file: true + use_regex: true + register: systemd_dropin_files_with_section + loop: + - path: '{{ ''/etc/systemd/coredump.conf'' | dirname }}' + pattern: '{{ ''/etc/systemd/coredump.conf'' | basename | regex_escape }}' + - path: /etc/systemd/coredump.conf.d + pattern: .*\.conf + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Count number of files which contain the correct + section + ansible.builtin.set_fact: + count_of_systemd_dropin_files_with_section: '{{systemd_dropin_files_with_section.results + | map(attribute=''matched'') | list | map(''int'') | sum}}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Add missing configuration to correct section + community.general.ini_file: + path: '{{item}}' section: Coredump option: Storage value: none + state: present + no_extra_spaces: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int > 0 + loop: '{{systemd_dropin_files_with_section.results | sum(attribute=''files'', start=[]) + | map(attribute=''path'') | list }}' + tags: + - DISA-STIG-OL09-00-002382 + - NIST-800-53-CM-6 + - PCI-DSS-Req-3.2 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - coredump_disable_storage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable storing core dump - Add configuration to new remediation file + community.general.ini_file: + path: /etc/systemd/coredump.conf.d/complianceascode_hardening.conf + section: Coredump + option: Storage + value: none + state: present + no_extra_spaces: true create: true - mode: 420 - when: '"systemd" in ansible_facts.packages' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"systemd" in ansible_facts.packages' + - count_of_systemd_dropin_files_with_section | int == 0 tags: - DISA-STIG-OL09-00-002382 - NIST-800-53-CM-6 @@ -88466,7 +101170,6 @@ fi DSS01.03 DSS03.05 DSS05.07 - CCI-000366 SR 6.2 SR 7.1 SR 7.2 @@ -88476,29 +101179,40 @@ fi SC-7(10) DE.CM-1 PR.DS-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 3.3.1.1 3.3.1 3.3 - OL09-00-002383 - SV-271731r1091905_rule + OL09-00-002383 + SV-271731r1091905_rule A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems. # Remediation is applicable only in certain platforms -if rpm --quiet -q pam; then +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q pam; }; then SECURITY_LIMITS_FILE="/etc/security/limits.conf" +DROPIN_DIR="/etc/security/limits.d" +DROPIN_FILE="$DROPIN_DIR/10-ssg-hardening.conf" +REGEX_CORRECT_VALUE="^\s*\*\s+hard\s+core\s+0\s*$" -if grep -qE '^\s*\*\s+hard\s+core' $SECURITY_LIMITS_FILE; then - sed -ri 's/(hard\s+core\s+)[[:digit:]]+/\1 0/' $SECURITY_LIMITS_FILE -else - echo "* hard core 0" >> $SECURITY_LIMITS_FILE +# Remove bad configuration in drop-ins +if [ -d "$DROPIN_DIR" ]; then + for override in "$DROPIN_DIR"/*.conf; do + if [ -f "$override" ] && ! grep -qE "$REGEX_CORRECT_VALUE" "$override"; then + sed -ir -E '/^[[:space:]]*\*[[:space:]]+hard[[:space:]]+core[[:space:]]+/ s/^/#/' "$override" + fi + done fi -if ls /etc/security/limits.d/*.conf > /dev/null; then - sed -ri '/^\s*\*\s+hard\s+core/d' /etc/security/limits.d/*.conf +if [ -d "$DROPIN_DIR" ] && grep -qEr "$REGEX_CORRECT_VALUE" "$DROPIN_DIR"; then + exit 0 +elif [ ! -d "$DROPIN_DIR" ] && grep -qE "$REGEX_CORRECT_VALUE" "$SECURITY_LIMITS_FILE"; then + exit 0 +else + mkdir -p "$DROPIN_DIR" + echo "* hard core 0" >> $DROPIN_FILE fi else @@ -88522,13 +101236,204 @@ fi - no_reboot_needed - restrict_strategy -- name: Disable core dumps with limits - lineinfile: - dest: /etc/security/limits.conf - regexp: ^[^#].*core - line: '* hard core 0' - create: true - when: '"pam" in ansible_facts.packages' +- name: Disable Core Dumps for All Users - Set dirs, files and regex variables + ansible.builtin.set_fact: + limits_dropin_dir: /etc/security/limits.d + limits_dropin_file: /etc/security/limits.d/10-ssg-hardening.conf + limits_main_file: /etc/security/limits.conf + limits_correct_regex: ^\s*\*\s+hard\s+core\s+0\s*$ + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Find valid drop-ins for core limit + ansible.builtin.find: + paths: '{{ limits_dropin_dir }}' + patterns: '*.conf' + contains: '{{ limits_correct_regex }}' + file_type: file + register: valid_dropins + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Find all drop-ins with any core limit + ansible.builtin.find: + paths: '{{ limits_dropin_dir }}' + patterns: '*.conf' + contains: ^\s*\*\s+hard\s+core\s+ + file_type: file + register: all_dropins + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Get invalid drop-ins + ansible.builtin.set_fact: + invalid_dropins: '{{ all_dropins.files | rejectattr(''path'', ''in'', valid_dropins.files + | map(attribute=''path'') | list) | map(attribute=''path'') | list }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Comment invalid * hard core lines in drop-ins + ansible.builtin.replace: + path: '{{ item }}' + regexp: (^\s*\*\s+hard\s+core\s+.*$) + replace: '#\1' + loop: '{{ invalid_dropins }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - invalid_dropins | length > 0 + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Check if main limits.conf contains correct + core limit + ansible.builtin.find: + paths: /etc/security + patterns: limits.conf + contains: '{{ limits_correct_regex }}' + file_type: file + register: main_valid + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not (valid_dropins.matched | default(0) > 0) + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Set fact if configuration is valid + ansible.builtin.set_fact: + core_limit_valid: '{{ (valid_dropins.matched | default(0)) > 0 or (main_valid.matched + | default(0)) > 0 }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Ensure drop-in directory exists + ansible.builtin.file: + path: '{{ limits_dropin_dir }}' + state: directory + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not core_limit_valid + tags: + - DISA-STIG-OL09-00-002383 + - NIST-800-53-CM-6 + - NIST-800-53-SC-7(10) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_users_coredumps + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Core Dumps for All Users - Deploy 10-ssg-hardening.conf drop-in with + correct core limit + ansible.builtin.copy: + dest: '{{ limits_dropin_file }}' + content: | + * hard core 0 + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"pam" in ansible_facts.packages' + - not core_limit_valid tags: - DISA-STIG-OL09-00-002383 - NIST-800-53-CM-6 @@ -88606,7 +101511,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for fs.suid_dumpable # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w fs.suid_dumpable="0" fi @@ -88655,16 +101560,12 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Disable Core Dumps for SUID programs - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*fs.suid_dumpable.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-SI-11(a) @@ -88679,13 +101580,62 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: Comment out any occurrences of fs.suid_dumpable from config files - replace: - path: '{{ item.path }}' +- name: Disable Core Dumps for SUID programs - Find all files that contain fs.suid_dumpable + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.suid_dumpable\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Disable Core Dumps for SUID programs - Find all files that set fs.suid_dumpable + to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*fs.suid_dumpable\s*=\s*0$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-SI-11(a) + - NIST-800-53-SI-11(b) + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_fs_suid_dumpable + +- name: Disable Core Dumps for SUID programs - Comment out any occurrences of fs.suid_dumpable + from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*fs.suid_dumpable replace: '#fs.suid_dumpable' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - NIST-800-53-SI-11(a) - NIST-800-53-SI-11(b) @@ -88699,8 +101649,9 @@ fi - reboot_required - sysctl_fs_suid_dumpable -- name: Ensure sysctl fs.suid_dumpable is set to 0 - sysctl: +- name: Disable Core Dumps for SUID programs - Ensure sysctl fs.suid_dumpable is set + to 0 + ansible.posix.sysctl: name: fs.suid_dumpable value: '0' sysctl_file: /etc/sysctl.conf @@ -88720,6 +101671,10 @@ fi - reboot_required - sysctl_fs_suid_dumpable + + + + @@ -88757,7 +101712,6 @@ ExecShield or is disabled in /etc/default/grub.APO13.01 DSS05.02 3.1.7 - CCI-002824 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -88781,9 +101735,10 @@ ExecShield or is disabled in /etc/default/grub.SC-39 CM-6(a) PR.PT-4 - SRG-OS-000433-GPOS-00192 - OL09-00-002422 - SV-271760r1091992_rule + SRG-OS-000433-GPOS-00192 + 1409 + OL09-00-002422 + SV-271760r1091992_rule ExecShield uses the segmentation feature on all x86 systems to prevent execution in memory higher than a certain address. It writes an address as a limit in the code segment descriptor, to control where code can be @@ -88791,9 +101746,9 @@ executed, on a per-process basis. When the kernel places a process's memory regions such as the stack and heap higher than this address, the hardware prevents execution in that address range. This is enabled by default on the latest Red Hat and Fedora systems if supported by the hardware. - + # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +if ( rpm --quiet -q kernel || rpm --quiet -q kernel-uek && ( grep -sqE "^.*\.x86_64$" /proc/sys/kernel/osrelease || grep -sqE "^x86_64$" /proc/sys/kernel/arch; ) ); then grubby --update-kernel=ALL --remove-args=noexec @@ -88816,9 +101771,51 @@ fi - restrict_strategy - sysctl_kernel_exec_shield +- name: Check if noexec argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + +- name: Check if noexec argument is present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + tags: + - DISA-STIG-OL09-00-002422 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-39 + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - sysctl_kernel_exec_shield + - name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --remove-args="noexec" - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --remove-args="noexec" + when: + - ( ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + and ansible_architecture == "x86_64" ) + - (grubby_info.stdout is search('noexec')) or ((etc_default_grub['content'] | b64decode) + is search('noexec')) tags: - DISA-STIG-OL09-00-002422 - NIST-800-171-3.1.7 @@ -88845,43 +101842,41 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.kptr_restrict = - CCI-000366 - CCI-002824 - CCI-001082 - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 SC-30 SC-30(2) SC-30(5) CM-6(a) FMT_SMF_EXT.1 - SRG-OS-000132-GPOS-00067 - SRG-OS-000433-GPOS-00192 - SRG-OS-000480-GPOS-00227 + SRG-OS-000132-GPOS-00067 + SRG-OS-000433-GPOS-00192 + SRG-OS-000480-GPOS-00227 R9 - OL09-00-002408 - SV-271747r1091953_rule + 1409 + OL09-00-002408 + SV-271747r1117266_rule Exposing kernel pointers (through procfs or seq_printf()) exposes kernel writeable structures which may contain functions pointers. If a write vulnerability occurs in the kernel, allowing write access to any of this structure, the kernel can @@ -88921,7 +101916,7 @@ sysctl_kernel_kptr_restrict_value=' tags: - always -- name: Ensure sysctl kernel.kptr_restrict is set - sysctl: +- name: Restrict Exposed Kernel Pointer Addresses Access - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: + - /etc/sysctl.d/ + - /run/sysctl.d/ + - /usr/local/lib/sysctl.d/ + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Find all files that contain + kernel.kptr_restrict + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kptr_restrict\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Find all files that set + kernel.kptr_restrict to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.kptr_restrict\s*=\s*{{ sysctl_kernel_kptr_restrict_value }}$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Comment out any occurrences + of kernel.kptr_restrict from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' + regexp: ^[\s]*kernel.kptr_restrict + replace: '#kernel.kptr_restrict' + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length + tags: + - DISA-STIG-OL09-00-002408 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - NIST-800-53-SC-30(5) + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_kptr_restrict + +- name: Restrict Exposed Kernel Pointer Addresses Access - Ensure sysctl kernel.kptr_restrict + is set + ansible.posix.sysctl: name: kernel.kptr_restrict value: '{{ sysctl_kernel_kptr_restrict_value }}' sysctl_file: /etc/sysctl.conf @@ -89040,6 +102082,10 @@ fi - reboot_required - sysctl_kernel_kptr_restrict + + + + @@ -89053,8 +102099,6 @@ fi To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d: kernel.randomize_va_space = 2 3.1.7 - CCI-000366 - CCI-002824 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -89062,42 +102106,43 @@ To make sure that the setting is persistent, add the following line to a file in 164.310(c) 164.312(a) 164.312(e) - CIP-002-5 R1.1 - CIP-002-5 R1.2 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 4.1 - CIP-004-6 4.2 - CIP-004-6 R2.2.3 - CIP-004-6 R2.2.4 - CIP-004-6 R2.3 - CIP-004-6 R4 - CIP-005-6 R1 - CIP-005-6 R1.1 - CIP-005-6 R1.2 - CIP-007-3 R3 - CIP-007-3 R3.1 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R8.4 - CIP-009-6 R.1.1 - CIP-009-6 R4 + CIP-002-5 R1.1 + CIP-002-5 R1.2 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 4.1 + CIP-004-6 4.2 + CIP-004-6 R2.2.3 + CIP-004-6 R2.2.4 + CIP-004-6 R2.3 + CIP-004-6 R4 + CIP-005-6 R1 + CIP-005-6 R1.1 + CIP-005-6 R1.2 + CIP-007-3 R3 + CIP-007-3 R3.1 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R8.4 + CIP-009-6 R.1.1 + CIP-009-6 R4 SC-30 SC-30(2) CM-6(a) Req-2.2.1 - SRG-OS-000433-GPOS-00193 - SRG-OS-000480-GPOS-00227 - SRG-APP-000450-CTR-001105 + SRG-OS-000433-GPOS-00193 + SRG-OS-000480-GPOS-00227 + SRG-APP-000450-CTR-001105 R9 + 1409 3.3.1.1 3.3.1 3.3 - OL09-00-002423 - SV-271761r1091995_rule + OL09-00-002423 + SV-271761r1091995_rule Address space layout randomization (ASLR) makes it more difficult for an attacker to predict the location of attack code they have introduced into a process's address space during an attempt at exploitation. Additionally, @@ -89136,7 +102181,7 @@ SYSCONFIG_FILE="/etc/sysctl.conf" # # Set runtime for kernel.randomize_va_space # -if [[ "$OSCAP_BOOTC_BUILD" != "YES" ]] ; then +if ! { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then /sbin/sysctl -q -n -w kernel.randomize_va_space="2" fi @@ -89189,16 +102234,12 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: List /etc/sysctl.d/*.conf files - find: - paths: +- name: Enable Randomized Layout of Virtual Address Space - Set fact for sysctl paths + ansible.builtin.set_fact: + sysctl_paths: - /etc/sysctl.d/ - /run/sysctl.d/ - /usr/local/lib/sysctl.d/ - contains: ^[\s]*kernel.randomize_va_space.*$ - patterns: '*.conf' - file_type: any - register: find_sysctl_d when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002423 @@ -89217,13 +102258,71 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: Comment out any occurrences of kernel.randomize_va_space from config files - replace: - path: '{{ item.path }}' +- name: Enable Randomized Layout of Virtual Address Space - Find all files that contain + kernel.randomize_va_space + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.randomize_va_space\s*=\s*.*$' + register: find_all_values + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Enable Randomized Layout of Virtual Address Space - Find all files that set + kernel.randomize_va_space to correct value + ansible.builtin.shell: + cmd: find -L {{ sysctl_paths | join(" ") }} -type f -name '*.conf' | xargs grep + -HP '^\s*kernel.randomize_va_space\s*=\s*2$' + register: find_correct_value + check_mode: false + changed_when: false + failed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002423 + - NIST-800-171-3.1.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-30 + - NIST-800-53-SC-30(2) + - PCI-DSS-Req-2.2.1 + - PCI-DSSv4-3.3 + - PCI-DSSv4-3.3.1 + - PCI-DSSv4-3.3.1.1 + - disable_strategy + - low_complexity + - medium_disruption + - medium_severity + - reboot_required + - sysctl_kernel_randomize_va_space + +- name: Enable Randomized Layout of Virtual Address Space - Comment out any occurrences + of kernel.randomize_va_space from config files + ansible.builtin.replace: + path: '{{ item | split(":") | first }}' regexp: ^[\s]*kernel.randomize_va_space replace: '#kernel.randomize_va_space' - loop: '{{ find_sysctl_d.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + loop: '{{ find_all_values.stdout_lines }}' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_correct_value.stdout_lines | length == 0 or find_all_values.stdout_lines + | length > find_correct_value.stdout_lines | length tags: - DISA-STIG-OL09-00-002423 - NIST-800-171-3.1.7 @@ -89241,8 +102340,9 @@ fi - reboot_required - sysctl_kernel_randomize_va_space -- name: Ensure sysctl kernel.randomize_va_space is set to 2 - sysctl: +- name: Enable Randomized Layout of Virtual Address Space - Ensure sysctl kernel.randomize_va_space + is set to 2 + ansible.posix.sysctl: name: kernel.randomize_va_space value: '2' sysctl_file: /etc/sysctl.conf @@ -89266,6 +102366,10 @@ fi - reboot_required - sysctl_kernel_randomize_va_space + + + + @@ -89303,7 +102407,6 @@ on AMD-based systems. BAI10.03 BAI10.05 3.1.7 - CCI-002824 4.3.4.3.2 4.3.4.3.3 SR 7.6 @@ -89316,13 +102419,13 @@ on AMD-based systems. SC-39 CM-6(a) PR.IP-1 - SRG-OS-000433-GPOS-00192 - SRG-APP-000450-CTR-001105 + SRG-OS-000433-GPOS-00192 + SRG-APP-000450-CTR-001105 2.2.1 2.2 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. - + @@ -89359,14 +102462,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... page_poison=1 ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="page_poison=1" - CCI-000366 - CCI-001084 CM-6(a) - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 R8 - OL09-00-002394 - SV-271738r1092600_rule + OL09-00-002394 + SV-271738r1092600_rule Poisoning writes an arbitrary value to freed pages, so any modification or reference to that page after being freed or before being initialized will be detected and prevented. @@ -89376,15 +102477,12 @@ Also prevents leak of data and detection of corrupted memory.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "page_poison" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_poison=[^\"]*\"(.*]\s*)/\1\"page_poison=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"page_poison=[^\"]*\"(.*]\s*)/\1\"page_poison=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"page_poison=$expected_value\"]" >> "$KARGS_DIR/10-page_poison.toml" + echo "kargs = [\"page_poison=1\"]" >> "$KARGS_DIR/10-page_poison.toml" fi else @@ -89409,8 +102507,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" +- name: Check if page_poison argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -89423,6 +102523,42 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if page_poison argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="page_poison=1" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('page_poison=1')) or ((etc_default_grub['content'] + | b64decode) is not search('page_poison=1')) + tags: + - DISA-STIG-OL09-00-002394 + - NIST-800-53-CM-6(a) + - grub2_page_poison_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "page_poison=1" @@ -89449,14 +102585,12 @@ default Grub2 command line for Linux operating systems. Modify the line within GRUB_CMDLINE_LINUX="... slub_debug= ..." Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="slub_debug=" - CCI-002824 - CCI-001084 CM-6(a) - SRG-OS-000433-GPOS-00192 - SRG-OS-000134-GPOS-00068 + SRG-OS-000433-GPOS-00192 + SRG-OS-000134-GPOS-00068 R8 - OL09-00-002390 - SV-271734r1091914_rule + OL09-00-002390 + SV-271734r1091914_rule Poisoning writes an arbitrary value to freed objects, so any modification or reference to that object after being freed or before being initialized will be detected and prevented. @@ -89468,15 +102602,14 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet - var_slub_debug_options='' -expected_value="$var_slub_debug_options" -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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 "slub_debug" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slub_debug=[^\"]*\"(.*]\s*)/\1\"slub_debug=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"slub_debug=[^\"]*\"(.*]\s*)/\1\"slub_debug=$var_slub_debug_options\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"slub_debug=$expected_value\"]" >> "$KARGS_DIR/10-slub_debug.toml" + echo "kargs = [\"slub_debug=$var_slub_debug_options\"]" >> "$KARGS_DIR/10-slub_debug.toml" fi else @@ -89506,9 +102639,10 @@ fi tags: - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ var_slub_debug_options - }}" +- name: Check if slub_debug argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -89521,6 +102655,43 @@ fi - medium_severity - reboot_required - restrict_strategy + +- name: Check if slub_debug argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="slub_debug={{ + var_slub_debug_options }}" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('slub_debug=' ~ var_slub_debug_options)) or + ((etc_default_grub['content'] | b64decode) is not search('slub_debug=' ~ var_slub_debug_options)) + tags: + - DISA-STIG-OL09-00-002390 + - NIST-800-53-CM-6(a) + - grub2_slub_debug_argument + - low_disruption + - medium_complexity + - medium_severity + - reboot_required + - restrict_strategy [customizations.kernel] append = "slub_debug=" @@ -89536,6 +102707,30 @@ append = "slub_debug= + Secure boot configuration + Secure Boot is a protocol that enables a safe and trusted path during the Linux boot process. +It verifies that the code the firmware loads on a motherboard is the code +that the user intends for the computer to load. + +Secure Boot is part of the Unified Extensible Firmware Interface (UEFI). The protocol +defines a process that prevents the loading of unsigned drivers, boot loaders, or +kernel modules (or those with unacceptable digital signatures). When Secure Boot +is enabled, system boot loaders, the Red Hat Enterprise Linux kernel, and all +kernel modules must be cryptographically signed with a private key. +This allows them to be authenticated with the corresponding public key. + + + Ensure that Secure Boot is enabled + Ensure that Secure Boot is enabled with the mokutil command. + 1745 + By ensuring the integrity of the boot process, Secure Boot protects against rootkits, +bootkits, and other low-level malware that could compromise the system before traditional defenses activate. This helps maintain both the confidentiality and integrity of the system, ensuring that sensitive data remains protected and only trusted code is executed. + + + + + SELinux SELinux is a feature of the Linux kernel which can be @@ -89621,7 +102816,7 @@ fi - package_libselinux_installed - name: Ensure libselinux is installed - package: + ansible.builtin.package: name: libselinux state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89664,10 +102859,9 @@ version = "*" $ sudo yum install policycoreutils-python-utils - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-000210 - SV-271468r1091116_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000210 + SV-271468r1091116_rule This package is required to operate and manage an SELinux environment and its policies. It provides utilities such as semanage, audit2allow, audit2why, chcat and sandbox. # Remediation is applicable only in certain platforms @@ -89694,7 +102888,7 @@ fi - package_policycoreutils-python-utils_installed - name: Ensure policycoreutils-python-utils is installed - package: + ansible.builtin.package: name: policycoreutils-python-utils state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89736,12 +102930,10 @@ version = "*" $ sudo yum install policycoreutils - CCI-000366 - CCI-001084 - SRG-OS-000480-GPOS-00227 - SRG-OS-000134-GPOS-00068 - OL09-00-000200 - SV-271467r1091113_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000134-GPOS-00068 + OL09-00-000200 + SV-271467r1091113_rule 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 Security-enhanced Linux kernel contains new architectural components originally @@ -89778,7 +102970,7 @@ fi - package_policycoreutils_installed - name: Ensure policycoreutils is installed - package: + ansible.builtin.package: name: policycoreutils state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89829,10 +103021,11 @@ have running on a server. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot-plugins -# from the system, and may remove any packages -# that depend on setroubleshoot-plugins. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot-plugins. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot-plugins" ; then yum remove -y "setroubleshoot-plugins" @@ -89853,8 +103046,9 @@ fi - no_reboot_needed - package_setroubleshoot-plugins_removed -- name: Ensure setroubleshoot-plugins is removed - package: +- name: 'Uninstall setroubleshoot-plugins Package: Ensure setroubleshoot-plugins is + removed' + ansible.builtin.package: name: setroubleshoot-plugins state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89866,7 +103060,8 @@ fi - no_reboot_needed - package_setroubleshoot-plugins_removed - include remove_setroubleshoot-plugins + +include remove_setroubleshoot-plugins class remove_setroubleshoot-plugins { package { 'setroubleshoot-plugins': @@ -89875,6 +103070,7 @@ class remove_setroubleshoot-plugins { } + package --remove=setroubleshoot-plugins @@ -89900,10 +103096,11 @@ running on a server. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot-server -# from the system, and may remove any packages -# that depend on setroubleshoot-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot-server" ; then yum remove -y "setroubleshoot-server" @@ -89924,8 +103121,9 @@ fi - no_reboot_needed - package_setroubleshoot-server_removed -- name: Ensure setroubleshoot-server is removed - package: +- name: 'Uninstall setroubleshoot-server Package: Ensure setroubleshoot-server is + removed' + ansible.builtin.package: name: setroubleshoot-server state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -89937,7 +103135,8 @@ fi - no_reboot_needed - package_setroubleshoot-server_removed - include remove_setroubleshoot-server + +include remove_setroubleshoot-server class remove_setroubleshoot-server { package { 'setroubleshoot-server': @@ -89946,6 +103145,7 @@ class remove_setroubleshoot-server { } + package --remove=setroubleshoot-server @@ -89972,10 +103172,11 @@ X Windows is removed or disabled. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove setroubleshoot -# from the system, and may remove any packages -# that depend on setroubleshoot. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on setroubleshoot. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "setroubleshoot" ; then yum remove -y "setroubleshoot" @@ -89996,8 +103197,8 @@ fi - no_reboot_needed - package_setroubleshoot_removed -- name: Ensure setroubleshoot is removed - package: +- name: 'Uninstall setroubleshoot Package: Ensure setroubleshoot is removed' + ansible.builtin.package: name: setroubleshoot state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90009,7 +103210,8 @@ fi - no_reboot_needed - package_setroubleshoot_removed - include remove_setroubleshoot + +include remove_setroubleshoot class remove_setroubleshoot { package { 'setroubleshoot': @@ -90018,6 +103220,7 @@ class remove_setroubleshoot { } + package --remove=setroubleshoot @@ -90026,7 +103229,8 @@ package --remove=setroubleshoot Verify Group Who Owns /etc/selinux Directory - To properly set the group owner of /etc/selinux, run the command: $ sudo chgrp root /etc/selinux + To properly set the group owner of /etc/selinux, run the command: +$ sudo chgrp root /etc/selinux R50 The ownership of the /etc/selinux directory by the root group is important @@ -90036,7 +103240,17 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -type d -exec chgrp -L root {} \; +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +find -P /etc/selinux/ -maxdepth 0 -type d ! -group root -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90053,11 +103267,42 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - directory_groupowner_etc_selinux_newgroup is undefined + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the directory_groupowner_etc_selinux_newgroup variable if root found + ansible.builtin.set_fact: + directory_groupowner_etc_selinux_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - directory_groupowner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/selinux/ - file: + ansible.builtin.file: path: /etc/selinux/ + follow: false state: directory - group: root + group: '{{ directory_groupowner_etc_selinux_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -90076,7 +103321,8 @@ fi Verify User Who Owns /etc/selinux Directory - To properly set the owner of /etc/selinux, run the command: $ sudo chown root /etc/selinux + To properly set the owner of /etc/selinux, run the command: +$ sudo chown root /etc/selinux R50 The ownership of the /etc/selinux directory by the root user is important @@ -90086,7 +103332,17 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/selinux/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90103,11 +103359,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the directory_owner_etc_selinux_newown variable if represented by uid + ansible.builtin.set_fact: + directory_owner_etc_selinux_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - directory_owner_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/selinux/ - file: + ansible.builtin.file: path: /etc/selinux/ + follow: false state: directory - owner: '0' + owner: '{{ directory_owner_etc_selinux_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy @@ -90136,7 +103405,7 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; +find -H /etc/selinux/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type d -exec chmod u-s,g-ws,o-wt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90154,7 +103423,8 @@ fi - no_reboot_needed - name: Find /etc/selinux/ file(s) - command: 'find -H /etc/selinux/ -maxdepth 1 -perm /u+s,g+ws,o+wt -type d ' + ansible.builtin.command: 'find -P /etc/selinux/ -maxdepth 0 -perm /u+s,g+ws,o+wt -type + d ' register: files_found changed_when: false failed_when: false @@ -90169,7 +103439,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/selinux/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-ws,o-wt state: directory @@ -90193,7 +103463,8 @@ fi Verify Group Who Owns /etc/sestatus.conf File - To properly set the group owner of /etc/sestatus.conf, run the command: $ sudo chgrp root /etc/sestatus.conf + To properly set the group owner of /etc/sestatus.conf, run the command: +$ sudo chgrp root /etc/sestatus.conf R50 The ownership of the /etc/sestatus.conf file by the root group is important @@ -90203,7 +103474,19 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp root /etc/sestatus.conf +newgroup="" +if getent group "root" >/dev/null 2>&1; then + newgroup="root" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "root is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/sestatus.conf" | grep -E -w -q "root"; then + chgrp --no-dereference "$newgroup" /etc/sestatus.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90220,8 +103503,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the root group is defined + ansible.builtin.getent: + database: group + key: root + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_sestatus_conf_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_sestatus_conf_newgroup variable if root found + ansible.builtin.set_fact: + file_groupowner_etc_sestatus_conf_newgroup: root + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["root"] is defined + tags: + - configure_strategy + - file_groupowner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90233,10 +103546,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner root on /etc/sestatus.conf - file: +- name: Ensure group owner on /etc/sestatus.conf + ansible.builtin.file: path: /etc/sestatus.conf - group: root + follow: false + group: '{{ file_groupowner_etc_sestatus_conf_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -90257,7 +103571,8 @@ fi Verify User Who Owns /etc/sestatus.conf File - To properly set the owner of /etc/sestatus.conf, run the command: $ sudo chown root /etc/sestatus.conf + To properly set the owner of /etc/sestatus.conf, run the command: +$ sudo chown root /etc/sestatus.conf R50 The ownership of the /etc/sestatus.conf file by the root user is important @@ -90267,7 +103582,19 @@ ensures exclusive control of the SELinux configuration. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/sestatus.conf +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/sestatus.conf" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/sestatus.conf +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -90284,8 +103611,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_sestatus_conf_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_sestatus_conf_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_sestatus_conf + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90297,10 +103636,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/sestatus.conf - file: +- name: Ensure owner on /etc/sestatus.conf + ansible.builtin.file: path: /etc/sestatus.conf - owner: '0' + follow: false + owner: '{{ file_owner_etc_sestatus_conf_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -90349,7 +103689,7 @@ fi - no_reboot_needed - name: Test for existence /etc/sestatus.conf - stat: + ansible.builtin.stat: path: /etc/sestatus.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -90362,7 +103702,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwt on /etc/sestatus.conf - file: + ansible.builtin.file: path: /etc/sestatus.conf mode: u-xs,g-xws,o-xwt when: @@ -90419,8 +103759,6 @@ file to prevent SELinux from being disabled at boot. MEA02.01 3.1.2 3.7.2 - CCI-000022 - CCI-000032 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -90526,16 +103864,16 @@ file to prevent SELinux from being disabled at boot. 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.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 AC-3(3)(a) DE.AE-1 @@ -90776,7 +104114,6 @@ can be achieved by amending SELinux policy. 3.1.2 3.1.5 3.7.2 - CCI-000366 4.3.3.3.9 4.3.3.5.1 4.3.3.5.2 @@ -90882,9 +104219,9 @@ can be achieved by amending SELinux policy. PR.IP-3 PR.PT-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002500 - SV-271769r1092019_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002500 + SV-271769r1092019_rule If a device file carries the SELinux type device_t or unlabeled_t, then SELinux cannot properly restrict access to the device file. @@ -91033,15 +104370,15 @@ daemons as outlined above. 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 + 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 CM-7(a) CM-7(b) CM-6(a) @@ -91071,7 +104408,9 @@ the system to boot into enforcing or permissive mode: SELINUX=enforcing OR SELINUX=permissive - +Ensure that all files have correct SELinux labels by running: +fixfiles onboot +Then reboot the system. In case the SELinux is "disabled", the automated remediation will adopt a more conservative approach and set it to "permissive" in order to avoid any system disruption and give the administrator the opportunity to assess the impact and necessary efforts @@ -91098,7 +104437,6 @@ printf '%s\n' "SELINUX=permissive" >> "/etc/selinux/config" rm "/etc/selinux/config.bak" fixfiles onboot -fixfiles -f relabel else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91115,11 +104453,26 @@ fi - restrict_strategy - selinux_not_disabled +- name: Ensure SELinux is Not Disabled - Check current SELinux state + ansible.builtin.command: + cmd: getenforce + register: selinux_state + check_mode: false + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled + - name: Ensure SELinux is Not Disabled block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91129,7 +104482,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91137,7 +104490,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91151,6 +104504,23 @@ fi - reboot_required - restrict_strategy - selinux_not_disabled + +- name: Ensure SELinux is Not Disabled - Mark system to relabel SELinux on next boot + ansible.builtin.file: + path: /.autorelabel + state: touch + access_time: preserve + modification_time: preserve + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - selinux_state.stdout | lower != "permissive" + tags: + - high_severity + - low_complexity + - low_disruption + - reboot_required + - restrict_strategy + - selinux_not_disabled @@ -91200,7 +104570,6 @@ use cases. MEA02.01 3.1.2 3.7.2 - CCI-002696 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -91306,19 +104675,19 @@ use cases. A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AC-3 AC-3(3)(a) AU-9 @@ -91333,8 +104702,8 @@ use cases. PR.PT-3 PR.PT-4 FMT_MOF_EXT.1 - SRG-OS-000445-GPOS-00199 - SRG-APP-000233-CTR-000585 + SRG-OS-000445-GPOS-00199 + SRG-APP-000233-CTR-000585 R46 R64 APP.4.4.A4 @@ -91342,10 +104711,11 @@ use cases. SYS.1.6.A18 SYS.1.6.A21 A.6.SEC-OL1 + 1409 1.2.6 1.2 - OL09-00-000065 - SV-271453r1091071_rule + OL09-00-000065 + SV-271453r1091071_rule Setting the SELinux policy to targeted or a more specialized policy ensures the system will confine processes that are likely to be targeted for exploitation, such as network or system services. @@ -91356,12 +104726,11 @@ temporarily place non-production systems in permissive mo temporary cases, SELinux policies should be developed, and once work is completed, the system should be reconfigured to . - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_selinux_policy_name='' - if [ -e "/etc/selinux/config" ] ; then LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config" @@ -91381,7 +104750,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -91394,11 +104763,11 @@ fi - NIST-800-53-SC-7(21) - PCI-DSSv4-1.2 - PCI-DSSv4-1.2.6 + - configure_strategy - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy + - no_reboot_needed - selinux_policytype - name: XCCDF Value var_selinux_policy_name # promote to variable set_fact: @@ -91410,7 +104779,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91420,7 +104789,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91428,7 +104797,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUXTYPE= @@ -91445,11 +104814,11 @@ fi - NIST-800-53-SC-7(21) - PCI-DSSv4-1.2 - PCI-DSSv4-1.2.6 + - configure_strategy - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy + - no_reboot_needed - selinux_policytype @@ -91467,7 +104836,9 @@ system boot time. In the file /etc/selinux/config, add o following line to configure the system to boot into enforcing mode: SELINUX= - +Ensure that all files have correct SELinux labels by running: +fixfiles onboot +Then reboot the system. 1 11 12 @@ -91498,8 +104869,6 @@ following line to configure the system to boot into enforcing mode: MEA02.01 3.1.2 3.7.2 - CCI-002696 - CCI-001084 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -91605,19 +104974,19 @@ following line to configure the system to boot into enforcing mode: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AC-3 AC-3(3)(a) AU-9 @@ -91632,8 +105001,8 @@ following line to configure the system to boot into enforcing mode: PR.PT-3 PR.PT-4 FMT_MOF_EXT.1 - SRG-OS-000445-GPOS-00199 - SRG-OS-000134-GPOS-00068 + SRG-OS-000445-GPOS-00199 + SRG-OS-000134-GPOS-00068 R37 R79 APP.4.4.A4 @@ -91641,10 +105010,11 @@ following line to configure the system to boot into enforcing mode: SYS.1.6.A18 SYS.1.6.A21 A.6.SEC-OL1 + 1409 1.2.6 1.2 - OL09-00-000060 - SV-271452r1091068_rule + OL09-00-000060 + SV-271452r1091068_rule Setting the SELinux state to enforcing ensures SELinux is able to confine potentially compromised processes to the security policy, which is designed to prevent them from causing damage to the system or further elevating their @@ -91671,7 +105041,6 @@ printf '%s\n' "SELINUX=$var_selinux_state" >> "/etc/selinux/config" rm "/etc/selinux/config.bak" fixfiles onboot -fixfiles -f relabel else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91702,11 +105071,35 @@ fi tags: - always +- name: Ensure SELinux State is Enforcing - Check current SELinux state + ansible.builtin.command: + cmd: getenforce + register: selinux_state + check_mode: false + changed_when: false + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state + - name: Ensure SELinux State is Enforcing block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91716,7 +105109,7 @@ fi register: dupes - name: Deduplicate values from /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91724,7 +105117,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/selinux/config - lineinfile: + ansible.builtin.lineinfile: path: /etc/selinux/config create: true regexp: (?i)^SELINUX= @@ -91747,6 +105140,33 @@ fi - no_reboot_needed - restrict_strategy - selinux_state + +- name: Ensure SELinux State is Enforcing - Mark system to relabel SELinux on next + boot + ansible.builtin.file: + path: /.autorelabel + state: touch + access_time: preserve + modification_time: preserve + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - selinux_state.stdout | lower != var_selinux_state + tags: + - DISA-STIG-OL09-00-000060 + - NIST-800-171-3.1.2 + - NIST-800-171-3.7.2 + - NIST-800-53-AC-3 + - NIST-800-53-AC-3(3)(a) + - NIST-800-53-AU-9 + - NIST-800-53-SC-7(21) + - PCI-DSSv4-1.2 + - PCI-DSSv4-1.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - selinux_state @@ -91760,7 +105180,7 @@ fi SELinux - Booleans Enable or Disable runtime customization of SELinux system policies without having to reload or recompile the SELinux policy. - + auditadm_exec_content SELinux Boolean default - Default SELinux boolean setting. @@ -91870,30 +105290,23 @@ To enable the auditadm_exec_content SELinux boolean, run 80424-5 0582 - 0584 - 05885 - 0586 0846 - 0957 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_auditadm_exec_content='' - setsebool -P auditadm_exec_content $var_auditadm_exec_content - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P auditadm_exec_content $var_auditadm_exec_content else >&2 echo 'Remediation is not applicable, nothing was done' @@ -91913,10 +105326,15 @@ fi - name: Enable the auditadm_exec_content SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-80424-5 - enable_strategy @@ -91933,13 +105351,16 @@ fi - name: Enable the auditadm_exec_content SELinux Boolean - Set SELinux Boolean auditadm_exec_content Accordingly - seboolean: + ansible.posix.seboolean: name: auditadm_exec_content state: '{{ var_auditadm_exec_content }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-80424-5 - enable_strategy @@ -91949,6 +105370,11 @@ fi - no_reboot_needed - sebool_auditadm_exec_content + + + + + @@ -91968,7 +105394,6 @@ To disable the authlogin_nsswitch_use_ldap SELinux boolea 3.7.2 0421 0422 - 0431 0974 1173 1401 @@ -91982,23 +105407,20 @@ To disable the authlogin_nsswitch_use_ldap SELinux boolea 1561 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_authlogin_nsswitch_use_ldap='' - setsebool -P authlogin_nsswitch_use_ldap $var_authlogin_nsswitch_use_ldap - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P authlogin_nsswitch_use_ldap $var_authlogin_nsswitch_use_ldap else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92018,10 +105440,15 @@ fi - name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92038,13 +105465,16 @@ fi - name: Disable the authlogin_nsswitch_use_ldap SELinux Boolean - Set SELinux Boolean authlogin_nsswitch_use_ldap Accordingly - seboolean: + ansible.posix.seboolean: name: authlogin_nsswitch_use_ldap state: '{{ var_authlogin_nsswitch_use_ldap }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92054,6 +105484,11 @@ fi - no_reboot_needed - sebool_authlogin_nsswitch_use_ldap + + + + + @@ -92073,7 +105508,6 @@ To disable the authlogin_radius SELinux boolean, run the 3.7.2 0421 0422 - 0431 0974 1173 1401 @@ -92087,23 +105521,20 @@ To disable the authlogin_radius SELinux boolean, run the 1561 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_authlogin_radius='' - setsebool -P authlogin_radius $var_authlogin_radius - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P authlogin_radius $var_authlogin_radius else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92123,10 +105554,15 @@ fi - name: Disable the authlogin_radius SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92143,13 +105579,16 @@ fi - name: Disable the authlogin_radius SELinux Boolean - Set SELinux Boolean authlogin_radius Accordingly - seboolean: + ansible.posix.seboolean: name: authlogin_radius state: '{{ var_authlogin_radius }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - NIST-800-171-3.7.2 - enable_strategy @@ -92159,6 +105598,11 @@ fi - no_reboot_needed - sebool_authlogin_radius + + + + + @@ -92183,6 +105627,11 @@ boolean in production systems. R48 Allowing user domain applications to map a memory region as both writable and executable makes them more susceptible to data execution attacks. + + + + + @@ -92205,23 +105654,20 @@ To enable the kerberos_enabled SELinux boolean, run the f 1402 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_kerberos_enabled='' - setsebool -P kerberos_enabled $var_kerberos_enabled - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P kerberos_enabled $var_kerberos_enabled else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92239,10 +105685,15 @@ fi - sebool_kerberos_enabled - name: Enable the kerberos_enabled SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92258,13 +105709,16 @@ fi - name: Enable the kerberos_enabled SELinux Boolean - Set SELinux Boolean kerberos_enabled Accordingly - seboolean: + ansible.posix.seboolean: name: kerberos_enabled state: '{{ var_kerberos_enabled }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92273,6 +105727,11 @@ fi - no_reboot_needed - sebool_kerberos_enabled + + + + + @@ -92293,23 +105752,20 @@ To set the polyinstantiation_enabled SELinux boolean, run R55 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_polyinstantiation_enabled='' - setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P polyinstantiation_enabled $var_polyinstantiation_enabled else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92328,10 +105784,15 @@ fi - name: Configure the polyinstantiation_enabled SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92347,13 +105808,16 @@ fi - name: Configure the polyinstantiation_enabled SELinux Boolean - Set SELinux Boolean polyinstantiation_enabled Accordingly - seboolean: + ansible.posix.seboolean: name: polyinstantiation_enabled state: '{{ var_polyinstantiation_enabled }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92362,6 +105826,11 @@ fi - no_reboot_needed - sebool_polyinstantiation_enabled + + + + + @@ -92382,7 +105851,7 @@ To set the secure_mode_insmod SELinux boolean, run the fo R48 # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then var_secure_mode_insmod='' @@ -92417,7 +105886,12 @@ fi ansible.builtin.package: name: libsemanage-python state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92432,7 +105906,12 @@ fi name: secure_mode_insmod state: '{{ var_secure_mode_insmod }}' persistent: true - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92448,7 +105927,12 @@ fi dest: /etc/modules-load.d/vfat.conf regexp: ^\s*\bvfat\b line: vfat - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92460,7 +105944,12 @@ fi - name: Configure the secure_mode_insmod SELinux Boolean - Regenerate initramfs ansible.builtin.command: cmd: dracut -f --regenerate-all - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92469,6 +105958,11 @@ fi - no_reboot_needed - sebool_secure_mode_insmod + + + + + @@ -92496,23 +105990,20 @@ To disable the selinuxuser_execheap SELinux boolean, run R48 Disabling code execution from the heap blocks buffer overflow attacks. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_execheap='' - setsebool -P selinuxuser_execheap $var_selinuxuser_execheap - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execheap $var_selinuxuser_execheap else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92531,10 +106022,15 @@ fi - name: Disable the selinuxuser_execheap SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92550,13 +106046,16 @@ fi - name: Disable the selinuxuser_execheap SELinux Boolean - Set SELinux Boolean selinuxuser_execheap Accordingly - seboolean: + ansible.posix.seboolean: name: selinuxuser_execheap state: '{{ var_selinuxuser_execheap }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92565,6 +106064,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execheap + + + + + @@ -92590,23 +106094,20 @@ To enable the selinuxuser_execmod SELinux boolean, run th 164.312(e) # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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='' - setsebool -P selinuxuser_execmod $var_selinuxuser_execmod - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execmod $var_selinuxuser_execmod else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92625,10 +106126,15 @@ fi - name: Enable the selinuxuser_execmod SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92644,13 +106150,16 @@ fi - name: Enable the selinuxuser_execmod SELinux Boolean - Set SELinux Boolean selinuxuser_execmod Accordingly - seboolean: + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92659,6 +106168,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execmod + + + + + @@ -92686,23 +106200,20 @@ To disable the selinuxuser_execstack SELinux boolean, run R48 Disabling code execution from the stack blocks buffer overflow attacks. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_execstack='' - setsebool -P selinuxuser_execstack $var_selinuxuser_execstack - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P selinuxuser_execstack $var_selinuxuser_execstack else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92721,10 +106232,15 @@ fi - name: Disable the selinuxuser_execstack SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92740,13 +106256,16 @@ fi - name: Disable the selinuxuser_execstack SELinux Boolean - Set SELinux Boolean selinuxuser_execstack Accordingly - seboolean: + ansible.posix.seboolean: name: selinuxuser_execstack state: '{{ var_selinuxuser_execstack }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92755,6 +106274,11 @@ fi - no_reboot_needed - sebool_selinuxuser_execstack + + + + + @@ -92771,9 +106295,7 @@ If this setting is enabled, it should be disabled. To disable the ssh_sysadm_login SELinux boolean, run the following command: $ sudo setsebool -P ssh_sysadm_login off - CCI-002165 - CCI-002235 - SRG-OS-000324-GPOS-00125 + SRG-OS-000324-GPOS-00125 R48 Preventing non-privileged users from executing privileged functions mitigates the risk that unauthorized individuals or processes may gain unnecessary access @@ -92786,23 +106308,20 @@ authorizations. Circumventing intrusion detection and prevention mechanisms or malicious code protection mechanisms are examples of privileged functions that require protection from non-privileged users. # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +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 || rpm --quiet -q kernel-uek; then if ! rpm -q --quiet "python3-libsemanage" ; then yum install -y "python3-libsemanage" fi -if selinuxenabled || [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +# 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_ssh_sysadm_login='' - setsebool -P ssh_sysadm_login $var_ssh_sysadm_login - -else - echo "Skipping remediation, SELinux is disabled"; - false -fi + /usr/sbin/setsebool -P ssh_sysadm_login $var_ssh_sysadm_login else >&2 echo 'Remediation is not applicable, nothing was done' @@ -92821,10 +106340,15 @@ fi - name: Disable the ssh_sysadm_login SELinux Boolean - Ensure python3-libsemanage Installed - package: + ansible.builtin.package: name: python3-libsemanage state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -92840,13 +106364,16 @@ fi - name: Disable the ssh_sysadm_login SELinux Boolean - Set SELinux Boolean ssh_sysadm_login Accordingly - seboolean: + ansible.posix.seboolean: name: ssh_sysadm_login state: '{{ var_ssh_sysadm_login }}' 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" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - ansible_facts.selinux.status == 'enabled' tags: - enable_strategy - low_complexity @@ -92855,6 +106382,11 @@ fi - no_reboot_needed - sebool_ssh_sysadm_login + + + + + @@ -92993,7 +106525,6 @@ The avahi-daemon service can be disabled with the followi DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -93050,6 +106581,7 @@ The avahi-daemon service can be disabled with the followi CM-6(a) PR.IP-1 PR.PT-3 + 1409 2.2.4 2.2 Because the Avahi daemon service keeps an open network @@ -93098,93 +106630,54 @@ fi - no_reboot_needed - service_avahi-daemon_disabled -- name: Disable Avahi Server Software - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Avahi Server Software - Disable service avahi-daemon + block: + + - name: Disable Avahi Server Software - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Avahi Server Software - Ensure avahi-daemon.service is Masked + ansible.builtin.systemd: + name: avahi-daemon.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("avahi-daemon.service", multiline=True) + + - name: Unit Socket Exists - avahi-daemon.socket + ansible.builtin.command: systemctl -q list-unit-files avahi-daemon.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Avahi Server Software - Disable Socket avahi-daemon + ansible.builtin.systemd: + name: avahi-daemon.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("avahi-daemon.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_avahi-daemon_disabled + - special_service_block when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Disable Avahi Server Software - Ensure avahi-daemon.service is Masked - ansible.builtin.systemd: - name: avahi-daemon.service - state: stopped - enabled: false - masked: true - when: - - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("avahi-daemon.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Unit Socket Exists - avahi-daemon.socket - ansible.builtin.command: systemctl -q list-unit-files avahi-daemon.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled - -- name: Disable Avahi Server Software - Disable Socket avahi-daemon - ansible.builtin.systemd: - name: avahi-daemon.socket - enabled: false - state: stopped - masked: true - when: - - ( "avahi" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("avahi-daemon.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_avahi-daemon_disabled include disable_avahi-daemon @@ -93199,6 +106692,10 @@ class disable_avahi-daemon { [customizations.services] masked = ["avahi-daemon"] + + + + @@ -93242,7 +106739,6 @@ The kdump service can be disabled with the following comm DSS05.03 DSS05.05 DSS06.06 - CCI-000366 164.308(a)(1)(ii)(D) 164.308(a)(3) 164.308(a)(4) @@ -93324,10 +106820,10 @@ The kdump service can be disabled with the following comm PR.PT-3 PR.PT-4 FMT_SMF_EXT.1.1 - SRG-OS-000269-GPOS-00103 - SRG-OS-000480-GPOS-00227 - OL09-00-002385 - SV-271733r1092598_rule + SRG-OS-000269-GPOS-00103 + SRG-OS-000480-GPOS-00227 + OL09-00-002385 + SV-271733r1092598_rule Kernel core dumps may contain the full contents of system memory at the time of the crash. Kernel core dumps consume a considerable amount of disk space and may result in denial of service by exhausting the available space @@ -93374,86 +106870,52 @@ fi - no_reboot_needed - service_kdump_disabled -- name: Disable KDump Kernel Crash Analyzer (kdump) - Collect systemd Services Present - in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable KDump Kernel Crash Analyzer (kdump) - Disable service kdump + block: + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Collect systemd Services Present + in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Ensure kdump.service is Masked + ansible.builtin.systemd: + name: kdump.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("kdump.service", multiline=True) + + - name: Unit Socket Exists - kdump.socket + ansible.builtin.command: systemctl -q list-unit-files kdump.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable KDump Kernel Crash Analyzer (kdump) - Disable Socket kdump + ansible.builtin.systemd: + name: kdump.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("kdump.socket", multiline=True) + tags: + - DISA-STIG-OL09-00-002385 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_kdump_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Disable KDump Kernel Crash Analyzer (kdump) - Ensure kdump.service is Masked - ansible.builtin.systemd: - name: kdump.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("kdump.service", multiline=True) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Unit Socket Exists - kdump.socket - ansible.builtin.command: systemctl -q list-unit-files kdump.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled - -- name: Disable KDump Kernel Crash Analyzer (kdump) - Disable Socket kdump - ansible.builtin.systemd: - name: kdump.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("kdump.socket", multiline=True) - tags: - - DISA-STIG-OL09-00-002385 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_kdump_disabled include disable_kdump @@ -93471,6 +106933,10 @@ kdump --disable [customizations.services] masked = ["kdump"] + + + + @@ -93499,7 +106965,6 @@ The oddjobd service can be disabled with the following co DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -93600,82 +107065,51 @@ fi - no_reboot_needed - service_oddjobd_disabled -- name: Disable Odd Job Daemon (oddjobd) - Collect systemd Services Present in the - System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Odd Job Daemon (oddjobd) - Disable service oddjobd + block: + + - name: Disable Odd Job Daemon (oddjobd) - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Odd Job Daemon (oddjobd) - Ensure oddjobd.service is Masked + ansible.builtin.systemd: + name: oddjobd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("oddjobd.service", multiline=True) + + - name: Unit Socket Exists - oddjobd.socket + ansible.builtin.command: systemctl -q list-unit-files oddjobd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Odd Job Daemon (oddjobd) - Disable Socket oddjobd + ansible.builtin.systemd: + name: oddjobd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("oddjobd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_oddjobd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Disable Odd Job Daemon (oddjobd) - Ensure oddjobd.service is Masked - ansible.builtin.systemd: - name: oddjobd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("oddjobd.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Unit Socket Exists - oddjobd.socket - ansible.builtin.command: systemctl -q list-unit-files oddjobd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled - -- name: Disable Odd Job Daemon (oddjobd) - Disable Socket oddjobd - ansible.builtin.systemd: - name: oddjobd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("oddjobd.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_oddjobd_disabled include disable_oddjobd @@ -93690,6 +107124,10 @@ class disable_oddjobd { [customizations.services] masked = ["oddjobd"] + + + + @@ -93736,7 +107174,6 @@ The rdisc service can be disabled with the following comm DSS05.07 DSS06.02 DSS06.06 - CCI-000382 4.2.3.4 4.3.3.4 4.3.3.5.1 @@ -93885,87 +107322,53 @@ fi - no_reboot_needed - service_rdisc_disabled -- name: Disable Network Router Discovery Daemon (rdisc) - Collect systemd Services - Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Network Router Discovery Daemon (rdisc) - Disable service rdisc + block: + + - name: Disable Network Router Discovery Daemon (rdisc) - Collect systemd Services + Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Network Router Discovery Daemon (rdisc) - Ensure rdisc.service is + Masked + ansible.builtin.systemd: + name: rdisc.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rdisc.service", multiline=True) + + - name: Unit Socket Exists - rdisc.socket + ansible.builtin.command: systemctl -q list-unit-files rdisc.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Network Router Discovery Daemon (rdisc) - Disable Socket rdisc + ansible.builtin.systemd: + name: rdisc.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rdisc.socket", multiline=True) + tags: + - NIST-800-53-AC-4 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rdisc_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Disable Network Router Discovery Daemon (rdisc) - Ensure rdisc.service is - Masked - ansible.builtin.systemd: - name: rdisc.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rdisc.service", multiline=True) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Unit Socket Exists - rdisc.socket - ansible.builtin.command: systemctl -q list-unit-files rdisc.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled - -- name: Disable Network Router Discovery Daemon (rdisc) - Disable Socket rdisc - ansible.builtin.systemd: - name: rdisc.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rdisc.socket", multiline=True) - tags: - - NIST-800-53-AC-4 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rdisc_disabled include disable_rdisc @@ -93980,6 +107383,10 @@ class disable_rdisc { [customizations.services] masked = ["rdisc"] + + + + @@ -94010,7 +107417,6 @@ configured defensively. DSS05.02 DSS05.05 DSS06.06 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -94071,7 +107477,7 @@ configured defensively. CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 The cron service allow periodic job execution, needed for almost all administrative tasks and services (software update, log rotating, etc.). Access to cron service should be restricted to administrative accounts only. @@ -94101,7 +107507,7 @@ fi - package_cron_installed - name: Ensure cronie is installed - package: + ansible.builtin.package: name: cronie state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -94251,7 +107657,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable cron Service - Enable Service crond @@ -94262,7 +107668,6 @@ fi masked: false when: - '"cronie" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6(a) - enable_strategy @@ -94271,6 +107676,8 @@ fi - medium_severity - no_reboot_needed - service_crond_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_crond @@ -94285,6 +107692,10 @@ class enable_crond { [customizations.services] enabled = ["crond"] + + + + @@ -94314,7 +107725,6 @@ The atd service can be disabled with the following comman DSS05.02 DSS05.05 DSS06.06 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -94414,81 +107824,50 @@ fi - no_reboot_needed - service_atd_disabled -- name: Disable At Service (atd) - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable At Service (atd) - Disable service atd + block: + + - name: Disable At Service (atd) - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable At Service (atd) - Ensure atd.service is Masked + ansible.builtin.systemd: + name: atd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("atd.service", multiline=True) + + - name: Unit Socket Exists - atd.socket + ansible.builtin.command: systemctl -q list-unit-files atd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable At Service (atd) - Disable Socket atd + ansible.builtin.systemd: + name: atd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("atd.socket", multiline=True) + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_atd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Disable At Service (atd) - Ensure atd.service is Masked - ansible.builtin.systemd: - name: atd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("atd.service", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Unit Socket Exists - atd.socket - ansible.builtin.command: systemctl -q list-unit-files atd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled - -- name: Disable At Service (atd) - Disable Socket atd - ansible.builtin.systemd: - name: atd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("atd.socket", multiline=True) - tags: - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_atd_disabled include disable_atd @@ -94503,6 +107882,10 @@ class disable_atd { [customizations.services] masked = ["atd"] + + + + @@ -94514,7 +107897,8 @@ masked = ["atd"] Verify Group Who Owns cron.d To properly set the group owner of /etc/cron.d, run the command: -$ sudo chgrp root /etc/cron.d + + $ sudo chgrp root /etc/cron.d 12 13 @@ -94528,7 +107912,6 @@ To properly set the group owner of /etc/cron.d, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94559,18 +107942,28 @@ To properly set the group owner of /etc/cron.d, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.d/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94592,11 +107985,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_d_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_d_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.d/ - file: + ansible.builtin.file: path: /etc/cron.d/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_d_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94622,7 +108033,8 @@ fi Verify Group Who Owns cron.daily To properly set the group owner of /etc/cron.daily, run the command: -$ sudo chgrp root /etc/cron.daily + + $ sudo chgrp root /etc/cron.daily 12 13 @@ -94636,7 +108048,6 @@ To properly set the group owner of /etc/cron.daily, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94667,18 +108078,28 @@ To properly set the group owner of /etc/cron.daily, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.daily/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94700,11 +108121,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_daily_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_daily_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.daily/ - file: + ansible.builtin.file: path: /etc/cron.daily/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_daily_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94730,20 +108169,32 @@ fi Verify Group Who Owns cron.deny To properly set the group owner of /etc/cron.deny, run the command: -$ sudo chgrp root /etc/cron.deny + + $ sudo chgrp root /etc/cron.deny - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00227 - OL09-00-002581 - SV-271828r1092196_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/cron.deny +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/cron.deny" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/cron.deny +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94762,8 +108213,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_deny_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_deny_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-CM-6 b + - configure_strategy + - file_groupowner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.deny - stat: + ansible.builtin.stat: path: /etc/cron.deny register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -94777,10 +108242,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/cron.deny - file: +- name: Ensure group owner on /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny - group: '0' + follow: false + group: '{{ file_groupowner_cron_deny_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -94805,7 +108271,8 @@ fi Verify Group Who Owns cron.hourly To properly set the group owner of /etc/cron.hourly, run the command: -$ sudo chgrp root /etc/cron.hourly + + $ sudo chgrp root /etc/cron.hourly 12 13 @@ -94819,7 +108286,6 @@ To properly set the group owner of /etc/cron.hourly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94850,18 +108316,28 @@ To properly set the group owner of /etc/cron.hourly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.hourly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94883,11 +108359,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_hourly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_hourly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.hourly/ - file: + ansible.builtin.file: path: /etc/cron.hourly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_hourly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -94913,7 +108407,8 @@ fi Verify Group Who Owns cron.monthly To properly set the group owner of /etc/cron.monthly, run the command: -$ sudo chgrp root /etc/cron.monthly + + $ sudo chgrp root /etc/cron.monthly 12 13 @@ -94927,7 +108422,6 @@ To properly set the group owner of /etc/cron.monthly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -94958,18 +108452,28 @@ To properly set the group owner of /etc/cron.monthly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.monthly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -94991,11 +108495,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_monthly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_monthly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.monthly/ - file: + ansible.builtin.file: path: /etc/cron.monthly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_monthly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -95021,7 +108543,8 @@ fi Verify Group Who Owns cron.weekly To properly set the group owner of /etc/cron.weekly, run the command: -$ sudo chgrp root /etc/cron.weekly + + $ sudo chgrp root /etc/cron.weekly 12 13 @@ -95035,7 +108558,6 @@ To properly set the group owner of /etc/cron.weekly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95066,18 +108588,28 @@ To properly set the group owner of /etc/cron.weekly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/cron.weekly/ -maxdepth 0 -type d ! -group 0 -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95099,11 +108631,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_weekly_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_weekly_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure group owner on /etc/cron.weekly/ - file: + ansible.builtin.file: path: /etc/cron.weekly/ + follow: false state: directory - group: '0' + group: '{{ file_groupowner_cron_weekly_newgroup }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002581 @@ -95129,7 +108679,8 @@ fi Verify Group Who Owns Crontab To properly set the group owner of /etc/crontab, run the command: -$ sudo chgrp root /etc/crontab + + $ sudo chgrp root /etc/crontab 12 13 @@ -95143,7 +108694,6 @@ To properly set the group owner of /etc/crontab, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95174,18 +108724,30 @@ To properly set the group owner of /etc/crontab, run the AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002581 - SV-271828r1092196_rule + OL09-00-002581 + SV-271828r1092196_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/crontab +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/crontab" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/crontab +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95207,8 +108769,25 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_crontab_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_crontab_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002581 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95225,10 +108804,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/crontab - file: +- name: Ensure group owner on /etc/crontab + ansible.builtin.file: path: /etc/crontab - group: '0' + follow: false + group: '{{ file_groupowner_crontab_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -95256,7 +108836,8 @@ fi Verify Owner on cron.d To properly set the owner of /etc/cron.d, run the command: -$ sudo chown root /etc/cron.d + + $ sudo chown root /etc/cron.d 12 13 @@ -95270,7 +108851,6 @@ To properly set the owner of /etc/cron.d, run the command DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95301,18 +108881,28 @@ To properly set the owner of /etc/cron.d, run the command AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.d/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95334,11 +108924,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_d_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_d_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.d/ - file: + ansible.builtin.file: path: /etc/cron.d/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_d_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95364,7 +108972,8 @@ fi Verify Owner on cron.daily To properly set the owner of /etc/cron.daily, run the command: -$ sudo chown root /etc/cron.daily + + $ sudo chown root /etc/cron.daily 12 13 @@ -95378,7 +108987,6 @@ To properly set the owner of /etc/cron.daily, run the com DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95409,18 +109017,28 @@ To properly set the owner of /etc/cron.daily, run the com AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.daily/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95442,11 +109060,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_daily_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_daily_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_daily + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.daily/ - file: + ansible.builtin.file: path: /etc/cron.daily/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_daily_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95472,20 +109108,32 @@ fi Verify Owner on cron.deny To properly set the owner of /etc/cron.deny, run the command: -$ sudo chown root /etc/cron.deny + + $ sudo chown root /etc/cron.deny - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00227 - OL09-00-002582 - SV-271829r1092199_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/cron.deny +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/cron.deny" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/cron.deny +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95504,8 +109152,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_deny_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_deny_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-CM-6 b + - configure_strategy + - file_owner_cron_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.deny - stat: + ansible.builtin.stat: path: /etc/cron.deny register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95519,10 +109181,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/cron.deny - file: +- name: Ensure owner on /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny - owner: '0' + follow: false + owner: '{{ file_owner_cron_deny_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -95547,7 +109210,8 @@ fi Verify Owner on cron.hourly To properly set the owner of /etc/cron.hourly, run the command: -$ sudo chown root /etc/cron.hourly + + $ sudo chown root /etc/cron.hourly 12 13 @@ -95561,7 +109225,6 @@ To properly set the owner of /etc/cron.hourly, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95592,18 +109255,28 @@ To properly set the owner of /etc/cron.hourly, run the co AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.hourly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95625,11 +109298,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_hourly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_hourly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_hourly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.hourly/ - file: + ansible.builtin.file: path: /etc/cron.hourly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_hourly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95655,7 +109346,8 @@ fi Verify Owner on cron.monthly To properly set the owner of /etc/cron.monthly, run the command: -$ sudo chown root /etc/cron.monthly + + $ sudo chown root /etc/cron.monthly 12 13 @@ -95669,7 +109361,6 @@ To properly set the owner of /etc/cron.monthly, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95700,18 +109391,28 @@ To properly set the owner of /etc/cron.monthly, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.monthly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95733,11 +109434,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_monthly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_monthly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_monthly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.monthly/ - file: + ansible.builtin.file: path: /etc/cron.monthly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_monthly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95763,7 +109482,8 @@ fi Verify Owner on cron.weekly To properly set the owner of /etc/cron.weekly, run the command: -$ sudo chown root /etc/cron.weekly + + $ sudo chown root /etc/cron.weekly 12 13 @@ -95777,7 +109497,6 @@ To properly set the owner of /etc/cron.weekly, run the co DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95808,18 +109527,28 @@ To properly set the owner of /etc/cron.weekly, run the co AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -type d -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +find -P /etc/cron.weekly/ -maxdepth 0 -type d ! -user 0 -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95841,11 +109570,29 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_weekly_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_weekly_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_weekly + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Ensure owner on directory /etc/cron.weekly/ - file: + ansible.builtin.file: path: /etc/cron.weekly/ + follow: false state: directory - owner: '0' + owner: '{{ file_owner_cron_weekly_newown }}' when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002582 @@ -95871,7 +109618,8 @@ fi Verify Owner on crontab To properly set the owner of /etc/crontab, run the command: -$ sudo chown root /etc/crontab + + $ sudo chown root /etc/crontab 12 13 @@ -95885,7 +109633,6 @@ To properly set the owner of /etc/crontab, run the comman DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -95916,18 +109663,30 @@ To properly set the owner of /etc/crontab, run the comman AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002582 - SV-271829r1092199_rule + OL09-00-002582 + SV-271829r1092199_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct user to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/crontab +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/crontab" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/crontab +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -95949,8 +109708,25 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_crontab_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_crontab_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002582 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_crontab + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -95967,10 +109743,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/crontab - file: +- name: Ensure owner on /etc/crontab + ansible.builtin.file: path: /etc/crontab - owner: '0' + follow: false + owner: '{{ file_owner_crontab_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -96012,7 +109789,6 @@ To properly set the permissions of /etc/cron.d, run the c DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96043,18 +109819,18 @@ To properly set the permissions of /etc/cron.d, run the c AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96077,7 +109853,8 @@ fi - no_reboot_needed - name: Find /etc/cron.d/ file(s) - command: 'find -H /etc/cron.d/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/cron.d/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -96097,7 +109874,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96142,7 +109919,6 @@ To properly set the permissions of /etc/cron.daily, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96173,18 +109949,18 @@ To properly set the permissions of /etc/cron.daily, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.daily/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96207,7 +109983,8 @@ fi - no_reboot_needed - name: Find /etc/cron.daily/ file(s) - command: 'find -H /etc/cron.daily/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d ' + ansible.builtin.command: 'find -P /etc/cron.daily/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type + d ' register: files_found changed_when: false failed_when: false @@ -96227,7 +110004,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.daily/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96272,7 +110049,6 @@ To properly set the permissions of /etc/cron.hourly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96303,18 +110079,18 @@ To properly set the permissions of /etc/cron.hourly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.hourly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96337,7 +110113,7 @@ fi - no_reboot_needed - name: Find /etc/cron.hourly/ file(s) - command: 'find -H /etc/cron.hourly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.hourly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96358,7 +110134,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.hourly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96403,7 +110179,6 @@ To properly set the permissions of /etc/cron.monthly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96434,18 +110209,18 @@ To properly set the permissions of /etc/cron.monthly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.monthly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96468,7 +110243,7 @@ fi - no_reboot_needed - name: Find /etc/cron.monthly/ file(s) - command: 'find -H /etc/cron.monthly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.monthly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96489,7 +110264,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.monthly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96534,7 +110309,6 @@ To properly set the permissions of /etc/cron.weekly, run DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96565,18 +110339,18 @@ To properly set the permissions of /etc/cron.weekly, run AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002580 - SV-271827r1092193_rule + OL09-00-002580 + SV-271827r1092193_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; +find -H /etc/cron.weekly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d -exec chmod u-s,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96599,7 +110373,7 @@ fi - no_reboot_needed - name: Find /etc/cron.weekly/ file(s) - command: 'find -H /etc/cron.weekly/ -maxdepth 1 -perm /u+s,g+xwrs,o+xwrt -type + ansible.builtin.command: 'find -P /etc/cron.weekly/ -maxdepth 0 -perm /u+s,g+xwrs,o+xwrt -type d ' register: files_found changed_when: false @@ -96620,7 +110394,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/cron.weekly/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-s,g-xwrs,o-xwrt state: directory @@ -96665,7 +110439,6 @@ To properly set the permissions of /etc/crontab, run the DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -96696,11 +110469,11 @@ To properly set the permissions of /etc/crontab, run the AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 - OL09-00-002583 - SV-271830r1092202_rule + OL09-00-002583 + SV-271830r1092202_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should have the correct access rights to prevent unauthorized changes. @@ -96730,7 +110503,7 @@ fi - no_reboot_needed - name: Test for existence /etc/crontab - stat: + ansible.builtin.stat: path: /etc/crontab register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96748,7 +110521,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/crontab - file: + ansible.builtin.file: path: /etc/crontab mode: u-xs,g-xwrs,o-xwrt when: @@ -96827,8 +110600,8 @@ fi - medium_severity - no_reboot_needed -- name: Remove /etc/at.deny - file: +- name: Ensure that /etc/at.deny does not exist - Remove /etc/at.deny + ansible.builtin.file: path: /etc/at.deny state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96881,8 +110654,8 @@ fi - medium_severity - no_reboot_needed -- name: Remove /etc/cron.deny - file: +- name: Ensure that /etc/cron.deny does not exist - Remove /etc/cron.deny + ansible.builtin.file: path: /etc/cron.deny state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96908,7 +110681,8 @@ fi If /etc/at.allow exists, it must be group-owned by root. To properly set the group owner of /etc/at.allow, run the command: -$ sudo chgrp root /etc/at.allow + + $ sudo chgrp root /etc/at.allow 2.2.6 2.2 @@ -96917,7 +110691,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/at.allow +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/at.allow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/at.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -96936,8 +110722,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_at_allow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_at_allow_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_at_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/at.allow - stat: + ansible.builtin.stat: path: /etc/at.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -96951,10 +110751,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/at.allow - file: +- name: Ensure group owner on /etc/at.allow + ansible.builtin.file: path: /etc/at.allow - group: '0' + follow: false + group: '{{ file_groupowner_at_allow_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -96980,7 +110781,8 @@ fi If /etc/cron.allow exists, it must be group-owned by root. To properly set the group owner of /etc/cron.allow, run the command: -$ sudo chgrp root /etc/cron.allow + + $ sudo chgrp root /etc/cron.allow 12 13 @@ -96994,7 +110796,6 @@ To properly set the group owner of /etc/cron.allow, run t DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -97025,7 +110826,7 @@ To properly set the group owner of /etc/cron.allow, run t AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the owner of the cron.allow file is not set to root, the possibility exists for an @@ -97033,7 +110834,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/cron.allow +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/cron.allow" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/cron.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -97054,8 +110867,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_cron_allow_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_cron_allow_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_groupowner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97071,10 +110900,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/cron.allow - file: +- name: Ensure group owner on /etc/cron.allow + ansible.builtin.file: path: /etc/cron.allow - group: '0' + follow: false + group: '{{ file_groupowner_cron_allow_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -97102,7 +110932,8 @@ fi If /etc/cron.allow exists, it must be owned by root. To properly set the owner of /etc/cron.allow, run the command: -$ sudo chown root /etc/cron.allow + + $ sudo chown root /etc/cron.allow 12 13 @@ -97116,7 +110947,6 @@ To properly set the owner of /etc/cron.allow, run the com DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -97147,7 +110977,7 @@ To properly set the owner of /etc/cron.allow, run the com AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the owner of the cron.allow file is not set to root, the possibility exists for an @@ -97155,7 +110985,19 @@ unauthorized user to view or edit sensitive information. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/cron.allow +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/cron.allow" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/cron.allow +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -97176,8 +111018,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_cron_allow_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_cron_allow_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - configure_strategy + - file_owner_cron_allow + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97193,10 +111051,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/cron.allow - file: +- name: Ensure owner on /etc/cron.allow + ansible.builtin.file: path: /etc/cron.allow - owner: '0' + follow: false + owner: '{{ file_owner_cron_allow_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -97255,7 +111114,7 @@ fi - no_reboot_needed - name: Test for existence /etc/at.allow - stat: + ansible.builtin.stat: path: /etc/at.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97270,7 +111129,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/at.allow - file: + ansible.builtin.file: path: /etc/at.allow mode: u-xs,g-xws,o-xwrt when: @@ -97302,8 +111161,7 @@ or more restrictive. To properly set the permissions of /etc/cron.allow, run the command: $ sudo chmod 0640 /etc/cron.allow - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 2.2.6 2.2 If the permissions of the cron.allow file are not set to 0640 or more restrictive, @@ -97331,7 +111189,7 @@ fi - no_reboot_needed - name: Test for existence /etc/cron.allow - stat: + ansible.builtin.stat: path: /etc/cron.allow register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -97346,7 +111204,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/cron.allow - file: + ansible.builtin.file: path: /etc/cron.allow mode: u-xs,g-xws,o-xwrt when: @@ -97473,17 +111331,18 @@ data transmission between client and server. Any confidential data can be listened and no integrity checking is made. # CAUTION: This remediation script will remove inetutils-telnetd -# from the system, and may remove any packages -# that depend on inetutils-telnetd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on inetutils-telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "inetutils-telnetd" ; then yum remove -y "inetutils-telnetd" fi - - name: Ensure inetutils-telnetd is removed - package: + - name: 'Uninstall the inet-based telnet server: Ensure inetutils-telnetd is removed' + ansible.builtin.package: name: inetutils-telnetd state: absent tags: @@ -97497,7 +111356,8 @@ fi - no_reboot_needed - package_inetutils-telnetd_removed - include remove_inetutils-telnetd + +include remove_inetutils-telnetd class remove_inetutils-telnetd { package { 'inetutils-telnetd': @@ -97506,6 +111366,7 @@ class remove_inetutils-telnetd { } + package --remove=inetutils-telnetd @@ -97519,17 +111380,18 @@ package --remove=inetutils-telnetd NIS does not support efficiently security constraints, ACL, etc. and should not be used. # CAUTION: This remediation script will remove nis -# from the system, and may remove any packages -# that depend on nis. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on nis. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "nis" ; then yum remove -y "nis" fi - - name: Ensure nis is removed - package: + - name: 'Uninstall the nis package: Ensure nis is removed' + ansible.builtin.package: name: nis state: absent tags: @@ -97540,7 +111402,8 @@ fi - no_reboot_needed - package_nis_removed - include remove_nis + +include remove_nis class remove_nis { package { 'nis': @@ -97549,6 +111412,7 @@ class remove_nis { } + package --remove=nis @@ -97652,17 +111516,18 @@ package --remove=nis When remote shell is required, up-to-date ssh daemon can be used. # CAUTION: This remediation script will remove telnetd-ssl -# from the system, and may remove any packages -# that depend on telnetd-ssl. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnetd-ssl. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnetd-ssl" ; then yum remove -y "telnetd-ssl" fi - - name: Ensure telnetd-ssl is removed - package: + - name: 'Uninstall the ssl compliant telnet server: Ensure telnetd-ssl is removed' + ansible.builtin.package: name: telnetd-ssl state: absent tags: @@ -97676,7 +111541,8 @@ fi - no_reboot_needed - package_telnetd-ssl_removed - include remove_telnetd-ssl + +include remove_telnetd-ssl class remove_telnetd-ssl { package { 'telnetd-ssl': @@ -97685,6 +111551,7 @@ class remove_telnetd-ssl { } + package --remove=telnetd-ssl @@ -97789,17 +111656,18 @@ any data transmission between client and server. Any confidential data can be listened and no integrity checking is made.' # CAUTION: This remediation script will remove telnetd -# from the system, and may remove any packages -# that depend on telnetd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnetd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnetd" ; then yum remove -y "telnetd" fi - - name: Ensure telnetd is removed - package: + - name: 'Uninstall the telnet server: Ensure telnetd is removed' + ansible.builtin.package: name: telnetd state: absent tags: @@ -97813,7 +111681,8 @@ fi - no_reboot_needed - package_telnetd_removed - include remove_telnetd + +include remove_telnetd class remove_telnetd { package { 'telnetd': @@ -97822,6 +111691,7 @@ class remove_telnetd { } + package --remove=telnetd @@ -98021,7 +111891,6 @@ $ sudo yum erase dhcp-server DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98085,17 +111954,18 @@ $ sudo yum erase dhcp-server accidentally reactivated and disrupt network operation. # CAUTION: This remediation script will remove dhcp -# from the system, and may remove any packages -# that depend on dhcp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on dhcp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "dhcp" ; then yum remove -y "dhcp" fi - - name: Ensure dhcp is removed - package: + - name: 'Uninstall DHCP Server Package: Ensure dhcp is removed' + ansible.builtin.package: name: dhcp state: absent tags: @@ -98111,7 +111981,8 @@ fi - no_reboot_needed - package_dhcp_removed - include remove_dhcp + +include remove_dhcp class remove_dhcp { package { 'dhcp': @@ -98120,6 +111991,7 @@ class remove_dhcp { } + package --remove=dhcp @@ -98163,7 +112035,6 @@ $ sudo yum erase bind DSS05.02 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98225,17 +112096,18 @@ $ sudo yum erase bind removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove bind -# from the system, and may remove any packages -# that depend on bind. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on bind. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "bind" ; then yum remove -y "bind" fi - - name: Ensure bind is removed - package: + - name: 'Uninstall bind Package: Ensure bind is removed' + ansible.builtin.package: name: bind state: absent tags: @@ -98249,7 +112121,8 @@ fi - no_reboot_needed - package_bind_removed - include remove_bind + +include remove_bind class remove_bind { package { 'bind': @@ -98258,6 +112131,7 @@ class remove_bind { } + package --remove=bind @@ -98282,16 +112156,15 @@ makes use of the kernel's fanotify interface to determine $ sudo yum install fapolicyd - CCI-001774 - CCI-001764 CM-6(a) SI-4(22) FMT_SMF_EXT.1 - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - OL09-00-000340 - SV-271506r1091230_rule + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + 1409 + OL09-00-000340 + SV-271506r1091230_rule fapolicyd (File Access Policy Daemon) implements application whitelisting to decide file access rights. # Remediation is applicable only in certain platforms @@ -98320,7 +112193,7 @@ fi - package_fapolicyd_installed - name: Ensure fapolicyd is installed - package: + ansible.builtin.package: name: fapolicyd state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -98365,16 +112238,15 @@ version = "*" The fapolicyd service can be enabled with the following command: $ sudo systemctl enable fapolicyd.service - CCI-001774 - CCI-001764 CM-6(a) SI-4(22) FMT_SMF_EXT.1 - SRG-OS-000370-GPOS-00155 - SRG-OS-000368-GPOS-00154 - SRG-OS-000480-GPOS-00230 - OL09-00-000341 - SV-271507r1091233_rule + SRG-OS-000370-GPOS-00155 + SRG-OS-000368-GPOS-00154 + SRG-OS-000480-GPOS-00230 + 1409 + OL09-00-000341 + SV-271507r1091233_rule The fapolicyd service (File Access Policy Daemon) implements application whitelisting to decide file access rights. # Remediation is applicable only in certain platforms @@ -98409,7 +112281,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the File Access Policy Service - Enable Service fapolicyd @@ -98420,7 +112292,6 @@ fi masked: false when: - '"fapolicyd" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000341 - NIST-800-53-CM-6(a) @@ -98431,6 +112302,8 @@ fi - medium_severity - no_reboot_needed - service_fapolicyd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_fapolicyd @@ -98445,6 +112318,10 @@ class enable_fapolicyd { [customizations.services] enabled = ["fapolicyd"] + + + + @@ -98455,13 +112332,12 @@ enabled = ["fapolicyd"] Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. The Fapolicy module must be configured to employ a deny-all, permit-by-exception policy to allow the execution of authorized software programs and to prevent unauthorized software from running. - CCI-001764 CM-7 (2) CM-7 (5) (b) CM-6 b - SRG-OS-000368-GPOS-00154 - SRG-OS-000370-GPOS-00155 - SRG-OS-000480-GPOS-00232 + SRG-OS-000368-GPOS-00154 + SRG-OS-000370-GPOS-00155 + SRG-OS-000480-GPOS-00232 Utilizing a whitelist provides a configuration management method for allowing the execution of only authorized software. Using only authorized software decreases risk by limiting the number of potential vulnerabilities. Verification of whitelisted software occurs prior to execution or at system startup. @@ -98513,6 +112389,22 @@ fi - no_reboot_needed - restrict_strategy +- name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy + to Allow the Execution of Authorized Software Programs. - Gather the package facts + ansible.builtin.package_facts: + manager: auto + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-CM-6 b + - NIST-800-53-CM-7 (2) + - NIST-800-53-CM-7 (5) (b) + - fapolicy_default_deny + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. - Ensure a Final Rule Denying Everything @@ -98523,8 +112415,10 @@ fi owner: root group: fapolicyd mode: '0644' + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' register: result_fapolicyd_final_rule - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6 b - NIST-800-53-CM-7 (2) @@ -98544,8 +112438,10 @@ fi regexp: ^(permissive\s*=).*$ line: \1 0 backrefs: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' register: result_fapolicyd_enforced - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-CM-6 b - NIST-800-53-CM-7 (2) @@ -98565,6 +112461,7 @@ fi state: restarted when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"fapolicyd" in ansible_facts.packages' - result_fapolicyd_final_rule is changed or result_fapolicyd_enforced is changed tags: - NIST-800-53-CM-6 b @@ -98589,9 +112486,8 @@ fi fapolicyd needs be configured so that users cannot give access to their home folders to other users. This rule is deprecated and there is no replacement at this time. Previous versions of this rule provided fixtext that would cause fapolicyd not to start. - CCI-000366 CM-6 b - SRG-OS-000480-GPOS-00230 + SRG-OS-000480-GPOS-00230 Users' home directories/folders may contain information of a sensitive nature. Non-privileged users should coordinate any sharing of information with a System Administrator (SA) through shared resources. fapolicyd can confine users to their home directory, not allowing them to make any changes outside of their own home directories. @@ -98629,17 +112525,18 @@ to run the system as a FTP server (for example, to allow anonymous downloads), i recommended that the package be removed to reduce the potential attack surface. # CAUTION: This remediation script will remove ftp -# from the system, and may remove any packages -# that depend on ftp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on ftp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "ftp" ; then yum remove -y "ftp" fi - - name: Ensure ftp is removed - package: + - name: 'Remove ftp Package: Ensure ftp is removed' + ansible.builtin.package: name: ftp state: absent tags: @@ -98652,7 +112549,8 @@ fi - no_reboot_needed - package_ftp_removed - include remove_ftp + +include remove_ftp class remove_ftp { package { 'ftp': @@ -98661,6 +112559,7 @@ class remove_ftp { } + package --remove=ftp @@ -98689,9 +112588,6 @@ possible. DSS05.02 DSS05.05 DSS06.06 - CCI-000366 - CCI-000197 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -98752,27 +112648,28 @@ possible. CM-7.1(ii) PR.IP-1 PR.PT-3 - SRG-OS-000074-GPOS-00042 - SRG-OS-000095-GPOS-00049 - SRG-OS-000480-GPOS-00227 + SRG-OS-000074-GPOS-00042 + SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 A.8.SEC-OL4 - OL09-00-000130 - SV-271462r1091098_rule + OL09-00-000130 + SV-271462r1091098_rule Removing the vsftpd package decreases the risk of its accidental activation. # CAUTION: This remediation script will remove vsftpd -# from the system, and may remove any packages -# that depend on vsftpd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on vsftpd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "vsftpd" ; then yum remove -y "vsftpd" fi - - name: Ensure vsftpd is removed - package: + - name: 'Uninstall vsftpd Package: Ensure vsftpd is removed' + ansible.builtin.package: name: vsftpd state: absent tags: @@ -98791,7 +112688,8 @@ fi - no_reboot_needed - package_vsftpd_removed - include remove_vsftpd + +include remove_vsftpd class remove_vsftpd { package { 'vsftpd': @@ -98800,6 +112698,7 @@ class remove_vsftpd { } + package --remove=vsftpd @@ -98875,17 +112774,18 @@ $ sudo yum erase cyrus-imapd removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove cyrus-imapd -# from the system, and may remove any packages -# that depend on cyrus-imapd. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on cyrus-imapd. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "cyrus-imapd" ; then yum remove -y "cyrus-imapd" fi - - name: Ensure cyrus-imapd is removed - package: + - name: 'Uninstall cyrus-imapd Package: Ensure cyrus-imapd is removed' + ansible.builtin.package: name: cyrus-imapd state: absent tags: @@ -98896,7 +112796,8 @@ fi - package_cyrus-imapd_removed - unknown_severity - include remove_cyrus-imapd + +include remove_cyrus-imapd class remove_cyrus-imapd { package { 'cyrus-imapd': @@ -98905,6 +112806,7 @@ class remove_cyrus-imapd { } + package --remove=cyrus-imapd @@ -98931,17 +112833,18 @@ $ sudo yum erase dovecot removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove dovecot -# from the system, and may remove any packages -# that depend on dovecot. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on dovecot. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "dovecot" ; then yum remove -y "dovecot" fi - - name: Ensure dovecot is removed - package: + - name: 'Uninstall dovecot Package: Ensure dovecot is removed' + ansible.builtin.package: name: dovecot state: absent tags: @@ -98952,7 +112855,8 @@ fi - package_dovecot_removed - unknown_severity - include remove_dovecot + +include remove_dovecot class remove_dovecot { package { 'dovecot': @@ -98961,6 +112865,7 @@ class remove_dovecot { } + package --remove=dovecot @@ -99005,8 +112910,7 @@ The postfix package can be installed with the following c $ sudo yum install postfix - CCI-000139 - SRG-OS-000046-GPOS-00022 + SRG-OS-000046-GPOS-00022 Emails can be used to notify designated personnel about important system events such as failures or warnings. # Remediation is applicable only in certain platforms @@ -99032,7 +112936,7 @@ fi - package_postfix_installed - name: Ensure postfix is installed - package: + ansible.builtin.package: name: postfix state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99074,11 +112978,10 @@ The s-nail package can be installed with the following co $ sudo yum install s-nail - CCI-001744 CM-3(5) - SRG-OS-000363-GPOS-00150 - OL09-00-000290 - SV-271495r1091197_rule + SRG-OS-000363-GPOS-00150 + OL09-00-000290 + SV-271495r1091197_rule Emails can be used to notify designated personnel about important system events such as failures or warnings. # Remediation is applicable only in certain platforms @@ -99106,7 +113009,7 @@ fi - package_s-nail_installed - name: Ensure s-nail is installed - package: + ansible.builtin.package: name: s-nail state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99162,8 +113065,6 @@ $ sudo yum erase sendmail DSS05.02 DSS05.05 DSS06.06 - CCI-000366 - CCI-000381 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -99220,11 +113121,11 @@ $ sudo yum erase sendmail CM-6(a) PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 - SRG-OS-000095-GPOS-00049 + SRG-OS-000480-GPOS-00227 + SRG-OS-000095-GPOS-00049 R62 - OL09-00-000150 - SV-271466r1091110_rule + OL09-00-000150 + SV-271466r1091110_rule The sendmail software was not developed with security in mind and its design prevents it from being effectively contained by SELinux. Postfix should be used instead. @@ -99232,10 +113133,11 @@ should be used instead. if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # CAUTION: This remediation script will remove sendmail -# from the system, and may remove any packages -# that depend on sendmail. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on sendmail. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "sendmail" ; then yum remove -y "sendmail" @@ -99260,8 +113162,8 @@ fi - no_reboot_needed - package_sendmail_removed -- name: Ensure sendmail is removed - package: +- name: 'Uninstall Sendmail Package: Ensure sendmail is removed' + ansible.builtin.package: name: sendmail state: absent when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -99277,7 +113179,8 @@ fi - no_reboot_needed - package_sendmail_removed - include remove_sendmail + +include remove_sendmail class remove_sendmail { package { 'sendmail': @@ -99286,6 +113189,7 @@ class remove_sendmail { } + package --remove=sendmail @@ -99336,7 +113240,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable Postfix Service - Enable Service postfix @@ -99347,14 +113251,15 @@ fi masked: false when: - '"postfix" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity - low_disruption - no_reboot_needed - service_postfix_enabled + - special_service_block - unknown_severity + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_postfix @@ -99369,6 +113274,10 @@ class enable_postfix { [customizations.services] enabled = ["postfix"] + + + + @@ -99408,12 +113317,11 @@ configure the alias: $ sudo echo "root: " >> /etc/aliases $ sudo newaliases - CCI-000139 CM-6(a) - SRG-OS-000046-GPOS-00022 + SRG-OS-000046-GPOS-00022 R75 - OL09-00-002405 - SV-271744r1091944_rule + OL09-00-002405 + SV-271744r1091944_rule A number of system services utilize email messages sent to the root user to notify system administrators of active or impending issues. These messages must be forwarded to at least one monitored email address. @@ -99433,12 +113341,11 @@ Check that the "/etc/aliases" file has a defined value for "root". postmaster: root - CCI-000139 AU-5(a) AU-5.1(ii) - SRG-OS-000046-GPOS-00022 - OL09-00-000815 - SV-271589r1091479_rule + SRG-OS-000046-GPOS-00022 + OL09-00-000815 + SV-271589r1091479_rule It is critical for the appropriate personnel to be aware if a system is at risk of failing to process audit logs as required. Without this notification, the security personnel may be unaware of an impending failure of the audit capability, and system operation may be adversely @@ -99490,7 +113397,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* @@ -99500,7 +113407,7 @@ fi register: dupes - name: Deduplicate values from /etc/aliases - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* @@ -99508,12 +113415,13 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/aliases - lineinfile: + ansible.builtin.lineinfile: path: /etc/aliases create: true regexp: (?i)^\s*postmaster\s*:\s* line: 'postmaster: root' state: present + register: aliases_postmaster_changed when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000815 @@ -99526,7 +113434,8 @@ fi - no_reboot_needed - postfix_client_configure_mail_alias_postmaster -- name: Check if newaliases command is available +- name: Configure System to Forward All Mail From Postmaster to The Root Account - + Check if newaliases command is available ansible.builtin.stat: path: /usr/bin/newaliases register: result_newaliases_present @@ -99542,12 +113451,14 @@ fi - no_reboot_needed - postfix_client_configure_mail_alias_postmaster -- name: Update postfix aliases +- name: Configure System to Forward All Mail From Postmaster to The Root Account - + Update postfix aliases ansible.builtin.command: cmd: newaliases when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - result_newaliases_present.stat.exists + - aliases_postmaster_changed is changed tags: - DISA-STIG-OL09-00-000815 - NIST-800-53-AU-5(a) @@ -99600,7 +113511,6 @@ may help prevent spam or viruses from being delivered. DSS05.02 DSS05.05 DSS06.06 - CCI-000382 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -99691,13 +113601,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: XCCDF Value var_postfix_inet_interfaces # promote to variable - set_fact: - var_postfix_inet_interfaces: !!str - tags: - - always - -- name: Gather list of packages + - name: Gather the package facts package_facts: manager: auto tags: @@ -99712,9 +113616,33 @@ fi - no_reboot_needed - postfix_network_listening_disabled - restrict_strategy +- name: XCCDF Value var_postfix_inet_interfaces # promote to variable + set_fact: + var_postfix_inet_interfaces: !!str + tags: + - always + +- name: Gather list of packages + ansible.builtin.package_facts: + manager: auto + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"postfix" in ansible_facts.packages' + tags: + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-1.4 + - PCI-DSSv4-1.4.2 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - postfix_network_listening_disabled + - restrict_strategy - name: Make changes to Postfix configuration file - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: false regexp: (?i)^inet_interfaces\s*=\s.* @@ -99772,10 +113700,9 @@ trusted to relay unconditionally, configure SMTP AUTH with SSL support.$ sudo postconf -e 'smtpd_client_restrictions = permit_mynetworks,reject' - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002425 - SV-271763r1092001_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002425 + SV-271763r1092001_rule If unrestricted mail relaying is permitted, unauthorized senders could use this host as a mail relay for the purpose of sending spam or other unauthorized activity. @@ -99809,7 +113736,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99819,7 +113746,7 @@ fi register: dupes - name: Deduplicate values from /etc/postfix/main.cf - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99827,7 +113754,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/postfix/main.cf - lineinfile: + ansible.builtin.lineinfile: path: /etc/postfix/main.cf create: true regexp: (?i)^[ \t]*smtpd_client_restrictions\s*=\s* @@ -99870,10 +113797,9 @@ clients, as well as to those operating as NFS servers. $ sudo yum erase nfs-utils - CCI-000381 - SRG-OS-000095-GPOS-00049 - OL09-00-000100 - SV-271456r1091080_rule + SRG-OS-000095-GPOS-00049 + OL09-00-000100 + SV-271456r1091080_rule nfs-utils provides a daemon for the kernel NFS server and related tools. This package also contains the showmount program. showmount queries the mount daemon on a remote host for information about the Network File System (NFS) server on the @@ -99881,17 +113807,18 @@ remote host. For example, showmount can display the clien that host. # CAUTION: This remediation script will remove nfs-utils -# from the system, and may remove any packages -# that depend on nfs-utils. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on nfs-utils. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "nfs-utils" ; then yum remove -y "nfs-utils" fi - - name: Ensure nfs-utils is removed - package: + - name: 'Uninstall nfs-utils Package: Ensure nfs-utils is removed' + ansible.builtin.package: name: nfs-utils state: absent tags: @@ -99903,7 +113830,8 @@ fi - no_reboot_needed - package_nfs-utils_removed - include remove_nfs-utils + +include remove_nfs-utils class remove_nfs-utils { package { 'nfs-utils': @@ -99912,6 +113840,7 @@ class remove_nfs-utils { } + package --remove=nfs-utils @@ -99955,7 +113884,6 @@ any NFS mounts. DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -99995,9 +113923,9 @@ any NFS mounts. AC-17(a) PR.AC-4 PR.AC-7 - SRG-OS-000480-GPOS-00227 - OL09-00-002010 - SV-271640r1091632_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002010 + SV-271640r1091632_rule When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle requests from the remote user. The userid and groupid could mistakenly or maliciously be set incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client @@ -100057,7 +113985,8 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have sec=krb5:krb5i:krb5p - command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nosec=krb5:krb5i:krb5p + -n -P register: points_register check_mode: false changed_when: false @@ -100080,7 +114009,7 @@ fi - no_reboot_needed - name: Add sec=krb5:krb5i:krb5p to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100132,7 +114061,6 @@ any NFS mounts. DSS05.05 DSS05.06 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -100195,9 +114123,9 @@ any NFS mounts. PR.IP-1 PR.PT-2 PR.PT-3 - SRG-OS-000480-GPOS-00227 - OL09-00-002011 - SV-271641r1091635_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002011 + SV-271641r1091635_rule Legitimate device files should only exist in the /dev directory. NFS mounts should not present device files to users. @@ -100250,7 +114178,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have nodev - command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonodev -n -P register: points_register check_mode: false changed_when: false @@ -100268,7 +114196,7 @@ fi - no_reboot_needed - name: Add nodev to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100312,7 +114240,6 @@ any NFS mounts. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -100345,9 +114272,9 @@ any NFS mounts. CM-6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002012 - SV-271642r1092593_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002012 + SV-271642r1092593_rule The noexec mount option causes the system not to execute binary files. This option must be used for mounting any file system not containing approved binary files as they may be incompatible. Executing files from untrusted file systems increases the opportunity for unprivileged users to attain unauthorized @@ -100404,7 +114331,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have noexec - command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n -P register: points_register check_mode: false changed_when: false @@ -100424,7 +114351,7 @@ fi - no_reboot_needed - name: Add noexec to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100470,7 +114397,6 @@ any NFS mounts. DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -100502,9 +114428,9 @@ any NFS mounts. CM6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002013 - SV-271643r1091641_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002013 + SV-271643r1091641_rule NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables should be installed to their default location on the local filesystem. @@ -100558,7 +114484,7 @@ fi - no_reboot_needed - name: Get nfs and nfs4 mount points, that don't have nosuid - command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P + ansible.builtin.command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n -P register: points_register check_mode: false changed_when: false @@ -100577,7 +114503,7 @@ fi - no_reboot_needed - name: Add nosuid to nfs and nfs4 mount points - mount: + ansible.posix.mount: path: '{{ item | regex_search(''TARGET="([^"]+)"'',''\1'') | first }}' src: '{{ item | regex_search(''SOURCE="([^"]+)"'',''\1'') | first }}' fstype: '{{ item | regex_search(''FSTYPE="([^"]+)"'',''\1'') | first }}' @@ -100639,7 +114565,6 @@ add sec=krb5:krb5i:krb5p to each export in /et DSS05.04 DSS05.10 DSS06.10 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -100685,12 +114610,15 @@ add sec=krb5:krb5i:krb5p to each export in /et AC-17(a) PR.AC-4 PR.AC-7 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 When an NFS server is configured to use AUTH_SYS a selected userid and groupid are used to handle requests from the remote user. The userid and groupid could mistakenly or maliciously be set incorrectly. The AUTH_GSS method of authentication uses certificates on the server and client systems to more securely authenticate the remote mount request. - + + # Remediation is applicable only in certain platforms +if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + nfs_exports=() readarray -t nfs_exports < <(grep -E "^/.*[[:space:]]+ .*\(.*\)[[:space:]]*$" /etc/exports | awk '{print $2}') @@ -100704,12 +114632,35 @@ do fi sed -i "s|$nfs_export|$correct_export|g" /etc/exports done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi - - name: Drop any security clause for every export - replace: + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(8) + - NIST-800-53-IA-2(9) + - configure_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - use_kerberos_security_all_exports + +- name: Drop any security clause for every export + ansible.builtin.replace: path: /etc/exports regexp: ^(/.*\w+.*\(.*),sec=[^,]*(.*\)\w*$) replace: \1\2 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -100726,10 +114677,11 @@ done - use_kerberos_security_all_exports - name: Add kerberos security when no security is defined for an export - replace: + ansible.builtin.replace: path: /etc/exports regexp: ^(/.*\w+.*\(.*)(\)\w*$) replace: \1,sec=krb5:krb5i:krb5p\2 + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(a) @@ -100790,7 +114742,7 @@ packages respectively. The default chronyd daemon can work well when external time references -are only intermittently accesible, can perform well even when the network is +are only intermittently accessible, can perform well even when the network is congested for longer periods of time, can usually synchronize the clock faster and with better time accuracy, and quickly adapts to sudden changes in the rate of the clock, for example, due to changes in the temperature of the crystal @@ -100835,6 +114787,8 @@ information on the capabilities and configuration of each of the NTP daemons.0.ntp.cloud.aliyuncs.com,1.ntp.aliyun.com,2.ntp1.aliyun.com,3.ntp1.cloud.aliyuncs.com 0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org + 0.debian.pool.ntp.org,1.debian.pool.ntp.org,2.debian.pool.ntp.org,3.debian.pool.ntp.org + time.nist.gov Vendor Approved Time Servers @@ -100850,6 +114804,8 @@ information on the capabilities and configuration of each of the NTP daemons.0.rhel.pool.ntp.org,1.rhel.pool.ntp.org,2.rhel.pool.ntp.org,3.rhel.pool.ntp.org 0.ubuntu.pool.ntp.org,1.ubuntu.pool.ntp.org,2.ubuntu.pool.ntp.org,3.ubuntu.pool.ntp.org 0.almalinux.pool.ntp.org,1.almalinux.pool.ntp.org,2.almalinux.pool.ntp.org,3.almalinux.pool.ntp.org + 0.debian.pool.ntp.org,1.debian.pool.ntp.org,2.debian.pool.ntp.org,3.debian.pool.ntp.org + time.nist.gov,time-a-g.nist.gov,time-b-g.nist.gov,time-c-g.nist.gov Maximum NTP or Chrony Poll @@ -100868,18 +114824,17 @@ The chrony package can be installed with the following co $ sudo yum install chrony - CCI-004923 - 0988 - 1405 FMT_SMF_EXT.1 Req-10.4 - SRG-OS-000355-GPOS-00143 + SRG-OS-000355-GPOS-00143 R71 A.3.SEC-OL3 + 0988 + 1405 10.6.1 10.6 - OL09-00-000310 - SV-271501r1091215_rule + OL09-00-000310 + SV-271501r1091215_rule Time synchronization is important to support time sensitive security mechanisms like Kerberos and also ensures log files have consistent time records across the enterprise, which aids in forensic investigations. @@ -100910,7 +114865,7 @@ fi - package_chrony_installed - name: Ensure chrony is installed - package: + ansible.builtin.package: name: chrony state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -100960,12 +114915,12 @@ Chrony can be configured to be a client and/or a server. To enable Chronyd service, you can run: # systemctl enable chronyd.service This recommendation only applies if chrony is in use on the system. - CCI-004923 + SRG-OS-000355-GPOS-00143 + R71 0988 1405 - SRG-OS-000355-GPOS-00143 - OL09-00-000311 - SV-271502r1091218_rule + OL09-00-000311 + SV-271502r1091218_rule If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly. @@ -100999,7 +114954,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: The Chronyd service is enabled - Enable Service chronyd @@ -101010,9 +114965,6 @@ fi masked: false when: - '"chrony" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"chrony" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-000311 - enable_strategy @@ -101021,6 +114973,10 @@ fi - medium_severity - no_reboot_needed - service_chronyd_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"chrony" in ansible_facts.packages' include enable_chronyd @@ -101035,6 +114991,10 @@ class enable_chronyd { [customizations.services] enabled = ["chronyd"] + + + + @@ -101053,17 +115013,14 @@ accurate. More information on chrony can be found at Add or edit server or pool lines to /etc/chrony.conf as appropriate: server <remote-server> Multiple servers may be configured. - CCI-001890 - CCI-004926 - CCI-004923 - 0988 - 1405 CM-6(a) AU-8(1)(a) Req-10.4.3 - SRG-OS-000355-GPOS-00143 + SRG-OS-000355-GPOS-00143 R71 A.3.SEC-OL3 + 0988 + 1405 10.6.2 10.6 If chrony is in use on the system proper configuration is vital to ensuring time @@ -101085,6 +115042,9 @@ if ! grep -q '^[[:space:]]*\(server\|pool\)[[:space:]]\+[[:graph:]]\+' "$config_ else sed -i 's/#[ \t]*server/server/g' "$config_file" fi + if [[ -s "$config_file" ]] && [[ -n "$(tail -c 1 -- "$config_file" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "$config_file" + fi fi else @@ -101113,7 +115073,7 @@ fi - always - name: Detect if chrony is already configured with pools or servers - find: + ansible.builtin.find: path: /etc patterns: chrony.conf contains: ^[\s]*(?:server|pool)[\s]+[\w]+ @@ -101135,7 +115095,7 @@ fi - no_reboot_needed - name: Configure remote time servers - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: server {{ item }} state: present @@ -101170,15 +115130,13 @@ fi The port option in /etc/chrony.conf can be set to 0 to make chrony daemon to never open any listening port for server operation and to operate strictly in a client-only mode. - CCI-000382 - CCI-000381 AU-8(1) AU-12(1) FMT_SMF_EXT.1 - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - OL09-00-002320 - SV-271697r1091803_rule + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002320 + SV-271697r1091803_rule In order to prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. Operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component. To support the requirements and principles of least functionality, the operating system must support the organizational requirements, providing only essential capabilities and limiting the use of ports, protocols, and/or services to only those required, authorized, and approved to conduct official business or to address authorized quality of life issues. @@ -101228,7 +115186,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101238,7 +115196,7 @@ fi register: dupes - name: Deduplicate values from /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101246,7 +115204,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*port\s+ @@ -101284,14 +115242,12 @@ accurate. More information on chrony can be found at Add or edit server or pool lines to /etc/chrony.conf as appropriate: server <remote-server> Multiple servers may be configured. - CCI-000160 - CCI-001891 - 0988 - 1405 CM-6(a) AU-8(1)(a) Req-10.4.3 R71 + 0988 + 1405 If chrony is in use on the system proper configuration is vital to ensuring time synchronization is working properly. @@ -101419,13 +115375,11 @@ fi The cmdport option in /etc/chrony.conf can be set to 0 to stop chrony daemon from listening on the UDP port 323 for management connections made by chronyc. - CCI-000382 - CCI-000381 CM-7(1) - SRG-OS-000096-GPOS-00050 - SRG-OS-000095-GPOS-00049 - OL09-00-002321 - SV-271698r1091806_rule + SRG-OS-000096-GPOS-00050 + SRG-OS-000095-GPOS-00049 + OL09-00-002321 + SV-271698r1091806_rule Minimizing the exposure of the server functionality of the chrony daemon diminishes the attack surface. @@ -101473,7 +115427,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101483,7 +115437,7 @@ fi register: dupes - name: Deduplicate values from /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101491,7 +115445,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/chrony.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf create: true regexp: (?i)^\s*cmdport\s+ @@ -101540,9 +115494,6 @@ should be configured too. DSS05.04 DSS05.07 MEA02.01 - CCI-001890 - CCI-004926 - CCI-004923 4.3.3.3.9 4.3.3.5.8 4.3.4.4.7 @@ -101563,11 +115514,11 @@ should be configured too. AU-8(1)(b) AU-12(1) PR.PT-1 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - OL09-00-002323 - SV-271699r1091809_rule + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule Inaccurate time stamps make it more difficult to correlate events and can lead to an inaccurate analysis. Determining the correct time a particular event occurred on a system is critical when conducting forensic analysis and investigating system events. Sources outside the configured acceptable allowance (drift) may be inaccurate. Synchronizing internal information system clocks provides uniformity of time stamps for information systems with multiple system clocks and systems connected over a network. Organizations should consider endpoints that may not have regular access to the authoritative time server (e.g., mobile, teleworking, and tactical endpoints). @@ -101586,7 +115537,9 @@ pof="/usr/sbin/pidof" CONFIG_FILES="/etc/ntp.conf" $pof ntpd || { CHRONY_D_PATH=/etc/chrony.d/ + mapfile -t CONFIG_FILES < <(find ${CHRONY_D_PATH}.* -type f -name '*.conf') + CONFIG_FILES+=(/etc/chrony.conf) } @@ -101830,9 +115783,6 @@ production environment, the Oracle Linux 9 system can be configured to utilize the services of the chronyd NTP daemon (the default), or services of the ntpd NTP daemon. Refer to - - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-configuring_ntp_using_the_chrony_suite - for more detailed comparison of the features of both of the choices, and for further guidance how to choose between the two NTP daemons. @@ -101869,8 +115819,6 @@ hostname of a remote NTP server for ntpserver: SR 2.12 SR 2.8 SR 2.9 - 0988 - 1405 A.12.4.1 A.12.4.2 A.12.4.3 @@ -101882,6 +115830,8 @@ hostname of a remote NTP server for ntpserver: AU-12(1) PR.PT-1 Req-10.4.3 + 0988 + 1405 Specifying additional NTP servers increases the availability of accurate time data, in the event that one of the specified servers becomes unavailable. This is typical for a system acting as an NTP server for @@ -101904,6 +115854,9 @@ if ! [ "$(grep -c '^server' "$config_file")" -gt 1 ] ; then else sed -i 's/#[ \t]*server/server/g' "$config_file" fi + if [[ -s "$config_file" ]] && [[ -n "$(tail -c 1 -- "$config_file" || true)" ]]; then + LC_ALL=C sed -i --follow-symlinks '$a'\\ "$config_file" + fi fi else @@ -101932,7 +115885,7 @@ fi - always - name: Detect if chrony configuration file is present - find: + ansible.builtin.find: path: /etc patterns: chrony.conf register: chrony_server_config @@ -101953,7 +115906,7 @@ fi - no_reboot_needed - name: Configure multiple time servers in chrony config - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: server {{ item }} state: present @@ -101977,7 +115930,7 @@ fi - no_reboot_needed - name: Detect if NTP configuration file is present - find: + ansible.builtin.find: path: /etc patterns: ntp.conf register: ntp_server_config @@ -101998,7 +115951,7 @@ fi - no_reboot_needed - name: Configure multiple time servers in NTP config - lineinfile: + ansible.builtin.lineinfile: path: /etc/chrony.conf line: pool {{ item }} state: present @@ -102078,7 +116031,7 @@ fi - no_reboot_needed - name: Detect if file /etc/sysconfig/chronyd is not empty or missing - find: + ansible.builtin.find: path: /etc/sysconfig/ patterns: chronyd contains: ^([\s]*OPTIONS=["]?[^"]*)("?) @@ -102097,7 +116050,7 @@ fi - no_reboot_needed - name: Remove any previous configuration of user used to run chronyd process - replace: + ansible.builtin.replace: path: /etc/sysconfig/chronyd regexp: \s*-u\s*\w+\s* replace: ' ' @@ -102126,14 +116079,11 @@ fi Ensure Chrony is only configured with the server directive Check that Chrony only has time sources configured with the server directive. This rule doesn't come with a remediation, the time source needs to be added by the administrator. - CCI-001890 - CCI-004926 - CCI-004923 - SRG-OS-000355-GPOS-00143 - SRG-OS-000356-GPOS-00144 - SRG-OS-000359-GPOS-00146 - OL09-00-002323 - SV-271699r1091809_rule + SRG-OS-000355-GPOS-00143 + SRG-OS-000356-GPOS-00144 + SRG-OS-000359-GPOS-00146 + OL09-00-002323 + SV-271699r1091809_rule Depending on the infrastructure being used the pool directive may not be supported. Using the server directive allows for better control of where the system gets time data from. @@ -102146,7 +116096,8 @@ Using the server directive allows for better control of w Verify Group Who Owns /etc/chrony.keys File - To properly set the group owner of /etc/chrony.keys, run the command: $ sudo chgrp chrony /etc/chrony.keys + To properly set the group owner of /etc/chrony.keys, run the command: +$ sudo chgrp chrony /etc/chrony.keys R50 The ownership of the /etc/chrony.keys file by the chrony group is important @@ -102156,7 +116107,19 @@ chrony ensures exclusive control of the chrony cryptography keys.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp chrony /etc/chrony.keys +newgroup="" +if getent group "chrony" >/dev/null 2>&1; then + newgroup="chrony" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "chrony is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/chrony.keys" | grep -E -w -q "chrony"; then + chgrp --no-dereference "$newgroup" /etc/chrony.keys +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -102173,8 +116136,38 @@ fi - medium_severity - no_reboot_needed +- name: Check that the chrony group is defined + ansible.builtin.getent: + database: group + key: chrony + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupowner_etc_chrony_keys_newgroup is undefined + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupowner_etc_chrony_keys_newgroup variable if chrony found + ansible.builtin.set_fact: + file_groupowner_etc_chrony_keys_newgroup: chrony + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["chrony"] is defined + tags: + - configure_strategy + - file_groupowner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102186,10 +116179,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner chrony on /etc/chrony.keys - file: +- name: Ensure group owner on /etc/chrony.keys + ansible.builtin.file: path: /etc/chrony.keys - group: chrony + follow: false + group: '{{ file_groupowner_etc_chrony_keys_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -102210,7 +116204,8 @@ fi Verify User Who Owns /etc/chrony.keys File - To properly set the owner of /etc/chrony.keys, run the command: $ sudo chown root /etc/chrony.keys + To properly set the owner of /etc/chrony.keys, run the command: +$ sudo chown root /etc/chrony.keys R50 The ownership of the /etc/chrony.keys file by the chrony user is important @@ -102220,7 +116215,19 @@ chrony ensures exclusive control of the chrony cryptographic keys.# Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/chrony.keys +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/chrony.keys" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/chrony.keys +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -102237,8 +116244,20 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_etc_chrony_keys_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_etc_chrony_keys_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_owner_etc_chrony_keys + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102250,10 +116269,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/chrony.keys - file: +- name: Ensure owner on /etc/chrony.keys + ansible.builtin.file: path: /etc/chrony.keys - owner: '0' + follow: false + owner: '{{ file_owner_etc_chrony_keys_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -102302,7 +116322,7 @@ fi - no_reboot_needed - name: Test for existence /etc/chrony.keys - stat: + ansible.builtin.stat: path: /etc/chrony.keys register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -102315,7 +116335,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/chrony.keys - file: + ansible.builtin.file: path: /etc/chrony.keys mode: u-xs,g-xws,o-xwrt when: @@ -102406,78 +116426,50 @@ fi - no_reboot_needed - service_rsyncd_disabled -- name: Ensure rsyncd service is disabled - Collect systemd Services Present in the - System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Ensure rsyncd service is disabled - Disable service rsyncd + block: + + - name: Ensure rsyncd service is disabled - Collect systemd Services Present in + the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Ensure rsyncd service is disabled - Ensure rsyncd.service is Masked + ansible.builtin.systemd: + name: rsyncd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rsyncd.service", multiline=True) + + - name: Unit Socket Exists - rsyncd.socket + ansible.builtin.command: systemctl -q list-unit-files rsyncd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Ensure rsyncd service is disabled - Disable Socket rsyncd + ansible.builtin.systemd: + name: rsyncd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rsyncd.socket", multiline=True) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.4 + - disable_strategy + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - service_rsyncd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Ensure rsyncd service is disabled - Ensure rsyncd.service is Masked - ansible.builtin.systemd: - name: rsyncd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rsyncd.service", multiline=True) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Unit Socket Exists - rsyncd.socket - ansible.builtin.command: systemctl -q list-unit-files rsyncd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled - -- name: Ensure rsyncd service is disabled - Disable Socket rsyncd - ansible.builtin.systemd: - name: rsyncd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rsyncd.socket", multiline=True) - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - service_rsyncd_disabled include disable_rsyncd @@ -102492,6 +116484,10 @@ class disable_rsyncd { [customizations.services] masked = ["rsyncd"] + + + + @@ -102504,244 +116500,6 @@ masked = ["rsyncd"] The Berkeley r-commands are legacy services which allow cleartext remote access and have an insecure trust model. - - Uninstall rsh-server Package - The rsh-server package can be removed with the following command: - -$ sudo yum erase rsh-server - - 11 - 12 - 14 - 15 - 3 - 8 - 9 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.05 - DSS06.06 - CCI-000381 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - 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 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.11.2.6 - A.12.1.2 - A.12.5.1 - A.12.6.2 - A.13.1.1 - A.13.2.1 - A.14.1.3 - A.14.2.2 - A.14.2.3 - A.14.2.4 - A.6.2.1 - A.6.2.2 - A.9.1.2 - CM-7(a) - CM-7(b) - CM-6(a) - IA-5(1)(c) - PR.AC-3 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000095-GPOS-00049 - R62 - 2.2.4 - 2.2 - OL09-00-000105 - SV-271457r1091083_rule - The rsh-server service provides unencrypted remote access service which does not -provide for the confidentiality and integrity of user passwords or the remote session and has very weak -authentication. If a privileged user were to login using this service, the privileged user password -could be compromised. The rsh-server package provides several obsolete and insecure -network services. Removing it decreases the risk of those services' accidental (or intentional) -activation. - -# CAUTION: This remediation script will remove rsh-server -# from the system, and may remove any packages -# that depend on rsh-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh-server" ; then -yum remove -y "rsh-server" -fi - - - name: Ensure rsh-server is removed - package: - name: rsh-server - state: absent - tags: - - DISA-STIG-OL09-00-000105 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh-server_removed - - include remove_rsh-server - -class remove_rsh-server { - package { 'rsh-server': - ensure => 'purged', - } -} - - -package --remove=rsh-server - - - - - - - - - - Uninstall rsh Package - -The rsh package contains the client commands - -for the rsh services - 3.1.13 - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - A.8.2.3 - A.13.1.1 - A.13.2.1 - A.13.2.3 - A.14.1.2 - A.14.1.3 - R62 - 2.2.4 - 2.2 - These legacy clients contain numerous security exposures and have -been replaced with the more secure SSH package. Even if the server is removed, -it is best to ensure the clients are also removed to prevent users from -inadvertently attempting to use these commands and therefore exposing - -their credentials. Note that removing the rsh package removes - -the clients for rsh,rcp, and rlogin. - -# CAUTION: This remediation script will remove rsh -# from the system, and may remove any packages -# that depend on rsh. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "rsh" ; then -yum remove -y "rsh" -fi - - - name: Ensure rsh is removed - package: - name: rsh - state: absent - tags: - - NIST-800-171-3.1.13 - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - package_rsh_removed - - unknown_severity - - include remove_rsh - -class remove_rsh { - package { 'rsh': - ensure => 'purged', - } -} - - -package --remove=rsh - - - - - - - - Disable rlogin Service The rlogin service, which is available with @@ -102779,7 +116537,6 @@ The rlogin socket can be disabled with the following comm DSS06.10 3.1.13 3.4.7 - CCI-001436 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -102921,93 +116678,53 @@ fi - no_reboot_needed - service_rlogin_disabled -- name: Disable rlogin Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable rlogin Service - Disable service rlogin + block: + + - name: Disable rlogin Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable rlogin Service - Ensure rlogin.service is Masked + ansible.builtin.systemd: + name: rlogin.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("rlogin.service", multiline=True) + + - name: Unit Socket Exists - rlogin.socket + ansible.builtin.command: systemctl -q list-unit-files rlogin.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable rlogin Service - Disable Socket rlogin + ansible.builtin.systemd: + name: rlogin.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("rlogin.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_rlogin_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Disable rlogin Service - Ensure rlogin.service is Masked - ansible.builtin.systemd: - name: rlogin.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("rlogin.service", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Unit Socket Exists - rlogin.socket - ansible.builtin.command: systemctl -q list-unit-files rlogin.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled - -- name: Disable rlogin Service - Disable Socket rlogin - ansible.builtin.systemd: - name: rlogin.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("rlogin.socket", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_rlogin_disabled include disable_rlogin @@ -103022,6 +116739,10 @@ class disable_rlogin { [customizations.services] masked = ["rlogin"] + + + + @@ -103035,10 +116756,9 @@ masked = ["rlogin"] system. To remove these files, run the following command to delete them from any location: $ sudo rm /[path]/[to]/[file]/shosts.equiv - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002419 - SV-271757r1092604_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002419 + SV-271757r1092604_rule The shosts.equiv files are used to configure host-based authentication for the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not require interactive identification and authentication of a connection request, @@ -103058,6 +116778,7 @@ done ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -103247,7 +116968,6 @@ location: DSS05.03 DSS05.05 DSS06.06 - CCI-001436 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -103357,7 +117077,7 @@ fi - restrict_strategy - name: Detect .rhosts files in users home directories - find: + ansible.builtin.find: paths: - /root - /home @@ -103380,7 +117100,7 @@ fi - restrict_strategy - name: Remove .rhosts files - file: + ansible.builtin.file: path: '{{ item }}' state: absent with_items: '{{ rhosts_locations.files | map(attribute=''path'') | list }}' @@ -103399,7 +117119,7 @@ fi - restrict_strategy - name: Remove /etc/hosts.equiv file - file: + ansible.builtin.file: path: /etc/hosts.equiv state: absent when: '"rsh-server" in ansible_facts.packages' @@ -103429,10 +117149,9 @@ local system. To remove these files, run the following command to delete them from any location: $ sudo find / -name '.shosts' -type f -delete - CCI-000366 - SRG-OS-000480-GPOS-00227 - OL09-00-002420 - SV-271758r1091986_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002420 + SV-271758r1091986_rule The .shosts files are used to configure host-based authentication for individual users or the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not @@ -103453,6 +117172,7 @@ done ansible.builtin.set_fact: excluded_fstypes: - afs + - autofs - ceph - cifs - smb3 @@ -103616,135 +117336,6 @@ done - - Chat/Messaging Services - The talk software makes it possible for users to send and receive messages -across systems through a terminal session. - - Uninstall talk-server Package - The talk-server package can be removed with the following command: $ sudo yum erase talk-server - - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - R62 - 2.2.4 - 2.2 - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk-server package decreases the -risk of the accidental (or intentional) activation of talk services. - -# CAUTION: This remediation script will remove talk-server -# from the system, and may remove any packages -# that depend on talk-server. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk-server" ; then -yum remove -y "talk-server" -fi - - - name: Ensure talk-server is removed - package: - name: talk-server - state: absent - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk-server_removed - - include remove_talk-server - -class remove_talk-server { - package { 'talk-server': - ensure => 'purged', - } -} - - -package --remove=talk-server - - - - - - - - - - Uninstall talk Package - The talk package contains the client program for the -Internet talk protocol, which allows the user to chat with other users on -different systems. Talk is a communication program which copies lines from one -terminal to the terminal of another user. -The talk package can be removed with the following command: - -$ sudo yum erase talk - - 164.308(a)(4)(i) - 164.308(b)(1) - 164.308(b)(3) - 164.310(b) - 164.312(e)(1) - 164.312(e)(2)(ii) - R62 - 2.2.4 - 2.2 - The talk software presents a security risk as it uses unencrypted protocols -for communications. Removing the talk package decreases the -risk of the accidental (or intentional) activation of talk client program. - -# CAUTION: This remediation script will remove talk -# from the system, and may remove any packages -# that depend on talk. Execute this -# remediation AFTER testing on a non-production -# system! - -if rpm -q --quiet "talk" ; then -yum remove -y "talk" -fi - - - name: Ensure talk is removed - package: - name: talk - state: absent - tags: - - PCI-DSSv4-2.2 - - PCI-DSSv4-2.2.4 - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_talk_removed - - include remove_talk - -class remove_talk { - package { 'talk': - ensure => 'purged', - } -} - - -package --remove=talk - - - - - - - - - Telnet The telnet protocol does not provide confidentiality or integrity @@ -103774,7 +117365,6 @@ $ sudo yum erase telnet-server DSS05.03 DSS05.05 DSS06.06 - CCI-000381 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -103855,17 +117445,18 @@ $ sudo yum erase telnet-server PR.PT-3 PR.PT-4 Req-2.2.2 - SRG-OS-000095-GPOS-00049 + SRG-OS-000095-GPOS-00049 R62 A.8.SEC-OL4 + 1409 2.2.4 2.2 - OL09-00-000110 - SV-271458r1091086_rule + OL09-00-000110 + SV-271458r1091086_rule It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or mission objectives. These unnecessary capabilities are often overlooked and therefore may remain -unsecure. They increase the risk to the platform by providing additional +insecure. They increase the risk to the platform by providing additional attack vectors. The telnet service provides an unencrypted remote access service which does @@ -103877,17 +117468,18 @@ Removing the telnet-server package decreases the risk of telnet service's accidental (or intentional) activation. # CAUTION: This remediation script will remove telnet-server -# from the system, and may remove any packages -# that depend on telnet-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnet-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnet-server" ; then yum remove -y "telnet-server" fi - - name: Ensure telnet-server is removed - package: + - name: 'Uninstall telnet-server Package: Ensure telnet-server is removed' + ansible.builtin.package: name: telnet-server state: absent tags: @@ -103905,7 +117497,8 @@ fi - no_reboot_needed - package_telnet-server_removed - include remove_telnet-server + +include remove_telnet-server class remove_telnet-server { package { 'telnet-server': @@ -103914,6 +117507,7 @@ class remove_telnet-server { } + package --remove=telnet-server @@ -103941,6 +117535,7 @@ the telnet protocol. A.14.1.2 A.14.1.3 R62 + 1409 2.2.4 2.2 The telnet protocol is insecure and unencrypted. The use @@ -103949,17 +117544,18 @@ to steal credentials. The ssh package provides an encrypted session and stronger security and is included in Oracle Linux 9. # CAUTION: This remediation script will remove telnet -# from the system, and may remove any packages -# that depend on telnet. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on telnet. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "telnet" ; then yum remove -y "telnet" fi - - name: Ensure telnet is removed - package: + - name: 'Remove telnet Clients: Ensure telnet is removed' + ansible.builtin.package: name: telnet state: absent tags: @@ -103973,7 +117569,8 @@ fi - no_reboot_needed - package_telnet_removed - include remove_telnet + +include remove_telnet class remove_telnet { package { 'telnet': @@ -103982,6 +117579,7 @@ class remove_telnet { } + package --remove=telnet @@ -104122,6 +117720,7 @@ telnet is not created automatically, therefore it might have different names.PR.IP-1 PR.PT-3 PR.PT-4 + 1409 The telnet protocol uses unencrypted network communication, which means that data from the login session, including passwords and all other information transmitted during the session, can be stolen by eavesdroppers on the network. The telnet protocol is also subject to @@ -104169,97 +117768,54 @@ fi - no_reboot_needed - service_telnet_disabled -- name: Disable telnet Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable telnet Service - Disable service telnet + block: + + - name: Disable telnet Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable telnet Service - Ensure telnet.service is Masked + ansible.builtin.systemd: + name: telnet.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("telnet.service", multiline=True) + + - name: Unit Socket Exists - telnet.socket + ansible.builtin.command: systemctl -q list-unit-files telnet.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable telnet Service - Disable Socket telnet + ansible.builtin.systemd: + name: telnet.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("telnet.socket", multiline=True) + tags: + - NIST-800-171-3.1.13 + - NIST-800-171-3.4.7 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-5(1)(c) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_telnet_disabled + - special_service_block when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Disable telnet Service - Ensure telnet.service is Masked - ansible.builtin.systemd: - name: telnet.service - state: stopped - enabled: false - masked: true - when: - - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("telnet.service", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Unit Socket Exists - telnet.socket - ansible.builtin.command: systemctl -q list-unit-files telnet.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled - -- name: Disable telnet Service - Disable Socket telnet - ansible.builtin.systemd: - name: telnet.socket - enabled: false - state: stopped - masked: true - when: - - ( "telnet-server" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("telnet.socket", multiline=True) - tags: - - NIST-800-171-3.1.13 - - NIST-800-171-3.4.7 - - NIST-800-53-CM-6(a) - - NIST-800-53-CM-7(a) - - NIST-800-53-CM-7(b) - - NIST-800-53-IA-5(1)(c) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_telnet_disabled include disable_telnet @@ -104274,6 +117830,10 @@ class disable_telnet { [customizations.services] masked = ["telnet"] + + + + @@ -104317,7 +117877,6 @@ found. DSS05.03 DSS05.05 DSS06.06 - CCI-000366 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -104391,34 +117950,35 @@ found. PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R62 A.8.SEC-OL4 2.2.4 2.2 - OL09-00-000135 - SV-271463r1091101_rule + OL09-00-000135 + SV-271463r1091101_rule Removing the tftp-server package decreases the risk of the accidental (or intentional) activation of tftp services. If TFTP is required for operational support (such as transmission of router configurations), its use must be documented with the Information Systems -Securty Manager (ISSM), restricted to only authorized personnel, and have +Security Manager (ISSM), restricted to only authorized personnel, and have access control rules established. # CAUTION: This remediation script will remove tftp-server -# from the system, and may remove any packages -# that depend on tftp-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tftp-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tftp-server" ; then yum remove -y "tftp-server" fi - - name: Ensure tftp-server is removed - package: + - name: 'Uninstall tftp-server Package: Ensure tftp-server is removed' + ansible.builtin.package: name: tftp-server state: absent tags: @@ -104435,7 +117995,8 @@ fi - no_reboot_needed - package_tftp-server_removed - include remove_tftp-server + +include remove_tftp-server class remove_tftp-server { package { 'tftp-server': @@ -104444,6 +118005,7 @@ class remove_tftp-server { } + package --remove=tftp-server @@ -104459,8 +118021,7 @@ package --remove=tftp-server typically used to automatically transfer configuration or boot files between systems. TFTP does not support authentication and can be easily hacked. The package tftp is a client program that allows for connections to a tftp server. - CCI-000197 - SRG-OS-000074-GPOS-00042 + SRG-OS-000074-GPOS-00042 R62 2.2.4 2.2 @@ -104469,17 +118030,18 @@ for TFTP (such as a boot server). In that case, use extreme caution when configu the services. # CAUTION: This remediation script will remove tftp -# from the system, and may remove any packages -# that depend on tftp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on tftp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "tftp" ; then yum remove -y "tftp" fi - - name: Ensure tftp is removed - package: + - name: 'Remove tftp Daemon: Ensure tftp is removed' + ansible.builtin.package: name: tftp state: absent tags: @@ -104492,7 +118054,8 @@ fi - no_reboot_needed - package_tftp_removed - include remove_tftp + +include remove_tftp class remove_tftp { package { 'tftp': @@ -104501,6 +118064,7 @@ class remove_tftp { } + package --remove=tftp @@ -104510,249 +118074,265 @@ package --remove=tftp - - Ensure tftp Daemon Uses Secure Mode + + Ensure tftp systemd Service Uses Secure Mode If running the Trivial File Transfer Protocol (TFTP) service is necessary, it should be configured to change its root directory at startup. To do so, find the path for the tftp systemd service: -$ sudo systemctl show tftp | grep FragmentPath= -FragmentPath=/etc/systemd/system/tftp.service +$ sudo systemctl show tftp | grep ExecStart= +ExecStart={ path=/usr/sbin/in.tftpd ; argv[]=/usr/sbin/in.tftpd -s /var/lib/tftpboot ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }e + and ensure the ExecStart line on that file includes the -s option with a subdirectory: ExecStart=/usr/sbin/in.tftpd -s - 11 - 12 - 13 - 14 - 15 - 16 - 18 - 3 - 5 - 8 - 9 - APO01.06 - APO13.01 - BAI10.01 - BAI10.02 - BAI10.03 - BAI10.05 - DSS01.04 - DSS05.02 - DSS05.03 - DSS05.04 - DSS05.05 - DSS05.07 - DSS06.02 - DSS06.06 - CCI-000366 - 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 3.1 - SR 3.5 - SR 3.8 - SR 4.1 - SR 4.3 - SR 5.1 - SR 5.2 - SR 5.3 - SR 7.1 - SR 7.6 - A.10.1.1 - A.11.1.4 - A.11.1.5 - A.11.2.1 - A.11.2.6 - 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.6.2.1 - A.6.2.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 - CM-6(b) - AC-6 - CM-7(a) - PR.AC-3 - PR.AC-4 - PR.DS-5 - PR.IP-1 - PR.PT-3 - PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-002426 - SV-271764r1092004_rule + IA-5 (1) (c) + SRG-OS-000074-GPOS-00042 + OL09-00-002426 + SV-271764r1092004_rule Using the -s option causes the TFTP service to only serve files from the given directory. Serving files from an intentionally-specified directory reduces the risk of sharing files which should remain private. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q tftp-server; then var_tftpd_secure_directory='' -if grep -q 'server_args' /etc/xinetd.d/tftp; then - sed -i -E "s;^([[:blank:]]*server_args[[:blank:]]+=[[:blank:]]+.*?)(-s[[:blank:]]+[[:graph:]]+)*(.*)$;\1 -s $var_tftpd_secure_directory \3;" /etc/xinetd.d/tftp +DROPIN_DIR="/etc/systemd/system/tftp.service.d" +DROPIN_FILE="$DROPIN_DIR/10-ssg-hardening.conf" +TFTP_SERVICE_FILE="/usr/lib/systemd/system/tftp.service" +REGEX_TFTP_SERVICE_FILE="^\s*ExecStart\s*=\s*/\S+\s+-s\s+(/\S+).*$" +REGEX_DROP_IN="(?s)\s*ExecStart=\s*.*(\s*ExecStart=\s*/\S+\s+-s\s+/\S+.*)" + +# Remove bad configuration in drop-ins +if [ -d "$DROPIN_DIR" ]; then + for override in "$DROPIN_DIR"/*.conf; do + if [ -f "$override" ] && ! grep -qPzo "$REGEX_DROP_IN" "$override"; then + sed -i '/^[[:space:]]*ExecStart=/ s/^/#/' "$override" + fi + done +fi + +if [ -d "$DROPIN_DIR" ] && grep -qPzor "$REGEX_DROP_IN" "$DROPIN_DIR"; then + exit 0 +elif [ ! -d "$DROPIN_DIR" ] && grep -qE "$REGEX_TFTP_SERVICE_FILE" "$TFTP_SERVICE_FILE"; then + exit 0 else - echo "server_args = -s $var_tftpd_secure_directory" >> /etc/xinetd.d/tftp + mkdir -p "$DROPIN_DIR" + + cat > "$DROPIN_FILE" << EOF +[Service] +# clear any existing ExecStart in the original unit +ExecStart= +ExecStart=/usr/sbin/in.tftpd -s $var_tftpd_secure_directory +EOF + systemctl daemon-reload + systemctl restart tftp.service fi else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd - name: XCCDF Value var_tftpd_secure_directory # promote to variable set_fact: var_tftpd_secure_directory: !!str tags: - always -- name: Find out if the file exists and contains the line configuring server arguments - find: - path: /etc/xinetd.d - patterns: tftp - contains: ^[\s]+server_args.*$ - register: tftpd_secure_config_line +- name: Ensure tftp systemd Service Uses Secure Mode - Find valid drop-ins + ansible.builtin.find: + paths: /etc/systemd/system/tftp.service.d + patterns: '*.conf' + contains: ^\s*ExecStart\s*=\s*/\S+\s+-s\s+/\S+$ + register: valid_dropins + failed_when: false when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd -- name: Ensure that TFTP server is configured to start with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - regexp: ^[\s]*(server_args[\s]+=[\s]+.*?)(-s[\s]+[/\.\w]+)*(.*)$ - line: \1 -s {{ var_tftpd_secure_directory }} \3 - state: present - backrefs: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched > 0 +- name: Ensure tftp systemd Service Uses Secure Mode - Find all drop-in files + ansible.builtin.find: + paths: /etc/systemd/system/tftp.service.d + patterns: '*.conf' + contains: ^\s*ExecStart\s*=.*$ + file_type: file + register: all_dropins + failed_when: false + when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd -- name: Insert correct config line to start TFTP server with secure directory - lineinfile: - path: /etc/xinetd.d/tftp - line: server_args = -s {{ var_tftpd_secure_directory }} - state: present - create: true - when: - - '"tftp-server" in ansible_facts.packages' - - tftpd_secure_config_line is defined and tftpd_secure_config_line.matched == 0 +- name: Ensure tftp systemd Service Uses Secure Mode - Get invalid drop-ins + ansible.builtin.set_fact: + invalid_dropins: '{{ all_dropins.files | rejectattr(''path'', ''in'', valid_dropins.files + | map(attribute=''path'') | list) | map(attribute=''path'') | list }}' + when: '"tftp-server" in ansible_facts.packages' tags: - DISA-STIG-OL09-00-002426 - - NIST-800-53-AC-6 - - NIST-800-53-CM-6(b) - - NIST-800-53-CM-7(a) + - NIST-800-53-IA-5 (1) (c) - configure_strategy - - low_complexity - low_disruption + - medium_complexity - medium_severity - no_reboot_needed - - tftpd_uses_secure_mode + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Comment all ExecStart in invalid + drop-ins + ansible.builtin.lineinfile: + path: '{{ item }}' + regexp: ^\s*ExecStart\s*=.* + state: absent + loop: '{{ invalid_dropins }}' + when: + - '"tftp-server" in ansible_facts.packages' + - invalid_dropins | length > 0 + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if a valid drop-in exists + ansible.builtin.set_fact: + tftp_config_valid: '{{ (valid_dropins.matched | default(0)) > 0 }}' + when: '"tftp-server" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if tftp.service contains + valid ExecStart + ansible.builtin.find: + paths: /usr/lib/systemd/system + patterns: tftp.service + contains: ^\s*ExecStart\s*=\s*/\S+\s+-s\s+/\S+ + register: valid_tftp_service + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Check if a valid tftp.service + exists + ansible.builtin.set_fact: + original_valid: '{{ (valid_tftp_service.matched | default(0)) > 0 }}' + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Recalculate global config validity + ansible.builtin.set_fact: + tftp_config_valid: '{{ tftp_config_valid or original_valid | default(false) }}' + when: '"tftp-server" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd + +- name: Ensure tftp systemd Service Uses Secure Mode - Remediate only if necessary + block: + + - name: Ensure drop-in directory exists + ansible.builtin.file: + path: /etc/systemd/system/tftp.service.d + state: directory + + - name: Deploy 10-ssg-hardening.conf drop-in + ansible.builtin.copy: + dest: /etc/systemd/system/tftp.service.d/10-ssg-hardening.conf + content: |- + [Service] + # clear any existing ExecStart in the original unit + ExecStart= + ExecStart=/usr/sbin/in.tftpd -s {{ var_tftpd_secure_directory }} + + - name: Reload systemd and restart tftp service + ansible.builtin.systemd: + daemon_reload: true + name: tftp + state: restarted + enabled: true + when: + - '"tftp-server" in ansible_facts.packages' + - not tftp_config_valid + tags: + - DISA-STIG-OL09-00-002426 + - NIST-800-53-IA-5 (1) (c) + - configure_strategy + - low_disruption + - medium_complexity + - medium_severity + - no_reboot_needed + - tftp_uses_secure_mode_systemd - - + - + @@ -104776,21 +118356,23 @@ and removed. The squid package can be removed with the following command: $ sudo yum erase squid A.8.SEC-OL4 + 1409 If there is no need to make the proxy server software available, removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove squid -# from the system, and may remove any packages -# that depend on squid. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on squid. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "squid" ; then yum remove -y "squid" fi - - name: Ensure squid is removed - package: + - name: 'Uninstall squid Package: Ensure squid is removed' + ansible.builtin.package: name: squid state: absent tags: @@ -104801,7 +118383,8 @@ fi - package_squid_removed - unknown_severity - include remove_squid + +include remove_squid class remove_squid { package { 'squid': @@ -104810,6 +118393,7 @@ class remove_squid { } + package --remove=squid @@ -104825,6 +118409,7 @@ package --remove=squid The squid service can be disabled with the following command: $ sudo systemctl mask --now squid.service + 1409 Running proxy server software provides a network-based avenue of attack, and should be removed if not needed. @@ -104864,73 +118449,48 @@ fi - service_squid_disabled - unknown_severity -- name: Disable Squid - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable Squid - Disable service squid + block: + + - name: Disable Squid - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Squid - Ensure squid.service is Masked + ansible.builtin.systemd: + name: squid.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("squid.service", multiline=True) + + - name: Unit Socket Exists - squid.socket + ansible.builtin.command: systemctl -q list-unit-files squid.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable Squid - Disable Socket squid + ansible.builtin.systemd: + name: squid.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("squid.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - no_reboot_needed + - service_squid_disabled + - special_service_block + - unknown_severity when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Disable Squid - Ensure squid.service is Masked - ansible.builtin.systemd: - name: squid.service - state: stopped - enabled: false - masked: true - when: - - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("squid.service", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Unit Socket Exists - squid.socket - ansible.builtin.command: systemctl -q list-unit-files squid.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity - -- name: Disable Squid - Disable Socket squid - ansible.builtin.systemd: - name: squid.socket - enabled: false - state: stopped - masked: true - when: - - ( "squid" in ansible_facts.packages and ("kernel" in ansible_facts.packages or - "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("squid.socket", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - no_reboot_needed - - service_squid_disabled - - unknown_severity include disable_squid @@ -104945,6 +118505,10 @@ class disable_squid { [customizations.services] masked = ["squid"] + + + + @@ -104968,8 +118532,7 @@ The rngd service can be enabled with the following comman For Oracle Linux 9 running with kernel FIPS mode enabled this rule is not applicable. The in-kernel deterministic random bit generator (DRBG) is used in FIPS mode instead. Consequently, the rngd service can't be started in FIPS mode. - CCI-000366 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 The rngd service feeds random data from hardware device to kernel random device. @@ -105002,7 +118565,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the Hardware RNG Entropy Gatherer Service - Enable Service rngd @@ -105013,7 +118576,6 @@ fi masked: false when: - '"rng-tools" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - enable_strategy - low_complexity @@ -105021,6 +118583,8 @@ fi - low_severity - no_reboot_needed - service_rngd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_rngd @@ -105035,6 +118599,10 @@ class enable_rngd { [customizations.services] enabled = ["rngd"] + + + + @@ -105067,7 +118635,6 @@ and removed. 8 APO13.01 DSS05.02 - CCI-000366 SR 3.1 SR 3.5 SR 3.8 @@ -105085,9 +118652,9 @@ and removed. CM-7(b) CM-6(a) PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000140 - SV-271464r1092459_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000140 + SV-271464r1092459_rule Routing software is typically used on routers to exchange network topology information with other routers. If routing software is used when not required, system network information may be unnecessarily transmitted across the network. @@ -105096,17 +118663,18 @@ If there is no need to make the router software available, removing it provides a safeguard against its activation. # CAUTION: This remediation script will remove quagga -# from the system, and may remove any packages -# that depend on quagga. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on quagga. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "quagga" ; then yum remove -y "quagga" fi - - name: Ensure quagga is removed - package: + - name: 'Uninstall quagga Package: Ensure quagga is removed' + ansible.builtin.package: name: quagga state: absent tags: @@ -105121,7 +118689,8 @@ fi - no_reboot_needed - package_quagga_removed - include remove_quagga + +include remove_quagga class remove_quagga { package { 'quagga': @@ -105130,6 +118699,7 @@ class remove_quagga { } + package --remove=quagga @@ -105170,17 +118740,18 @@ removing the package provides a safeguard against its activation. # CAUTION: This remediation script will remove net-snmp -# from the system, and may remove any packages -# that depend on net-snmp. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on net-snmp. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "net-snmp" ; then yum remove -y "net-snmp" fi - - name: Ensure net-snmp is removed - package: + - name: 'Uninstall net-snmp Package: Ensure net-snmp is removed' + ansible.builtin.package: name: net-snmp state: absent tags: @@ -105193,7 +118764,8 @@ fi - package_net-snmp_removed - unknown_severity - include remove_net-snmp + +include remove_net-snmp class remove_net-snmp { package { 'net-snmp': @@ -105202,6 +118774,7 @@ class remove_net-snmp { } + package --remove=net-snmp @@ -105257,73 +118830,48 @@ fi - no_reboot_needed - service_snmpd_disabled -- name: Disable snmpd Service - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable snmpd Service - Disable service snmpd + block: + + - name: Disable snmpd Service - Collect systemd Services Present in the System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable snmpd Service - Ensure snmpd.service is Masked + ansible.builtin.systemd: + name: snmpd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("snmpd.service", multiline=True) + + - name: Unit Socket Exists - snmpd.socket + ansible.builtin.command: systemctl -q list-unit-files snmpd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable snmpd Service - Disable Socket snmpd + ansible.builtin.systemd: + name: snmpd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("snmpd.socket", multiline=True) + tags: + - disable_strategy + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - service_snmpd_disabled + - special_service_block when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Disable snmpd Service - Ensure snmpd.service is Masked - ansible.builtin.systemd: - name: snmpd.service - state: stopped - enabled: false - masked: true - when: - - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - service_exists.stdout_lines is search("snmpd.service", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Unit Socket Exists - snmpd.socket - ansible.builtin.command: systemctl -q list-unit-files snmpd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled - -- name: Disable snmpd Service - Disable Socket snmpd - ansible.builtin.systemd: - name: snmpd.socket - enabled: false - state: stopped - masked: true - when: - - ( "net-snmp" in ansible_facts.packages and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) - - socket_file_exists.stdout_lines is search("snmpd.socket", multiline=True) - tags: - - disable_strategy - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - - service_snmpd_disabled include disable_snmpd @@ -105338,6 +118886,10 @@ class disable_snmpd { [customizations.services] masked = ["snmpd"] + + + + @@ -105387,7 +118939,6 @@ detailed documentation is available from its website, https://www.openssh.com. Its server program is called sshd and provided by the RPM package openssh-server. - SSH enabled firewalld zone Specify firewalld zone to enable SSH service. This value is used only for remediation purposes. @@ -105423,11 +118974,13 @@ Its server program is called sshd and provided by the RPM that are used for data integrity protection by the SSH server. hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 hmac-sha2-512,hmac-sha2-256,hmac-sha1,hmac-sha1-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-256-etm@openssh.com + hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 SSH session Idle time @@ -105474,12 +119027,15 @@ A value of 2 indicates that OpenSSH server package is required by the policy.hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com + -hmac-md5,hmac-md5-96,hmac-ripemd160,hmac-sha1-96,umac-64@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,hmac-ripemd160-etm@openssh.com,hmac-sha1-96-etm@openssh.com,umac-64-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,hmac-ripemd160 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 + hmac-sha2-512,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-256-etm@openssh.com hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512 + hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256 SSH Max Sessions Count @@ -105508,44 +119064,24 @@ A value of 2 indicates that OpenSSH server package is required by the policy. $ sudo yum install openssh-clients - CCI-000366 FIA_UAU.5 FTP_ITC_EXT.1 FCS_SSH_EXT.1 FCS_SSHC_EXT.1 - SRG-OS-000480-GPOS-00227 - OL09-00-000260 - SV-271488r1091176_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000260 + SV-271488r1091176_rule This package includes utilities to make encrypted connections and transfer files securely to SSH servers. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + if ! rpm -q --quiet "openssh-clients" ; then yum install -y "openssh-clients" fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - DISA-STIG-OL09-00-000260 - - enable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-clients_installed - -- name: Ensure openssh-clients is installed - package: + - name: Ensure openssh-clients is installed + ansible.builtin.package: name: openssh-clients state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000260 - enable_strategy @@ -105593,10 +119129,6 @@ $ sudo yum install openssh-server DSS05.07 DSS06.02 DSS06.06 - CCI-002420 - CCI-002421 - CCI-002418 - CCI-002422 SR 3.1 SR 3.8 SR 4.1 @@ -105632,15 +119164,16 @@ $ sudo yum install openssh-server FTP_ITC_EXT.1 FCS_SSH_EXT.1 FCS_SSHS_EXT.1 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - OL09-00-000250 - SV-271482r1091158_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000250 + SV-271482r1091158_rule Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105666,7 +119199,7 @@ fi - package_openssh-server_installed - name: Ensure openssh-server is installed - package: + ansible.builtin.package: name: openssh-server state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -105713,39 +119246,22 @@ $ sudo yum erase openssh-server Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + # CAUTION: This remediation script will remove openssh-server -# from the system, and may remove any packages -# that depend on openssh-server. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on openssh-server. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "openssh-server" ; then yum remove -y "openssh-server" fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - disable_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - package_openssh-server_removed - -- name: Ensure openssh-server is removed - package: + - name: 'Remove the OpenSSH Server Package: Ensure openssh-server is removed' + ansible.builtin.package: name: openssh-server state: absent - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - disable_strategy - low_complexity @@ -105754,7 +119270,8 @@ fi - no_reboot_needed - package_openssh-server_removed - include remove_openssh-server + +include remove_openssh-server class remove_openssh-server { package { 'openssh-server': @@ -105763,6 +119280,7 @@ class remove_openssh-server { } + package --remove=openssh-server @@ -105790,10 +119308,6 @@ The sshd service can be enabled with the following comman 3.1.13 3.5.4 3.13.8 - CCI-002420 - CCI-002421 - CCI-002418 - CCI-002422 SR 3.1 SR 3.8 SR 4.1 @@ -105830,12 +119344,12 @@ The sshd service can be enabled with the following comman SC-8(4) PR.DS-2 PR.DS-5 - SRG-OS-000423-GPOS-00187 - SRG-OS-000424-GPOS-00188 - SRG-OS-000425-GPOS-00189 - SRG-OS-000426-GPOS-00190 - OL09-00-000251 - SV-271483r1091161_rule + SRG-OS-000423-GPOS-00187 + SRG-OS-000424-GPOS-00188 + SRG-OS-000425-GPOS-00189 + SRG-OS-000426-GPOS-00190 + OL09-00-000251 + SV-271483r1091161_rule Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered. @@ -105846,6 +119360,7 @@ of information system components from which information can be transmitted (e.g. mobile devices, notebook computers, printers, copiers, scanners, etc). Communication paths outside the physical protection of a controlled boundary are exposed to the possibility of interception and modification. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105885,7 +119400,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the OpenSSH Service - Enable Service sshd @@ -105896,7 +119411,6 @@ fi masked: false when: - '"openssh-server" in ansible_facts.packages' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-000251 - NIST-800-171-3.1.13 @@ -105914,6 +119428,8 @@ fi - medium_severity - no_reboot_needed - service_sshd_enabled + - special_service_block + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) include enable_sshd @@ -105928,6 +119444,10 @@ class enable_sshd { [customizations.services] enabled = ["sshd"] + + + + @@ -105944,9 +119464,10 @@ This is unusual, as SSH is a common method for encrypted and authenticated remote access. CM-3(6) IA-2(4) - SRG-APP-000185-CTR-000490 - SRG-APP-000141-CTR-000315 + SRG-APP-000185-CTR-000490 + SRG-APP-000141-CTR-000315 + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -105985,77 +119506,50 @@ fi - no_reboot_needed - service_sshd_disabled -- name: Disable SSH Server If Possible - Collect systemd Services Present in the System - ansible.builtin.command: systemctl -q list-unit-files --type service - register: service_exists - changed_when: false - failed_when: service_exists.rc not in [0, 1] - check_mode: false +- name: Disable SSH Server If Possible - Disable service sshd + block: + + - name: Disable SSH Server If Possible - Collect systemd Services Present in the + System + ansible.builtin.command: systemctl -q list-unit-files --type service + register: service_exists + changed_when: false + failed_when: service_exists.rc not in [0, 1] + check_mode: false + + - name: Disable SSH Server If Possible - Ensure sshd.service is Masked + ansible.builtin.systemd: + name: sshd.service + state: stopped + enabled: false + masked: true + when: service_exists.stdout_lines is search("sshd.service", multiline=True) + + - name: Unit Socket Exists - sshd.socket + ansible.builtin.command: systemctl -q list-unit-files sshd.socket + register: socket_file_exists + changed_when: false + failed_when: socket_file_exists.rc not in [0, 1] + check_mode: false + + - name: Disable SSH Server If Possible - Disable Socket sshd + ansible.builtin.systemd: + name: sshd.socket + enabled: false + state: stopped + masked: true + when: socket_file_exists.stdout_lines is search("sshd.socket", multiline=True) + tags: + - NIST-800-53-CM-3(6) + - NIST-800-53-IA-2(4) + - disable_strategy + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - service_sshd_disabled + - special_service_block when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Disable SSH Server If Possible - Ensure sshd.service is Masked - ansible.builtin.systemd: - name: sshd.service - state: stopped - enabled: false - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - service_exists.stdout_lines is search("sshd.service", multiline=True) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Unit Socket Exists - sshd.socket - ansible.builtin.command: systemctl -q list-unit-files sshd.socket - register: socket_file_exists - changed_when: false - failed_when: socket_file_exists.rc not in [0, 1] - check_mode: false - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled - -- name: Disable SSH Server If Possible - Disable Socket sshd - ansible.builtin.systemd: - name: sshd.socket - enabled: false - state: stopped - masked: true - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - socket_file_exists.stdout_lines is search("sshd.socket", multiline=True) - tags: - - NIST-800-53-CM-3(6) - - NIST-800-53-IA-2(4) - - disable_strategy - - high_severity - - low_complexity - - low_disruption - - no_reboot_needed - - service_sshd_disabled include disable_sshd @@ -106070,6 +119564,10 @@ class disable_sshd { [customizations.services] masked = ["sshd"] + + + + @@ -106081,7 +119579,8 @@ masked = ["sshd"] Verify Group Who Owns SSH Server config file To properly set the group owner of /etc/ssh/sshd_config, run the command: -$ sudo chgrp root /etc/ssh/sshd_config + + $ sudo chgrp root /etc/ssh/sshd_config 12 13 @@ -106095,7 +119594,6 @@ To properly set the group owner of /etc/ssh/sshd_config, DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106122,32 +119620,45 @@ To properly set the group owner of /etc/ssh/sshd_config, 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 + 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-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002507 - SV-271776r1092040_rule + OL09-00-002507 + SV-271776r1092040_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chgrp 0 /etc/ssh/sshd_config +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +if ! stat -c "%g %G" "/etc/ssh/sshd_config" | grep -E -w -q "0"; then + chgrp --no-dereference "$newgroup" /etc/ssh/sshd_config +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106168,8 +119679,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupowner_sshd_config_newgroup variable if represented by gid + ansible.builtin.set_fact: + file_groupowner_sshd_config_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002507 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_groupowner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106185,10 +119712,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure group owner 0 on /etc/ssh/sshd_config - file: +- name: Ensure group owner on /etc/ssh/sshd_config + ansible.builtin.file: path: /etc/ssh/sshd_config - group: '0' + follow: false + group: '{{ file_groupowner_sshd_config_newgroup }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -106219,10 +119747,21 @@ group-owned by ssh_keys group. keys are generated post-deployment. R50 If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended -regex '^.*_key$' -exec chgrp -L ssh_keys {} \; +newgroup="" +if getent group "ssh_keys" >/dev/null 2>&1; then + newgroup="ssh_keys" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "ssh_keys is not a defined group on the system" +else +find -P /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended -regex '^.*_key$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106239,9 +119778,40 @@ fi - medium_severity - no_reboot_needed +- name: Check that the ssh_keys group is defined + ansible.builtin.getent: + database: group + key: ssh_keys + ignore_errors: true + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - file_groupownership_sshd_private_key_newgroup is undefined + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + +- name: Set the file_groupownership_sshd_private_key_newgroup variable if ssh_keys + found + ansible.builtin.set_fact: + file_groupownership_sshd_private_key_newgroup: ssh_keys + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_facts.getent_group["ssh_keys"] is defined + tags: + - configure_strategy + - file_groupownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys -regextype posix-extended - -regex "^.*_key$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -group ssh_keys + -regextype posix-extended -regex "^.*_key$" register: files_found changed_when: false failed_when: false @@ -106256,9 +119826,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/ssh/ file(s) matching ^.*_key$ - file: + ansible.builtin.file: path: '{{ item }}' - group: ssh_keys + follow: false + group: '{{ file_groupownership_sshd_private_key_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106287,10 +119858,21 @@ keys are generated post-deployment. R50 If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.pub$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi + +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.pub$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106307,9 +119889,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupownership_sshd_pub_key_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupownership_sshd_pub_key_newgroup: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -group 0 -regextype + posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -106324,9 +119919,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_sshd_pub_key_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106350,7 +119946,8 @@ fi Verify Owner on SSH Server config file To properly set the owner of /etc/ssh/sshd_config, run the command: -$ sudo chown root /etc/ssh/sshd_config + + $ sudo chown root /etc/ssh/sshd_config 12 13 @@ -106364,7 +119961,6 @@ To properly set the owner of /etc/ssh/sshd_config, run th DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106391,32 +119987,45 @@ To properly set the owner of /etc/ssh/sshd_config, run th 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 + 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-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 - OL09-00-002508 - SV-271777r1092043_rule + OL09-00-002508 + SV-271777r1092043_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -chown 0 /etc/ssh/sshd_config +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else +if ! stat -c "%u %U" "/etc/ssh/sshd_config" | grep -E -w -q "0"; then + chown --no-dereference "$newown" /etc/ssh/sshd_config +fi + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106437,8 +120046,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_owner_sshd_config_newown variable if represented by uid + ansible.builtin.set_fact: + file_owner_sshd_config_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002508 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - configure_strategy + - file_owner_sshd_config + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106454,10 +120079,11 @@ fi - medium_severity - no_reboot_needed -- name: Ensure owner 0 on /etc/ssh/sshd_config - file: +- name: Ensure owner on /etc/ssh/sshd_config + ansible.builtin.file: path: /etc/ssh/sshd_config - owner: '0' + follow: false + owner: '{{ file_owner_sshd_config_newown }}' when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - file_exists.stat is defined and file_exists.stat.exists @@ -106488,10 +120114,22 @@ by root user. keys are generated post-deployment. R50 If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*_key$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*_key$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106508,9 +120146,22 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_sshd_private_key_newown variable if represented by + uid + ansible.builtin.set_fact: + file_ownership_sshd_private_key_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_private_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*_key$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*_key$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*_key$" register: files_found changed_when: false failed_when: false @@ -106525,9 +120176,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/ssh/ file(s) matching ^.*_key$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_sshd_private_key_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106556,10 +120208,22 @@ keys are generated post-deployment. R50 If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.pub$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi + +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*\.pub$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -106576,9 +120240,21 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_sshd_pub_key_newown variable if represented by uid + ansible.builtin.set_fact: + file_ownership_sshd_pub_key_newown: '0' + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_sshd_pub_key + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/ssh/ file(s) matching ^.*\.pub$ - command: find -H /etc/ssh/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -106593,9 +120269,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/ssh/ file(s) matching ^.*\.pub$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_sshd_pub_key_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -106633,7 +120310,6 @@ To properly set the permissions of /etc/ssh/sshd_config, DSS05.04 DSS05.07 DSS06.02 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106660,30 +120336,31 @@ To properly set the permissions of /etc/ssh/sshd_config, 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 + 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-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002509 - SV-271778r1092046_rule + OL09-00-002509 + SV-271778r1092046_rule Service configuration files enable or disable features of their respective services that if configured incorrectly can lead to insecure and vulnerable configurations. Therefore, service configuration files should be owned by the correct group to prevent unauthorized changes. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -106711,7 +120388,7 @@ fi - no_reboot_needed - name: Test for existence /etc/ssh/sshd_config - stat: + ansible.builtin.stat: path: /etc/ssh/sshd_config register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -106730,7 +120407,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xwrs,o-xwrt on /etc/ssh/sshd_config - file: + ansible.builtin.file: path: /etc/ssh/sshd_config mode: u-xs,g-xwrs,o-xwrt when: @@ -106760,7 +120437,7 @@ fi Verify Permissions on SSH Server Private *_key Key Files SSH server private keys - files that match the /etc/ssh/*_key glob, have to have restricted permissions. -If those files are owned by the root user and the root group, they have to have the 0600 permission or stricter. +If those files are owned by the root user and the root group, they have to have the 0640 permission or stricter. If they are owned by the root user, but by a dedicated group ssh_keys, they can have the 0640 permission or stricter. Remediation is not possible at bootable container build time because SSH host keys are generated post-deployment. @@ -106778,7 +120455,6 @@ keys are generated post-deployment. DSS06.02 3.1.13 3.13.10 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -106805,29 +120481,31 @@ keys are generated post-deployment. 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 + 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-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-2.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 + 1449 2.2.6 2.2 - OL09-00-002502 - SV-271771r1092025_rule + OL09-00-002502 + SV-271771r1092025_rule If an unauthorized user obtains the private SSH host key file, the host could be impersonated. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -106835,7 +120513,7 @@ for keyfile in /etc/ssh/*_key; do test -f "$keyfile" || continue if test root:root = "$(stat -c "%U:%G" "$keyfile")"; then - chmod u-xs,g-xwrs,o-xwrt "$keyfile" + chmod u-xs,g-xws,o-xwrt "$keyfile" elif test root:ssh_keys = "$(stat -c "%U:%G" "$keyfile")"; then chmod u-xs,g-xws,o-xwrt "$keyfile" @@ -106870,7 +120548,7 @@ fi - name: Find root:root-owned keys ansible.builtin.command: find -H /etc/ssh/ -maxdepth 1 -user root -regex ".*_key$" - -type f -group root -perm /u+xs,g+xwrs,o+xwrt + -type f -group root -perm /u+xs,g+xws,o+xwrt register: root_owned_keys changed_when: false failed_when: false @@ -106896,7 +120574,7 @@ fi - name: Set permissions for root:root-owned keys ansible.builtin.file: path: '{{ item }}' - mode: u-xs,g-xwrs,o-xwrt + mode: u-xs,g-xws,o-xwrt state: file with_items: - '{{ root_owned_keys.stdout_lines }}' @@ -107004,7 +120682,6 @@ keys are generated post-deployment. DSS06.02 3.1.13 3.13.10 - CCI-000366 4.3.3.7.3 SR 2.1 SR 5.2 @@ -107031,33 +120708,34 @@ keys are generated post-deployment. 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 + 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-17(a) CM-6(a) AC-6(1) PR.AC-4 PR.DS-5 Req-2.2.4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 R50 2.2.6 2.2 - OL09-00-002503 - SV-271772r1092028_rule + OL09-00-002503 + SV-271772r1092028_rule If a public host key file is modified by an unauthorized user, the SSH service may be compromised. + # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype posix-extended -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; +find -P /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype posix-extended -regex '^.*\.pub$' -exec chmod u-xs,g-xws,o-xwt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107084,8 +120762,8 @@ fi - no_reboot_needed - name: Find /etc/ssh/ file(s) - command: find -H /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type f -regextype - posix-extended -regex "^.*\.pub$" + ansible.builtin.command: find -P /etc/ssh/ -maxdepth 1 -perm /u+xs,g+xws,o+xwt -type + f -regextype posix-extended -regex "^.*\.pub$" register: files_found changed_when: false failed_when: false @@ -107109,7 +120787,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/ssh/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwt state: file @@ -107154,12 +120832,12 @@ class ssh_public_key_perms { The /etc/ssh/sshd_config.d/50-redhat.conf file must exist as it contains important settings to secure SSH. There is no remediation available for this rule since this file needs to have the correct content for the given system. - CCI-001453 AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000252 - SV-271484r1092624_rule + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule The file must exist to configure SSH correctly. + @@ -107179,6 +120857,7 @@ This is unusual, as SSH is a common method for encrypted and authenticated remote access. If inbound SSH connections are not expected, disallowing access to the SSH port will avoid possible exploitation of the port by an attacker. + Configure OpenSSH Client if Necessary @@ -107204,17 +120883,14 @@ the include directive in the main config file lexicographical order of file names. Make sure that there is no file processed before 02-rekey-limit.conf containing definition of RekeyLimit. - CCI-000068 FCS_SSH_EXT.1.8 - SRG-OS-000423-GPOS-00187 - SRG-OS-000033-GPOS-00014 - SRG-OS-000424-GPOS-00188 + SRG-OS-000423-GPOS-00187 + SRG-OS-000033-GPOS-00014 + SRG-OS-000424-GPOS-00188 By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited. - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - + var_ssh_client_rekey_limit_size='' var_ssh_client_rekey_limit_time='' @@ -107246,22 +120922,8 @@ cp "/etc/ssh/ssh_config.d/02-rekey-limit.conf" "/etc/ssh/ssh_config.d/02-rekey-l printf '%s\n' "RekeyLimit $var_ssh_client_rekey_limit_size $var_ssh_client_rekey_limit_time" >> "/etc/ssh/ssh_config.d/02-rekey-limit.conf" # Clean up after ourselves. rm "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak" - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - name: Gather the package facts - package_facts: - manager: auto - tags: - - configure_strategy - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - ssh_client_rekey_limit -- name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable + - name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable set_fact: var_ssh_client_rekey_limit_size: !!str tags: @@ -107273,12 +120935,11 @@ fi - always - name: Ensure RekeyLimit is not configured in /etc/ssh/ssh_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/ssh_config create: false regexp: ^\s*RekeyLimit.*$ state: absent - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107288,12 +120949,11 @@ fi - ssh_client_rekey_limit - name: Collect all include config files for ssh client which configure RekeyLimit - find: + ansible.builtin.find: paths: /etc/ssh/ssh_config.d/ contains: ^[\s]*RekeyLimit.*$ patterns: '*.config' register: ssh_config_include_files - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107302,14 +120962,13 @@ fi - no_reboot_needed - ssh_client_rekey_limit -- name: Remove all occurences of RekeyLimit configuration from include config files +- name: Remove all occurrences of RekeyLimit configuration from include config files of ssh client - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' regexp: ^[\s]*RekeyLimit.*$ state: absent loop: '{{ ssh_config_include_files.files }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107320,14 +120979,13 @@ fi - name: Ensure that rekey limit is set to {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time }} in /etc/ssh/ssh_config.d/02-rekey-limit.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/ssh_config.d/02-rekey-limit.conf create: true regexp: ^\s*RekeyLimit.*$ line: RekeyLimit {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time }} state: present - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - configure_strategy - low_complexity @@ -107352,13 +121010,15 @@ fi You can create such keys with the following command: $ sudo ssh-keygen -n [passphrase] Oracle Linux 9, for certificate-based authentication, must enforce authorized access to the corresponding private key. - CCI-000186 - SRG-OS-000067-GPOS-00035 - OL09-00-000905 - SV-271605r1091527_rule + SRG-OS-000067-GPOS-00035 + OL09-00-000905 + SV-271605r1091527_rule If an unauthorized user obtains access to a private key without a passcode, that user would have unauthorized access to any system where the associated public key has been installed. + + + @@ -107371,6 +121031,7 @@ certain changes should be made to the OpenSSH daemon configuration file /etc/ssh/sshd_config. The following recommendations can be applied to this file. See the sshd_config(5) man page for more detailed information. + SSH RekeyLimit - size Specify the size component of the rekey limit. @@ -107421,11 +121082,10 @@ The following line should be present in /etc/ssh/sshd_configInclude /etc/crypto-policies/back-ends/opensshserver.config There is no automated remediation because recommended action could severely disrupt the system and might not be efficient in fixing the problem. - CCI-001453 AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000252 - SV-271484r1092624_rule + SRG-OS-000250-GPOS-00093 + OL09-00-000252 + SV-271484r1092624_rule Without cryptographic integrity protections, information can be altered by unauthorized users without detection. @@ -107445,7 +121105,7 @@ To ensure the SSH timeout occurs precisely when the value of 0 in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: 1 12 13 @@ -107471,9 +121131,6 @@ value of 0 in DSS06.03 DSS06.10 3.1.11 - CCI-000879 - CCI-001133 - CCI-002361 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -107528,12 +121185,12 @@ value of 0 in A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-2(5) AC-12 AC-17(a) @@ -107547,9 +121204,9 @@ value of 0 in PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 This ensures a user login will be terminated as soon as the ClientAliveInterval is reached. @@ -107564,21 +121221,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveCountMax 0" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107604,7 +121267,7 @@ fi - sshd_set_keepalive_0 - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -107626,7 +121289,7 @@ fi - sshd_set_keepalive_0 - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveCountMax.*)$ replace: '# \1' @@ -107648,36 +121311,124 @@ fi - restrict_strategy - sshd_set_keepalive_0 +- name: Set SSH Client Alive Count Max to zero - Check if the parameter ClientAliveCountMax + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Set SSH Client Alive Count Max to zero - Check if the parameter ClientAliveCountMax + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+0$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + - name: Set SSH Client Alive Count Max to zero block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveCountMax is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ line: ClientAliveCountMax 0 state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive_0 + +- name: Set SSH Client Alive Count Max to zero - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -107743,8 +121494,6 @@ a keep alive message. DSS06.03 DSS06.10 3.1.11 - CCI-001133 - CCI-002361 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -107799,12 +121548,12 @@ a keep alive message. A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-2(5) AC-12 AC-17(a) @@ -107818,13 +121567,13 @@ a keep alive message. PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 A.5.SEC-OL7 8.2.8 8.2 - OL09-00-002346 - SV-271709r1091839_rule + OL09-00-002346 + SV-271709r1091839_rule This ensures a user login will be terminated as soon as the ClientAliveInterval is reached. @@ -107834,7 +121583,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_set_keepalive='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -107843,21 +121591,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveCountMax/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveCountMax $var_sshd_set_keepalive" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -107891,7 +121645,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -107916,7 +121670,7 @@ fi - sshd_set_keepalive - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveCountMax.*)$ replace: '# \1' @@ -107941,36 +121695,134 @@ fi - restrict_strategy - sshd_set_keepalive +- name: Set SSH Client Alive Count Max - Check if the parameter ClientAliveCountMax + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Set SSH Client Alive Count Max - Check if the parameter ClientAliveCountMax + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+{{ var_sshd_set_keepalive + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + - name: Set SSH Client Alive Count Max block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveCountMax is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveCountMax\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveCountMax"| regex_escape }}\s+ line: ClientAliveCountMax {{ var_sshd_set_keepalive }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002346 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_keepalive + +- name: Set SSH Client Alive Count Max - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108049,9 +121901,6 @@ configuring ClientAliveCountMax in the SSH service configuration.DSS06.03 DSS06.10 3.1.11 - CCI-001133 - CCI-002361 - CCI-002891 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -108100,12 +121949,12 @@ configuring ClientAliveCountMax in the SSH service configuration.A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-004-6 R2.2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 CM-6(a) AC-17(a) AC-2(5) @@ -108121,15 +121970,15 @@ configuring ClientAliveCountMax in the SSH service configuration.PR.AC-7 PR.IP-2 Req-8.1.8 - SRG-OS-000126-GPOS-00066 - SRG-OS-000163-GPOS-00072 - SRG-OS-000279-GPOS-00109 - SRG-OS-000395-GPOS-00175 + SRG-OS-000126-GPOS-00066 + SRG-OS-000163-GPOS-00072 + SRG-OS-000279-GPOS-00109 + SRG-OS-000395-GPOS-00175 A.5.SEC-OL7 8.2.8 8.2 - OL09-00-002347 - SV-271710r1092596_rule + OL09-00-002347 + SV-271710r1092596_rule Terminating an idle ssh session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been let unattended. @@ -108140,7 +121989,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then sshd_idle_timeout_value='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -108149,21 +121997,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*ClientAliveInterval/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -108199,7 +122053,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -108226,7 +122080,7 @@ fi - sshd_set_idle_timeout - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*ClientAliveInterval.*)$ replace: '# \1' @@ -108253,36 +122107,140 @@ fi - restrict_strategy - sshd_set_idle_timeout +- name: Set SSH Client Alive Interval - Check if the parameter ClientAliveInterval + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Set SSH Client Alive Interval - Check if the parameter ClientAliveInterval + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+{{ sshd_idle_timeout_value + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + - name: Set SSH Client Alive Interval block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter ClientAliveInterval is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*ClientAliveInterval\s+ + regexp: (?i)(?i)^\s*{{ "ClientAliveInterval"| regex_escape }}\s+ line: ClientAliveInterval {{ sshd_idle_timeout_value }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002347 + - NIST-800-171-3.1.11 + - NIST-800-53-AC-12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-2(5) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-SC-10 + - PCI-DSS-Req-8.1.8 + - PCI-DSSv4-8.2 + - PCI-DSSv4-8.2.8 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_idle_timeout + +- name: Set SSH Client Alive Interval - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108328,7 +122286,7 @@ To explicitly disable host-based authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: HostbasedAuthentication no @@ -108353,7 +122311,6 @@ following line in DSS06.03 DSS06.06 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -108405,20 +122362,6 @@ following line in SR 2.6 SR 2.7 SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.12.1.2 A.12.5.1 A.12.6.2 @@ -108433,16 +122376,16 @@ following line in 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.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 AC-17(a) CM-7(a) @@ -108453,11 +122396,25 @@ following line in PR.IP-1 PR.PT-3 FIA_UAU.1 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 + 0421 + 0422 + 0484 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 8.3.1 8.3 - OL09-00-002357 - SV-271719r1091869_rule + OL09-00-002357 + SV-271719r1091869_rule SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts. # Remediation is applicable only in certain platforms @@ -108471,21 +122428,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*HostbasedAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "HostbasedAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -108513,7 +122476,7 @@ fi - restrict_strategy - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -108537,7 +122500,7 @@ fi - restrict_strategy - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*HostbasedAuthentication.*)$ replace: '# \1' @@ -108561,36 +122524,130 @@ fi - no_reboot_needed - restrict_strategy +- name: Disable Host-Based Authentication - Check if the parameter HostbasedAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Host-Based Authentication - Check if the parameter HostbasedAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - name: Disable Host-Based Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter HostbasedAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*HostbasedAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+ line: HostbasedAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002357 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-3 + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-8.3 + - PCI-DSSv4-8.3.1 + - disable_host_auth + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Disable Host-Based Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -108651,15 +122708,12 @@ properly migrated from ifcfg format to NetworkManager key rule won't be able to check the configuration. The migration can be accomplished by nmcli connection migrate command. 3.1.12 - CCI-000382 - 1416 AC-17(a) CM-6(b) CM-7(a) CM-7(b) - SRG-OS-000096-GPOS-00050 - OL09-00-000222 - SV-271471r1091125_rule + SRG-OS-000096-GPOS-00050 + 1416 If inbound SSH connections are expected, adding the SSH port to the proper firewalld zone will allow remote access through the SSH port. # Remediation is applicable only in certain platforms @@ -108674,7 +122728,7 @@ fi firewalld_sshd_zone='' -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]]; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; }; then # By default, NetworkManager interfaces are created only once # container image is booted so we do not have information about # what interfaces will be created during container build time. @@ -108700,7 +122754,7 @@ else if test "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)"; then # TODO: NM (nmcli) now has --offline mode support, and it could operate without NM service. # See: https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1183 - # The feature is not quite straighforward (and probably incomplete), though. + # The feature is not quite straightforward (and probably incomplete), though. echo "Not applicable in offline mode. Remediation aborted!" else if systemctl is-active NetworkManager && systemctl is-active firewalld; then @@ -108742,7 +122796,6 @@ fi package_facts: manager: auto tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108770,7 +122823,6 @@ fi - NetworkManager when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108786,10 +122838,8 @@ fi - name: Enable SSH Server firewalld Firewall Exception - Collect facts about system services ansible.builtin.service_facts: null - register: result_services_states when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108811,7 +122861,9 @@ fi ansible.builtin.shell: cmd: nmcli -g UUID,TYPE con | grep -v loopback | awk -F ':' '{ print $1 }' register: result_nmcli_cmd_connections_names + check_mode: false changed_when: false + failed_when: false - name: Enable SSH Server firewalld Firewall Exception - Collect NetworkManager connections zones @@ -108820,20 +122872,27 @@ fi $2}' register: result_nmcli_cmd_connections_zones changed_when: false + failed_when: false with_items: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' + - '{{ result_nmcli_cmd_connections_names.stdout_lines | default([]) }}' + when: + - result_nmcli_cmd_connections_names.stdout_lines is defined + - result_nmcli_cmd_connections_names.stdout_lines | length > 0 - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections are assigned to a firewalld zone ansible.builtin.command: cmd: nmcli connection modify {{ item.0 }} connection.zone {{ firewalld_sshd_zone }} - register: result_nmcli_cmd_connections_assignment + register: result_nmcli_cmd_zone_assignment + changed_when: true with_together: - - '{{ result_nmcli_cmd_connections_names.stdout_lines }}' - - '{{ result_nmcli_cmd_connections_zones.results }}' + - '{{ result_nmcli_cmd_connections_names.stdout_lines | default([]) }}' + - '{{ result_nmcli_cmd_connections_zones.stdout_lines | default([]) }}' when: - - item.1.stdout == '--' + - result_nmcli_cmd_connections_zones.stdout_lines is defined + - result_nmcli_cmd_connections_zones.stdout_lines | length > 0 + - item.1.stdout == '--' or item.1.stdout != firewalld_sshd_zone - name: Enable SSH Server firewalld Firewall Exception - Ensure NetworkManager connections changes are applied @@ -108841,7 +122900,10 @@ fi name: NetworkManager state: restarted when: - - result_nmcli_cmd_connections_assignment is changed + - result_nmcli_cmd_zone_assignment is defined + - result_nmcli_cmd_zone_assignment is changed + - result_nmcli_cmd_zone_assignment.results | selectattr('changed', 'equalto', + true) | list | length > 0 - name: Enable SSH Server firewalld Firewall Exception - Collect firewalld active zones @@ -108849,30 +122911,27 @@ fi cmd: firewall-cmd --get-active-zones | grep -v "^ " | cut -d " " -f 1 register: result_firewall_cmd_zones_names changed_when: false + failed_when: false - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld zones allow SSH - ansible.builtin.command: - cmd: firewall-cmd --permanent --zone={{ item }} --add-service=ssh - register: result_nmcli_cmd_connections_assignment - changed_when: - - '''ALREADY_ENABLED'' not in result_nmcli_cmd_connections_assignment.stderr' + ansible.posix.firewalld: + zone: '{{ item }}' + service: ssh + permanent: true + state: enabled + immediate: true + register: result_firewall_ssh_service_assignment with_items: - - '{{ result_firewall_cmd_zones_names.stdout_lines }}' - - - name: Enable SSH Server firewalld Firewall Exception - Ensure firewalld changes - are applied - ansible.builtin.service: - name: firewalld - state: reloaded + - '{{ result_firewall_cmd_zones_names.stdout_lines | default([]) }}' when: - - result_nmcli_cmd_connections_assignment is changed + - result_firewall_cmd_zones_names.stdout_lines is defined + - result_firewall_cmd_zones_names.stdout_lines | length > 0 when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - ansible_facts.services['firewalld.service'].state == 'running' - ansible_facts.services['NetworkManager.service'].state == 'running' tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108889,8 +122948,9 @@ fi on services states ansible.builtin.assert: that: - - ansible_facts.services['firewalld.service'].state == 'running' - - ansible_facts.services['NetworkManager.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['firewalld.service'].state == 'running' + - ansible_check_mode or ansible_facts.services['NetworkManager.service'].state + == 'running' fail_msg: - firewalld and NetworkManager services are not active. Remediation aborted! - This remediation could not be applied because it depends on firewalld and NetworkManager @@ -108901,7 +122961,6 @@ fi - Enable SSH Server firewalld Firewall Exception remediation successfully executed when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - DISA-STIG-OL09-00-000222 - NIST-800-171-3.1.12 - NIST-800-53-AC-17(a) - NIST-800-53-CM-6(b) @@ -108953,8 +123012,6 @@ supported is version 2, and line Protocol 2 in DSS06.10 3.1.13 3.5.4 - CCI-000197 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -108997,9 +123054,6 @@ supported is version 2, and line Protocol 2 in SR 5.3 SR 7.1 SR 7.6 - 0487 - 1449 - 1506 A.11.2.6 A.13.1.1 A.13.2.1 @@ -109016,9 +123070,9 @@ supported is version 2, and line Protocol 2 in A.9.3.1 A.9.4.2 A.9.4.3 - CIP-003-8 R4.2 - CIP-007-3 R5.1 - CIP-007-3 R7.1 + CIP-003-8 R4.2 + CIP-007-3 R5.1 + CIP-007-3 R7.1 CM-6(a) AC-17(a) AC-17(2) @@ -109030,8 +123084,9 @@ supported is version 2, and line Protocol 2 in PR.AC-6 PR.AC-7 PR.PT-4 - SRG-OS-000074-GPOS-00042 - SRG-OS-000480-GPOS-00227 + SRG-OS-000074-GPOS-00042 + SRG-OS-000480-GPOS-00227 + 1483 SSH protocol version 1 is an insecure implementation of the SSH protocol and has many well-known vulnerability exploits. Exploits of the SSH daemon could provide immediate root access to the system. @@ -109046,21 +123101,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Protocol/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Protocol\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Protocol 2" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Protocol 2" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109087,7 +123148,7 @@ fi - sshd_allow_only_protocol2 - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109110,7 +123171,7 @@ fi - sshd_allow_only_protocol2 - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Protocol.*)$ replace: '# \1' @@ -109133,36 +123194,126 @@ fi - restrict_strategy - sshd_allow_only_protocol2 +- name: Allow Only SSH Protocol 2 - Check if the parameter Protocol is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Allow Only SSH Protocol 2 - Check if the parameter Protocol is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+2$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + - name: Allow Only SSH Protocol 2 block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Protocol\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Protocol\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Protocol is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Protocol"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Protocol\s+ + regexp: (?i)(?i)^\s*{{ "Protocol"| regex_escape }}\s+ line: Protocol 2 state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.13 + - NIST-800-171-3.5.4 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-MA-4(6) + - NIST-800-53-SC-13 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_allow_only_protocol2 + +- name: Allow Only SSH Protocol 2 - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -109208,7 +123359,6 @@ a user has successfully authenticated, add or correct the following line in the BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109229,9 +123379,9 @@ a user has successfully authenticated, add or correct the following line in the CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 - OL09-00-002355 - SV-271717r1091863_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002355 + SV-271717r1091863_rule If compression is allowed in an SSH connection prior to authentication, vulnerabilities in the compression software could result in compromise of the system from an unauthenticated connection, potentially with root privileges. @@ -109241,7 +123391,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_disable_compression='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -109250,21 +123399,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Compression/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Compression\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Compression $var_sshd_disable_compression" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Compression $var_sshd_disable_compression" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109293,7 +123448,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109313,7 +123468,7 @@ fi - sshd_disable_compression - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Compression.*)$ replace: '# \1' @@ -109333,36 +123488,119 @@ fi - restrict_strategy - sshd_disable_compression +- name: Disable Compression Or Set Compression to delayed - Check if the parameter + Compression is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Disable Compression Or Set Compression to delayed - Check if the parameter + Compression is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+{{ var_sshd_disable_compression + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + - name: Disable Compression Or Set Compression to delayed block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Compression\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Compression\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Compression is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Compression"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Compression\s+ + regexp: (?i)(?i)^\s*{{ "Compression"| regex_escape }}\s+ line: Compression {{ var_sshd_disable_compression }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002355 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_compression + +- name: Disable Compression Or Set Compression to delayed - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002355 @@ -109397,7 +123635,7 @@ To explicitly disallow SSH login from accounts with empty passwords, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitEmptyPasswords no @@ -109428,8 +123666,6 @@ should prevent users from being able to assign themselves empty passwords.DSS06.06 3.1.1 3.1.5 - CCI-000766 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109523,13 +123759,14 @@ should prevent users from being able to assign themselves empty passwords.PR.PT-3 FIA_UAU.1 Req-2.2.4 - SRG-OS-000106-GPOS-00053 - SRG-OS-000480-GPOS-00229 - SRG-OS-000480-GPOS-00227 + SRG-OS-000106-GPOS-00053 + SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00227 + 1546 2.2.6 2.2 - OL09-00-002343 - SV-271706r1091830_rule + OL09-00-002343 + SV-271706r1091830_rule Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -109544,21 +123781,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitEmptyPasswords/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitEmptyPasswords no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109587,7 +123830,7 @@ fi - sshd_disable_empty_passwords - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109612,7 +123855,7 @@ fi - sshd_disable_empty_passwords - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitEmptyPasswords.*)$ replace: '# \1' @@ -109637,36 +123880,133 @@ fi - restrict_strategy - sshd_disable_empty_passwords +- name: Disable SSH Access via Empty Passwords - Check if the parameter PermitEmptyPasswords + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Disable SSH Access via Empty Passwords - Check if the parameter PermitEmptyPasswords + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + - name: Disable SSH Access via Empty Passwords block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitEmptyPasswords is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PermitEmptyPasswords\s+ + regexp: (?i)(?i)^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+ line: PermitEmptyPasswords no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002343 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_disable_empty_passwords + +- name: Disable SSH Access via Empty Passwords - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -109706,7 +124046,7 @@ configuration is used if no value is set for GSSAPIAuthentication/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: GSSAPIAuthentication no @@ -109718,8 +124058,6 @@ To explicitly disable GSSAPI authentication, add or correct the following line i BAI10.03 BAI10.05 3.1.12 - CCI-000366 - CCI-001813 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109729,9 +124067,6 @@ To explicitly disable GSSAPI authentication, add or correct the following line i 4.3.4.3.2 4.3.4.3.3 SR 7.6 - 0418 - 1055 - 1402 A.12.1.2 A.12.5.1 A.12.6.2 @@ -109745,10 +124080,13 @@ To explicitly disable GSSAPI authentication, add or correct the following line i PR.IP-1 FTP_ITC_EXT.1 FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - OL09-00-002341 - SV-271704r1091824_rule + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + 0418 + 1055 + 1402 + OL09-00-002341 + SV-271704r1091824_rule GSSAPI authentication is used to provide additional authentication mechanisms to applications. Allowing GSSAPI authentication through SSH exposes the system's GSSAPI to remote hosts, increasing the attack surface of the system. @@ -109763,21 +124101,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "GSSAPIAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "GSSAPIAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -109801,7 +124145,7 @@ fi - sshd_disable_gssapi_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -109821,7 +124165,7 @@ fi - sshd_disable_gssapi_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*GSSAPIAuthentication.*)$ replace: '# \1' @@ -109841,36 +124185,118 @@ fi - restrict_strategy - sshd_disable_gssapi_auth +- name: Disable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Disable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + - name: Disable GSSAPI Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter GSSAPIAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ line: GSSAPIAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002341 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_gssapi_auth + +- name: Disable GSSAPI Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002341 @@ -109905,7 +124331,7 @@ The appropriate configuration is used if no value is set for Kerberos To explicitly disable Kerberos authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: KerberosAuthentication no @@ -109917,8 +124343,6 @@ To explicitly disable Kerberos authentication, add or correct the following line BAI10.03 BAI10.05 3.1.12 - CCI-000366 - CCI-001813 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -109928,20 +124352,6 @@ To explicitly disable Kerberos authentication, add or correct the following line 4.3.4.3.2 4.3.4.3.3 SR 7.6 - 0421 - 0422 - 0431 - 0974 - 1173 - 1401 - 1504 - 1505 - 1546 - 1557 - 1558 - 1559 - 1560 - 1561 A.12.1.2 A.12.5.1 A.12.6.2 @@ -109955,10 +124365,23 @@ To explicitly disable Kerberos authentication, add or correct the following line PR.IP-1 FTP_ITC_EXT.1 FCS_SSH_EXT.1.2 - SRG-OS-000364-GPOS-00151 - SRG-OS-000480-GPOS-00227 - OL09-00-002356 - SV-271718r1091866_rule + SRG-OS-000364-GPOS-00151 + SRG-OS-000480-GPOS-00227 + 0421 + 0422 + 0974 + 1173 + 1401 + 1504 + 1505 + 1546 + 1557 + 1558 + 1559 + 1560 + 1561 + OL09-00-002356 + SV-271718r1091866_rule Kerberos authentication for SSH is often implemented using GSSAPI. If Kerberos is enabled through SSH, the SSH daemon provides a means of access to the system's Kerberos implementation. @@ -109974,21 +124397,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*KerberosAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "KerberosAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "KerberosAuthentication no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110012,7 +124441,7 @@ fi - sshd_disable_kerb_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110032,7 +124461,7 @@ fi - sshd_disable_kerb_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*KerberosAuthentication.*)$ replace: '# \1' @@ -110052,36 +124481,118 @@ fi - restrict_strategy - sshd_disable_kerb_auth +- name: Disable Kerberos Authentication - Check if the parameter KerberosAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Disable Kerberos Authentication - Check if the parameter KerberosAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + - name: Disable Kerberos Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter KerberosAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*KerberosAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "KerberosAuthentication"| regex_escape }}\s+ line: KerberosAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002356 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_kerb_auth + +- name: Disable Kerberos Authentication - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002356 @@ -110112,7 +124623,7 @@ authentication mechanisms. To disable PubkeyAuthentication authentication, add o correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PubkeyAuthentication no @@ -110130,21 +124641,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PubkeyAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PubkeyAuthentication no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110162,7 +124679,7 @@ fi - sshd_disable_pubkey_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110176,7 +124693,7 @@ fi - sshd_disable_pubkey_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PubkeyAuthentication.*)$ replace: '# \1' @@ -110190,36 +124707,100 @@ fi - restrict_strategy - sshd_disable_pubkey_auth +- name: Disable PubkeyAuthentication Authentication - Check if the parameter PubkeyAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Disable PubkeyAuthentication Authentication - Check if the parameter PubkeyAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + - name: Disable PubkeyAuthentication Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PubkeyAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ line: PubkeyAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_pubkey_auth + +- name: Disable PubkeyAuthentication Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -110249,7 +124830,7 @@ configuration is used if no value is set for IgnoreRhosts To explicitly disable support for .rhosts files, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: IgnoreRhosts yes @@ -110274,7 +124855,6 @@ To explicitly disable support for .rhosts files, add or correct the following li DSS06.03 DSS06.06 3.1.12 - CCI-000366 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -110342,11 +124922,12 @@ To explicitly disable support for .rhosts files, add or correct the following li PR.AC-6 PR.IP-1 PR.PT-3 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 1546 2.2.6 2.2 - OL09-00-002348 - SV-271711r1091845_rule + OL09-00-002348 + SV-271711r1091845_rule SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts. # Remediation is applicable only in certain platforms @@ -110360,21 +124941,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*IgnoreRhosts/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*IgnoreRhosts\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "IgnoreRhosts yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110401,7 +124988,7 @@ fi - sshd_disable_rhosts - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110424,7 +125011,7 @@ fi - sshd_disable_rhosts - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*IgnoreRhosts.*)$ replace: '# \1' @@ -110447,36 +125034,127 @@ fi - restrict_strategy - sshd_disable_rhosts +- name: Disable SSH Support for .rhosts Files - Check if the parameter IgnoreRhosts + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Disable SSH Support for .rhosts Files - Check if the parameter IgnoreRhosts + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + - name: Disable SSH Support for .rhosts Files block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter IgnoreRhosts is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*IgnoreRhosts\s+ + regexp: (?i)(?i)^\s*{{ "IgnoreRhosts"| regex_escape }}\s+ line: IgnoreRhosts yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002348 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts + +- name: Disable SSH Support for .rhosts Files - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -110525,7 +125203,6 @@ necessary. BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -110546,7 +125223,7 @@ necessary. CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -110561,21 +125238,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*RhostsRSAAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "RhostsRSAAuthentication no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "RhostsRSAAuthentication no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110598,7 +125281,7 @@ fi - sshd_disable_rhosts_rsa - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110617,7 +125300,7 @@ fi - sshd_disable_rhosts_rsa - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*RhostsRSAAuthentication.*)$ replace: '# \1' @@ -110636,36 +125319,115 @@ fi - restrict_strategy - sshd_disable_rhosts_rsa +- name: Disable SSH Support for Rhosts RSA Authentication - Check if the parameter + RhostsRSAAuthentication is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Disable SSH Support for Rhosts RSA Authentication - Check if the parameter + RhostsRSAAuthentication is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + - name: Disable SSH Support for Rhosts RSA Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter RhostsRSAAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*RhostsRSAAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "RhostsRSAAuthentication"| regex_escape }}\s+ line: RhostsRSAAuthentication no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_rhosts_rsa + +- name: Disable SSH Support for Rhosts RSA Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.12 @@ -110695,7 +125457,7 @@ system directly over a network. To disable root login via SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitRootLogin no @@ -110722,8 +125484,6 @@ To disable root login via SSH, add or correct the following line in DSS06.10 3.1.1 3.1.5 - CCI-000366 - CCI-004045 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -110804,20 +125564,20 @@ To disable root login via SSH, add or correct the following line in A.9.4.3 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.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 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.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 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-6(2) AC-17(a) IA-2 @@ -110833,15 +125593,16 @@ To disable root login via SSH, add or correct the following line in PR.PT-3 FAU_GEN.1 Req-2.2.4 - SRG-OS-000109-GPOS-00056 - SRG-OS-000480-GPOS-00227 - SRG-APP-000148-CTR-000335 - SRG-APP-000190-CTR-000500 + SRG-OS-000109-GPOS-00056 + SRG-OS-000480-GPOS-00227 + SRG-APP-000148-CTR-000335 + SRG-APP-000190-CTR-000500 R33 + 1546 2.2.6 2.2 - OL09-00-002345 - SV-271708r1092594_rule + OL09-00-002345 + SV-271708r1092594_rule Even though the communications channel may be encrypted, an additional layer of security is gained by extending the policy of not logging directly on as root. In addition, logging in with a user-specific account provides individual @@ -110858,21 +125619,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitRootLogin no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -110904,7 +125671,7 @@ fi - sshd_disable_root_login - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -110932,7 +125699,7 @@ fi - sshd_disable_root_login - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitRootLogin.*)$ replace: '# \1' @@ -110960,36 +125727,141 @@ fi - restrict_strategy - sshd_disable_root_login +- name: Disable SSH Root Login - Check if the parameter PermitRootLogin is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Disable SSH Root Login - Check if the parameter PermitRootLogin is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + - name: Disable SSH Root Login block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitRootLogin is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ line: PermitRootLogin no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002345 + - NIST-800-171-3.1.1 + - NIST-800-171-3.1.5 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6(2) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - NIST-800-53-IA-2 + - NIST-800-53-IA-2(5) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_login + +- name: Disable SSH Root Login - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -111026,7 +125898,7 @@ fi To disable password-based root logins over SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitRootLogin prohibit-password @@ -111051,21 +125923,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitRootLogin/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitRootLogin\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitRootLogin prohibit-password" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitRootLogin prohibit-password" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111083,7 +125961,7 @@ fi - sshd_disable_root_password_login - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111097,7 +125975,7 @@ fi - sshd_disable_root_password_login - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitRootLogin.*)$ replace: '# \1' @@ -111111,36 +125989,100 @@ fi - restrict_strategy - sshd_disable_root_password_login +- name: Disable SSH root Login with a Password (Insecure) - Check if the parameter + PermitRootLogin is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Disable SSH root Login with a Password (Insecure) - Check if the parameter + PermitRootLogin is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+prohibit-password$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + - name: Disable SSH root Login with a Password (Insecure) block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitRootLogin is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PermitRootLogin\s+ + regexp: (?i)(?i)^\s*{{ "PermitRootLogin"| regex_escape }}\s+ line: PermitRootLogin prohibit-password state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_root_password_login + +- name: Disable SSH root Login with a Password (Insecure) - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -111164,7 +126106,7 @@ fi To disable TCP forwarding, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: AllowTcpForwarding no @@ -111182,21 +126124,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*AllowTcpForwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*AllowTcpForwarding\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "AllowTcpForwarding no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "AllowTcpForwarding no" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111216,7 +126164,7 @@ fi - sshd_disable_tcp_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111232,7 +126180,7 @@ fi - sshd_disable_tcp_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*AllowTcpForwarding.*)$ replace: '# \1' @@ -111248,36 +126196,106 @@ fi - restrict_strategy - sshd_disable_tcp_forwarding +- name: Disable SSH TCP Forwarding - Check if the parameter AllowTcpForwarding is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Disable SSH TCP Forwarding - Check if the parameter AllowTcpForwarding is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + - name: Disable SSH TCP Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter AllowTcpForwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*AllowTcpForwarding\s+ + regexp: (?i)(?i)^\s*{{ "AllowTcpForwarding"| regex_escape }}\s+ line: AllowTcpForwarding no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_tcp_forwarding + +- name: Disable SSH TCP Forwarding - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -111306,7 +126324,7 @@ systems public keys is available. This should be disabled. To ensure this behavior is disabled, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: IgnoreUserKnownHosts yes @@ -111318,7 +126336,6 @@ To ensure this behavior is disabled, add or correct the following line in BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -111339,9 +126356,10 @@ To ensure this behavior is disabled, add or correct the following line in CM-7(b) CM-6(a) PR.IP-1 - SRG-OS-000480-GPOS-00227 - OL09-00-002349 - SV-271712r1091848_rule + SRG-OS-000480-GPOS-00227 + 1546 + OL09-00-002349 + SV-271712r1091848_rule Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere. @@ -111356,21 +126374,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "IgnoreUserKnownHosts yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "IgnoreUserKnownHosts yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111394,7 +126418,7 @@ fi - sshd_disable_user_known_hosts - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111414,7 +126438,7 @@ fi - sshd_disable_user_known_hosts - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*IgnoreUserKnownHosts.*)$ replace: '# \1' @@ -111434,36 +126458,118 @@ fi - restrict_strategy - sshd_disable_user_known_hosts +- name: Disable SSH Support for User Known Hosts - Check if the parameter IgnoreUserKnownHosts + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Disable SSH Support for User Known Hosts - Check if the parameter IgnoreUserKnownHosts + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + - name: Disable SSH Support for User Known Hosts block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter IgnoreUserKnownHosts is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*IgnoreUserKnownHosts\s+ + regexp: (?i)(?i)^\s*{{ "IgnoreUserKnownHosts"| regex_escape }}\s+ line: IgnoreUserKnownHosts yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002349 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_user_known_hosts + +- name: Disable SSH Support for User Known Hosts - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002349 @@ -111500,17 +126606,17 @@ configuration is used if no value is set for X11Forwarding/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11Forwarding no - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 0484 2.2.6 2.2 - OL09-00-002350 - SV-271713r1091851_rule + OL09-00-002350 + SV-271713r1091851_rule Disable X11 forwarding unless there is an operational requirement to use X11 applications directly. There is a small risk that the remote X11 servers of users who are logged in via SSH with X11 forwarding could be compromised by @@ -111527,21 +126633,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11Forwarding no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11Forwarding no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111563,7 +126675,7 @@ fi - sshd_disable_x11_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111581,7 +126693,7 @@ fi - sshd_disable_x11_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11Forwarding.*)$ replace: '# \1' @@ -111599,36 +126711,111 @@ fi - restrict_strategy - sshd_disable_x11_forwarding +- name: Disable X11 Forwarding - Check if the parameter X11Forwarding is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Disable X11 Forwarding - Check if the parameter X11Forwarding is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + - name: Disable X11 Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11Forwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ line: X11Forwarding no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002350 + - NIST-800-53-CM-6(b) + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_disable_x11_forwarding + +- name: Disable X11 Forwarding - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002350 @@ -111660,7 +126847,7 @@ configuration is used if no value is set for PermitUserEnvironment/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PermitUserEnvironment no @@ -111673,7 +126860,6 @@ To explicitly disable Environment options, add or correct the following BAI10.03 BAI10.05 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -111695,11 +126881,12 @@ To explicitly disable Environment options, add or correct the following CM-6(a) PR.IP-1 Req-2.2.4 - SRG-OS-000480-GPOS-00229 + SRG-OS-000480-GPOS-00229 + 1546 2.2.6 2.2 - OL09-00-002358 - SV-271720r1091872_rule + OL09-00-002358 + SV-271720r1091872_rule SSH environment options potentially allow users to bypass access restriction in some configurations. # Remediation is applicable only in certain platforms @@ -111713,21 +126900,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PermitUserEnvironment/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PermitUserEnvironment no" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111755,7 +126948,7 @@ fi - sshd_do_not_permit_user_env - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111779,7 +126972,7 @@ fi - sshd_do_not_permit_user_env - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PermitUserEnvironment.*)$ replace: '# \1' @@ -111803,36 +126996,130 @@ fi - restrict_strategy - sshd_do_not_permit_user_env +- name: Do Not Allow SSH Environment Options - Check if the parameter PermitUserEnvironment + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Do Not Allow SSH Environment Options - Check if the parameter PermitUserEnvironment + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+no$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + - name: Do Not Allow SSH Environment Options block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PermitUserEnvironment is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PermitUserEnvironment\s+ + regexp: (?i)(?i)^\s*{{ "PermitUserEnvironment"| regex_escape }}\s+ line: PermitUserEnvironment no state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-002358 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - NIST-800-53-CM-7(a) + - NIST-800-53-CM-7(b) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_do_not_permit_user_env + +- name: Do Not Allow SSH Environment Options - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -111862,12 +127149,12 @@ fi Enable GSSAPI Authentication - Sites setup to use Kerberos or other GSSAPI Authenticaion require setting + Sites setup to use Kerberos or other GSSAPI Authentication require setting sshd to accept this authentication. To enable GSSAPI authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: GSSAPIAuthentication yes @@ -111890,21 +127177,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*GSSAPIAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "GSSAPIAuthentication yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "GSSAPIAuthentication yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -111922,7 +127215,7 @@ fi - sshd_enable_gssapi_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -111936,7 +127229,7 @@ fi - sshd_enable_gssapi_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*GSSAPIAuthentication.*)$ replace: '# \1' @@ -111950,36 +127243,100 @@ fi - restrict_strategy - sshd_enable_gssapi_auth +- name: Enable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Enable GSSAPI Authentication - Check if the parameter GSSAPIAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + - name: Enable GSSAPI Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter GSSAPIAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*GSSAPIAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+ line: GSSAPIAuthentication yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_gssapi_auth + +- name: Enable GSSAPI Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - low_complexity @@ -112007,16 +127364,15 @@ authentication types. To enable PAM authentication, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: UsePAM yes - CCI-000877 - SRG-OS-000125-GPOS-00065 + SRG-OS-000125-GPOS-00065 2.2.6 2.2 - OL09-00-002344 - SV-271707r1091833_rule + OL09-00-002344 + SV-271707r1091833_rule When UsePAM is set to yes, PAM runs through account and session types properly. This is important if you want to restrict access to services based off of IP, time or other factors of the account. Additionally, you can make sure users inherit certain environment variables @@ -112032,21 +127388,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*UsePAM/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*UsePAM\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "UsePAM yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112067,7 +127429,7 @@ fi - sshd_enable_pam - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112084,7 +127446,7 @@ fi - sshd_enable_pam - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*UsePAM.*)$ replace: '# \1' @@ -112101,36 +127463,107 @@ fi - restrict_strategy - sshd_enable_pam +- name: Enable PAM - Check if the parameter UsePAM is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Enable PAM - Check if the parameter UsePAM is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + - name: Enable PAM block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePAM\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePAM\s+ + create: false + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter UsePAM is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*UsePAM\s+ + regexp: (?i)(?i)^\s*{{ "UsePAM"| regex_escape }}\s+ line: UsePAM yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002344 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pam + +- name: Enable PAM - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002344 @@ -112161,25 +127594,23 @@ configuration is used if no value is set for PubkeyAuthentication/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PubkeyAuthentication yes - CCI-000765 - CCI-000766 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - OL09-00-002359 - SV-271721r1091875_rule + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 + OL09-00-002359 + SV-271721r1091875_rule Without the use of multifactor authentication, the ease of access to privileged functions is greatly increased. Multifactor authentication requires using two or more factors to achieve authentication. A privileged account is defined as an information system account with authorizations of a privileged user. -The DoD CAC with DoD-approved PKI is an example of multifactor -authentication. +Smart cards or hardware tokens paired with digital certificates are +common examples of multifactor implementations. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -112191,21 +127622,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PubkeyAuthentication/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PubkeyAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PubkeyAuthentication yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PubkeyAuthentication yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112224,7 +127661,7 @@ fi - sshd_enable_pubkey_auth - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112239,7 +127676,7 @@ fi - sshd_enable_pubkey_auth - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PubkeyAuthentication.*)$ replace: '# \1' @@ -112254,36 +127691,103 @@ fi - restrict_strategy - sshd_enable_pubkey_auth +- name: Enable Public Key Authentication - Check if the parameter PubkeyAuthentication + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Enable Public Key Authentication - Check if the parameter PubkeyAuthentication + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + - name: Enable Public Key Authentication block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PubkeyAuthentication is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*PubkeyAuthentication\s+ + regexp: (?i)(?i)^\s*{{ "PubkeyAuthentication"| regex_escape }}\s+ line: PubkeyAuthentication yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002359 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_pubkey_auth + +- name: Enable Public Key Authentication - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002359 @@ -112314,7 +127818,7 @@ configuration is used if no value is set for StrictModes. To explicitly enable StrictModes in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: StrictModes yes @@ -112331,7 +127835,6 @@ To explicitly enable StrictModes in SSH, add or correct t DSS05.07 DSS06.02 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112364,23 +127867,24 @@ To explicitly enable StrictModes in SSH, add or correct t 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 + 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 AC-17(a) CM-6(a) PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 - OL09-00-002351 - SV-271714r1091854_rule + SRG-OS-000480-GPOS-00227 + 1409 + OL09-00-002351 + SV-271714r1091854_rule If other users have access to modify user-specific SSH configuration files, they may be able to log into the system as another user. # Remediation is applicable only in certain platforms @@ -112394,21 +127898,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*StrictModes/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "StrictModes yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "StrictModes yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112431,7 +127941,7 @@ fi - sshd_enable_strictmodes - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112450,7 +127960,7 @@ fi - sshd_enable_strictmodes - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*StrictModes.*)$ replace: '# \1' @@ -112469,36 +127979,115 @@ fi - restrict_strategy - sshd_enable_strictmodes +- name: Enable Use of Strict Mode Checking - Check if the parameter StrictModes is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Enable Use of Strict Mode Checking - Check if the parameter StrictModes is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + - name: Enable Use of Strict Mode Checking block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*StrictModes\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*StrictModes\s+ + create: false + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter StrictModes is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*StrictModes\s+ + regexp: (?i)(?i)^\s*{{ "StrictModes"| regex_escape }}\s+ line: StrictModes yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002351 + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_strictmodes + +- name: Enable Use of Strict Mode Checking - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002351 @@ -112527,7 +128116,7 @@ fi across the system, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: Banner /etc/issue Another section contains information on how to create an @@ -112541,12 +128130,6 @@ appropriate system-wide warning banner. DSS05.10 DSS06.10 3.1.9 - CCI-001387 - CCI-001384 - CCI-000048 - CCI-001386 - CCI-001388 - CCI-001385 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112582,10 +128165,11 @@ appropriate system-wide warning banner. PR.AC-7 FTA_TAB.1 Req-2.2.4 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 - OL09-00-000256 - SV-271487r1091173_rule + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 + 0484 + OL09-00-000256 + SV-271487r1091173_rule The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems whose ownership should not be obvious should ensure usage of a banner that does @@ -112602,21 +128186,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Banner /etc/issue" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112642,7 +128232,7 @@ fi - sshd_enable_warning_banner - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112664,7 +128254,7 @@ fi - sshd_enable_warning_banner - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Banner.*)$ replace: '# \1' @@ -112686,36 +128276,122 @@ fi - restrict_strategy - sshd_enable_warning_banner +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+/etc/issue$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + - name: Enable SSH Warning Banner block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Banner\s+ + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ line: Banner /etc/issue state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - DISA-STIG-OL09-00-000256 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner + +- name: Enable SSH Warning Banner - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -112756,13 +128432,6 @@ appropriate system-wide warning banner. DSS05.10 DSS06.10 3.1.9 - CCI-000048 - CCI-000050 - CCI-001384 - CCI-001385 - CCI-001386 - CCI-001387 - CCI-001388 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -112796,8 +128465,8 @@ appropriate system-wide warning banner. AC-17(a) CM-6(a) PR.AC-7 - SRG-OS-000023-GPOS-00006 - SRG-OS-000228-GPOS-00088 + SRG-OS-000023-GPOS-00006 + SRG-OS-000228-GPOS-00088 A.11.SEC-OL4 The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems @@ -112815,21 +128484,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*Banner/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "Banner /etc/issue.net" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "Banner /etc/issue.net" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -112853,7 +128528,7 @@ fi - sshd_enable_warning_banner_net - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -112873,7 +128548,7 @@ fi - sshd_enable_warning_banner_net - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*Banner.*)$ replace: '# \1' @@ -112893,36 +128568,116 @@ fi - restrict_strategy - sshd_enable_warning_banner_net +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Enable SSH Warning Banner - Check if the parameter Banner is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+/etc/issue.net$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + - name: Enable SSH Warning Banner block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*Banner\s+ + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "Banner"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*Banner\s+ + regexp: (?i)(?i)^\s*{{ "Banner"| regex_escape }}\s+ line: Banner /etc/issue.net state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - CJIS-5.5.6 + - NIST-800-171-3.1.9 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-8(a) + - NIST-800-53-AC-8(c) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_enable_warning_banner_net + +- name: Enable SSH Warning Banner - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.5.6 @@ -112956,7 +128711,7 @@ by users. SSH has the capability to encrypt remote X11 connections when SSH's To enable X11 Forwarding, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11Forwarding yes @@ -112980,7 +128735,6 @@ To enable X11 Forwarding, add or correct the following line in BAI10.05 DSS03.01 3.1.13 - CCI-000366 4.3.4.3.2 4.3.4.3.3 4.4.3.3 @@ -112995,14 +128749,14 @@ To enable X11 Forwarding, add or correct the following line in A.14.2.2 A.14.2.3 A.14.2.4 - CIP-007-3 R7.1 + CIP-007-3 R7.1 CM-6(a) AC-17(a) AC-17(2) DE.AE-1 PR.DS-7 PR.IP-1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Non-encrypted X displays allow an attacker to capture keystrokes and to execute commands remotely. # Remediation is applicable only in certain platforms @@ -113016,21 +128770,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11Forwarding/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11Forwarding yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11Forwarding yes" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113052,7 +128812,7 @@ fi - sshd_enable_x11_forwarding - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113070,7 +128830,7 @@ fi - sshd_enable_x11_forwarding - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11Forwarding.*)$ replace: '# \1' @@ -113088,36 +128848,112 @@ fi - restrict_strategy - sshd_enable_x11_forwarding +- name: Enable Encrypted X11 Forwarding - Check if the parameter X11Forwarding is + configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Enable Encrypted X11 Forwarding - Check if the parameter X11Forwarding is + configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + - name: Enable Encrypted X11 Forwarding block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11Forwarding is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*X11Forwarding\s+ + regexp: (?i)(?i)^\s*{{ "X11Forwarding"| regex_escape }}\s+ line: X11Forwarding yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.13 + - NIST-800-53-AC-17(2) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - high_severity + - low_complexity + - low_disruption + - no_reboot_needed + - restrict_strategy + - sshd_enable_x11_forwarding + +- name: Enable Encrypted X11 Forwarding - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.13 @@ -113232,16 +129068,16 @@ because each system has unique user names and group names. 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.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 AC-3 CM-6(a) PR.AC-4 @@ -113270,7 +129106,7 @@ The appropriate configuration is used if no value is set for PrintLas To explicitly enable LastLog in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: PrintLastLog yes @@ -113281,7 +129117,6 @@ To explicitly enable LastLog in SSH, add or correct the following line in DSS05.04 DSS05.10 DSS06.10 - CCI-000366 4.3.3.6.1 4.3.3.6.2 4.3.3.6.3 @@ -113307,9 +129142,11 @@ To explicitly enable LastLog in SSH, add or correct the following line in AC-9 AC-9(1) PR.AC-7 - SRG-OS-000480-GPOS-00227 - OL09-00-002352 - SV-271715r1091857_rule + SRG-OS-000480-GPOS-00227 + 0582 + 0846 + OL09-00-002352 + SV-271715r1091857_rule Providing users feedback on when account accesses last occurred facilitates user recognition and reporting of unauthorized account use. # Remediation is applicable only in certain platforms @@ -113323,21 +129160,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*PrintLastLog/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "PrintLastLog yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "PrintLastLog yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113358,7 +129201,7 @@ fi - sshd_print_last_log - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113375,7 +129218,7 @@ fi - sshd_print_last_log - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*PrintLastLog.*)$ replace: '# \1' @@ -113392,36 +129235,108 @@ fi - restrict_strategy - sshd_print_last_log +- name: Enable SSH Print Last Log - Check if the parameter PrintLastLog is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Enable SSH Print Last Log - Check if the parameter PrintLastLog is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + - name: Enable SSH Print Last Log block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ + create: false + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter PrintLastLog is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*PrintLastLog\s+ + regexp: (?i)(?i)^\s*{{ "PrintLastLog"| regex_escape }}\s+ line: PrintLastLog yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002352 + - NIST-800-53-AC-9 + - NIST-800-53-AC-9(1) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_print_last_log + +- name: Enable SSH Print Last Log - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002352 @@ -113451,20 +129366,17 @@ elapsed. To decrease the default limits, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: RekeyLimit - CCI-002421 - CCI-000068 - CCI-002418 FCS_SSH_EXT.1.8 - SRG-OS-000480-GPOS-00227 - SRG-OS-000033-GPOS-00014 - OL09-00-002342 - SV-271705r1091827_rule + SRG-OS-000480-GPOS-00227 + SRG-OS-000033-GPOS-00014 + OL09-00-002342 + SV-271705r1091827_rule By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited. @@ -113476,7 +129388,6 @@ var_rekey_limit_time=' Set LogLevel to INFO - The INFO parameter specifices that record login and logout activity will be logged. + The INFO parameter specifies that record login and logout activity will be logged. The default SSH configuration sets the log level to INFO. The appropriate configuration is used if no value is set for LogLevel. @@ -113765,12 +129826,13 @@ configuration is used if no value is set for LogLevel. To explicitly specify the log level in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: LogLevel INFO AC-17(a) CM-6(a) + 1409 SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. INFO level is the @@ -113788,21 +129850,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "LogLevel INFO" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113822,7 +129890,7 @@ fi - sshd_set_loglevel_info - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -113838,7 +129906,7 @@ fi - sshd_set_loglevel_info - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*LogLevel.*)$ replace: '# \1' @@ -113854,36 +129922,104 @@ fi - restrict_strategy - sshd_set_loglevel_info +- name: Set LogLevel to INFO - Check if the parameter LogLevel is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Set LogLevel to INFO - Check if the parameter LogLevel is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+INFO$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + - name: Set LogLevel to INFO block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter LogLevel is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ line: LogLevel INFO state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - low_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_info + +- name: Set LogLevel to INFO - set file mode for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AC-17(a) @@ -113910,21 +130046,20 @@ To specify the log level in SSH, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: LogLevel VERBOSE - CCI-000067 - CIP-007-3 R7.1 + CIP-007-3 R7.1 AC-17(a) AC-17(1) CM-6(a) Req-2.2.4 - SRG-OS-000032-GPOS-00013 + SRG-OS-000032-GPOS-00013 2.2.6 2.2 - OL09-00-002340 - SV-271703r1091821_rule + OL09-00-002340 + SV-271703r1091821_rule SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. INFO or @@ -113943,21 +130078,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*LogLevel/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "LogLevel VERBOSE" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "LogLevel VERBOSE" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -113982,7 +130123,7 @@ fi - sshd_set_loglevel_verbose - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114003,7 +130144,7 @@ fi - sshd_set_loglevel_verbose - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*LogLevel.*)$ replace: '# \1' @@ -114024,36 +130165,120 @@ fi - restrict_strategy - sshd_set_loglevel_verbose +- name: Set SSH Daemon LogLevel to VERBOSE - Check if the parameter LogLevel is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Set SSH Daemon LogLevel to VERBOSE - Check if the parameter LogLevel is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+VERBOSE$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + - name: Set SSH Daemon LogLevel to VERBOSE block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter LogLevel is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*LogLevel\s+ + regexp: (?i)(?i)^\s*{{ "LogLevel"| regex_escape }}\s+ line: LogLevel VERBOSE state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002340 + - NIST-800-53-AC-17(1) + - NIST-800-53-AC-17(a) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-2.2.4 + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_loglevel_verbose + +- name: Set SSH Daemon LogLevel to VERBOSE - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002340 @@ -114088,7 +130313,6 @@ to set MaxAUthTries edit /etc/ssh/sshd_config as follows: 0421 0422 - 0431 0974 1173 1401 @@ -114110,7 +130334,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then sshd_max_auth_tries_value='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114119,21 +130342,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxAuthTries/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxAuthTries\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxAuthTries $sshd_max_auth_tries_value" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114158,7 +130387,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114174,7 +130403,7 @@ fi - sshd_set_max_auth_tries - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxAuthTries.*)$ replace: '# \1' @@ -114190,36 +130419,107 @@ fi - restrict_strategy - sshd_set_max_auth_tries +- name: Set SSH authentication attempt limit - Check if the parameter MaxAuthTries + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Set SSH authentication attempt limit - Check if the parameter MaxAuthTries + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+{{ sshd_max_auth_tries_value + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + - name: Set SSH authentication attempt limit block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxAuthTries is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxAuthTries\s+ + regexp: (?i)(?i)^\s*{{ "MaxAuthTries"| regex_escape }}\s+ line: MaxAuthTries {{ sshd_max_auth_tries_value }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_auth_tries + +- name: Set SSH authentication attempt limit - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114258,7 +130558,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_max_sessions='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114267,21 +130566,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxSessions/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxSessions\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxSessions $var_sshd_max_sessions" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114306,7 +130611,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114322,7 +130627,7 @@ fi - sshd_set_max_sessions - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxSessions.*)$ replace: '# \1' @@ -114338,36 +130643,106 @@ fi - restrict_strategy - sshd_set_max_sessions +- name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Set SSH MaxSessions limit - Check if the parameter MaxSessions is configured + correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+{{ var_sshd_max_sessions + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + - name: Set SSH MaxSessions limit block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxSessions is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxSessions\s+ + regexp: (?i)(?i)^\s*{{ "MaxSessions"| regex_escape }}\s+ line: MaxSessions {{ var_sshd_max_sessions }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_max_sessions + +- name: Set SSH MaxSessions limit - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114408,7 +130783,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_set_maxstartups='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114417,21 +130791,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*MaxStartups/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*MaxStartups\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "MaxStartups $var_sshd_set_maxstartups" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114456,7 +130836,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114472,7 +130852,7 @@ fi - sshd_set_maxstartups - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*MaxStartups.*)$ replace: '# \1' @@ -114488,36 +130868,107 @@ fi - restrict_strategy - sshd_set_maxstartups +- name: Ensure SSH MaxStartups is configured - Check if the parameter MaxStartups + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Ensure SSH MaxStartups is configured - Check if the parameter MaxStartups + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+{{ var_sshd_set_maxstartups + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + - name: Ensure SSH MaxStartups is configured block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ + create: false + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter MaxStartups is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*MaxStartups\s+ + regexp: (?i)(?i)^\s*{{ "MaxStartups"| regex_escape }}\s+ line: MaxStartups {{ var_sshd_set_maxstartups }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - PCI-DSSv4-2.2 + - PCI-DSSv4-2.2.6 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_set_maxstartups + +- name: Ensure SSH MaxStartups is configured - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - PCI-DSSv4-2.2 @@ -114545,6 +130996,7 @@ Ideally, don't have any active configuration directives in that file, and distri to several files in the /etc/ssh/sshd_config.d directory. 164.312(a) FCS_SSH_EXT.1 + 1409 This form of distributed configuration is considered as a good practice, and as other sshd rules assume that directives in files in the /etc/ssh/sshd_config.d config directory are effective, there has to be a rule that ensures this. Aside from that, having multiple configuration files makes the SSH Server configuration changes easier to partition according to the reason that they were introduced, and therefore it should help to perform merges of hardening updates. # Remediation is applicable only in certain platforms @@ -114600,7 +131052,6 @@ SSH, add or correct the following line in the /etc/ssh/sshd_configDSS05.07 DSS06.02 3.1.12 - CCI-000366 164.308(a)(4)(i) 164.308(b)(1) 164.308(b)(3) @@ -114633,21 +131084,21 @@ SSH, add or correct the following line in the /etc/ssh/sshd_configA.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 + 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 CM-6(a) AC-17(a) AC-6 PR.AC-4 PR.DS-5 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 SSH daemon privilege separation causes the SSH process to drop root privileges when not needed which would decrease the impact of software vulnerabilities in the unprivileged section. @@ -114657,7 +131108,6 @@ if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then var_sshd_priv_separation='' - # Find the include keyword, extract from the line the glob expression representing included files. # And if it is a relative path prepend '/etc/ssh/' included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*include\s*//I' | sed -e 's|^[^/]|/etc/ssh/&|') @@ -114666,21 +131116,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +chmod 0600 /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + +LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then - LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" # Insert at the beginning of the file -printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" +cat "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -114707,7 +131163,7 @@ fi - always - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -114725,7 +131181,7 @@ fi - sshd_use_priv_separation - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*UsePrivilegeSeparation.*)$ replace: '# \1' @@ -114743,36 +131199,113 @@ fi - restrict_strategy - sshd_use_priv_separation +- name: Enable Use of Privilege Separation - Check if the parameter UsePrivilegeSeparation + is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Enable Use of Privilege Separation - Check if the parameter UsePrivilegeSeparation + is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+{{ var_sshd_priv_separation + }}$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + - name: Enable Use of Privilege Separation block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + create: false + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter UsePrivilegeSeparation is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf create: true - regexp: (?i)(?i)^\s*UsePrivilegeSeparation\s+ + regexp: (?i)(?i)^\s*{{ "UsePrivilegeSeparation"| regex_escape }}\s+ line: UsePrivilegeSeparation {{ var_sshd_priv_separation }} state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - NIST-800-171-3.1.12 + - NIST-800-53-AC-17(a) + - NIST-800-53-AC-6 + - NIST-800-53-CM-6(a) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_use_priv_separation + +- name: Enable Use of Privilege Separation - set file mode for /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-171-3.1.12 @@ -114795,155 +131328,6 @@ fi - - Use Only Strong MACs - Limit the MACs to strong hash algorithms. -The following line in /etc/ssh/sshd_config demonstrates use -of those MACs: -MACs - - - CCI-001453 - AC-17 (2) - SRG-OS-000250-GPOS-00093 - OL09-00-000262 - SV-271490r1092628_rule - MD5 and 96-bit MAC algorithms are considered weak and have been shown to increase -exploitability in SSH downgrade attacks. Weak algorithms continue to have a great deal of -attention as a weak spot that can be exploited with expanded computing power. An -attacker that breaks the algorithm could take advantage of a MiTM position to decrypt the -SSH tunnel and capture credentials and information - # Remediation is applicable only in certain platforms -if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then - -sshd_strong_macs='' - - -# 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' <<< "^MACs") - -# shellcheck disable=SC2059 -printf -v formatted_output "%s %s" "$stripped_key" "$sshd_strong_macs" - -# 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 "^MACs\\>" "/etc/ssh/sshd_config"; then - escaped_formatted_output=$(sed -e 's|/|\\/|g' <<< "$formatted_output") - LC_ALL=C sed -i --follow-symlinks "s/^MACs\\>.*/$escaped_formatted_output/gi" "/etc/ssh/sshd_config" -else - if [[ -s "/etc/ssh/sshd_config" ]] && [[ -n "$(tail -c 1 -- "/etc/ssh/sshd_config" || true)" ]]; then - LC_ALL=C sed -i --follow-symlinks '$a'\\ "/etc/ssh/sshd_config" - fi - printf '%s\n' "$formatted_output" >> "/etc/ssh/sshd_config" -fi - -else - >&2 echo 'Remediation is not applicable, nothing was done' -fi - - - name: Gather the package facts - package_facts: - manager: auto - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs -- name: XCCDF Value sshd_strong_macs # promote to variable - set_fact: - sshd_strong_macs: !!str - tags: - - always - -- name: Find sshd_config included files - shell: |- - included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') - [[ -n $included_files ]] && ls $included_files || true - register: sshd_config_included_files - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - -- name: Comment conf from included files - replace: - path: '{{ item }}' - regexp: ^(\s*MACs.*)$ - replace: '# \1' - loop: '{{ sshd_config_included_files.stdout_lines }}' - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - -- name: Use Only Strong MACs - block: - - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - state: absent - when: dupes.found is defined and dupes.found > 1 - - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*MACs\s+ - line: MACs {{ sshd_strong_macs }} - state: present - insertbefore: BOF - validate: /usr/sbin/sshd -t -f %s - when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - DISA-STIG-OL09-00-000262 - - NIST-800-53-AC-17 (2) - - low_complexity - - low_disruption - - medium_severity - - no_reboot_needed - - restrict_strategy - - sshd_use_strong_macs - - - - - - - - - - Prevent remote hosts from connecting to the proxy display The SSH daemon should prevent remote hosts from connecting to the proxy @@ -114956,15 +131340,14 @@ To explicitly prevent remote connections to the proxy display, add or correct the following line in -/etc/ssh/sshd_config: +/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf: X11UseLocalhost yes - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-002354 - SV-271716r1091860_rule + SRG-OS-000480-GPOS-00227 + OL09-00-002354 + SV-271716r1091860_rule When X11 forwarding is enabled, there may be additional exposure to the server and client displays if the sshd proxy display is configured to listen on the wildcard address. By default, sshd binds the forwarding server to the @@ -114982,21 +131365,27 @@ for included_file in ${included_files} ; do LC_ALL=C sed -i "/^\s*X11UseLocalhost/Id" "$included_file" done -if [ -e "/etc/ssh/sshd_config" ] ; then +mkdir -p /etc/ssh/sshd_config.d +touch /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf +chmod 0600 /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" +LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf +if [ -e "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" ] ; then - LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config" + LC_ALL=C sed -i "/^\s*X11UseLocalhost\s\+/Id" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" else - touch "/etc/ssh/sshd_config" + touch "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" fi # make sure file has newline at the end -sed -i -e '$a\' "/etc/ssh/sshd_config" +sed -i -e '$a\' "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" -cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak" +cp "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" # Insert at the beginning of the file -printf '%s\n' "X11UseLocalhost yes" > "/etc/ssh/sshd_config" -cat "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config" +printf '%s\n' "X11UseLocalhost yes" > "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" +cat "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" >> "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf" # Clean up after ourselves. -rm "/etc/ssh/sshd_config.bak" +rm "/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf.bak" else >&2 echo 'Remediation is not applicable, nothing was done' @@ -115016,7 +131405,7 @@ fi - sshd_x11_use_localhost - name: Find sshd_config included files - shell: |- + ansible.builtin.shell: |- included_files=$(grep -oP "^\s*(?i)include.*" /etc/ssh/sshd_config | sed -e 's/\s*Include\s*//i' | sed -e 's|^[^/]|/etc/ssh/&|') [[ -n $included_files ]] && ls $included_files || true register: sshd_config_included_files @@ -115032,7 +131421,7 @@ fi - sshd_x11_use_localhost - name: Comment conf from included files - replace: + ansible.builtin.replace: path: '{{ item }}' regexp: ^(\s*X11UseLocalhost.*)$ replace: '# \1' @@ -115048,36 +131437,107 @@ fi - restrict_strategy - sshd_x11_use_localhost +- name: Prevent remote hosts from connecting to the proxy display - Check if the parameter + X11UseLocalhost is configured + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + register: _sshd_config_has_parameter + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Prevent remote hosts from connecting to the proxy display - Check if the parameter + X11UseLocalhost is configured correctly + ansible.builtin.find: + paths: + - /etc/ssh/sshd_config + - /etc/ssh/sshd_config.d + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+yes$ + register: _sshd_config_correctly + when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + - name: Prevent remote hosts from connecting to the proxy display block: - - name: Check for duplicate values - lineinfile: - path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ - state: absent - check_mode: true - changed_when: false - register: dupes - - name: Deduplicate values from /etc/ssh/sshd_config - lineinfile: + ansible.builtin.lineinfile: path: /etc/ssh/sshd_config - create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + create: false + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ state: absent - when: dupes.found is defined and dupes.found > 1 - - name: Insert correct line to /etc/ssh/sshd_config - lineinfile: - path: /etc/ssh/sshd_config + - name: Check if /etc/ssh/sshd_config.d exists + ansible.builtin.stat: + path: /etc/ssh/sshd_config.d + register: _etc_ssh_sshd_config_d_exists + + - name: Check if the parameter X11UseLocalhost is present in /etc/ssh/sshd_config.d + ansible.builtin.find: + paths: /etc/ssh/sshd_config.d + recurse: 'yes' + follow: 'no' + contains: (?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + register: _etc_ssh_sshd_config_d_has_parameter + when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir + + - name: Remove parameter from files in /etc/ssh/sshd_config.d + ansible.builtin.lineinfile: + path: '{{ item.path }}' + create: false + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ + state: absent + with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}' + when: _etc_ssh_sshd_config_d_has_parameter.matched + + - name: Insert correct line to /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf create: true - regexp: (?i)(?i)^\s*X11UseLocalhost\s+ + regexp: (?i)(?i)^\s*{{ "X11UseLocalhost"| regex_escape }}\s+ line: X11UseLocalhost yes state: present insertbefore: BOF validate: /usr/sbin/sshd -t -f %s + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - _sshd_config_correctly.matched == 0 or _sshd_config_has_parameter.matched != 1 + tags: + - DISA-STIG-OL09-00-002354 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - sshd_x11_use_localhost + +- name: Prevent remote hosts from connecting to the proxy display - set file mode + for /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + ansible.builtin.file: + path: /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + mode: '0600' + state: touch + modification_time: preserve + access_time: preserve when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - DISA-STIG-OL09-00-002354 @@ -115178,7 +131638,10 @@ $ sudo yum install sssd PR.AC-1 PR.AC-6 PR.AC-7 + SRG-OS-000375-GPOS-00160 R67 + OL09-00-000285 + SV-271493r1091191_rule # Remediation is applicable only in certain platforms if rpm --quiet -q sssd-common; then @@ -115195,6 +131658,7 @@ fi package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000285 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -115204,11 +131668,12 @@ fi - package_sssd_installed - name: Ensure sssd is installed - package: + ansible.builtin.package: name: sssd state: present when: '"sssd-common" in ansible_facts.packages' tags: + - DISA-STIG-OL09-00-000285 - NIST-800-53-CM-6(a) - enable_strategy - low_complexity @@ -115298,11 +131763,14 @@ The sssd service can be enabled with the following comman PR.AC-1 PR.AC-6 PR.AC-7 + SRG-OS-000375-GPOS-00160 R67 + OL09-00-000286 + SV-271494r1091194_rule - + # Remediation is applicable only in certain platforms -if rpm --quiet -q sssd-common && { rpm --quiet -q kernel || rpm --quiet -q kernel-uek; }; then +if rpm --quiet -q sssd-common && { ( rpm --quiet -q sssd-common && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ); }; then SYSTEMCTL_EXEC='/usr/bin/systemctl' "$SYSTEMCTL_EXEC" unmask 'sssd.service' @@ -115319,6 +131787,7 @@ fi package_facts: manager: auto tags: + - DISA-STIG-OL09-00-000286 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(10) - enable_strategy @@ -115332,7 +131801,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the SSSD Service - Enable Service sssd @@ -115343,10 +131812,8 @@ fi masked: false when: - '"sssd-common" in ansible_facts.packages' - when: - - '"sssd-common" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: + - DISA-STIG-OL09-00-000286 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(10) - enable_strategy @@ -115355,6 +131822,11 @@ fi - medium_severity - no_reboot_needed - service_sssd_enabled + - special_service_block + when: + - '"sssd-common" in ansible_facts.packages' + - ( "sssd-common" in ansible_facts.packages and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_sssd @@ -115369,6 +131841,10 @@ class enable_sssd { [customizations.services] enabled = ["sssd"] + + + + @@ -115383,13 +131859,11 @@ for example, hardware tokens providing time-based or challenge-response authenti Configuring certificate_verification to ocsp_dgst= ensures that certificates for multifactor solutions are checked via Online Certificate Status Protocol (OCSP). - CCI-001954 - CCI-004046 IA-2(11) - SRG-OS-000375-GPOS-00160 - SRG-OS-000377-GPOS-00162 - OL09-00-000930 - SV-271608r1091536_rule + SRG-OS-000375-GPOS-00160 + SRG-OS-000377-GPOS-00162 + OL09-00-000930 + SV-271608r1091536_rule Ensuring that multifactor solutions certificates are checked via Online Certificate Status Protocol (OCSP) ensures the security of the system. # Remediation is applicable only in certain platforms @@ -115415,10 +131889,13 @@ for f in $(echo -n "$MAIN_CONF /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[sssd\]([^\n\[]*\n+)+?[[:space:]]*certificate_verification" "$f"; then + if ! grep -qPz "certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function" "$f"; then sed -i "s/certificate_verification[^(\n)]*/certificate_verification=ocsp_dgst=$var_sssd_certificate_verification_digest_function/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[sssd\]" "$f"; then @@ -115463,7 +131940,7 @@ fi - always - name: Ensure that "certificate_verification" is not set in /etc/sssd/sssd.conf - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: sssd option: certificate_verification @@ -115481,7 +131958,7 @@ fi - sssd_certificate_verification - name: Ensure that "certificate_verification" is not set in /etc/sssd/conf.d/*.conf - ini_file: + community.general.ini_file: path: /etc/sssd/conf.d/*.conf section: sssd option: certificate_verification @@ -115499,7 +131976,7 @@ fi - sssd_certificate_verification - name: Ensure that "certificate_verification" is set - ini_file: + community.general.ini_file: path: /etc/sssd/conf.d/certificate_verification.conf section: sssd option: certificate_verification @@ -115539,11 +132016,10 @@ domains = testing.test Automatic remediation of this control is not available, since all of the settings in in the certmap need to be customized. - CCI-000187 IA-5 (2) (c) - SRG-OS-000068-GPOS-00036 - OL09-00-000910 - SV-271606r1091530_rule + SRG-OS-000068-GPOS-00036 + OL09-00-000910 + SV-271606r1091530_rule Without mapping the certificate used to authenticate to the user account, the ability to determine the identity of the individual user or group will not be available for forensic analysis. @@ -115575,9 +132051,6 @@ services = sudo, autofs, pam DSS05.10 DSS06.03 DSS06.10 - CCI-004046 - CCI-001953 - CCI-001954 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -115617,9 +132090,9 @@ services = sudo, autofs, pam PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000375-GPOS-00160 - SRG-OS-000376-GPOS-00161 - SRG-OS-000377-GPOS-00162 + SRG-OS-000375-GPOS-00160 + SRG-OS-000376-GPOS-00161 + SRG-OS-000377-GPOS-00162 R67 Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is @@ -115788,7 +132261,7 @@ fi - sssd_enable_pam_services - name: Configure PAM in SSSD Services - Insert entry to /etc/sssd/sssd.conf - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: sssd option: services @@ -115834,12 +132307,14 @@ Also add or update "pam_sss.so" line in auth section of "/etc/pam.d/smartcard-au include the "allow_missing_name" option, like in the following example: /etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name - CCI-000765 - CCI-004047 - CCI-004046 + Req-8.3 + SRG-OS-000375-GPOS-00160 + SRG-OS-000105-GPOS-00052 + SRG-OS-000106-GPOS-00053 + SRG-OS-000107-GPOS-00054 + SRG-OS-000108-GPOS-00055 0421 0422 - 0431 0974 1173 1401 @@ -115851,14 +132326,8 @@ include the "allow_missing_name" option, like in the following example: 1559 1560 1561 - Req-8.3 - SRG-OS-000375-GPOS-00160 - SRG-OS-000105-GPOS-00052 - SRG-OS-000106-GPOS-00053 - SRG-OS-000107-GPOS-00054 - SRG-OS-000108-GPOS-00055 - OL09-00-000925 - SV-271607r1091533_rule + OL09-00-000925 + SV-271607r1091533_rule Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the @@ -115867,9 +132336,8 @@ authentication device. Multi-Factor Authentication (MFA) solutions that require devices separate from information systems gaining access include, for example, hardware tokens -providing time-based or challenge-response authenticators and smart cards such -as the U.S. Government Personal Identity Verification card and the DoD Common -Access Card. +providing time-based or challenge-response authenticators and smart cards +or similar secure authentication devices issued by an organization or identity provider. # Remediation is applicable only in certain platforms if rpm --quiet -q sssd-common; then @@ -115888,10 +132356,13 @@ for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*pam_cert_auth" "$f"; then + if ! grep -qPz "pam_cert_auth=True" "$f"; then sed -i "s/pam_cert_auth[^(\n)]*/pam_cert_auth=True/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[pam\]" "$f"; then @@ -115977,7 +132448,7 @@ fi - sssd_enable_smartcards - name: Test for domain group - command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '^\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -115994,7 +132465,7 @@ fi - sssd_enable_smartcards - name: Add default domain group (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116023,7 +132494,7 @@ fi - sssd_enable_smartcards - name: Enable Smartcards in SSSD - ini_file: + community.general.ini_file: dest: /etc/sssd/sssd.conf section: pam option: pam_cert_auth @@ -116042,7 +132513,7 @@ fi - sssd_enable_smartcards - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116097,13 +132568,14 @@ fi cmd: authselect check register: result_authselect_check_cmd changed_when: false + check_mode: false failed_when: false - name: Enable Smartcards in SSSD - Informative message based on the authselect integrity check result ansible.builtin.assert: that: - - result_authselect_check_cmd.rc == 0 + - 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 @@ -116120,6 +132592,7 @@ fi 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 @@ -116240,6 +132713,7 @@ fi state: present register: result_pam_sssd_enable_smartcards_add when: + - result_pam_module_sssd_enable_smartcards_option_present.found is defined - result_pam_module_sssd_enable_smartcards_option_present.found == 0 - name: Enable Smartcards in SSSD - Define a fact for control already filtered in @@ -116328,6 +132802,7 @@ fi state: present register: result_pam_sssd_enable_smartcards_add when: + - result_pam_module_sssd_enable_smartcards_option_present.found is defined - result_pam_module_sssd_enable_smartcards_option_present.found == 0 when: - '"sssd-common" in ansible_facts.packages' @@ -116353,13 +132828,11 @@ fi SSSD Has a Correct Trust Anchor SSSD must have acceptable trust anchor present. Automatic remediation of this control is not available. - CCI-004068 - CCI-000185 IA-5 (2) (a) - SRG-OS-000066-GPOS-00034 - SRG-OS-000384-GPOS-00167 - OL09-00-000900 - SV-271604r1091524_rule + SRG-OS-000066-GPOS-00034 + SRG-OS-000384-GPOS-00167 + OL09-00-000900 + SV-271604r1091524_rule Without path validation, an informed trust decision by the relying party cannot be made when presented with any certificate not already explicitly trusted. @@ -116410,7 +132883,6 @@ offline_credentials_expiration = 1 DSS05.10 DSS06.03 DSS06.10 - CCI-002007 4.3.3.2.2 4.3.3.5.1 4.3.3.5.2 @@ -116450,9 +132922,9 @@ offline_credentials_expiration = 1 PR.AC-1 PR.AC-6 PR.AC-7 - SRG-OS-000383-GPOS-00166 - OL09-00-000935 - SV-271609r1091539_rule + SRG-OS-000383-GPOS-00166 + OL09-00-000935 + SV-271609r1091539_rule If cached authentication information is out-of-date, the validity of the authentication information may be questionable. # Remediation is applicable only in certain platforms @@ -116473,10 +132945,13 @@ for f in $(echo -n "/etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf"); do # find key in section and change value if grep -qzosP "[[:space:]]*\[pam\]([^\n\[]*\n+)+?[[:space:]]*offline_credentials_expiration" "$f"; then + if ! grep -qPz "offline_credentials_expiration=1" "$f"; then sed -i "s/offline_credentials_expiration[^(\n)]*/offline_credentials_expiration=1/" "$f" - found=true + fi + + found=true # find section and add key = value to it elif grep -qs "[[:space:]]*\[pam\]" "$f"; then @@ -116517,7 +132992,7 @@ fi - sssd_offline_cred_expiration - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -116535,7 +133010,7 @@ fi - sssd_offline_cred_expiration - name: Add default domain group (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116565,7 +133040,7 @@ fi - sssd_offline_cred_expiration - name: Configure SSD to Expire Offline Credentials - ini_file: + community.general.ini_file: dest: /etc/sssd/sssd.conf section: pam option: offline_credentials_expiration @@ -116585,7 +133060,7 @@ fi - sssd_offline_cred_expiration - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116644,10 +133119,9 @@ allows SSSD to fetch identity information from an LDAP server.ldap_tls_reqcert option in /etc/sssd/sssd.conf to demand. - CCI-001453 SC-12(3) CM-6(a) - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 R67 Without a valid certificate presented to the LDAP client backend, the identity of a server can be forged compromising LDAP remote access sessions. @@ -116702,7 +133176,7 @@ fi - unknown_strategy - name: Test for id_provider different than Active Directory (ad) - command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + ansible.builtin.command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' /etc/sssd/sssd.conf register: test_id_provider failed_when: false @@ -116722,7 +133196,7 @@ fi - unknown_strategy - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -116742,7 +133216,7 @@ fi - name: Add default domain group and set ldap_tls_reqcert in sssd configuration (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -116773,7 +133247,7 @@ fi - unknown_strategy - name: Set ldap_tls_reqcert in sssd configuration - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' option: ldap_tls_reqcert @@ -116797,7 +133271,7 @@ fi - unknown_strategy - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -116870,7 +133344,6 @@ set to ldap or ipa, use the follow DSS05.03 DSS05.05 DSS06.06 - CCI-001453 4.3.3.5.1 4.3.3.5.2 4.3.3.5.3 @@ -116944,7 +133417,7 @@ set to ldap or ipa, use the follow PR.IP-1 PR.PT-3 PR.PT-4 - SRG-OS-000250-GPOS-00093 + SRG-OS-000250-GPOS-00093 R67 Without cryptographic integrity protections, information can be altered by unauthorized users without detection. The ssl directive specifies @@ -117002,7 +133475,7 @@ fi - unknown_strategy - name: Test for id_provider different than Active Directory (ad) - command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' + ansible.builtin.command: grep -qzosP '[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$' /etc/sssd/sssd.conf register: test_id_provider failed_when: false @@ -117023,7 +133496,7 @@ fi - unknown_strategy - name: Test for domain group - command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf + ansible.builtin.command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf register: test_grep_domain failed_when: false changed_when: false @@ -117044,7 +133517,7 @@ fi - name: Add default domain group and set ldap_id_use_start_tls in sssd configuration (if no domain there) - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ item.section }}' option: '{{ item.option }}' @@ -117076,7 +133549,7 @@ fi - unknown_strategy - name: Set ldap_id_use_start_tls in sssd configuration - ini_file: + community.general.ini_file: path: /etc/sssd/sssd.conf section: '{{ test_grep_domain.stdout | regex_replace(''\[(.*)\]'',''\1'') }}' option: ldap_id_use_start_tls @@ -117101,7 +133574,7 @@ fi - unknown_strategy - name: Find all the conf files inside /etc/sssd/conf.d/ - find: + ansible.builtin.find: paths: /etc/sssd/conf.d/ patterns: '*.conf' register: sssd_conf_d_files @@ -117159,17 +133632,15 @@ The usbguard package can be installed with the following $ sudo yum install usbguard - CCI-001958 - CCI-003959 - 1418 CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - SRG-APP-000141-CTR-000315 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 A.23.SEC-OL1 - OL09-00-000320 - SV-271503r1091221_rule + 1418 + OL09-00-000320 + SV-271503r1091221_rule usbguard is a software framework that helps to protect against rogue USB devices by implementing basic whitelisting/blacklisting capabilities based on USB device attributes. @@ -117199,7 +133670,7 @@ fi - package_usbguard_installed - name: Ensure usbguard is installed - package: + ansible.builtin.package: name: usbguard state: present when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages @@ -117255,17 +133726,15 @@ version = "*" The usbguard service can be enabled with the following command: $ sudo systemctl enable usbguard.service - CCI-001958 - CCI-003959 - 1418 CM-8(3)(a) IA-3 FMT_SMF_EXT.1 - SRG-OS-000378-GPOS-00163 - SRG-APP-000141-CTR-000315 + SRG-OS-000378-GPOS-00163 + SRG-APP-000141-CTR-000315 A.23.SEC-OL1 - OL09-00-000321 - SV-271504r1091224_rule + 1418 + OL09-00-000321 + SV-271504r1091224_rule The usbguard service must be running in order to enforce the USB device authorization policy for all USB devices. # Remediation is applicable only in certain platforms @@ -117300,7 +133769,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable the USBGuard Service - Enable Service usbguard @@ -117311,8 +133780,6 @@ fi masked: false when: - '"usbguard" in ansible_facts.packages' - when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages - or "kernel-uek" in ansible_facts.packages) ) tags: - DISA-STIG-OL09-00-000321 - NIST-800-53-CM-8(3)(a) @@ -117323,6 +133790,9 @@ fi - medium_severity - no_reboot_needed - service_usbguard_enabled + - special_service_block + when: ( ansible_architecture != "s390x" and ("kernel" in ansible_facts.packages + or "kernel-uek" in ansible_facts.packages) ) include enable_usbguard @@ -117352,6 +133822,10 @@ spec: [customizations.services] enabled = ["usbguard"] + + + + @@ -117365,25 +133839,24 @@ enabled = ["usbguard"] (as opposed directly to a file), AuditBackend option in /etc/usbguard/usbguard-daemon.conf needs to be set to LinuxAudit. - CCI-000169 AU-2 CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000062-GPOS-00031 - SRG-OS-000471-GPOS-00215 - SRG-APP-000141-CTR-000315 - OL09-00-002330 - SV-271700r1091812_rule + SRG-OS-000062-GPOS-00031 + SRG-OS-000471-GPOS-00215 + SRG-APP-000141-CTR-000315 + OL09-00-002330 + SV-271700r1091812_rule Using the Linux Audit logging allows for centralized trace of events. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if ( ! ( grep -sqE "^.*\.s390x$" /proc/sys/kernel/osrelease || grep -sqE "^s390x$" /proc/sys/kernel/arch; ) && rpm --quiet -q kernel || rpm --quiet -q kernel-uek ) && { rpm --quiet -q usbguard; }; then if [ -e "/etc/usbguard/usbguard-daemon.conf" ] ; then - LC_ALL=C sed -i "/^\s*AuditBackend=/d" "/etc/usbguard/usbguard-daemon.conf" + LC_ALL=C sed -i "/^[ \\t]*AuditBackend=/Id" "/etc/usbguard/usbguard-daemon.conf" else touch "/etc/usbguard/usbguard-daemon.conf" fi @@ -117400,7 +133873,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -117408,39 +133881,39 @@ fi - NIST-800-53-AU-2 - NIST-800-53-CM-8(3) - NIST-800-53-IA-3 + - configure_strategy - configure_usbguard_auditbackend - low_complexity - low_disruption - low_severity - no_reboot_needed - - restrict_strategy - name: Log USBGuard daemon audit events using Linux Audit block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= state: absent check_mode: true changed_when: false register: dupes - name: Deduplicate values from /etc/usbguard/usbguard-daemon.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= state: absent when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/usbguard/usbguard-daemon.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/usbguard-daemon.conf create: true - regexp: (?i)^\s*AuditBackend= + regexp: (?i)^[ \\t]*AuditBackend= line: AuditBackend=LinuxAudit state: present when: @@ -117452,12 +133925,12 @@ fi - NIST-800-53-AU-2 - NIST-800-53-CM-8(3) - NIST-800-53-IA-3 + - configure_strategy - configure_usbguard_auditbackend - low_complexity - low_disruption - low_severity - no_reboot_needed - - restrict_strategy --- apiVersion: machineconfiguration.openshift.io/v1 @@ -117496,8 +133969,9 @@ to /etc/usbguard/rules.conf. CM-8(3) IA-3 FMT_SMF_EXT.1 - SRG-OS-000114-GPOS-00059 - SRG-APP-000092-CTR-000165 + SRG-OS-000114-GPOS-00059 + SRG-APP-000092-CTR-000165 + 1418 Without allowing Human Interface Devices, it might not be possible to interact with the system. Without allowing hubs, it might not be possible to use any USB devices on the system. @@ -117524,7 +133998,7 @@ fi - usbguard_allow_hid_and_hub - name: Allow HID devices and hubs - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/rules.conf create: true regexp: '' @@ -117573,13 +134047,12 @@ spec: to inaccessible system if they use USB mouse/keyboard. To prevent this scenario, the initial policy configuration must be generated based on current connected USB devices. - CCI-001958 CM-8(3)(a) IA-3 - SRG-OS-000378-GPOS-00163 + SRG-OS-000378-GPOS-00163 A.23.SEC-OL1 - OL09-00-002331 - SV-271701r1091815_rule + OL09-00-002331 + SV-271701r1091815_rule The usbguard must be configured to allow connected USB devices to work properly, avoiding the system to become inaccessible. # Remediation is applicable only in certain platforms @@ -117630,35 +134103,35 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Check that the /etc/usbguard/rules.conf exists - stat: + ansible.builtin.stat: path: /etc/usbguard/rules.conf register: policy_file - name: Create USBGuard Policy configuration - command: usbguard generate-policy + ansible.builtin.command: usbguard generate-policy register: policy when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Copy the Generated Policy configuration to a persistent file - copy: + ansible.builtin.copy: content: '{{ policy.stdout }}' dest: /etc/usbguard/rules.conf mode: 384 when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Add comment into /etc/usbguard/rules.conf when system has no USB devices - lineinfile: + ansible.builtin.lineinfile: path: /etc/usbguard/rules.conf line: '# No USB devices found' state: present when: not policy_file.stat.exists or policy_file.stat.size == 0 - name: Enable service usbguard - systemd: + ansible.builtin.systemd: name: usbguard enabled: 'yes' state: started @@ -117719,7 +134192,6 @@ continuing installation. DSS01.04 DSS05.02 DSS05.03 - CCI-000366 4.3.3.6.6 SR 1.13 SR 2.6 @@ -117744,22 +134216,23 @@ continuing installation. CM-6(a) PR.AC-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security vulnerabilities and should not be installed unless approved and documented. # CAUTION: This remediation script will remove xorg-x11-server-common -# from the system, and may remove any packages -# that depend on xorg-x11-server-common. Execute this -# remediation AFTER testing on a non-production -# system! +# from the system, and may remove any packages +# that depend on xorg-x11-server-common. Execute this +# remediation AFTER testing on a non-production +# system! + if rpm -q --quiet "xorg-x11-server-common" ; then yum remove -y "xorg-x11-server-common" fi - - name: Ensure xorg-x11-server-common is removed - package: + - name: 'Remove the X Windows Package Group: Ensure xorg-x11-server-common is removed' + ansible.builtin.package: name: xorg-x11-server-common state: absent tags: @@ -117773,7 +134246,8 @@ fi - no_reboot_needed - package_xorg-x11-server-common_removed - include remove_xorg-x11-server-common + +include remove_xorg-x11-server-common class remove_xorg-x11-server-common { package { 'xorg-x11-server-common': @@ -117782,6 +134256,7 @@ class remove_xorg-x11-server-common { } + package --remove=xorg-x11-server-common @@ -117793,14 +134268,15 @@ package --remove=xorg-x11-server-common Disable graphical user interface - By removing the following packages, the system no longer has X Windows installed. - -xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland + By removing the following packages, the system no longer has X Windows installed. + xorg-x11-server-Xorg + xorg-x11-server-common + xorg-x11-server-utils + xorg-x11-server-Xwayland If X Windows is not installed then the system cannot boot into graphical user mode. This prevents the system from being accidentally or maliciously booted into a graphical.target mode. To do so, run the following command: - sudo yum remove xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland The installation and use of a Graphical User Interface (GUI) increases your attack vector and decreases your @@ -117810,37 +134286,76 @@ again. The rule xwindows_runlevel_target can be used to configure the system to boot into the multi-user.target. If a GUI is an operational requirement, a tailored profile that removes this rule should be used before continuing installation. - CCI-000366 CM-6(b) - SRG-OS-000480-GPOS-00227 - OL09-00-000145 - SV-271465r1091107_rule - Unnecessary service packages must not be installed to decrease the attack surface of the system. X windows has a long history of security -vulnerabilities and should not be installed unless approved and documented. + SRG-OS-000480-GPOS-00227 + OL09-00-000145 + SV-271465r1091107_rule + Unnecessary service packages must not be installed to decrease the attack surface of the system. +X windows has a long history of security vulnerabilities and should not be installed unless approved and documented. - # remove packages + if rpm -q --quiet "xorg-x11-server-Xorg" ; then yum remove -y "xorg-x11-server-Xorg" fi -if rpm -q --quiet "xorg-x11-server-utils" ; then -yum remove -y "xorg-x11-server-utils" -fi + if rpm -q --quiet "xorg-x11-server-common" ; then yum remove -y "xorg-x11-server-common" fi +if rpm -q --quiet "xorg-x11-server-utils" ; then +yum remove -y "xorg-x11-server-utils" +fi + if rpm -q --quiet "xorg-x11-server-Xwayland" ; then yum remove -y "xorg-x11-server-Xwayland" fi - - name: Ensure xorg packages are removed - package: - name: - - xorg-x11-server-Xorg - - xorg-x11-server-common - - xorg-x11-server-utils - - xorg-x11-server-Xwayland + - name: Disable graphical user interface - Ensure xorg-x11-server-Xorg is removed + ansible.builtin.package: + name: xorg-x11-server-Xorg + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-common is removed + ansible.builtin.package: + name: xorg-x11-server-common + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-utils is removed + ansible.builtin.package: + name: xorg-x11-server-utils + state: absent + tags: + - DISA-STIG-OL09-00-000145 + - NIST-800-53-CM-6(b) + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + - xwindows_remove_packages + +- name: Disable graphical user interface - Ensure xorg-x11-server-Xwayland is removed + ansible.builtin.package: + name: xorg-x11-server-Xwayland state: absent tags: - DISA-STIG-OL09-00-000145 @@ -117853,7 +134368,15 @@ fi - xwindows_remove_packages -package --remove=xorg-x11-server-Xorg --remove=xorg-x11-server-common --remove=xorg-x11-server-utils --remove=xorg-x11-server-Xwayland +# remove packages + +package --remove=xorg-x11-server-Xorg + +package --remove=xorg-x11-server-common + +package --remove=xorg-x11-server-utils + +package --remove=xorg-x11-server-Xwayland @@ -117881,7 +134404,6 @@ Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/syst DSS01.04 DSS05.02 DSS05.03 - CCI-000366 4.3.3.6.6 SR 1.13 SR 2.6 @@ -117906,9 +134428,9 @@ Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/syst CM-6(a) PR.AC-3 PR.PT-4 - SRG-OS-000480-GPOS-00227 - OL09-00-000020 - SV-271440r1092462_rule + SRG-OS-000480-GPOS-00227 + OL09-00-000020 + SV-271440r1092462_rule Services that are not required for system and application processes must not be active to decrease the attack surface of the system. @@ -117937,7 +134459,7 @@ fi - xwindows_runlevel_target - name: Switch to multi-user runlevel - file: + ansible.builtin.file: src: /usr/lib/systemd/system/multi-user.target dest: /etc/systemd/system/default.target state: link @@ -118050,18 +134572,25 @@ the process, which in this case, is exe="/usr/sbin/httpd" + + Audit backlog limit + Value of the audit_backlog_limit argument in GRUB 2 configuration. +The audit_backlog_limit parameter determines how auditd records can +be held in the auditd backlog. + 8192 + 8192 + Install audispd-plugins Package The audispd-plugins package can be installed with the following command: $ sudo yum install audispd-plugins - CCI-001851 - SRG-OS-000342-GPOS-00133 + SRG-OS-000342-GPOS-00133 10.3.3 10.3 - OL09-00-000450 - SV-271521r1091275_rule + OL09-00-000450 + SV-271521r1091275_rule audispd-plugins provides plugins for the real-time interface to the audit subsystem, audispd. These plugins can do things like relay events to remote machines or analyze events for suspicious behavior. @@ -118091,7 +134620,7 @@ fi - package_audispd-plugins_installed - name: Ensure audispd-plugins is installed - package: + ansible.builtin.package: name: audispd-plugins state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -118132,38 +134661,13 @@ version = "*" Ensure the audit Subsystem is Installed The audit package should be installed. - CCI-000133 - CCI-001881 - CCI-001875 - CCI-000154 - CCI-001882 - CCI-000158 - CCI-001914 - CCI-000169 - CCI-001464 - CCI-001878 - CCI-001877 - CCI-001889 - CCI-000135 - CCI-002884 - CCI-001487 - CCI-003938 - CCI-000132 - CCI-000134 - CCI-000172 - CCI-000130 - CCI-000131 - CCI-001879 - CCI-001880 - CCI-001876 - CCI-000159 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) - CIP-004-6 R3.3 - CIP-007-3 R6.5 + CIP-004-6 R3.3 + CIP-007-3 R6.5 AC-7(a) AU-7(1) AU-7(2) @@ -118173,36 +134677,38 @@ version = "*" CM-6(a) 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-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 R33 R73 + 0582 + 0846 10.2.1 10.2 - OL09-00-000440 - SV-271519r1091269_rule + OL09-00-000440 + SV-271519r1091269_rule The auditd service is an access monitoring and accounting daemon, watching system calls to audit any access, in comparison with potential local access control policy such as SELinux policy. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -118238,7 +134744,7 @@ fi - package_audit_installed - name: Ensure audit is installed - package: + ansible.builtin.package: name: audit state: present when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -118340,31 +134846,6 @@ The auditd service can be enabled with the following comm 3.3.1 3.3.2 3.3.6 - CCI-000133 - CCI-001881 - CCI-001875 - CCI-000154 - CCI-001882 - CCI-000158 - CCI-001914 - CCI-000169 - CCI-001464 - CCI-001878 - CCI-001877 - CCI-001889 - CCI-000135 - CCI-002884 - CCI-001487 - CCI-003938 - CCI-000132 - CCI-004188 - CCI-000134 - CCI-000172 - CCI-000130 - CCI-000131 - CCI-001879 - CCI-001880 - CCI-001876 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(C) 164.310(a)(2)(iv) @@ -118418,8 +134899,8 @@ The auditd service can be enabled with the following comm A.16.1.7 A.6.2.1 A.6.2.2 - CIP-004-6 R3.3 - CIP-007-3 R6.5 + CIP-004-6 R3.3 + CIP-007-3 R6.5 AC-2(g) AU-3 AU-10 @@ -118442,40 +134923,41 @@ The auditd service can be enabled with the following comm 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 + 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 - OL09-00-000441 - SV-271520r1091272_rule + OL09-00-000441 + SV-271520r1091272_rule 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 @@ -118533,7 +135015,7 @@ fi block: - name: Gather the package facts - package_facts: + ansible.builtin.package_facts: manager: auto - name: Enable auditd Service - Enable Service auditd @@ -118544,9 +135026,6 @@ fi masked: false when: - '"audit" in ansible_facts.packages' - when: - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - '"audit" in ansible_facts.packages' tags: - CJIS-5.4.1.1 - DISA-STIG-OL09-00-000441 @@ -118571,6 +135050,10 @@ fi - medium_severity - no_reboot_needed - service_auditd_enabled + - special_service_block + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"audit" in ansible_facts.packages' include enable_auditd @@ -118597,6 +135080,10 @@ spec: [customizations.services] enabled = ["auditd"] + + + + @@ -118656,12 +135143,6 @@ Run the following command to update command line for already installed kernels:< MEA01.05 MEA02.01 3.3.1 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-001464 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(C) 164.310(a)(2)(iv) @@ -118728,18 +135209,18 @@ Run the following command to update command line for already installed kernels:< 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 + 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 - OL09-00-000750 - SV-271577r1091443_rule + OL09-00-000750 + SV-271577r1091443_rule 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 @@ -118748,15 +135229,12 @@ ensures it is set for every process during boot. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="1" - - -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit=[^\"]*\"(.*]\s*)/\1\"audit=1\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"audit=$expected_value\"]" >> "$KARGS_DIR/10-audit.toml" + echo "kargs = [\"audit=1\"]" >> "$KARGS_DIR/10-audit.toml" fi else @@ -118790,8 +135268,10 @@ fi - reboot_required - restrict_strategy -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="audit=1" +- name: Check if audit argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -118813,6 +135293,60 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if audit argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 + - 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: /sbin/grubby --update-kernel=ALL --args="audit=1" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('audit=1')) or ((etc_default_grub['content'] + | b64decode) is not search('audit=1')) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-000750 + - 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 [customizations.kernel] append = "audit=1" @@ -118827,32 +135361,33 @@ append = "audit=1" Extend Audit Backlog Limit for the Audit Daemon To improve the kernel capacity to queue all log events, even those which occurred -prior to the audit daemon, add the argument audit_backlog_limit=8192 to the default +prior to the audit daemon, add the argument audit_backlog_limit= + to the default GRUB 2 command line for the Linux operating system. -To ensure that audit_backlog_limit=8192 is added as a kernel command line -argument to newly installed kernels, add audit_backlog_limit=8192 to the +To ensure that audit_backlog_limit= + is added as a kernel command line +argument to newly installed kernels, add audit_backlog_limit= + to the default Grub2 command line for Linux operating systems. Modify the line within /etc/default/grub as shown below: -GRUB_CMDLINE_LINUX="... audit_backlog_limit=8192 ..." -Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=8192" +GRUB_CMDLINE_LINUX="... audit_backlog_limit= ..." +Run the following command to update command line for already installed kernels:# grubby --update-kernel=ALL --args="audit_backlog_limit=" - CCI-001849 - CCI-001464 CM-6(a) FAU_STG.1 FAU_STG.3 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000254-GPOS-00095 - SRG-OS-000341-GPOS-00132 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000254-GPOS-00095 + SRG-OS-000341-GPOS-00132 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 10.7.2 10.7 - OL09-00-000830 - SV-271592r1091488_rule + OL09-00-000830 + SV-271592r1091488_rule audit_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. Until the audit daemon is up and running, all log messages are stored in this queue. If the queue is overrun during boot process, the action @@ -118861,19 +135396,20 @@ defined by audit failure flag is taken. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek && { rpm --quiet -q grub2-common; }; then -expected_value="8192" +var_audit_backlog_limit='' -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; 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_backlog_limit" "$KARGS_DIR/*.toml" ; then - sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit_backlog_limit=[^\"]*\"(.*]\s*)/\1\"audit_backlog_limit=$expected_value\"\2/" "$KARGS_DIR/*.toml" + sed -i -E "s/^(\s*kargs\s*=\s*\[.*)\"audit_backlog_limit=[^\"]*\"(.*]\s*)/\1\"audit_backlog_limit=$var_audit_backlog_limit\"\2/" "$KARGS_DIR/*.toml" else - echo "kargs = [\"audit_backlog_limit=$expected_value\"]" >> "$KARGS_DIR/10-audit_backlog_limit.toml" + echo "kargs = [\"audit_backlog_limit=$var_audit_backlog_limit\"]" >> "$KARGS_DIR/10-audit_backlog_limit.toml" fi else - grubby --update-kernel=ALL --args=audit_backlog_limit=8192 + grubby --update-kernel=ALL --args=audit_backlog_limit=$var_audit_backlog_limit fi @@ -118895,9 +135431,16 @@ fi - medium_complexity - reboot_required - restrict_strategy +- name: XCCDF Value var_audit_backlog_limit # promote to variable + set_fact: + var_audit_backlog_limit: !!str + tags: + - always -- name: Update grub defaults and the bootloader menu - command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit=8192" +- name: Check if audit_backlog_limit argument is already present in /etc/default/grub + ansible.builtin.slurp: + src: /etc/default/grub + register: etc_default_grub when: - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - '"grub2-common" in ansible_facts.packages' @@ -118912,11 +135455,54 @@ fi - medium_complexity - reboot_required - restrict_strategy + +- name: Check if audit_backlog_limit argument is already present + ansible.builtin.command: /sbin/grubby --info=ALL + register: grubby_info + check_mode: false + changed_when: false + failed_when: false + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + tags: + - DISA-STIG-OL09-00-000830 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_backlog_limit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy + +- name: Update grub defaults and the bootloader menu + ansible.builtin.command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit={{ + var_audit_backlog_limit }}" + when: + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - '"grub2-common" in ansible_facts.packages' + - (grubby_info.stdout is not search('audit_backlog_limit=' ~ var_audit_backlog_limit)) + or ((etc_default_grub['content'] | b64decode) is not search('audit_backlog_limit=' + ~ var_audit_backlog_limit)) + tags: + - DISA-STIG-OL09-00-000830 + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.7 + - PCI-DSSv4-10.7.2 + - grub2_audit_backlog_limit_argument + - low_disruption + - low_severity + - medium_complexity + - reboot_required + - restrict_strategy [customizations.kernel] -append = "audit_backlog_limit=8192" +append = "audit_backlog_limit=" + @@ -118974,6 +135560,359 @@ If the value is set to "1", the system is configured to only send information to 1 2 + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + At a minimum, the audit system should collect administrator actions +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/cron.d/ -p wa -k cronjobs + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/cron.d/ -p wa -k cronjobs + + SRG-OS-000471-GPOS-00215 + OL09-00-002584 + SV-278952r1135407_rule + The actions taken by system administrators should be audited to keep a record +of what was executed on the system, as well as, for accountability purposes. +Editing the sudoers file may be sign of an attacker trying to +establish persistent methods to a system, auditing the editing of the sudoers +files mitigates this risk. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/cron.d/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/cron.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/cron.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/cron.d/ -p wa -k actions" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/cron.d/" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/actions.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/actions.rules" + # If the actions.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/cron.d/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/cron.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/cron.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/cron.d/ -p wa -k actions" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Check if watch + rule for /etc/cron.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/etc/cron.d/\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)actions$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/actions.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Add watch rule + for /etc/cron.d/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /etc/cron.d/ -p wa -k actions + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Check if watch + rule for /etc/cron.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/etc/cron.d/\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ - Add watch rule + for /etc/cron.d/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/cron.d/ -p wa -k actions + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_etc_cron_d + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Make the auditd Configuration Immutable If the auditd daemon is configured to use the @@ -119028,9 +135967,6 @@ With this setting, a reboot will be required to change any audit rules.MEA02.01 3.3.1 3.4.3 - CCI-000163 - CCI-000164 - CCI-000162 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -119104,16 +136040,16 @@ With this setting, a reboot will be required to change any audit rules.RS.AN-1 RS.AN-4 Req-10.5.2 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000119-CTR-000245 - SRG-APP-000120-CTR-000250 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000119-CTR-000245 + SRG-APP-000120-CTR-000250 R73 10.3.2 10.3 - OL09-00-008005 - SV-271886r1092370_rule + OL09-00-008005 + SV-271886r1092370_rule Making the audit configuration immutable prevents accidental as well as malicious modification of the audit rules, although it may be problematic if legitimate changes are needed during system @@ -119169,8 +136105,9 @@ fi - reboot_required - restrict_strategy -- name: Collect all files from /etc/audit/rules.d with .rules extension - find: +- name: Make the auditd Configuration Immutable - Collect all files from /etc/audit/rules.d + with .rules extension + ansible.builtin.find: paths: /etc/audit/rules.d/ patterns: '*.rules' register: find_rules_d @@ -119194,13 +136131,14 @@ fi - reboot_required - restrict_strategy -- name: Remove the -e option from all Audit config files - lineinfile: +- name: Make the auditd Configuration Immutable - Check if target files exist and + get their content + ansible.builtin.stat: path: '{{ item }}' - regexp: ^\s*(?:-e)\s+.*$ - state: absent - loop: '{{ find_rules_d.files | map(attribute=''path'') | list + [''/etc/audit/audit.rules''] - }}' + register: audit_files_stat + loop: + - /etc/audit/audit.rules + - /etc/audit/rules.d/immutable.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -119221,11 +136159,130 @@ fi - reboot_required - restrict_strategy -- name: Add Audit -e option into /etc/audit/rules.d/immutable.rules and /etc/audit/audit.rules - lineinfile: +- name: Make the auditd Configuration Immutable - Read content of existing audit files + ansible.builtin.slurp: + src: '{{ item.item }}' + register: audit_files_content + loop: '{{ audit_files_stat.results }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - item.stat.exists + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Check if -e 2 is already correctly + set in target files + ansible.builtin.set_fact: + immutable_correctly_set: |- + {{ + audit_files_content.results + | selectattr('content', 'defined') + | map(attribute='content') + | map('b64decode') + | select('search', '^-e 2$', multiline=True) + | list + | length == 2 + }} + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Remove any existing -e option from + all Audit config files + ansible.builtin.lineinfile: + path: '{{ item }}' + regexp: ^\s*-e\s+.*$ + state: absent + loop: '{{ find_rules_d.files | map(attribute=''path'') | list + [''/etc/audit/audit.rules''] + }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Ensure target directories exist + ansible.builtin.file: + path: '{{ item | dirname }}' + state: directory + mode: '0750' + loop: + - /etc/audit/audit.rules + - /etc/audit/rules.d/immutable.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set + tags: + - CJIS-5.4.1.1 + - DISA-STIG-OL09-00-008005 + - NIST-800-171-3.3.1 + - NIST-800-171-3.4.3 + - NIST-800-53-AC-6(9) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.2 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.2 + - audit_rules_immutable + - low_complexity + - low_disruption + - medium_severity + - reboot_required + - restrict_strategy + +- name: Make the auditd Configuration Immutable - Add Audit -e 2 option to make rules + immutable + ansible.builtin.lineinfile: path: '{{ item }}' create: true line: -e 2 + regexp: ^\s*-e\s+.*$ mode: g-rwx,o-rwx loop: - /etc/audit/audit.rules @@ -119233,6 +136290,7 @@ fi when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - not immutable_correctly_set tags: - CJIS-5.4.1.1 - DISA-STIG-OL09-00-008005 @@ -119274,17 +136332,13 @@ utility to read audit rules during daemon startup, add the following line to immutable: --loginuid-immutable - CCI-000163 - CCI-000172 - CCI-000164 - CCI-000162 - SRG-OS-000462-GPOS-00206 - SRG-OS-000475-GPOS-00220 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - OL09-00-008000 - SV-271885r1092367_rule + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + OL09-00-008000 + SV-271885r1092367_rule If modification of login UIDs is not prevented, they can be changed by unprivileged users and make auditing complicated or impossible. # Remediation is applicable only in certain platforms @@ -119564,7 +136618,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -119572,7 +136628,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -119588,12 +136646,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -119612,8 +136674,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/selinux/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -119641,7 +136705,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -119649,7 +136715,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -119665,12 +136733,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done @@ -119697,8 +136769,9 @@ fi - reboot_required - restrict_strategy -- name: Check if watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Check if + watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -119722,8 +136795,9 @@ fi - reboot_required - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key MAC-policy - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Search + /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)MAC-policy$ patterns: '*.rules' @@ -119749,8 +136823,9 @@ fi - reboot_required - restrict_strategy -- name: Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls - Use /etc/audit/rules.d/MAC-policy.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/MAC-policy.rules when: @@ -119774,8 +136849,9 @@ fi - reboot_required - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -119799,8 +136875,9 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /etc/selinux/ in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls - Add watch + rule for /etc/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/selinux/ -p wa -k MAC-policy create: true @@ -119826,8 +136903,9 @@ fi - reboot_required - restrict_strategy -- name: Check if watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Mandatory Access Controls - Check if + watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -119851,8 +136929,9 @@ fi - reboot_required - restrict_strategy -- name: Add watch rule for /etc/selinux/ in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls - Add watch + rule for /etc/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/selinux/ -p wa -k MAC-policy state: present dest: /etc/audit/audit.rules @@ -119886,16 +136965,396 @@ fi + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/selinux/ -p wa -k MAC-policy + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/selinux/ -p wa -k MAC-policy + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + Req-10.5.5 + R73 + 10.3.4 + 10.3 + The system's mandatory access policy (SELinux) should not be +arbitrarily changed by anything other than administrator action. All changes to +MAC policy should be audited. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/selinux/" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/MAC-policy.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/MAC-policy.rules" + # If the MAC-policy.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/etc/selinux/" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/etc/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /etc/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Check if watch rule for /etc/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Search /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)MAC-policy$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/MAC-policy.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Add watch rule for /etc/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /etc/selinux/ -p wa -k MAC-policy + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Check if watch rule for /etc/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/etc/selinux/\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + - Add watch rule for /etc/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/selinux/ -p wa -k MAC-policy + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - PCI-DSS-Req-10.5.5 + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.4 + - audit_rules_mac_modification_etc_selinux + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following line to a file with suffix .rules in the + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the directory /etc/audit/rules.d: + -w /usr/share/selinux/ -p wa -k MAC-policy + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /usr/share/selinux/ -p wa -k MAC-policy APO10.01 @@ -120003,6 +137462,12 @@ MAC policy should be audited. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -120026,7 +137491,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/usr/share/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -120034,7 +137501,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/share/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -120050,12 +137519,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/usr/share/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /usr/share/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -120074,8 +137547,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/MAC-policy.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/usr/share/selinux/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -120103,7 +137578,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/usr/share/selinux/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -120111,7 +137588,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/usr/share/selinux/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -120127,12 +137606,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/usr/share/selinux/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /usr/share/selinux/ -p wa -k MAC-policy" >> "$audit_rules_file" + fi done @@ -120140,7 +137623,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -120153,11 +137636,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/usr/share/selinux/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -120175,11 +137659,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key MAC-policy - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Search /etc/audit/rules.d for other rules with specified key MAC-policy + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)MAC-policy$ patterns: '*.rules' @@ -120199,11 +137684,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Use /etc/audit/rules.d/MAC-policy.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/MAC-policy.rules when: @@ -120221,11 +137707,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -120243,11 +137730,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /usr/share/selinux/ in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Add watch rule for /usr/share/selinux/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /usr/share/selinux/ -p wa -k MAC-policy create: true @@ -120267,11 +137755,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Check if watch rule for /usr/share/selinux/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/usr/share/selinux/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -120289,11 +137778,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /usr/share/selinux/ in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Mandatory Access Controls in usr/share + - Add watch rule for /usr/share/selinux/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /usr/share/selinux/ -p wa -k MAC-policy state: present dest: /etc/audit/audit.rules @@ -120314,7 +137804,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -120330,13 +137820,15 @@ fi events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in -the directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +the directory /etc/audit/rules.d, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your +system is 64-bit: -a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your +system is 64-bit: -a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export 1 @@ -120384,11 +137876,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -120460,13 +137947,13 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-APP-000495-CTR-001235 + 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-APP-000495-CTR-001235 R73 A.3.SEC-OL10 10.2.1.7 @@ -120489,7 +137976,7 @@ do OTHER_FILTERS="" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="mount" - KEY="perm_mod" + KEY="export" SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' @@ -120826,7 +138313,7 @@ fi - restrict_strategy - name: Set architecture for audit mount tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -120855,13 +138342,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -120870,43 +138357,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/export.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/export.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -120918,23 +138406,23 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -120943,17 +138431,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -120965,10 +138454,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present @@ -120998,13 +138487,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -121013,43 +138502,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/export.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/export.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -121061,23 +138551,23 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - mount syscall_grouping: [] - name: Check existence of mount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -121086,17 +138576,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -121108,10 +138599,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=perm_mod + -F auid!=unset -F key=export create: true mode: g-rwx,o-rwx state: present @@ -121150,8 +138641,9 @@ fi If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your system +is 64-bit: -a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification @@ -121161,8 +138653,9 @@ appropriate for your system: If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for +32-bit system, or having two lines for both b32 and b64 in case your system +is 64-bit: -a always,exit -F arch=ARCH -S sethostname,setdomainname -F key=audit_rules_networkconfig_modification -w /etc/issue -p wa -k audit_rules_networkconfig_modification -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification @@ -121286,6 +138779,7 @@ appropriate for your system: RS.AN-4 Req-10.5.5 R73 + 0582 10.3.4 10.3 The network environment should not be modified by anything other @@ -121639,7 +139133,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121647,7 +139143,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121663,12 +139161,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121687,8 +139189,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121716,7 +139220,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121724,7 +139230,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121740,12 +139248,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121771,7 +139283,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121779,7 +139293,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121795,12 +139311,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121819,8 +139339,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/issue.net" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121848,7 +139370,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/issue.net" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121856,7 +139380,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/issue.net $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121872,12 +139398,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/issue.net$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/issue.net -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121903,7 +139433,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121911,7 +139443,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -121927,12 +139461,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -121951,8 +139489,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/hosts" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -121980,7 +139520,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/hosts" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -121988,7 +139530,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/hosts $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122004,12 +139548,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/hosts$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/hosts -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done @@ -122036,7 +139584,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sysconfig/network" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -122044,7 +139594,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sysconfig/network $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122060,12 +139612,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sysconfig/network$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -122084,8 +139640,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_networkconfig_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sysconfig/network" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -122113,7 +139671,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sysconfig/network" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -122121,7 +139681,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sysconfig/network $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -122137,12 +139699,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sysconfig/network$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification" >> "$audit_rules_file" + fi done @@ -122171,7 +139737,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -122199,7 +139765,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122208,7 +139774,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122217,43 +139783,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_rules_networkconfig_modification.rules - set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122264,7 +139831,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122273,7 +139840,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122282,7 +139849,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122291,17 +139858,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122312,7 +139880,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122343,7 +139911,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122352,7 +139920,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122361,43 +139929,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_rules_networkconfig_modification.rules - set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_rules_networkconfig_modification.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122408,7 +139977,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122417,7 +139986,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - sethostname - setdomainname @@ -122426,7 +139995,7 @@ fi - setdomainname - name: Check existence of sethostname, setdomainname in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -122435,17 +140004,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -122456,7 +140026,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_rules_networkconfig_modification create: true @@ -122484,8 +140054,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/issue\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122510,8 +140081,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122538,9 +140110,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122565,8 +140137,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122591,8 +140164,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/issue -p wa -k audit_rules_networkconfig_modification create: true @@ -122619,8 +140193,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/issue\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -122645,8 +140220,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/issue -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -122674,8 +140250,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue.net already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue.net already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/issue.net\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122700,8 +140277,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122728,9 +140306,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122755,8 +140333,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122781,8 +140360,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue.net in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue.net in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification create: true @@ -122809,8 +140389,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/issue.net already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/issue.net already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/issue.net\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -122835,8 +140416,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/issue.net in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/issue.net in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/issue.net -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -122864,8 +140446,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/hosts already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/hosts already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/hosts\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -122890,8 +140473,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -122918,9 +140502,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -122945,8 +140529,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -122971,8 +140556,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/hosts in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/hosts in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/hosts -p wa -k audit_rules_networkconfig_modification create: true @@ -122999,8 +140585,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/hosts already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/hosts already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/hosts\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -123025,8 +140612,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/hosts in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/hosts in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/hosts -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -123054,8 +140642,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sysconfig/network already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/sysconfig/network already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sysconfig/network\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -123080,8 +140669,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_networkconfig_modification - find: +- name: Record Events that Modify the System's Network Environment - Search /etc/audit/rules.d + for other rules with specified key audit_rules_networkconfig_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_networkconfig_modification$ patterns: '*.rules' @@ -123108,9 +140698,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules as the - recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use /etc/audit/rules.d/audit_rules_networkconfig_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_networkconfig_modification.rules when: @@ -123135,8 +140725,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify the System's Network Environment - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -123161,8 +140752,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sysconfig/network in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/sysconfig/network in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification create: true @@ -123189,8 +140781,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sysconfig/network already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify the System's Network Environment - Check if watch + rule for /etc/sysconfig/network already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sysconfig/network\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -123215,8 +140808,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sysconfig/network in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify the System's Network Environment - Add watch rule + for /etc/sysconfig/network in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sysconfig/network -p wa -k audit_rules_networkconfig_modification state: present dest: /etc/audit/audit.rules @@ -123251,70 +140845,27 @@ fi - - Record Attempts to Alter Process and Session Initiation Information + + Record Attempts to Alter Process and Session Initiation Information btmp The audit system already collects process information for all -users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing such process information: --w /var/run/utmp -p wa -k session --w /var/log/btmp -p wa -k session --w /var/log/wtmp -p wa -k session +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/btmp -p wa -k session + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for attempted manual -edits of files involved in storing such process information: --w /var/run/utmp -p wa -k session --w /var/log/btmp -p wa -k session --w /var/log/wtmp -p wa -k session +/etc/audit/audit.rules: + +-w /var/log/btmp -p wa -k session - 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.1.7 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -123322,87 +140873,28 @@ edits of files involved in storing such process information: 164.312(b) 164.312(d) 164.312(e) - 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 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 - 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 - AU-2(d) AU-12(c) - CM-6(a) - 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 - Req-10.2.3 - SRG-APP-000505-CTR-001285 + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 R73 A.3.SEC-OL1 + 0582 + 0846 10.2.1.3 10.2.1 10.2 Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. - # Remediation is applicable only in certain platforms + # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -123426,139 +140918,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit is 'augenrules', then check if rule is already defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/run/utmp" /etc/audit/rules.d/*.rules) - -# For each of the matched entries -for match in "${matches[@]}" -do - # Extract filepath from the match - rulesd_audit_file=$(echo $match | cut -f1 -d ':') - # Append that path into list of files for inspection - files_to_inspect+=("$rulesd_audit_file") -done -# Case when particular audit rule isn't defined yet -if [ "${#files_to_inspect[@]}" -eq "0" ] -then - # Append '/etc/audit/rules.d/session.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/session.rules" - # If the session.rules file doesn't exist yet, create it with correct permissions - if [ ! -e "$key_rule_file" ] - then - touch "$key_rule_file" - chmod 0600 "$key_rule_file" - fi - files_to_inspect+=("$key_rule_file") -fi - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - - -# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# into the list of files to be inspected -files_to_inspect+=('/etc/audit/audit.rules') - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -123566,7 +140928,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -123582,12 +140946,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -123606,8 +140974,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/btmp" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -123635,7 +141005,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/btmp" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -123643,7 +141015,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/btmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -123659,144 +141033,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/btmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/btmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' -# into the list of files to be inspected -files_to_inspect+=('/etc/audit/audit.rules') - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" - fi -done -# Create a list of audit *.rules files that should be inspected for presence and correctness -# of a particular audit rule. The scheme is as follows: -# -# ----------------------------------------------------------------------------------------- -# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | -# ----------------------------------------------------------------------------------------- -# auditctl | Doesn't matter | /etc/audit/audit.rules | -# ----------------------------------------------------------------------------------------- -# augenrules | Yes | /etc/audit/rules.d/*.rules | -# augenrules | No | /etc/audit/rules.d/$key.rules | -# ----------------------------------------------------------------------------------------- -files_to_inspect=() - -# If the audit is 'augenrules', then check if rule is already defined -# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. -readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/wtmp" /etc/audit/rules.d/*.rules) - -# For each of the matched entries -for match in "${matches[@]}" -do - # Extract filepath from the match - rulesd_audit_file=$(echo $match | cut -f1 -d ':') - # Append that path into list of files for inspection - files_to_inspect+=("$rulesd_audit_file") -done -# Case when particular audit rule isn't defined yet -if [ "${#files_to_inspect[@]}" -eq "0" ] -then - # Append '/etc/audit/rules.d/session.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/session.rules" - # If the session.rules file doesn't exist yet, create it with correct permissions - if [ ! -e "$key_rule_file" ] - then - touch "$key_rule_file" - chmod 0600 "$key_rule_file" - fi - files_to_inspect+=("$key_rule_file") -fi - -# Finally perform the inspection and possible subsequent audit rule -# correction for each of the files previously identified for inspection -for audit_rules_file in "${files_to_inspect[@]}" -do - # Check if audit watch file system object rule for given path already present - if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" - then - # Rule is found => verify yet if existing rule definition contains - # all of the required access type bits - - # Define BRE whitespace class shortcut - sp="[[:space:]]" - # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule - current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") - # Split required access bits string into characters array - # (to check bit's presence for one bit at a time) - for access_bit in $(echo "wa" | grep -o .) - do - # For each from the required access bits (e.g. 'w', 'a') check - # if they are already present in current access bits for rule. - # If not, append that bit at the end - if ! grep -q "$access_bit" <<< "$current_access_bits" - then - # Concatenate the existing mask with the missing bit - current_access_bits="$current_access_bits$access_bit" - fi - done - # Propagate the updated rule's access bits (original + the required - # ones) back into the /etc/audit/audit.rules file for that rule - sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" - else - # Rule isn't present yet. Append it at the end of $audit_rules_file file - # with proper key - - echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" fi done @@ -123804,217 +141050,25 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/run/utmp already exists in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ - patterns: '*.rules' - register: find_existing_watch_rules_d - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Search /etc/audit/rules.d for other rules with specified key session - find: - paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)session$ - patterns: '*.rules' - register: find_watch_key - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: - all_files: - - /etc/audit/rules.d/session.rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use matched file as the recipient for the rule - set_fact: - all_files: - - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/run/utmp in /etc/audit/rules.d/ - lineinfile: - path: '{{ all_files[0] }}' - line: -w /var/run/utmp -p wa -k session - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/run/utmp already exists in /etc/audit/audit.rules - find: - paths: /etc/audit/ - contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ - patterns: audit.rules - register: find_existing_watch_audit_rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/run/utmp in /etc/audit/audit.rules - lineinfile: - line: -w /var/run/utmp -p wa -k session - state: present - dest: /etc/audit/audit.rules - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/btmp already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Check if watch rule for /var/log/btmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/btmp\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124023,24 +141077,21 @@ fi - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key session - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)session$ patterns: '*.rules' @@ -124051,24 +141102,21 @@ fi - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/session.rules when: @@ -124077,24 +141125,21 @@ fi - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -124103,24 +141148,21 @@ fi - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/btmp in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Add watch rule for /var/log/btmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/btmp -p wa -k session create: true @@ -124131,24 +141173,21 @@ fi - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/btmp already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Check if watch rule for /var/log/btmp already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/btmp\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -124157,24 +141196,21 @@ fi - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/btmp in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Process and Session Initiation Information btmp - + Add watch rule for /var/log/btmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/btmp -p wa -k session state: present dest: /etc/audit/audit.rules @@ -124186,259 +141222,858 @@ fi - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched == 0 tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 + - NIST-800-53-AU-12.1(iv) - PCI-DSSv4-10.2 - PCI-DSSv4-10.2.1 - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events + - audit_rules_session_events_btmp - low_complexity - low_disruption - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/wtmp already exists in /etc/audit/rules.d/ - find: - paths: /etc/audit/rules.d - contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ - patterns: '*.rules' - register: find_existing_watch_rules_d - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Search /etc/audit/rules.d for other rules with specified key session - find: - paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)session$ - patterns: '*.rules' - register: find_watch_key - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use /etc/audit/rules.d/session.rules as the recipient for the rule - set_fact: - all_files: - - /etc/audit/rules.d/session.rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Use matched file as the recipient for the rule - set_fact: - all_files: - - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched - is defined and find_existing_watch_rules_d.matched == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/log/wtmp in /etc/audit/rules.d/ - lineinfile: - path: '{{ all_files[0] }}' - line: -w /var/log/wtmp -p wa -k session - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Check if watch rule for /var/log/wtmp already exists in /etc/audit/audit.rules - find: - paths: /etc/audit/ - contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ - patterns: audit.rules - register: find_existing_watch_audit_rules - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required - - restrict_strategy - -- name: Add watch rule for /var/log/wtmp in /etc/audit/audit.rules - lineinfile: - line: -w /var/log/wtmp -p wa -k session - state: present - dest: /etc/audit/audit.rules - create: true - mode: '0600' - when: - - '"audit" in ansible_facts.packages' - - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) - - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched - == 0 - tags: - - CJIS-5.4.1.1 - - NIST-800-171-3.1.7 - - NIST-800-53-AU-12(c) - - NIST-800-53-AU-2(d) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.3 - - PCI-DSSv4-10.2 - - PCI-DSSv4-10.2.1 - - PCI-DSSv4-10.2.1.3 - - audit_rules_session_events - - low_complexity - - low_disruption - - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy - + + + + + + + + Record Attempts to Alter Process and Session Initiation Information utmp + The audit system already collects process information for all +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/run/utmp -p wa -k session + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/run/utmp -p wa -k session + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + AU-12(c) + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 + R73 + A.3.SEC-OL1 + 0582 + 0846 + 10.2.1.3 + 10.2.1 + 10.2 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/run/utmp" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/session.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/session.rules" + # If the session.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/run/utmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/run/utmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/run/utmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/run/utmp -p wa -k session" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Check if watch rule for /var/run/utmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)session$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/session.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Add watch rule for /var/run/utmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/run/utmp -p wa -k session + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Check if watch rule for /var/run/utmp already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/run/utmp\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information utmp - + Add watch rule for /var/run/utmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/run/utmp -p wa -k session + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_utmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + The audit system already collects process information for all +users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/wtmp -p wa -k session + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/log/wtmp -p wa -k session + + 164.308(a)(1)(ii)(D) + 164.308(a)(3)(ii)(A) + 164.308(a)(5)(ii)(C) + 164.312(a)(2)(i) + 164.312(b) + 164.312(d) + 164.312(e) + AU-12(c) + AU-12.1(iv) + SRG-OS-000472-GPOS-00217 + R73 + A.3.SEC-OL1 + 0582 + 0846 + 10.2.1.3 + 10.2.1 + 10.2 + Manual editing of these files may indicate nefarious activity, such +as an attacker attempting to remove evidence of an intrusion. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/session.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/wtmp" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/session.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/session.rules" + # If the session.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/log/wtmp" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/wtmp $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/log/wtmp$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/log/wtmp -p wa -k session" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Check if watch rule for /var/log/wtmp already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Search /etc/audit/rules.d for other rules with specified key session + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)session$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Use /etc/audit/rules.d/session.rules as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/session.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Add watch rule for /var/log/wtmp in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/log/wtmp -p wa -k session + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Check if watch rule for /var/log/wtmp already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/log/wtmp\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Attempts to Alter Process and Session Initiation Information wtmp - + Add watch rule for /var/log/wtmp in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/log/wtmp -p wa -k session + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-12.1(iv) + - PCI-DSSv4-10.2 + - PCI-DSSv4-10.2.1 + - PCI-DSSv4-10.2.1.3 + - audit_rules_session_events_wtmp + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/sudoers -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/sudoers -p wa -k actions - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 - OL09-00-000500 - SV-271527r1092474_rule + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000500 + SV-271527r1092474_rule The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to @@ -124448,6 +142083,12 @@ files mitigates this risk. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -124471,7 +142112,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124479,7 +142122,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124495,12 +142140,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -124519,8 +142168,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -124548,7 +142199,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124556,7 +142209,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124572,12 +142227,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done @@ -124597,8 +142256,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Check + if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124615,8 +142275,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Search + /etc/audit/rules.d for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -124635,8 +142296,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -124653,8 +142315,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -124671,8 +142334,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Add watch + rule for /etc/sudoers in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers -p wa -k actions create: true @@ -124691,8 +142355,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Check + if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -124709,8 +142374,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers - Add watch + rule for /etc/sudoers in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -124740,47 +142406,44 @@ fi Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: +for all users and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/sudoers.d/ -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/sudoers.d/ -p wa -k actions - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 - OL09-00-000505 - SV-271528r1092476_rule + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 + OL09-00-000505 + SV-271528r1092476_rule The actions taken by system administrators should be audited to keep a record of what was executed on the system, as well as, for accountability purposes. Editing the sudoers file may be sign of an attacker trying to @@ -124790,6 +142453,12 @@ files mitigates this risk. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -124813,7 +142482,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124821,7 +142492,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124837,12 +142510,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -124861,8 +142538,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers.d/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -124890,7 +142569,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -124898,7 +142579,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -124914,12 +142597,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done @@ -124939,8 +142626,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Check + if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -124957,8 +142645,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Search + /etc/audit/rules.d for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -124977,8 +142666,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Use + /etc/audit/rules.d/actions.rules as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -124995,8 +142685,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Use + matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -125013,8 +142704,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Add + watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers.d/ -p wa -k actions create: true @@ -125033,8 +142725,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Check + if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -125051,8 +142744,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - Add + watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers.d/ -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -125100,24 +142794,22 @@ If both the "b32" and "b64" audit rules for "SUID" files are not defined, this i If both the "b32" and "b64" audit rules for "SGID" files are not defined, this is a finding. Note that these rules can be configured in a number of ways while still achieving the desired effect. - CCI-002233 - CCI-002234 CM-5(1) AU-7(a) AU-7(b) AU-8(b) AU-12(3) AC-6(9) - SRG-OS-000326-GPOS-00126 - SRG-OS-000327-GPOS-00127 - SRG-APP-000343-CTR-000780 - SRG-APP-000381-CTR-000905 - SRG-OS-000755-GPOS-00220 + SRG-OS-000326-GPOS-00126 + SRG-OS-000327-GPOS-00127 + SRG-APP-000343-CTR-000780 + SRG-APP-000381-CTR-000905 + SRG-OS-000755-GPOS-00220 10.2.1.2 10.2.1 10.2 - OL09-00-000715 - SV-271570r1092558_rule + OL09-00-000715 + SV-271570r1092558_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised information system accounts, is a serious and ongoing concern @@ -125139,7 +142831,9 @@ do AUID_FILTERS="" SYSCALL="execve" + KEY="setuid" + SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a @@ -125457,7 +143151,9 @@ do AUID_FILTERS="" SYSCALL="execve" + KEY="setgid" + SYSCALL_GROUPING="" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a @@ -125942,18 +143638,40 @@ fi Ensure auditd Collects System Administrator Actions - At a minimum, the audit system should collect administrator actions -for all users and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: --w /etc/sudoers -p wa -k actions --w /etc/sudoers.d/ -p wa -k actions + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/sudoers -p wa -k actions + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: --w /etc/sudoers -p wa -k actions --w /etc/sudoers.d/ -p wa -k actions +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/sudoers -p wa -k actions + + + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/sudoers.d/ -p wa -k actions + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /etc/sudoers.d/ -p wa -k actions 1 11 @@ -126002,12 +143720,6 @@ utility to read audit rules during daemon startup, add the following line to MEA01.05 MEA02.01 3.1.7 - CCI-000126 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -126113,34 +143825,35 @@ utility to read audit rules during daemon startup, add the following line to RS.AN-4 Req-10.2.2 Req-10.2.5.b - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 @@ -126151,6 +143864,7 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -126174,7 +143888,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126182,7 +143898,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126198,12 +143916,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126222,8 +143944,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -126251,7 +143975,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126259,7 +143985,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126275,12 +144003,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126306,7 +144038,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126314,7 +144048,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126330,12 +144066,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -126354,8 +144094,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/actions.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/sudoers.d/" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -126383,7 +144125,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/sudoers.d/" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -126391,7 +144135,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/sudoers.d/ $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -126407,12 +144153,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/sudoers.d/$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/sudoers.d/ -p wa -k actions" >> "$audit_rules_file" + fi done @@ -126443,8 +144193,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -126472,8 +144223,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -126504,8 +144256,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -126533,8 +144286,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -126564,8 +144318,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -126593,8 +144348,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use matched file as + the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -126622,8 +144378,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers -p wa -k actions create: true @@ -126653,8 +144410,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/audit.rules - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers.d/ already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -126682,8 +144440,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/audit.rules - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers.d/ + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/sudoers.d/ -p wa -k actions state: present dest: /etc/audit/audit.rules @@ -126714,8 +144473,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ - find: +- name: Ensure auditd Collects System Administrator Actions - Check if watch rule + for /etc/sudoers.d/ already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/sudoers.d/\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -126743,8 +144503,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key actions - find: +- name: Ensure auditd Collects System Administrator Actions - Search /etc/audit/rules.d + for other rules with specified key actions + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)actions$ patterns: '*.rules' @@ -126774,8 +144535,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/actions.rules as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use /etc/audit/rules.d/actions.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/actions.rules when: @@ -126803,8 +144565,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Ensure auditd Collects System Administrator Actions - Use matched file as + the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -126832,8 +144595,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/sudoers.d/ in /etc/audit/rules.d/ - lineinfile: +- name: Ensure auditd Collects System Administrator Actions - Add watch rule for /etc/sudoers.d/ + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/sudoers.d/ -p wa -k actions create: true @@ -126898,8 +144662,6 @@ bottom of the /etc/audit/audit.rules file: MEA02.01 3.3.1 3.3.4 - CCI-000140 - CCI-000139 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -126927,10 +144689,10 @@ bottom of the /etc/audit/audit.rules file: SC-24 CM-6(a) PR.PT-1 - SRG-OS-000046-GPOS-00022 - SRG-OS-000047-GPOS-00023 - OL09-00-000820 - SV-271590r1091482_rule + SRG-OS-000046-GPOS-00022 + SRG-OS-000047-GPOS-00023 + OL09-00-000820 + SV-271590r1091482_rule It is critical for the appropriate personnel to be aware if a system is at risk of failing to process audit logs as required. Without this notification, the security personnel may be unaware of an impending failure of @@ -126986,7 +144748,7 @@ fi - always - name: Collect all files from /etc/audit/rules.d with .rules extension - find: + ansible.builtin.find: paths: /etc/audit/rules.d/ patterns: '*.rules' register: find_rules_d @@ -127008,7 +144770,7 @@ fi - restrict_strategy - name: Remove the -f option from all Audit config files - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' regexp: ^\s*(?:-f)\s+.*$ state: absent @@ -127032,7 +144794,7 @@ fi - restrict_strategy - name: Add Audit -f option into /etc/audit/rules.d/immutable.rules and /etc/audit/audit.rules - lineinfile: + ansible.builtin.lineinfile: path: '{{ item }}' create: true mode: '0600' @@ -127140,11 +144902,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000018 - CCI-000130 - CCI-000172 - CCI-001403 - CCI-002130 4.2.3.10 4.3.2.6.7 4.3.3.2.2 @@ -127222,14 +144979,14 @@ separate rule for each syscall that needs to be checked. For example: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -127250,27 +145007,27 @@ separate rule for each syscall that needs to be checked. For example: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000239-GPOS-00089 - SRG-OS-000241-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000476-GPOS-00221 - SRG-APP-000026-CTR-000070 - SRG-APP-000027-CTR-000075 - SRG-APP-000028-CTR-000080 - SRG-APP-000291-CTR-000675 - SRG-APP-000292-CTR-000680 - SRG-APP-000293-CTR-000685 - SRG-APP-000294-CTR-000690 - SRG-APP-000319-CTR-000745 - SRG-APP-000320-CTR-000750 - SRG-APP-000509-CTR-001305 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000239-GPOS-00089 + SRG-OS-000241-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000476-GPOS-00221 + SRG-APP-000026-CTR-000070 + SRG-APP-000027-CTR-000075 + SRG-APP-000028-CTR-000080 + SRG-APP-000291-CTR-000675 + SRG-APP-000292-CTR-000680 + SRG-APP-000293-CTR-000685 + SRG-APP-000294-CTR-000690 + SRG-APP-000319-CTR-000745 + SRG-APP-000320-CTR-000750 + SRG-APP-000509-CTR-001305 In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -127301,7 +145058,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127309,7 +145068,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127325,12 +145086,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127349,8 +145114,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/group" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127378,7 +145145,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127386,7 +145155,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127402,12 +145173,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127433,7 +145208,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127441,7 +145218,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127457,12 +145236,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127481,8 +145264,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/passwd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127510,7 +145295,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127518,7 +145305,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127534,12 +145323,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127565,7 +145358,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127573,7 +145368,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127589,12 +145386,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127613,8 +145414,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/gshadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127642,7 +145445,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127650,7 +145455,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127666,12 +145473,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127697,7 +145508,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127705,7 +145518,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127721,12 +145536,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127745,8 +145564,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/shadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127774,7 +145595,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127782,7 +145605,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127798,12 +145623,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127829,7 +145658,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127837,7 +145668,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127853,12 +145686,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -127877,8 +145714,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/security/opasswd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -127906,7 +145745,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -127914,7 +145755,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -127930,12 +145773,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -127952,23 +145799,22 @@ fi Record Events that Modify User/Group Information - /etc/group - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/group -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/group -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/group -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/group -p wa -k audit_rules_usergroup_modification 1 11 @@ -128017,17 +145863,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -128112,14 +145947,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -128140,31 +145975,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000510 - SV-271529r1092478_rule + OL09-00-000510 + SV-271529r1092478_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -128173,6 +146009,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -128196,7 +146037,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128204,7 +146047,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128220,12 +146065,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -128244,8 +146093,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/group" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -128273,7 +146124,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/group" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128281,7 +146134,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/group $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128297,12 +146152,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/group$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/group -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -128310,7 +146169,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -128330,11 +146189,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/group already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/group - Check if watch + rule for /etc/group already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/group\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -128359,11 +146219,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/group - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -128390,12 +146251,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/group - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -128420,11 +146281,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/group - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -128449,11 +146311,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/group in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/group - Add watch + rule for /etc/group in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/group -p wa -k audit_rules_usergroup_modification create: true @@ -128480,11 +146343,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/group already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/group - Check if watch + rule for /etc/group already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/group\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -128509,11 +146373,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/group in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/group - Add watch + rule for /etc/group in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/group -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -128541,7 +146406,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -128553,23 +146418,22 @@ fi Record Events that Modify User/Group Information - /etc/gshadow - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/gshadow -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/gshadow -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification 1 11 @@ -128618,17 +146482,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -128713,14 +146566,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -128741,31 +146594,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000515 - SV-271530r1092480_rule + OL09-00-000515 + SV-271530r1092480_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -128774,6 +146628,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -128797,7 +146656,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128805,7 +146666,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128821,12 +146684,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -128845,8 +146712,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/gshadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -128874,7 +146743,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/gshadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -128882,7 +146753,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/gshadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -128898,12 +146771,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/gshadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/gshadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -128911,7 +146788,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -128931,11 +146808,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/gshadow already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Check if + watch rule for /etc/gshadow already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/gshadow\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -128960,11 +146838,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -128991,12 +146870,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -129021,11 +146900,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -129050,11 +146930,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/gshadow in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Add watch + rule for /etc/gshadow in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification create: true @@ -129081,11 +146962,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/gshadow already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Check if + watch rule for /etc/gshadow already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/gshadow\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -129110,11 +146992,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/gshadow in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/gshadow - Add watch + rule for /etc/gshadow in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -129142,7 +147025,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -129154,23 +147037,22 @@ fi Record Events that Modify User/Group Information - /etc/security/opasswd - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification 1 11 @@ -129219,17 +147101,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -129314,14 +147185,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -129342,33 +147213,34 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000520 - SV-271531r1092482_rule + OL09-00-000520 + SV-271531r1092482_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -129377,6 +147249,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -129400,7 +147277,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -129408,7 +147287,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -129424,12 +147305,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -129448,8 +147333,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/security/opasswd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -129477,7 +147364,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/security/opasswd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -129485,7 +147374,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/security/opasswd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -129501,12 +147392,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/security/opasswd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -129514,7 +147409,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -129534,11 +147429,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/security/opasswd already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Check if watch rule for /etc/security/opasswd already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/security/opasswd\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -129563,11 +147459,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -129594,12 +147491,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient for the rule - set_fact: + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -129624,11 +147522,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Use matched file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -129653,11 +147552,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/security/opasswd in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Add watch rule for /etc/security/opasswd in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification create: true @@ -129684,11 +147584,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/security/opasswd already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Check if watch rule for /etc/security/opasswd already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/security/opasswd\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -129713,11 +147614,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/security/opasswd in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/security/opasswd - + Add watch rule for /etc/security/opasswd in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -129745,7 +147647,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -129757,23 +147659,22 @@ fi Record Events that Modify User/Group Information - /etc/passwd - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/passwd -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/passwd -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification 1 11 @@ -129822,17 +147723,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -129917,14 +147807,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -129945,36 +147835,37 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000276-GPOS-00106 - SRG-OS-000277-GPOS-00107 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000276-GPOS-00106 + SRG-OS-000277-GPOS-00107 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000525 - SV-271532r1092484_rule + OL09-00-000525 + SV-271532r1092484_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -129983,6 +147874,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -130006,7 +147902,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130014,7 +147912,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130030,12 +147930,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -130053,9 +147957,11 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/passwd" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -130067,9 +147973,9 @@ done # Case when particular audit rule isn't defined yet if [ "${#files_to_inspect[@]}" -eq "0" ] then - # Append '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/audit_rules_usergroup_modification.rules" - # If the audit_rules_usergroup_modification.rules file doesn't exist yet, create it with correct permissions + # Append '/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules" + # If the audit_rules_usergroup_modification_passwd.rules file doesn't exist yet, create it with correct permissions if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" @@ -130083,7 +147989,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/passwd" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130091,7 +147999,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/passwd $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130107,12 +148017,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/passwd$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + + echo "-w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd" >> "$audit_rules_file" + fi done @@ -130120,7 +148034,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -130140,11 +148054,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/passwd already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Check if + watch rule for /etc/passwd already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/passwd\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -130169,13 +148084,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification_passwd + ansible.builtin.find: paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ + contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification_passwd$ patterns: '*.rules' register: find_watch_key when: @@ -130200,14 +148116,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/passwd - Use /etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - - /etc/audit/rules.d/audit_rules_usergroup_modification.rules + - /etc/audit/rules.d/audit_rules_usergroup_modification_passwd.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -130230,11 +148146,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/passwd - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -130259,13 +148176,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/passwd in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/passwd - Add watch + rule for /etc/passwd in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' - line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification + line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd create: true mode: '0600' when: @@ -130290,11 +148208,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/passwd already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/passwd - Check if + watch rule for /etc/passwd already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/passwd\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -130319,12 +148238,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/passwd in /etc/audit/audit.rules - lineinfile: - line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification +- name: Record Events that Modify User/Group Information - /etc/passwd - Add watch + rule for /etc/passwd in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification_passwd state: present dest: /etc/audit/audit.rules create: true @@ -130351,7 +148271,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -130363,23 +148283,22 @@ fi Record Events that Modify User/Group Information - /etc/shadow - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d, in order to capture events that modify -account changes: - - - -w /etc/shadow -p wa -k audit_rules_usergroup_modification - - + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file, in order to capture events that modify -account changes: - - - -w /etc/shadow -p wa -k audit_rules_usergroup_modification +/etc/audit/audit.rules: + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification 1 11 @@ -130428,17 +148347,6 @@ account changes: MEA01.05 MEA02.01 3.1.7 - CCI-001403 - CCI-001404 - CCI-001405 - CCI-000172 - CCI-000130 - CCI-002130 - CCI-000135 - CCI-000169 - CCI-002884 - CCI-000018 - CCI-000015 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -130523,14 +148431,14 @@ account changes: A.9.4.3 A.9.4.4 A.9.4.5 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -130551,31 +148459,32 @@ account changes: RS.AN-1 RS.AN-4 Req-10.2.5 - SRG-OS-000004-GPOS-00004 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000304-GPOS-00121 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000470-GPOS-00214 - SRG-OS-000471-GPOS-00215 - SRG-OS-000239-GPOS-00089 - SRG-OS-000240-GPOS-00090 - SRG-OS-000241-GPOS-00091 - SRG-OS-000303-GPOS-00120 - SRG-OS-000466-GPOS-00210 - SRG-OS-000476-GPOS-00221 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000503-CTR-001275 + SRG-OS-000004-GPOS-00004 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000304-GPOS-00121 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000470-GPOS-00214 + SRG-OS-000471-GPOS-00215 + SRG-OS-000239-GPOS-00089 + SRG-OS-000240-GPOS-00090 + SRG-OS-000241-GPOS-00091 + SRG-OS-000303-GPOS-00120 + SRG-OS-000466-GPOS-00210 + SRG-OS-000476-GPOS-00221 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000503-CTR-001275 R73 A.3.SEC-OL7 + 0582 10.2.1.5 10.2.1 10.2 - OL09-00-000530 - SV-271533r1092486_rule + OL09-00-000530 + SV-271533r1092486_rule In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy. @@ -130584,6 +148493,11 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -130607,7 +148521,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130615,7 +148531,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130631,12 +148549,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -130655,8 +148577,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_rules_usergroup_modification.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/shadow" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -130684,7 +148608,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/shadow" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -130692,7 +148618,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/shadow $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -130708,12 +148636,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/shadow$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/shadow -p wa -k audit_rules_usergroup_modification" >> "$audit_rules_file" + fi done @@ -130721,7 +148653,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -130741,11 +148673,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/shadow already exists in /etc/audit/rules.d/ - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Check if + watch rule for /etc/shadow already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/shadow\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -130770,11 +148703,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_rules_usergroup_modification - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Search /etc/audit/rules.d + for other rules with specified key audit_rules_usergroup_modification + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_rules_usergroup_modification$ patterns: '*.rules' @@ -130801,12 +148735,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules as the recipient - for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/shadow - Use /etc/audit/rules.d/audit_rules_usergroup_modification.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_rules_usergroup_modification.rules when: @@ -130831,11 +148765,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Events that Modify User/Group Information - /etc/shadow - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -130860,11 +148795,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/shadow in /etc/audit/rules.d/ - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/shadow - Add watch + rule for /etc/shadow in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification create: true @@ -130891,11 +148827,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/shadow already exists in /etc/audit/audit.rules - find: +- name: Record Events that Modify User/Group Information - /etc/shadow - Check if + watch rule for /etc/shadow already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/shadow\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -130920,11 +148857,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/shadow in /etc/audit/audit.rules - lineinfile: +- name: Record Events that Modify User/Group Information - /etc/shadow - Add watch + rule for /etc/shadow in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification state: present dest: /etc/audit/audit.rules @@ -130952,7 +148890,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -130962,6 +148900,358 @@ fi + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/spool/cron -p wa -k cronjobs + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/spool/cron -p wa -k cronjobs + + SRG-OS-000363-GPOS-00150 + SRG-OS-000363-GPOS-00150 + SRG-OS-000446-GPOS-00200 + SRG-OS-000447-GPOS-00201 + OL09-00-002584 + SV-278952r1135407_rule + In addition to auditing new user and group accounts, these watches +will alert the system administrator(s) to any modifications. Any unexpected +users, groups, or modifications should be investigated for legitimacy. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +# Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + + +# If the audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# into the list of files to be inspected +files_to_inspect+=('/etc/audit/audit.rules') + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/spool/cron" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/spool/cron $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/spool/cron$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/spool/cron -p wa -k cronjobs" >> "$audit_rules_file" + + fi +done +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +files_to_inspect=() + +# If the audit is 'augenrules', then check if rule is already defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/cronjobs.rules' to list of files for inspection. + +readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/spool/cron" /etc/audit/rules.d/*.rules) + + +# For each of the matched entries +for match in "${matches[@]}" +do + # Extract filepath from the match + rulesd_audit_file=$(echo $match | cut -f1 -d ':') + # Append that path into list of files for inspection + files_to_inspect+=("$rulesd_audit_file") +done +# Case when particular audit rule isn't defined yet +if [ "${#files_to_inspect[@]}" -eq "0" ] +then + # Append '/etc/audit/rules.d/cronjobs.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/cronjobs.rules" + # If the cronjobs.rules file doesn't exist yet, create it with correct permissions + if [ ! -e "$key_rule_file" ] + then + touch "$key_rule_file" + chmod 0600 "$key_rule_file" + fi + files_to_inspect+=("$key_rule_file") +fi + +# Finally perform the inspection and possible subsequent audit rule +# correction for each of the files previously identified for inspection +for audit_rules_file in "${files_to_inspect[@]}" +do + # Check if audit watch file system object rule for given path already present + + if grep -q -P -- "^[\s]*-w[\s]+/var/spool/cron" "$audit_rules_file" + + then + # Rule is found => verify yet if existing rule definition contains + # all of the required access type bits + + # Define BRE whitespace class shortcut + sp="[[:space:]]" + # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/spool/cron $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + + # Split required access bits string into characters array + # (to check bit's presence for one bit at a time) + for access_bit in $(echo "wa" | grep -o .) + do + # For each from the required access bits (e.g. 'w', 'a') check + # if they are already present in current access bits for rule. + # If not, append that bit at the end + if ! grep -q "$access_bit" <<< "$current_access_bits" + then + # Concatenate the existing mask with the missing bit + current_access_bits="$current_access_bits$access_bit" + fi + done + # Propagate the updated rule's access bits (original + the required + # ones) back into the /etc/audit/audit.rules file for that rule + + sed -i "s#\($sp*-w$sp\+/var/spool/cron$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + + else + # Rule isn't present yet. Append it at the end of $audit_rules_file file + # with proper key + + + echo "-w /var/spool/cron -p wa -k cronjobs" >> "$audit_rules_file" + + fi +done + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Check if watch + rule for /var/spool/cron already exists in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^\s*-w\s+/var/spool/cron\s+-p\s+wa(\s|$)+ + patterns: '*.rules' + register: find_existing_watch_rules_d + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Search /etc/audit/rules.d + for other rules with specified key cronjobs + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: ^.*(?:-F key=|-k\s+)cronjobs$ + patterns: '*.rules' + register: find_watch_key + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Use /etc/audit/rules.d/cronjobs.rules + as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - /etc/audit/rules.d/cronjobs.rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched == 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: + all_files: + - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_watch_key.matched is defined and find_watch_key.matched > 0 and find_existing_watch_rules_d.matched + is defined and find_existing_watch_rules_d.matched == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Add watch + rule for /var/spool/cron in /etc/audit/rules.d/ + ansible.builtin.lineinfile: + path: '{{ all_files[0] }}' + line: -w /var/spool/cron -p wa -k cronjobs + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_rules_d.matched is defined and find_existing_watch_rules_d.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Check if watch + rule for /var/spool/cron already exists in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit/ + contains: ^\s*-w\s+/var/spool/cron\s+-p\s+wa(\s|$)+ + patterns: audit.rules + register: find_existing_watch_audit_rules + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron - Add watch + rule for /var/spool/cron in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/spool/cron -p wa -k cronjobs + state: present + dest: /etc/audit/audit.rules + create: true + mode: '0600' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - find_existing_watch_audit_rules.matched is defined and find_existing_watch_audit_rules.matched + == 0 + tags: + - DISA-STIG-OL09-00-002584 + - audit_rules_var_spool_cron + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + Record Attempts to perform maintenance activities The Oracle Linux 9 operating system must generate audit records for @@ -130972,13 +149262,28 @@ Verify the operating system audits activities performed during nonlocal maintenance and diagnostic sessions. Run the following command: $ sudo auditctl -l | grep sudo.log -w /var/log/sudo.log -p wa -k maintenance + + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + +-w /var/log/sudo.log -p wa -k maintenance + +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + +-w /var/log/sudo.log -p wa -k maintenance - CCI-000172 - CCI-002884 Req-10.2.2 Req-10.2.5.b - SRG-OS-000392-GPOS-00172 - SRG-OS-000471-GPOS-00215 + SRG-OS-000392-GPOS-00172 + SRG-OS-000471-GPOS-00215 R73 A.3.SEC-OL7 10.2.1.3 @@ -131009,6 +149314,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -131032,7 +149341,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -131040,7 +149351,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -131056,12 +149369,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + + echo "-w /var/log/sudo.log -p wa -k maintenance" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -131079,9 +149396,11 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. -# If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. +# If rule isn't defined, add '/etc/audit/rules.d/maintenance.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/sudo.log" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -131093,9 +149412,9 @@ done # Case when particular audit rule isn't defined yet if [ "${#files_to_inspect[@]}" -eq "0" ] then - # Append '/etc/audit/rules.d/logins.rules' into list of files for inspection - key_rule_file="/etc/audit/rules.d/logins.rules" - # If the logins.rules file doesn't exist yet, create it with correct permissions + # Append '/etc/audit/rules.d/maintenance.rules' into list of files for inspection + key_rule_file="/etc/audit/rules.d/maintenance.rules" + # If the maintenance.rules file doesn't exist yet, create it with correct permissions if [ ! -e "$key_rule_file" ] then touch "$key_rule_file" @@ -131109,7 +149428,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/sudo.log" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -131117,7 +149438,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/sudo.log $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -131133,12 +149456,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/sudo.log$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key - echo "-w /var/log/sudo.log -p wa -k logins" >> "$audit_rules_file" + + echo "-w /var/log/sudo.log -p wa -k maintenance" >> "$audit_rules_file" + fi done @@ -131146,7 +149473,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -131159,11 +149486,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to perform maintenance activities - Check if watch rule for + /var/log/sudo.log already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -131181,13 +149509,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to perform maintenance activities - Search /etc/audit/rules.d + for other rules with specified key maintenance + ansible.builtin.find: paths: /etc/audit/rules.d - contains: ^.*(?:-F key=|-k\s+)logins$ + contains: ^.*(?:-F key=|-k\s+)maintenance$ patterns: '*.rules' register: find_watch_key when: @@ -131205,13 +149534,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to perform maintenance activities - Use /etc/audit/rules.d/maintenance.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - - /etc/audit/rules.d/logins.rules + - /etc/audit/rules.d/maintenance.rules when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -131227,11 +149557,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to perform maintenance activities - Use matched file as the + recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -131249,13 +149580,14 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/sudo.log in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to perform maintenance activities - Add watch rule for /var/log/sudo.log + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' - line: -w /var/log/sudo.log -p wa -k logins + line: -w /var/log/sudo.log -p wa -k maintenance create: true mode: '0600' when: @@ -131273,11 +149605,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/sudo.log already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to perform maintenance activities - Check if watch rule for + /var/log/sudo.log already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/sudo.log\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -131295,12 +149628,13 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/sudo.log in /etc/audit/audit.rules - lineinfile: - line: -w /var/log/sudo.log -p wa -k logins +- name: Record Attempts to perform maintenance activities - Add watch rule for /var/log/sudo.log + in /etc/audit/audit.rules + ansible.builtin.lineinfile: + line: -w /var/log/sudo.log -p wa -k maintenance state: present dest: /etc/audit/audit.rules create: true @@ -131320,7 +149654,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -131335,7 +149669,8 @@ fi The audit system should collect access events to read audit log directory. The following audit rule will assure that access to audit log directory are collected. --a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail +Set ARCH to either b32 for 32-bit system, or have two lines for both b32 and b64 in case your system is 64-bit. +-a always,exit -F arch=ARCH -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the rule to a file with suffix .rules in the directory @@ -131354,14 +149689,18 @@ Auditing these events could serve as evidence of potential system compromise.'# Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" OTHER_FILTERS="-F dir=/var/log/audit/ -F perm=r" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="access-audit-trail" SYSCALL_GROUPING="" +[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64") + +for ARCH in "${RULE_ARCHS[@]}" +do # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' -unset syscall_a + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + unset syscall_a unset syscall_grouping unset syscall_string unset syscall @@ -131520,7 +149859,7 @@ if [ "$skip" -ne 0 ]; then sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" fi fi -unset syscall_a + unset syscall_a unset syscall_grouping unset syscall_string unset syscall @@ -131666,6 +150005,7 @@ if [ "$skip" -ne 0 ]; then sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" fi fi +done else >&2 echo 'Remediation is not applicable, nothing was done' @@ -131688,63 +150028,87 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /var/log/audit +- name: Record Access Events to Audit Log Directory - Set architecture for audit tasks + ansible.builtin.set_fact: + audit_arch: b64 + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - ansible_architecture == "aarch64" or ansible_architecture == "ppc64" or ansible_architecture + == "ppc64le" or ansible_architecture == "s390x" or ansible_architecture == "x86_64" + tags: + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - directory_access_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Record Access Events to Audit Log Directory - Perform remediation of Audit + rules for /var/log/audit block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ patterns: '*.rules' register: find_command loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access-audit-trail.rules - set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (?:-k |-F key=)\w+) line: \1\2\3{{ missing_syscalls | join("\3") }}\4 @@ -131754,45 +150118,46 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r - -F auid>=1000 -F auid!=unset -F key=access-audit-trail + line: -a always,exit -F arch=b32{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit - contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F - dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ patterns: audit.rules register: find_command loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( - -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset - (?:-k |-F key=)\w+) + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 + -F auid!=unset (?:-k |-F key=)\w+) line: \1\2\3{{ missing_syscalls | join("\3") }}\4 backrefs: true state: present @@ -131800,10 +150165,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' - line: -a always,exit{{ syscalls | join(',') }} -F dir=/var/log/audit/ -F perm=r - -F auid>=1000 -F auid!=unset -F key=access-audit-trail + line: -a always,exit -F arch=b32{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail create: true mode: g-rwx,o-rwx state: present @@ -131824,6 +150189,147 @@ fi - medium_severity - no_reboot_needed - restrict_strategy + +- name: Record Access Events to Audit Log Directory - Perform remediation of Audit + rules for /var/log/audit for x86_64 platform + block: + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: [] + syscall_grouping: [] + + - name: Check existence of in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/access-audit-trail.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access-audit-trail.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F + auid>=1000 -F auid!=unset (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: [] + syscall_grouping: [] + + - name: Check existence of in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F dir=/var/log/audit/ -F perm=r -F auid>=1000 + -F auid!=unset (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64{{ syscalls | join(',') }} -F dir=/var/log/audit/ + -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + - audit_arch == "b64" + tags: + - NIST-800-53-AC-6(9) + - NIST-800-53-AU-12(c) + - NIST-800-53-AU-2(d) + - NIST-800-53-CM-6(a) + - PCI-DSSv4-10.3 + - PCI-DSSv4-10.3.1 + - directory_access_var_log_audit + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy @@ -131837,7 +150343,10 @@ fi All audit directories must be group owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the group owner of /var/log/audit, run the command: -$ sudo chgrp root /var/log/audit + + $ sudo chgrp root /var/log/audit + + If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the group ownership of the audit directories to this specific group. @@ -131871,10 +150380,6 @@ group account, change the group ownership of the audit directories to this speci DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -131936,12 +150441,12 @@ group account, change the group ownership of the audit directories to this speci RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - OL09-00-000785 - SV-271583r1091461_rule + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000785 + SV-271583r1091461_rule Unauthorized disclosure of audit records can reveal system and configuration data to attackers, thus compromising its confidentiality. # Remediation is applicable only in certain platforms @@ -132045,7 +150550,8 @@ fi All audit directories must be owned by root user. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit + + $ sudo chown root /var/log/audit 1 11 @@ -132077,10 +150583,6 @@ To properly set the owner of /var/log/audit, run the comm DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132142,12 +150644,12 @@ To properly set the owner of /var/log/audit, run the comm RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - OL09-00-000790 - SV-271584r1091464_rule + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + OL09-00-000790 + SV-271584r1091464_rule Unauthorized disclosure of audit records can reveal system and configuration data to attackers, thus compromising its confidentiality. # Remediation is applicable only in certain platforms @@ -132275,9 +150777,6 @@ Otherwise, change the mode of the audit log files with the following command: DSS05.07 DSS06.02 MEA02.01 - CCI-000162 - CCI-000163 - CCI-000164 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132328,18 +150827,18 @@ Otherwise, change the mode of the audit log files with the following command: A.9.4.1 A.9.4.4 A.9.4.5 - CIP-003-8 R5.1.1 - CIP-003-8 R5.2 - CIP-003-8 R5.3 - CIP-004-6 R2.3 - CIP-004-6 R3.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 - CIP-007-3 R6.5 + CIP-003-8 R5.1.1 + CIP-003-8 R5.2 + CIP-003-8 R5.3 + CIP-004-6 R2.3 + CIP-004-6 R3.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 + CIP-007-3 R6.5 CM-6(a) AC-6(1) AU-9 @@ -132350,9 +150849,9 @@ Otherwise, change the mode of the audit log files with the following command: PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 A.3.SEC-OL2 If users can write to audit logs, audit trails can be modified or destroyed. # Remediation is applicable only in certain platforms @@ -132394,7 +150893,10 @@ be configured via log_file parameter in /etc/au or, by default, the path for audit log is /var/log/audit/. To properly set the group owner of /var/log/audit/*, run the command: -$ sudo chgrp root /var/log/audit/* + + $ sudo chgrp root /var/log/audit/* + + If log_group in /etc/audit/auditd.conf is set to a group other than the root group account, change the group ownership of the audit logs @@ -132429,10 +150931,6 @@ to this specific group. DSS06.02 MEA02.01 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132494,10 +150992,10 @@ to this specific group. RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 A.3.SEC-OL2 10.3.2 10.3 @@ -132540,8 +151038,7 @@ fi All audit configuration files must be owned by group root. chown :root /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - CCI-000171 - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132553,9 +151050,18 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chgrp -L 0 {} \; +newgroup="" +if getent group "0" >/dev/null 2>&1; then + newgroup="0" +fi -find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.rules$' -exec chgrp -L 0 {} \; +if [[ -z "${newgroup}" ]]; then + >&2 echo "0 is not a defined group on the system" +else +find -P /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chgrp --no-dereference "$newgroup" {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended -regex '^.*\.rules$' -exec chgrp --no-dereference "$newgroup" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132572,9 +151078,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_groupownership_audit_configuration_newgroup variable if represented + by gid + ansible.builtin.set_fact: + file_groupownership_audit_configuration_newgroup: '0' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_groupownership_audit_configuration + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -type f ! -group 0 -regextype + posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132591,9 +151112,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_audit_configuration_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132609,8 +151131,8 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -group 0 -regextype posix-extended - -regex "^.*\.rules$" + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -group + 0 -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false @@ -132627,9 +151149,10 @@ fi - no_reboot_needed - name: Ensure group owner on /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - file: + ansible.builtin.file: path: '{{ item }}' - group: '0' + follow: false + group: '{{ file_groupownership_audit_configuration_newgroup }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132656,13 +151179,16 @@ fi All audit configuration files must be owned by root user. To properly set the owner of /etc/audit/, run the command: -$ sudo chown root /etc/audit/ + + $ sudo chown root /etc/audit/ + + To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ + + $ sudo chown root /etc/audit/rules.d/ - CCI-000171 - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132674,9 +151200,20 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chown -L 0 {} \; +newown="" +if id "0" >/dev/null 2>&1; then + newown="0" +fi -find -L /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended -regex '^.*\.rules$' -exec chown -L 0 {} \; +if [[ -z "$newown" ]]; then + >&2 echo "0 is not a defined user on the system" +else + +find -P /etc/audit/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chown --no-dereference "$newown" {} \; + +find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -user 0 -regextype posix-extended -regex '^.*\.rules$' -exec chown --no-dereference "$newown" {} \; + +fi else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132693,9 +151230,24 @@ fi - medium_severity - no_reboot_needed +- name: Set the file_ownership_audit_configuration_newown variable if represented + by uid + ansible.builtin.set_fact: + file_ownership_audit_configuration_newown: '0' + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - configure_strategy + - file_ownership_audit_configuration + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - name: Find /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - command: find -H /etc/audit/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -type f ! -user 0 -regextype + posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132712,9 +151264,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/audit/ file(s) matching ^.*audit(\.rules|d\.conf)$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_audit_configuration_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132730,8 +151283,8 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - command: find -H /etc/audit/rules.d/ -maxdepth 1 -type f ! -uid 0 -regextype posix-extended - -regex "^.*\.rules$" + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -type f ! -user + 0 -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false failed_when: false @@ -132748,9 +151301,10 @@ fi - no_reboot_needed - name: Ensure owner on /etc/audit/rules.d/ file(s) matching ^.*\.rules$ - file: + ansible.builtin.file: path: '{{ item }}' - owner: '0' + follow: false + owner: '{{ file_ownership_audit_configuration_newown }}' state: file with_items: - '{{ files_found.stdout_lines }}' @@ -132777,10 +151331,14 @@ fi All audit logs must be owned by root user and group. By default, the path for audit log is /var/log/audit/. To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit + + $ sudo chown root /var/log/audit + + To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* + + $ sudo chown root /var/log/audit/* 1 11 @@ -132812,10 +151370,6 @@ To properly set the owner of /var/log/audit/*, run the co DSS06.02 MEA02.01 3.3.1 - CCI-000162 - CCI-000163 - CCI-000164 - CCI-001314 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -132866,15 +151420,15 @@ To properly set the owner of /var/log/audit/*, run the co 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 + 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 CM-6(a) AC-6(1) AU-9(4) @@ -132886,10 +151440,10 @@ To properly set the owner of /var/log/audit/*, run the co RS.AN-1 RS.AN-4 Req-10.5.1 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000118-CTR-000240 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000118-CTR-000240 A.3.SEC-OL2 10.3.2 10.3 @@ -132928,9 +151482,8 @@ fi All audit configuration files permissions must be 640 or more restrictive. chmod 0640 /etc/audit/audit*.{rules,conf} /etc/audit/rules.d/* - CCI-000171 AU-12 b - SRG-OS-000063-GPOS-00032 + SRG-OS-000063-GPOS-00032 A.3.SEC-OL4 Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able @@ -132942,9 +151495,9 @@ to an incident or identify those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -P /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*audit(\.rules|d\.conf)$' -exec chmod u-xs,g-xws,o-xwrt {} \; -find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex '^.*\.rules$' -exec chmod u-xs,g-xws,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -132963,8 +151516,8 @@ fi - no_reboot_needed - name: Find /etc/audit/ file(s) - command: find -H /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype - posix-extended -regex "^.*audit(\.rules|d\.conf)$" + ansible.builtin.command: find -P /etc/audit/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type + f -regextype posix-extended -regex "^.*audit(\.rules|d\.conf)$" register: files_found changed_when: false failed_when: false @@ -132982,7 +151535,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwrt state: file @@ -133001,7 +151554,7 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) - command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xws,o+xwrt -type f -regextype posix-extended -regex "^.*\.rules$" register: files_found changed_when: false @@ -133020,7 +151573,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/rules.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xws,o-xwrt state: file @@ -133086,10 +151639,6 @@ By default, audit_log_file is "/var/log/audit/audit.log".DSS06.02 MEA02.01 3.3.1 - CCI-000163 - CCI-000164 - CCI-001314 - CCI-000162 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -133140,15 +151689,15 @@ By default, audit_log_file is "/var/log/audit/audit.log".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 + 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 CM-6(a) AC-6(1) AU-9(4) @@ -133160,16 +151709,16 @@ By default, audit_log_file is "/var/log/audit/audit.log".RS.AN-1 RS.AN-4 Req-10.5 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-OS-000206-GPOS-00084 - SRG-APP-000118-CTR-000240 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-OS-000206-GPOS-00084 + SRG-APP-000118-CTR-000240 A.3.SEC-OL2 10.3.1 10.3 - OL09-00-000795 - SV-271585r1091467_rule + OL09-00-000795 + SV-271585r1091467_rule If users can write to audit logs, audit trails can be modified or destroyed. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -133208,8 +151757,10 @@ fi - restrict_strategy - name: Get audit log files - command: grep -iw ^log_file /etc/audit/auditd.conf + ansible.builtin.command: grep -iw ^log_file /etc/audit/auditd.conf failed_when: false + changed_when: false + check_mode: false register: log_file_exists when: - '"audit" in ansible_facts.packages' @@ -133232,8 +151783,10 @@ fi - restrict_strategy - name: Parse log file line - command: awk -F '=' '/^log_file/ {print $2}' /etc/audit/auditd.conf + ansible.builtin.command: awk -F '=' '/^log_file/ {print $2}' /etc/audit/auditd.conf register: log_file_line + changed_when: false + check_mode: false when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -133256,7 +151809,7 @@ fi - restrict_strategy - name: Set default log_file if not set - set_fact: + ansible.builtin.set_fact: log_file: /var/log/audit/audit.log when: - '"audit" in ansible_facts.packages' @@ -133281,7 +151834,7 @@ fi - restrict_strategy - name: Set log_file from log_file_line if not set already - set_fact: + ansible.builtin.set_fact: log_file: '{{ log_file_line.stdout | trim }}' when: - '"audit" in ansible_facts.packages' @@ -133306,7 +151859,7 @@ fi - restrict_strategy - name: Apply mode to log file - file: + ansible.builtin.file: path: '{{ log_file }}' mode: 384 failed_when: false @@ -133347,12 +151900,16 @@ calls. Additionally, these rules can be configured in a number of ways while still achieving the desired effect. An example of this is that the "-S" calls could be split up and placed on separate lines, however, this is less efficient. Add the following to /etc/audit/audit.rules: + -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod + -a always,exit -F arch=b32 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows: + -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod + -a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -133422,11 +151979,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -133497,29 +152049,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 + 0582 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -133874,7 +152427,7 @@ fi - restrict_strategy - name: Set architecture for audit chmod tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -133903,7 +152456,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -133912,7 +152465,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -133921,43 +152474,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -133969,7 +152523,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -133979,7 +152533,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -133988,7 +152542,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -133997,17 +152551,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134019,7 +152574,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134052,7 +152607,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -134061,7 +152616,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134070,43 +152625,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134118,7 +152674,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134128,7 +152684,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chmod syscall_grouping: @@ -134137,7 +152693,7 @@ fi - fchmodat - name: Check existence of chmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134146,17 +152702,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134168,7 +152725,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134271,11 +152828,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -134346,30 +152898,31 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 + 0582 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -134724,7 +153277,7 @@ fi - restrict_strategy - name: Set architecture for audit chown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -134753,7 +153306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134763,7 +153316,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134772,43 +153325,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134820,7 +153374,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134830,7 +153384,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134840,7 +153394,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134849,17 +153403,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -134871,7 +153426,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134904,7 +153459,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134914,7 +153469,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -134923,43 +153478,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -134971,7 +153527,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -134981,7 +153537,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - chown syscall_grouping: @@ -134991,7 +153547,7 @@ fi - lchown - name: Check existence of chown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135000,17 +153556,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135022,7 +153579,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135125,11 +153682,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -135200,29 +153752,29 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -135576,7 +154128,7 @@ fi - restrict_strategy - name: Set architecture for audit fchmod tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -135604,7 +154156,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135613,7 +154165,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135622,43 +154174,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -135670,7 +154223,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135680,7 +154233,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135689,7 +154242,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135698,17 +154251,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135720,7 +154274,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135752,7 +154306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135761,7 +154315,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135770,43 +154324,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -135818,7 +154373,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135828,7 +154383,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmod syscall_grouping: @@ -135837,7 +154392,7 @@ fi - fchmodat - name: Check existence of fchmod in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -135846,17 +154401,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -135868,7 +154424,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -135970,11 +154526,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -136045,29 +154596,29 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000640 - SV-271555r1092530_rule + OL09-00-000640 + SV-271555r1092530_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -136421,7 +154972,7 @@ fi - restrict_strategy - name: Set architecture for audit fchmodat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -136449,7 +155000,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136458,7 +155009,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136467,43 +155018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -136515,7 +155067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136525,7 +155077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136534,7 +155086,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136543,17 +155095,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -136565,7 +155118,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136597,7 +155150,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136606,7 +155159,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136615,43 +155168,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -136663,7 +155217,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136673,7 +155227,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchmodat syscall_grouping: @@ -136682,7 +155236,7 @@ fi - fchmodat - name: Check existence of fchmodat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -136691,17 +155245,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -136713,7 +155268,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -136818,11 +155373,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -136893,30 +155443,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -137270,7 +155820,7 @@ fi - restrict_strategy - name: Set architecture for audit fchown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -137298,7 +155848,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137308,7 +155858,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137317,43 +155867,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -137365,7 +155916,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137375,7 +155926,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137385,7 +155936,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137394,17 +155945,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -137416,7 +155968,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137448,7 +156000,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137458,7 +156010,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137467,43 +156019,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -137515,7 +156068,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137525,7 +156078,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchown syscall_grouping: @@ -137535,7 +156088,7 @@ fi - lchown - name: Check existence of fchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -137544,17 +156097,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -137566,7 +156120,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -137668,11 +156222,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -137743,30 +156292,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -138120,7 +156669,7 @@ fi - restrict_strategy - name: Set architecture for audit fchownat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -138148,7 +156697,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138158,7 +156707,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138167,43 +156716,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -138215,7 +156765,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138225,7 +156775,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138235,7 +156785,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138244,17 +156794,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -138266,7 +156817,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138298,7 +156849,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138308,7 +156859,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138317,43 +156868,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -138365,7 +156917,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138375,7 +156927,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fchownat syscall_grouping: @@ -138385,7 +156937,7 @@ fi - lchown - name: Check existence of fchownat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -138394,17 +156946,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -138416,7 +156969,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -138531,11 +157084,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -138606,35 +157154,35 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -138963,6 +157511,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="fremovexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -138988,7 +157855,7 @@ fi - restrict_strategy - name: Set architecture for audit fremovexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -139016,7 +157883,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139028,7 +157895,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139037,43 +157904,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139085,7 +157953,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139095,7 +157963,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139107,7 +157975,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139116,17 +157984,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -139138,7 +158007,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139146,6 +158015,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -139170,7 +158171,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139182,7 +158183,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139191,43 +158192,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139239,7 +158241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139249,7 +158251,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fremovexattr syscall_grouping: @@ -139261,7 +158263,7 @@ fi - setxattr - name: Check existence of fremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139270,17 +158272,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -139292,7 +158295,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139300,6 +158303,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -139398,11 +158533,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -139473,36 +158603,36 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -139831,6 +158961,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="fsetxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -139856,7 +159305,7 @@ fi - restrict_strategy - name: Set architecture for audit fsetxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -139884,7 +159333,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -139896,7 +159345,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139905,43 +159354,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -139953,7 +159403,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -139963,7 +159413,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -139975,7 +159425,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -139984,17 +159434,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140006,7 +159457,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140014,6 +159465,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -140038,7 +159621,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -140050,7 +159633,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140059,43 +159642,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140107,7 +159691,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140117,7 +159701,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - fsetxattr syscall_grouping: @@ -140129,7 +159713,7 @@ fi - setxattr - name: Check existence of fsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140138,17 +159722,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140160,7 +159745,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140168,6 +159753,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - fsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of fsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -140262,11 +159979,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -140337,30 +160049,30 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000064-GPOS-00033 - SRG-OS-000466-GPOS-00210 - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 + 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-000064-GPOS-00033 + SRG-OS-000466-GPOS-00210 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000645 - SV-271556r1092532_rule + OL09-00-000645 + SV-271556r1092532_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -140715,7 +160427,7 @@ fi - restrict_strategy - name: Set architecture for audit lchown tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -140744,7 +160456,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140754,7 +160466,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140763,43 +160475,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140811,7 +160524,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140821,7 +160534,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140831,7 +160544,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140840,17 +160553,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -140862,7 +160576,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140895,7 +160609,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140905,7 +160619,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140914,43 +160628,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -140962,7 +160677,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -140972,7 +160687,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lchown syscall_grouping: @@ -140982,7 +160697,7 @@ fi - lchown - name: Check existence of lchown in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -140991,17 +160706,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141013,7 +160729,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141129,11 +160845,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -141204,37 +160915,37 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -141563,6 +161274,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="lremovexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -141588,7 +161618,7 @@ fi - restrict_strategy - name: Set architecture for audit lremovexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -141616,7 +161646,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141628,7 +161658,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141637,43 +161667,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -141685,7 +161716,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141695,7 +161726,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141707,7 +161738,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141716,17 +161747,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141738,7 +161770,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141746,6 +161778,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -141770,7 +161934,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141782,7 +161946,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141791,43 +161955,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -141839,7 +162004,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141849,7 +162014,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lremovexattr syscall_grouping: @@ -141861,7 +162026,7 @@ fi - setxattr - name: Check existence of lremovexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -141870,17 +162035,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -141892,7 +162058,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -141900,6 +162066,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lremovexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lremovexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -141998,11 +162296,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -142073,36 +162366,36 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000466-GPOS-00210 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000466-GPOS-00210 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -142431,6 +162724,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="lsetxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -142456,7 +163068,7 @@ fi - restrict_strategy - name: Set architecture for audit lsetxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -142484,7 +163096,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142496,7 +163108,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142505,43 +163117,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -142553,7 +163166,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142563,7 +163176,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142575,7 +163188,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142584,17 +163197,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -142606,7 +163220,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142614,6 +163228,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -142638,7 +163384,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142650,7 +163396,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142659,43 +163405,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -142707,7 +163454,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142717,7 +163464,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - lsetxattr syscall_grouping: @@ -142729,7 +163476,7 @@ fi - setxattr - name: Check existence of lsetxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -142738,17 +163485,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -142760,7 +163508,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -142768,6 +163516,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - lsetxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of lsetxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -142874,11 +163754,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -142949,37 +163824,37 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000458-GPOS-00203 - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000474-GPOS-00219 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000458-GPOS-00203 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000474-GPOS-00219 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -143308,6 +164183,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="removexattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -143333,7 +164527,7 @@ fi - restrict_strategy - name: Set architecture for audit removexattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -143361,7 +164555,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143373,7 +164567,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143382,43 +164576,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -143430,7 +164625,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143440,7 +164635,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143452,7 +164647,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143461,17 +164656,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -143483,7 +164679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143491,6 +164687,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -143515,7 +164843,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143527,7 +164855,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143536,43 +164864,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -143584,7 +164913,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143594,7 +164923,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - removexattr syscall_grouping: @@ -143606,7 +164935,7 @@ fi - setxattr - name: Check existence of removexattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -143615,17 +164944,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -143637,7 +164967,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -143645,6 +164975,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - removexattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of removexattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -143743,11 +165205,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -143818,28 +165275,28 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-1 RS.AN-4 Req-10.5.5 - 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-000466-GPOS-00210 - SRG-OS-000471-GPOS-00215 - SRG-OS-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 - SRG-APP-000495-CTR-001235 + 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-000466-GPOS-00210 + SRG-OS-000471-GPOS-00215 + SRG-OS-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL7 10.3.4 10.3 - OL09-00-000545 - SV-271536r1092492_rule + OL09-00-000545 + SV-271536r1092492_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -144168,6 +165625,325 @@ if [ "$skip" -ne 0 ]; then fi done + + +for ARCH in "${RULE_ARCHS[@]}" +do + ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" + OTHER_FILTERS="" + AUID_FILTERS="-F auid=0" + SYSCALL="setxattr" + KEY="perm_mod" + SYSCALL_GROUPING="fremovexattr lremovexattr removexattr fsetxattr lsetxattr setxattr" + + # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + +# If audit tool is 'augenrules', then check if the audit rule is defined +# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection +# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection +default_file="/etc/audit/rules.d/$KEY.rules" +# As other_filters may include paths, lets use a different delimiter for it +# The "F" script expression tells sed to print the filenames where the expressions matched +readarray -t files_to_inspect < <(sed -s -n -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" -e "F" /etc/audit/rules.d/*.rules) +# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet +if [ ${#files_to_inspect[@]} -eq "0" ] +then + file_to_inspect="/etc/audit/rules.d/$KEY.rules" + files_to_inspect=("$file_to_inspect") + if [ ! -e "$file_to_inspect" ] + then + touch "$file_to_inspect" + chmod 0600 "$file_to_inspect" + fi +fi + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi + unset syscall_a +unset syscall_grouping +unset syscall_string +unset syscall +unset file_to_edit +unset rule_to_edit +unset rule_syscalls_to_edit +unset other_string +unset auid_string +unset full_rule + +# Load macro arguments into arrays +read -a syscall_a <<< $SYSCALL +read -a syscall_grouping <<< $SYSCALL_GROUPING + +# Create a list of audit *.rules files that should be inspected for presence and correctness +# of a particular audit rule. The scheme is as follows: +# +# ----------------------------------------------------------------------------------------- +# Tool used to load audit rules | Rule already defined | Audit rules file to inspect | +# ----------------------------------------------------------------------------------------- +# auditctl | Doesn't matter | /etc/audit/audit.rules | +# ----------------------------------------------------------------------------------------- +# augenrules | Yes | /etc/audit/rules.d/*.rules | +# augenrules | No | /etc/audit/rules.d/$key.rules | +# ----------------------------------------------------------------------------------------- +# +files_to_inspect=() + + +# If audit tool is 'auditctl', then add '/etc/audit/audit.rules' +# file to the list of files to be inspected +default_file="/etc/audit/audit.rules" +files_to_inspect+=('/etc/audit/audit.rules' ) + +# After converting to jinja, we cannot return; therefore we skip the rest of the macro if needed instead +skip=1 + +for audit_file in "${files_to_inspect[@]}" +do + # Filter existing $audit_file rules' definitions to select those that satisfy the rule pattern, + # i.e, collect rules that match: + # * the action, list and arch, (2-nd argument) + # * the other filters, (3-rd argument) + # * the auid filters, (4-rd argument) + readarray -t similar_rules < <(sed -e "/^$ACTION_ARCH_FILTERS/!d" -e "\#$OTHER_FILTERS#!d" -e "/$AUID_FILTERS/!d" "$audit_file") + + candidate_rules=() + # Filter out rules that have more fields then required. This will remove rules more specific than the required scope + for s_rule in "${similar_rules[@]}" + do + # Strip all the options and fields we know of, + # than check if there was any field left over + extra_fields=$(sed -E -e "s/^$ACTION_ARCH_FILTERS//" -e "s#$OTHER_FILTERS##" -e "s/$AUID_FILTERS//" -e "s/((:?-S [[:alnum:],]+)+)//g" -e "s/-F key=\w+|-k \w+//"<<< "$s_rule") + grep -q -- "-F" <<< "$extra_fields" || candidate_rules+=("$s_rule") + done + + if [[ ${#syscall_a[@]} -ge 1 ]] + then + # Check if the syscall we want is present in any of the similar existing rules + for rule in "${candidate_rules[@]}" + do + rule_syscalls=$(echo "$rule" | grep -o -P '(-S [\w,]+)+' | xargs) + all_syscalls_found=0 + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "$rule_syscalls" || { + # A syscall was not found in the candidate rule + all_syscalls_found=1 + } + done + if [[ $all_syscalls_found -eq 0 ]] + then + # We found a rule with all the syscall(s) we want; skip rest of macro + skip=0 + break + fi + + # Check if this rule can be grouped with our target syscall and keep track of it + for syscall_g in "${syscall_grouping[@]}" + do + if grep -q -- "\b${syscall_g}\b" <<< "$rule_syscalls" + then + file_to_edit=${audit_file} + rule_to_edit=${rule} + rule_syscalls_to_edit=${rule_syscalls} + fi + done + done + else + # If there is any candidate rule, it is compliant; skip rest of macro + if [ "${#candidate_rules[@]}" -gt 0 ] + then + skip=0 + fi + fi + + if [ "$skip" -eq 0 ]; then + break + fi +done + +if [ "$skip" -ne 0 ]; then + # We checked all rules that matched the expected resemblance pattern (action, arch & auid) + # At this point we know if we need to either append the $full_rule or group + # the syscall together with an exsiting rule + + # Append the full_rule if it cannot be grouped to any other rule + if [ -z ${rule_to_edit+x} ] + then + # Build full_rule while avoid adding double spaces when other_filters is empty + if [ "${#syscall_a[@]}" -gt 0 ] + then + syscall_string="" + for syscall in "${syscall_a[@]}" + do + syscall_string+=" -S $syscall" + done + fi + other_string=$([[ $OTHER_FILTERS ]] && echo " $OTHER_FILTERS") || /bin/true + auid_string=$([[ $AUID_FILTERS ]] && echo " $AUID_FILTERS") || /bin/true + full_rule="$ACTION_ARCH_FILTERS${syscall_string}${other_string}${auid_string} -F key=$KEY" || /bin/true + echo "$full_rule" >> "$default_file" + chmod 0600 ${default_file} + else + # Check if the syscalls are declared as a comma separated list or + # as multiple -S parameters + if grep -q -- "," <<< "${rule_syscalls_to_edit}" + then + delimiter="," + else + delimiter=" -S " + fi + new_grouped_syscalls="${rule_syscalls_to_edit}" + for syscall in "${syscall_a[@]}" + do + grep -q -- "\b${syscall}\b" <<< "${rule_syscalls_to_edit}" || { + # A syscall was not found in the candidate rule + new_grouped_syscalls+="${delimiter}${syscall}" + } + done + + # Group the syscall in the rule + sed -i -e "\#${rule_to_edit}#s#${rule_syscalls_to_edit}#${new_grouped_syscalls}#" "$file_to_edit" + fi +fi +done + else >&2 echo 'Remediation is not applicable, nothing was done' fi @@ -144193,7 +165969,7 @@ fi - restrict_strategy - name: Set architecture for audit setxattr tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -144221,7 +165997,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144233,7 +166009,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144242,43 +166018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144290,7 +166067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144300,7 +166077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144312,7 +166089,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144321,17 +166098,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -144343,7 +166121,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144351,6 +166129,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -144375,7 +166285,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144387,7 +166297,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144396,43 +166306,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144444,7 +166355,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144454,7 +166365,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - setxattr syscall_grouping: @@ -144466,7 +166377,7 @@ fi - setxattr - name: Check existence of setxattr in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144475,17 +166386,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -144497,7 +166409,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144505,6 +166417,138 @@ fi mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/rules.d/ + ansible.builtin.find: + paths: /etc/audit/rules.d + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: '*.rules' + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Reset syscalls found per file + ansible.builtin.set_fact: + syscalls_per_file: {} + found_paths_dict: {} + + - name: Declare syscalls found per file + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" + loop: '{{ find_command.results | selectattr(''matched'') | list }}' + + - name: Declare files where syscalls were found + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" + + - name: Count occurrences of syscalls in paths + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + 0) }) }}" + loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') + | list }}' + + - name: Get path with most syscalls + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + | last).key }}" + when: found_paths | length >= 1 + + - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + when: found_paths | length == 0 + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] + | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 + + - name: Declare list of syscalls + ansible.builtin.set_fact: + syscalls: + - setxattr + syscall_grouping: + - fremovexattr + - lremovexattr + - removexattr + - fsetxattr + - lsetxattr + - setxattr + + - name: Check existence of setxattr in /etc/audit/audit.rules + ansible.builtin.find: + paths: /etc/audit + contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S + |,)\w+)* -F auid=0 (-k\s+|-F\s+key=)\S+\s*$ + patterns: audit.rules + register: find_command + loop: '{{ (syscall_grouping + syscalls) | unique }}' + + - name: Set path to /etc/audit/audit.rules + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" + + - name: Declare found syscalls + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" + + - name: Declare missing syscalls + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" + + - name: Replace the audit rule in {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | + join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid=0 (?:-k |-F key=)\w+) + line: \1\2\3{{ missing_syscalls | join("\3") }}\4 + backrefs: true + state: present + mode: g-rwx,o-rwx + when: syscalls_found | length > 0 and missing_syscalls | length > 0 + + - name: Add the audit rule to {{ audit_file }} + ansible.builtin.lineinfile: + path: '{{ audit_file }}' + line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid=0 -F + key=perm_mod + create: true + mode: g-rwx,o-rwx + state: present + when: syscalls_found | length == 0 when: - '"audit" in ansible_facts.packages' - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -144550,18 +166594,14 @@ utility to read audit rules during daemon startup, add the following line to number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient. - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000840 - SV-271594r1092582_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000840 + SV-271594r1092582_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -144904,13 +166944,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount syscall_grouping: [] - name: Check existence of umount in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144919,43 +166959,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -144967,7 +167008,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -144977,13 +167018,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount syscall_grouping: [] - name: Check existence of umount in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -144992,17 +167033,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145014,7 +167056,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145063,19 +167105,15 @@ If the system is 64 bit then also add the following line: number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient. - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000062-GPOS-00031 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 + SRG-OS-000037-GPOS-00015 + SRG-OS-000062-GPOS-00031 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 R73 - OL09-00-000845 - SV-271595r1092584_rule + OL09-00-000845 + SV-271595r1092584_rule The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and @@ -145421,7 +167459,7 @@ fi - restrict_strategy - name: Set architecture for audit umount2 tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -145441,13 +167479,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145456,43 +167494,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -145504,7 +167543,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145514,13 +167553,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145529,17 +167568,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145551,7 +167591,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145575,13 +167615,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145590,43 +167630,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/perm_mod.rules - set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/perm_mod.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -145638,7 +167679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145648,13 +167689,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - umount2 syscall_grouping: [] - name: Check existence of umount2 in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -145663,17 +167704,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -145685,7 +167727,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=perm_mod @@ -145720,33 +167762,34 @@ fi ACL privileged commands for all users and root. Record Any Attempts to Run chacl - At a minimum, the audit system should collect any execution attempt -of the chacl command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - 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-000466-GPOS-00210 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - OL09-00-000665 - SV-271560r1092540_rule + 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-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000665 + SV-271560r1092540_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -145756,12 +167799,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chacl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -146085,16 +168131,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chacl +- name: Record Any Attempts to Run chacl - Perform remediation of Audit rules for + /usr/bin/chacl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146103,43 +168150,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chacl -F perm=x -F @@ -146151,7 +168199,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146161,12 +168209,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146175,17 +168223,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset @@ -146197,7 +168246,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146226,31 +168275,32 @@ fi Record Any Attempts to Run setfacl - At a minimum, the audit system should collect any execution attempt -of the setfacl command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - 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-APP-000495-CTR-001235 - OL09-00-000560 - SV-271539r1092498_rule + 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-APP-000495-CTR-001235 + OL09-00-000560 + SV-271539r1092498_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -146260,12 +168310,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/setfacl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -146589,16 +168642,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/setfacl +- name: Record Any Attempts to Run setfacl - Perform remediation of Audit rules for + /usr/bin/setfacl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146607,43 +168661,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/setfacl -F perm=x @@ -146655,7 +168710,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146665,12 +168720,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -146679,17 +168734,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset @@ -146701,7 +168757,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -146735,15 +168791,21 @@ fi SELinux privileged commands for all users and root. Record Any Attempts to Run chcon - At a minimum, the audit system should collect any execution attempt -of the chcon command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -146778,11 +168840,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -146821,23 +168878,24 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - 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-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 - OL09-00-000555 - SV-271538r1092496_rule + 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-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + 0582 + OL09-00-000555 + SV-271538r1092496_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -146852,12 +168910,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chcon -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -147186,16 +169247,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chcon +- name: Record Any Attempts to Run chcon - Perform remediation of Audit rules for + /usr/bin/chcon block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147204,43 +169266,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chcon -F perm=x -F @@ -147252,7 +169315,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147262,12 +169325,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147276,17 +169339,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset @@ -147298,7 +169362,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147332,15 +169396,21 @@ fi Record Any Attempts to Run restorecon - At a minimum, the audit system should collect any execution attempt -of the restorecon command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -147375,8 +169445,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -147415,9 +169483,10 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000392-GPOS-00172 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 + SRG-OS-000392-GPOS-00172 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + 0582 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -147432,12 +169501,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/restorecon -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -147765,16 +169837,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/restorecon +- name: Record Any Attempts to Run restorecon - Perform remediation of Audit rules + for /usr/sbin/restorecon block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147783,43 +169856,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/restorecon -F perm=x @@ -147831,7 +169905,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147841,12 +169915,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -147855,17 +169929,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset @@ -147877,7 +169952,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -147910,15 +169985,21 @@ fi Record Any Attempts to Run semanage - At a minimum, the audit system should collect any execution attempt -of the semanage command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -147953,11 +170034,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -147987,14 +170063,14 @@ utility to read audit rules during daemon startup, add the following lines to A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -148005,20 +170081,21 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - 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-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000650 - SV-271557r1092534_rule + 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-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000650 + SV-271557r1092534_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -148033,12 +170110,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/semanage -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -148368,16 +170448,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/semanage +- name: Record Any Attempts to Run semanage - Perform remediation of Audit rules for + /usr/sbin/semanage block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148386,43 +170467,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/semanage -F perm=x @@ -148434,7 +170516,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148444,12 +170526,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148458,17 +170540,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset @@ -148480,7 +170563,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148515,40 +170598,42 @@ fi Record Any Attempts to Run setfiles - At a minimum, the audit system should collect any execution attempt -of the setfiles command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-2(d) AU-12(c) AC-6(9) CM-6(a) - 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-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000655 - SV-271558r1092536_rule + 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-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000655 + SV-271558r1092536_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -148563,12 +170648,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/setfiles -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -148896,16 +170984,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/setfiles +- name: Record Any Attempts to Run setfiles - Perform remediation of Audit rules for + /usr/sbin/setfiles block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148914,43 +171003,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setfiles -F perm=x @@ -148962,7 +171052,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -148972,12 +171062,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -148986,17 +171076,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset @@ -149008,7 +171099,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149041,15 +171132,21 @@ fi Record Any Attempts to Run setsebool - At a minimum, the audit system should collect any execution attempt -of the setsebool command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -149084,11 +171181,6 @@ utility to read audit rules during daemon startup, add the following lines to MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -149127,20 +171219,21 @@ utility to read audit rules during daemon startup, add the following lines to DE.CM-7 ID.SC-4 PR.PT-1 - 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-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-APP-000495-CTR-001235 - SRG-APP-000496-CTR-001240 - SRG-APP-000497-CTR-001245 - SRG-APP-000498-CTR-001250 - OL09-00-000660 - SV-271559r1092538_rule + 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-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-APP-000495-CTR-001235 + SRG-APP-000496-CTR-001240 + SRG-APP-000497-CTR-001245 + SRG-APP-000498-CTR-001250 + 0582 + OL09-00-000660 + SV-271559r1092538_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -149155,12 +171248,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/setsebool -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -149489,16 +171585,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/setsebool +- name: Record Any Attempts to Run setsebool - Perform remediation of Audit rules + for /usr/sbin/setsebool block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -149507,43 +171604,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setsebool -F perm=x @@ -149555,7 +171653,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149565,12 +171663,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -149579,17 +171677,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset @@ -149601,7 +171700,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -149635,22 +171734,28 @@ fi Record Any Attempts to Run seunshare - At a minimum, the audit system should collect any execution attempt -of the seunshare command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-2(d) AU-12(c) AC-6(9) CM-6(a) + 0582 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -149665,12 +171770,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/seunshare -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -149997,16 +172105,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/seunshare +- name: Record Any Attempts to Run seunshare - Perform remediation of Audit rules + for /usr/sbin/seunshare block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -150015,43 +172124,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/seunshare -F perm=x @@ -150063,7 +172173,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -150073,12 +172183,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -150087,17 +172197,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset @@ -150109,7 +172220,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -150146,14 +172257,14 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete Ensure auditd Collects File Deletion Events by User @@ -150161,19 +172272,19 @@ appropriate for your system: for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat,renameat2 -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: --a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename -S renameat -F auid>=1000 -F auid!=unset -F key=delete +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -S rmdir,unlink,unlinkat,rename,renameat2 -S renameat -F auid>=1000 -F auid!=unset -F key=delete This rule checks for multiple syscalls related to file deletion; it was written with DISA STIG in mind. Other policies should use a separate rule for each syscall that needs to be checked. For example: -audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkat +audit_rules_file_deletion_events_rmdiraudit_rules_file_deletion_events_unlinkaudit_rules_file_deletion_events_unlinkataudit_rules_file_deletion_events_renameaudit_rules_file_deletion_events_renameataudit_rules_file_deletion_events_renameat2 1 11 @@ -150220,9 +172331,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000366 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -150301,9 +172409,9 @@ do ACTION_ARCH_FILTERS="-a always,exit -F arch=$ARCH" OTHER_FILTERS="" AUID_FILTERS="-F auid>=1000 -F auid!=unset" - SYSCALL="rmdir unlink unlinkat rename renameat" + SYSCALL="rmdir unlink unlinkat rename renameat renameat2" KEY="delete" - SYSCALL_GROUPING="rmdir unlink unlinkat rename renameat" + SYSCALL_GROUPING="rmdir unlink unlinkat rename renameat renameat2" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -150629,13 +172737,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rename -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -150682,11 +172790,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -150763,25 +172866,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + 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-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -150800,7 +172903,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="rename" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -151134,7 +173237,7 @@ fi - restrict_strategy - name: Set architecture for audit rename tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -151163,7 +173266,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151171,10 +173274,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151183,43 +173287,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -151231,7 +173336,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151241,7 +173346,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151249,10 +173354,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151261,17 +173367,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -151283,7 +173390,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151316,7 +173423,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151324,10 +173431,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151336,43 +173444,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -151384,7 +173493,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151394,7 +173503,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rename syscall_grouping: @@ -151402,10 +173511,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rename in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -151414,17 +173524,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -151436,7 +173547,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -151479,13 +173590,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S renameat -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -151532,11 +173643,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -151613,25 +173719,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + 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-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -151649,7 +173755,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="renameat" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -151983,7 +174089,7 @@ fi - restrict_strategy - name: Set architecture for audit renameat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -152011,7 +174117,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152019,10 +174125,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152031,43 +174138,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152079,7 +174187,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152089,7 +174197,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152097,10 +174205,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152109,17 +174218,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152131,7 +174241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152163,7 +174273,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152171,10 +174281,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152183,43 +174294,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152231,7 +174343,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152241,7 +174353,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - renameat syscall_grouping: @@ -152249,10 +174361,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of renameat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152261,17 +174374,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152283,7 +174397,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152325,13 +174439,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S rmdir -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -152378,11 +174492,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -152459,25 +174568,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + 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-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -152496,7 +174605,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="rmdir" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -152830,7 +174939,7 @@ fi - restrict_strategy - name: Set architecture for audit rmdir tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -152859,7 +174968,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -152867,10 +174976,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152879,43 +174989,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -152927,7 +175038,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -152937,7 +175048,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -152945,10 +175056,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -152957,17 +175069,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -152979,7 +175092,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153012,7 +175125,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -153020,10 +175133,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153032,43 +175146,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153080,7 +175195,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153090,7 +175205,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - rmdir syscall_grouping: @@ -153098,10 +175213,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of rmdir in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153110,17 +175226,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153132,7 +175249,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153175,13 +175292,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlink -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -153228,11 +175345,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -153309,25 +175421,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + 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-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -153346,7 +175458,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="unlink" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -153680,7 +175792,7 @@ fi - restrict_strategy - name: Set architecture for audit unlink tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -153709,7 +175821,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153717,10 +175829,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153729,43 +175842,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153777,7 +175891,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153787,7 +175901,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153795,10 +175909,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153807,17 +175922,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153829,7 +175945,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153862,7 +175978,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153870,10 +175986,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153882,43 +175999,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -153930,7 +176048,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -153940,7 +176058,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlink syscall_grouping: @@ -153948,10 +176066,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlink in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -153960,17 +176079,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -153982,7 +176102,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154025,13 +176145,13 @@ fi for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the -directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as -appropriate for your system: +directory /etc/audit/rules.d, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file, setting ARCH to either b32 or b64 as -appropriate for your system: +/etc/audit/audit.rules file, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S unlinkat -F auid>=1000 -F auid!=unset -F key=delete 1 @@ -154078,11 +176198,6 @@ appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -154159,25 +176274,25 @@ appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000466-GPOS-00210 - SRG-OS-000467-GPOS-00211 - SRG-OS-000468-GPOS-00212 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + 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-000466-GPOS-00210 + SRG-OS-000467-GPOS-00211 + SRG-OS-000468-GPOS-00212 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 R73 10.2.1.7 10.2.1 10.2 - OL09-00-000680 - SV-271563r1092546_rule + OL09-00-000680 + SV-271563r1092546_rule Auditing file deletions will create an audit trail for files that are removed from the system. The audit trail could aid in system troubleshooting, as well as, detecting malicious processes that attempt to delete log files to conceal their presence. @@ -154195,7 +176310,7 @@ do AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="unlinkat" KEY="delete" - SYSCALL_GROUPING="unlink unlinkat rename renameat rmdir" + SYSCALL_GROUPING="unlink unlinkat rename renameat renameat2 rmdir" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -154529,7 +176644,7 @@ fi - restrict_strategy - name: Set architecture for audit unlinkat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -154557,7 +176672,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154565,10 +176680,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154577,43 +176693,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -154625,7 +176742,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154635,7 +176752,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154643,10 +176760,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154655,17 +176773,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -154677,7 +176796,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154709,7 +176828,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154717,10 +176836,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154729,43 +176849,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/delete.rules - set_fact: audit_file="/etc/audit/rules.d/delete.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/delete.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -154777,7 +176898,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154787,7 +176908,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - unlinkat syscall_grouping: @@ -154795,10 +176916,11 @@ fi - unlinkat - rename - renameat + - renameat2 - rmdir - name: Check existence of unlinkat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -154807,17 +176929,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -154829,7 +176952,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=delete @@ -154956,8 +177079,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -154989,12 +177110,6 @@ separate rule for each syscall that needs to be checked. For example: SR 6.2 SR 7.1 SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.11.2.6 A.12.4.1 A.12.4.2 @@ -155754,11 +177869,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -155830,20 +177940,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. @@ -156506,7 +178618,7 @@ fi - restrict_strategy - name: Set architecture for audit creat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -156533,7 +178645,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156545,7 +178657,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156554,43 +178666,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156602,7 +178715,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156612,7 +178725,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156624,7 +178737,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156633,17 +178746,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156655,7 +178769,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156686,7 +178800,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156698,7 +178812,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156707,43 +178821,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156755,7 +178870,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156765,7 +178880,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156777,7 +178892,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156786,17 +178901,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -156808,7 +178924,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -156840,7 +178956,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156852,7 +178968,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156861,43 +178977,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -156909,7 +179026,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -156919,7 +179036,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -156931,7 +179048,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -156940,17 +179057,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -156962,7 +179080,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -156993,7 +179111,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -157005,7 +179123,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -157014,43 +179132,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -157062,7 +179181,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -157072,7 +179191,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - creat syscall_grouping: @@ -157084,7 +179203,7 @@ fi - open_by_handle_at - name: Check existence of creat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -157093,17 +179212,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -157115,7 +179235,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -157224,11 +179344,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -157300,20 +179415,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -157975,7 +180092,7 @@ fi - restrict_strategy - name: Set architecture for audit ftruncate tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -158001,7 +180118,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158013,7 +180130,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158022,43 +180139,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158070,7 +180188,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158080,7 +180198,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158092,7 +180210,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158101,17 +180219,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158123,7 +180242,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158153,7 +180272,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158165,7 +180284,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158174,43 +180293,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158222,7 +180342,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158232,7 +180352,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158244,7 +180364,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158253,17 +180373,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -158275,7 +180396,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -158306,7 +180427,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158318,7 +180439,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158327,43 +180448,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158375,7 +180497,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158385,7 +180507,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158397,7 +180519,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158406,17 +180528,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158428,7 +180551,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158458,7 +180581,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158470,7 +180593,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158479,43 +180602,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158527,7 +180651,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158537,7 +180661,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - ftruncate syscall_grouping: @@ -158549,7 +180673,7 @@ fi - open_by_handle_at - name: Check existence of ftruncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -158558,17 +180682,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -158580,7 +180705,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -158688,11 +180813,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -158764,20 +180884,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. @@ -159440,7 +181562,7 @@ fi - restrict_strategy - name: Set architecture for audit open tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -159467,7 +181589,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159479,7 +181601,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159488,43 +181610,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159536,7 +181659,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159546,7 +181669,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159558,7 +181681,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159567,17 +181690,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159589,7 +181713,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159620,7 +181744,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159632,7 +181756,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159641,43 +181765,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159689,7 +181814,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159699,7 +181824,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159711,7 +181836,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159720,17 +181845,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -159742,7 +181868,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -159774,7 +181900,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159786,7 +181912,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159795,43 +181921,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159843,7 +181970,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -159853,7 +181980,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159865,7 +181992,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159874,17 +182001,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159896,7 +182024,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -159927,7 +182055,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -159939,7 +182067,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -159948,43 +182076,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -159996,7 +182125,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -160006,7 +182135,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open syscall_grouping: @@ -160018,7 +182147,7 @@ fi - open_by_handle_at - name: Check existence of open in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -160027,17 +182156,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -160049,7 +182179,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -160155,11 +182285,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -160231,18 +182356,20 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 - OL09-00-000635 - SV-271554r1092528_rule + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -160904,7 +183031,7 @@ fi - restrict_strategy - name: Set architecture for audit open_by_handle_at tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -160931,7 +183058,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -160943,7 +183070,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -160952,43 +183079,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161000,7 +183128,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161010,7 +183138,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161022,7 +183150,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161031,17 +183159,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161053,7 +183182,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161084,7 +183213,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161096,7 +183225,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161105,43 +183234,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161153,7 +183283,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161163,7 +183293,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161175,7 +183305,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161184,17 +183314,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -161206,7 +183337,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -161237,7 +183368,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161249,7 +183380,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161258,43 +183389,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161306,7 +183438,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161316,7 +183448,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161328,7 +183460,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161337,17 +183469,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161359,7 +183492,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161389,7 +183522,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161401,7 +183534,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161410,43 +183543,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161458,7 +183592,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161468,7 +183602,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - open_by_handle_at syscall_grouping: @@ -161480,7 +183614,7 @@ fi - open_by_handle_at - name: Check existence of open_by_handle_at in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -161489,17 +183623,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -161511,7 +183646,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -161619,11 +183754,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -161695,20 +183825,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -162370,7 +184502,7 @@ fi - restrict_strategy - name: Set architecture for audit openat tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -162396,7 +184528,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162408,7 +184540,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162417,43 +184549,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162465,7 +184598,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162475,7 +184608,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162487,7 +184620,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162496,17 +184629,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162518,7 +184652,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162548,7 +184682,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162560,7 +184694,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162569,43 +184703,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162617,7 +184752,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162627,7 +184762,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162639,7 +184774,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162648,17 +184783,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -162670,7 +184806,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -162701,7 +184837,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162713,7 +184849,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162722,43 +184858,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162770,7 +184907,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162780,7 +184917,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162792,7 +184929,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162801,17 +184938,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162823,7 +184961,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162853,7 +184991,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162865,7 +185003,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162874,43 +185012,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162922,7 +185061,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -162932,7 +185071,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - openat syscall_grouping: @@ -162944,7 +185083,7 @@ fi - open_by_handle_at - name: Check existence of openat in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -162953,17 +185092,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -162975,7 +185115,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -163083,11 +185223,6 @@ calls with others as identifying earlier in this guide is more efficient.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -163159,20 +185294,22 @@ calls with others as identifying earlier in this guide is more efficient.RS.AN-4 Req-10.2.4 Req-10.2.1 - 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-000064-GPOS-00033 - SRG-OS-000458-GPOS-00203 - SRG-OS-000461-GPOS-00205 - SRG-APP-000495-CTR-001235 + 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-000064-GPOS-00033 + SRG-OS-000458-GPOS-00203 + SRG-OS-000461-GPOS-00205 + SRG-APP-000495-CTR-001235 R73 A.3.SEC-OL9 - OL09-00-000635 - SV-271554r1092528_rule + 0582 + 0846 + OL09-00-000635 + SV-271554r1092528_rule Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise. # Remediation is applicable only in certain platforms @@ -163834,7 +185971,7 @@ fi - restrict_strategy - name: Set architecture for audit truncate tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -163860,7 +185997,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -163872,7 +186009,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -163881,43 +186018,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -163929,7 +186067,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -163939,7 +186077,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -163951,7 +186089,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -163960,17 +186098,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -163982,7 +186121,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164012,7 +186151,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164024,7 +186163,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164033,43 +186172,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -164081,7 +186221,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164091,7 +186231,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164103,7 +186243,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EACCES -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164112,17 +186252,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EACCES -F auid>=1000 -F auid!=unset @@ -164134,7 +186275,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access @@ -164165,7 +186306,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164177,7 +186318,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164186,43 +186327,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164234,7 +186376,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164244,7 +186386,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164256,7 +186398,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164265,17 +186407,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164287,7 +186430,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164317,7 +186460,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164329,7 +186472,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164338,43 +186481,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/access.rules - set_fact: audit_file="/etc/audit/rules.d/access.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/access.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164386,7 +186530,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164396,7 +186540,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - truncate syscall_grouping: @@ -164408,7 +186552,7 @@ fi - open_by_handle_at - name: Check existence of truncate in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F exit=-EPERM -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -164417,17 +186561,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F exit=-EPERM -F auid>=1000 -F auid!=unset @@ -164439,7 +186584,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access @@ -164547,7 +186692,6 @@ add the lines to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -164612,6 +186756,7 @@ add the lines to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 + 0582 The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -164967,7 +187112,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -164993,7 +187138,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165004,7 +187149,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165013,43 +187158,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules - set_fact: audit_file="/etc/audit/rules.d/modules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165061,7 +187207,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165071,7 +187217,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165082,7 +187228,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165091,17 +187237,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165113,7 +187260,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165143,7 +187290,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165154,7 +187301,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165163,43 +187310,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules - set_fact: audit_file="/etc/audit/rules.d/modules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165211,7 +187359,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165221,7 +187369,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module - delete_module @@ -165232,7 +187380,7 @@ fi - finit_module - name: Check existence of init_module, delete_module, finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165241,17 +187389,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165263,7 +187412,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 -F auid!=unset -F key=modules @@ -165299,7 +187448,8 @@ fi Ensure auditd Collects Information on Kernel Module Unloading - delete_module - To capture kernel module unloading events, use following line, setting ARCH to + +To capture kernel module loading and unloading events, use the following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S delete_module -F auid>=1000 -F auid!=unset -F key=modules @@ -165355,11 +187505,6 @@ add the line to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -165431,19 +187576,19 @@ add the line to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + 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-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000685 - SV-271564r1092548_rule + OL09-00-000685 + SV-271564r1092548_rule The removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -165467,7 +187612,7 @@ do SYSCALL="delete_module" KEY="modules" - SYSCALL_GROUPING="delete_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -165798,8 +187943,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit delete_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Set architecture for audit ['delete_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -165821,17 +187967,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for delete_module for 32bit platform +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Perform remediation of Audit rules for ['delete_module'] for 32bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165840,43 +187992,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -165888,23 +188041,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165913,17 +188071,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -165935,10 +188094,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -165961,17 +188120,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for delete_module for 64bit platform +- name: Ensure auditd Collects Information on Kernel Module Unloading - delete_module + - Perform remediation of Audit rules for ['delete_module'] for 64bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -165980,43 +188145,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166028,23 +188194,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - delete_module - syscall_grouping: [] + syscall_grouping: + - create_module + - delete_module + - finit_module + - init_module + - query_module - name: Check existence of delete_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166053,17 +188224,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166075,10 +188247,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166111,19 +188283,19 @@ fi Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - If the auditd daemon is configured to use the augenrules program -to read audit rules during daemon startup (the default), add the following lines to a file -with suffix .rules in the directory /etc/audit/rules.d to capture kernel module -loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system: + +To capture kernel module loading and unloading events, use the following line, setting ARCH to +either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules - If the auditd daemon is configured to use the auditctl utility to read audit -rules during daemon startup, add the following lines to /etc/audit/audit.rules file -in order to capture kernel module loading and unloading events, setting ARCH to either b32 or -b64 as appropriate for your system: --a always,exit -F arch=ARCH -S finit_module -F auid>=1000 -F auid!=unset -F key=modules - + +Place to add the line depends on a way auditd daemon is configured. If it is configured +to use the augenrules program (the default), add the line to a file with suffix +.rules in the directory /etc/audit/rules.d. + +If the auditd daemon is configured to use the auditctl utility, +add the line to file /etc/audit/audit.rules. 1 11 12 @@ -166168,11 +188340,6 @@ b64 as appropriate for your system: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -166244,19 +188411,19 @@ b64 as appropriate for your system: RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + 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-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000690 - SV-271565r1092550_rule + OL09-00-000690 + SV-271565r1092550_rule The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -166280,7 +188447,7 @@ do SYSCALL="finit_module" KEY="modules" - SYSCALL_GROUPING="init_module finit_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -166611,8 +188778,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit finit_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Set architecture for audit ['finit_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -166634,19 +188802,24 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for finit_module for x86 platform +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Perform remediation of Audit rules for ['finit_module'] for 32bit + platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166655,43 +188828,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166703,25 +188877,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166730,17 +188907,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166752,10 +188930,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166778,19 +188956,24 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for finit_module for x86_64 platform +- name: Ensure auditd Collects Information on Kernel Module Loading and Unloading + - finit_module - Perform remediation of Audit rules for ['finit_module'] for 64bit + platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166799,43 +188982,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -166847,25 +189031,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - finit_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of finit_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -166874,17 +189061,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -166896,10 +189084,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -166932,7 +189120,8 @@ fi Ensure auditd Collects Information on Kernel Module Loading - init_module - To capture kernel module loading events, use following line, setting ARCH to + +To capture kernel module loading and unloading events, use the following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit: -a always,exit -F arch=ARCH -S init_module -F auid>=1000 -F auid!=unset -F key=modules @@ -166988,11 +189177,6 @@ add the line to file /etc/audit/audit.rules.MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -167064,19 +189248,19 @@ add the line to file /etc/audit/audit.rules.RS.AN-1 RS.AN-4 Req-10.2.7 - 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-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + 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-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000690 - SV-271565r1092550_rule + OL09-00-000690 + SV-271565r1092550_rule The addition of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel. @@ -167100,7 +189284,7 @@ do SYSCALL="init_module" KEY="modules" - SYSCALL_GROUPING="init_module finit_module" + SYSCALL_GROUPING="create_module delete_module finit_module init_module query_module" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -167431,8 +189615,9 @@ fi - medium_severity - no_reboot_needed -- name: Set architecture for audit init_module tasks - set_fact: +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Set architecture for audit ['init_module'] tasks + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -167454,19 +189639,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for init_module for 32bit platform +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Perform remediation of Audit rules for ['init_module'] for 32bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167475,43 +189664,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -167523,25 +189713,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167550,17 +189743,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -167572,10 +189766,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -167598,19 +189792,23 @@ fi - medium_severity - no_reboot_needed -- name: Perform remediation of Audit rules for init_module for 64bit platform +- name: Ensure auditd Collects Information on Kernel Module Loading - init_module + - Perform remediation of Audit rules for ['init_module'] for 64bit platform block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167619,43 +189817,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - - name: No file with syscall found, set path to /etc/audit/rules.d/module-change.rules - set_fact: audit_file="/etc/audit/rules.d/module-change.rules" + - name: No file with syscall found, set path to /etc/audit/rules.d/modules.rules + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/modules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k @@ -167667,25 +189866,28 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - init_module syscall_grouping: - - init_module + - create_module + - delete_module - finit_module + - init_module + - query_module - name: Check existence of init_module in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -167694,17 +189896,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F auid>=1000 -F auid!=unset (?:-k |-F @@ -167716,10 +189919,10 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F auid>=1000 - -F auid!=unset -F key=module-change + -F auid!=unset -F key=modules create: true mode: g-rwx,o-rwx state: present @@ -167759,13 +189962,17 @@ and root. If the auditd daemon is configured to use the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d in order to watch for attempted manual edits of files involved in storing logon events: + -w /var/log/tallylog -p wa -k logins -w -p wa -k logins -w /var/log/lastlog -p wa -k logins + + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to watch for unattempted manual edits of files involved in storing logon events: + -w /var/log/tallylog -p wa -k logins -w -p wa -k logins -w /var/log/lastlog -p wa -k logins @@ -167839,8 +190046,6 @@ separate rule for each syscall that needs to be checked. For example: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -167938,7 +190143,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -167946,7 +190153,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -167962,12 +190171,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -167986,8 +190199,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/tallylog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168015,7 +190230,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168023,7 +190240,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168039,12 +190258,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168071,7 +190294,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168079,7 +190304,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168095,12 +190322,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168119,8 +190350,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168148,7 +190381,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168156,7 +190391,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168172,12 +190409,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168204,7 +190445,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168212,7 +190455,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168228,12 +190473,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168252,8 +190501,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/lastlog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168281,7 +190532,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168289,7 +190542,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168305,12 +190560,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168326,16 +190585,22 @@ fi Record Attempts to Alter Logon and Logout Events - faillock The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w -p wa -k logins 1 @@ -168382,8 +190647,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -168455,18 +190718,19 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - SRG-APP-000503-CTR-001275 - SRG-APP-000506-CTR-001290 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 R73 A.3.SEC-OL1 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000720 - SV-271571r1092560_rule + OL09-00-000720 + SV-271571r1092560_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -168477,6 +190741,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne var_accounts_passwords_pam_faillock_dir='' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -168500,7 +190768,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168508,7 +190778,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168524,12 +190796,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -168548,8 +190824,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -168577,7 +190855,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+${var_accounts_passwords_pam_faillock_dir}" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -168585,7 +190865,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir} $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -168601,12 +190883,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+${var_accounts_passwords_pam_faillock_dir}$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w ${var_accounts_passwords_pam_faillock_dir} -p wa -k logins" >> "$audit_rules_file" + fi done @@ -168614,7 +190900,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -168632,7 +190918,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy - name: XCCDF Value var_accounts_passwords_pam_faillock_dir # promote to variable set_fact: @@ -168640,9 +190926,9 @@ fi tags: - always -- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already - exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Check if watch + rule for {{ var_accounts_passwords_pam_faillock_dir }} already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -168665,11 +190951,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -168694,11 +190981,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -168721,11 +191009,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -168748,11 +191037,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Add watch rule + for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins create: true @@ -168777,12 +191067,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for {{ var_accounts_passwords_pam_faillock_dir }} already - exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Check if watch + rule for {{ var_accounts_passwords_pam_faillock_dir }} already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+{{ var_accounts_passwords_pam_faillock_dir }}\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -168805,11 +191095,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - faillock - Add watch rule + for {{ var_accounts_passwords_pam_faillock_dir }} in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w {{ var_accounts_passwords_pam_faillock_dir }} -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -168835,7 +191126,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -168849,16 +191140,22 @@ fi Record Attempts to Alter Logon and Logout Events - lastlog The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /var/log/lastlog -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w /var/log/lastlog -p wa -k logins 1 @@ -168905,11 +191202,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -168981,24 +191273,25 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.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-000470-GPOS-00214 - SRG-APP-000495-CTR-001235 - SRG-APP-000503-CTR-001275 - SRG-APP-000506-CTR-001290 + 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-000470-GPOS-00214 + SRG-APP-000495-CTR-001235 + SRG-APP-000503-CTR-001275 + SRG-APP-000506-CTR-001290 R73 A.3.SEC-OL1 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000700 - SV-271567r1092554_rule + OL09-00-000700 + SV-271567r1092554_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -169007,6 +191300,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -169030,7 +191327,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169038,7 +191337,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169054,12 +191355,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -169078,8 +191383,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/lastlog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -169107,7 +191414,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/lastlog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169115,7 +191424,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/lastlog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169131,12 +191442,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/lastlog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/lastlog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -169144,7 +191459,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -169162,11 +191477,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/lastlog already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Check if watch + rule for /var/log/lastlog already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/lastlog\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -169189,11 +191505,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -169218,11 +191535,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -169245,11 +191563,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Use matched file + as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -169272,11 +191591,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/lastlog in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Add watch rule + for /var/log/lastlog in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/lastlog -p wa -k logins create: true @@ -169301,11 +191621,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/lastlog already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Check if watch + rule for /var/log/lastlog already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/lastlog\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -169328,11 +191649,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/lastlog in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - lastlog - Add watch rule + for /var/log/lastlog in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/lastlog -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -169358,7 +191680,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -169371,16 +191693,22 @@ fi Record Attempts to Alter Logon and Logout Events - tallylog The audit system already collects login information for all users -and root. If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), add the following lines to a file with suffix .rules in the -directory /etc/audit/rules.d in order to watch for attempted manual -edits of files involved in storing logon events: +and root. + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /var/log/tallylog -p wa -k logins + If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file in order to watch for unattempted manual -edits of files involved in storing logon events: +/etc/audit/audit.rules: + -w /var/log/tallylog -p wa -k logins 1 @@ -169427,8 +191755,6 @@ edits of files involved in storing logon events: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -169500,15 +191826,16 @@ edits of files involved in storing logon events: RS.AN-1 RS.AN-4 Req-10.2.3 - SRG-OS-000392-GPOS-00172 - SRG-OS-000470-GPOS-00214 - SRG-OS-000473-GPOS-00218 - SRG-APP-000503-CTR-001275 + SRG-OS-000392-GPOS-00172 + SRG-OS-000470-GPOS-00214 + SRG-OS-000473-GPOS-00218 + SRG-APP-000503-CTR-001275 + 0582 10.2.1.3 10.2.1 10.2 - OL09-00-000725 - SV-271572r1092562_rule + OL09-00-000725 + SV-271572r1092562_rule Manual editing of these files may indicate nefarious activity, such as an attacker attempting to remove evidence of an intrusion. # Remediation is applicable only in certain platforms @@ -169517,6 +191844,10 @@ if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kerne # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -169540,7 +191871,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169548,7 +191881,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169564,12 +191899,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -169588,8 +191927,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/logins.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/var/log/tallylog" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -169617,7 +191958,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/var/log/tallylog" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -169625,7 +191968,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/var/log/tallylog $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -169641,12 +191986,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/var/log/tallylog$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /var/log/tallylog -p wa -k logins" >> "$audit_rules_file" + fi done @@ -169654,7 +192003,7 @@ else >&2 echo 'Remediation is not applicable, nothing was done' fi - - name: Gather the package facts + - name: Gather the package facts package_facts: manager: auto tags: @@ -169672,11 +192021,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/tallylog already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Check if watch + rule for /var/log/tallylog already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/var/log/tallylog\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -169699,11 +192049,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key logins - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Search /etc/audit/rules.d + for other rules with specified key logins + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)logins$ patterns: '*.rules' @@ -169728,11 +192079,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/logins.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Use /etc/audit/rules.d/logins.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/logins.rules when: @@ -169755,11 +192107,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Use matched + file as the recipient for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -169782,11 +192135,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/tallylog in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Add watch rule + for /var/log/tallylog in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /var/log/tallylog -p wa -k logins create: true @@ -169811,11 +192165,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /var/log/tallylog already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Check if watch + rule for /var/log/tallylog already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/var/log/tallylog\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -169838,11 +192193,12 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy -- name: Add watch rule for /var/log/tallylog in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter Logon and Logout Events - tallylog - Add watch rule + for /var/log/tallylog in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /var/log/tallylog -p wa -k logins state: present dest: /etc/audit/audit.rules @@ -169868,7 +192224,7 @@ fi - low_complexity - low_disruption - medium_severity - - reboot_required + - no_reboot_needed - restrict_strategy @@ -169885,32 +192241,40 @@ fi privileged commands for all users and root. Ensure auditd Collects Information on the Use of Privileged Commands - init - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/init -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000730 - SV-271573r1092564_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000730 + SV-271573r1092564_rule Misuse of the init command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/init -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -170235,16 +192599,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/init +- name: Ensure auditd Collects Information on the Use of Privileged Commands - init + - Perform remediation of Audit rules for /usr/sbin/init block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170253,43 +192618,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/init -F perm=x -F @@ -170301,7 +192667,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170311,12 +192677,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170325,17 +192691,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset @@ -170347,7 +192714,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/init -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170377,32 +192744,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/poweroff -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000735 - SV-271574r1092566_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000735 + SV-271574r1092566_rule Misuse of the poweroff command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/poweroff -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -170727,16 +193102,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/poweroff +- name: Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + - Perform remediation of Audit rules for /usr/sbin/poweroff block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170745,43 +193121,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/poweroff -F perm=x @@ -170793,7 +193170,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170803,12 +193180,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -170817,17 +193194,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset @@ -170839,7 +193217,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/poweroff -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -170869,32 +193247,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - reboot - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/reboot -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000740 - SV-271575r1092568_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000740 + SV-271575r1092568_rule Misuse of the reboot command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/reboot -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -171219,16 +193605,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/reboot +- name: Ensure auditd Collects Information on the Use of Privileged Commands - reboot + - Perform remediation of Audit rules for /usr/sbin/reboot block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171237,43 +193624,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/reboot -F perm=x @@ -171285,7 +193673,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171295,12 +193683,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171309,17 +193697,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset @@ -171331,7 +193720,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/reboot -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171361,32 +193750,40 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/shutdown -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-12(c) - SRG-OS-000477-GPOS-00222 - OL09-00-000745 - SV-271576r1092570_rule + SRG-OS-000477-GPOS-00222 + OL09-00-000745 + SV-271576r1092570_rule Misuse of the shutdown command may cause availability issues for the system. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/shutdown -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -171711,16 +194108,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/shutdown +- name: Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + - Perform remediation of Audit rules for /usr/sbin/shutdown block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171729,43 +194127,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/shutdown -F perm=x @@ -171777,7 +194176,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171787,12 +194186,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -171801,17 +194200,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset @@ -171823,7 +194223,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/shutdown -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -171864,8 +194264,9 @@ setuid / setgid programs using the following command: $ sudo find PARTITION -xdev -perm /6000 -type f 2>/dev/null For each setuid / setgid program identified by the previous command, an audit rule must be -present in the appropriate place using the following line structure: --a always,exit -F path=PROG_PATH -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged +present in the appropriate place using the following line structure, setting ARCH to either b32 for 32-bit +system, or having two lines for both b32 and b64 in case your system is 64-bit: +-a always,exit -F arch=ARCH -F path=PROG_PATH -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup, add the line to a file with suffix .rules in the @@ -171931,7 +194332,6 @@ file system during check or remediation caused undesirable errors.MEA01.05 MEA02.01 3.1.7 - CCI-002234 4.2.3.10 4.3.2.6.7 4.3.3.3.9 @@ -171966,12 +194366,6 @@ file system during check or remediation caused undesirable errors.SR 6.2 SR 7.1 SR 7.6 - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 A.11.2.6 A.12.4.1 A.12.4.2 @@ -171993,14 +194387,14 @@ file system during check or remediation caused undesirable errors.A.6.1.3 A.6.2.1 A.6.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -172021,8 +194415,10 @@ file system during check or remediation caused undesirable errors.RS.AN-4 RS.CO-2 Req-10.2.2 - SRG-OS-000327-GPOS-00127 + SRG-OS-000327-GPOS-00127 R73 + 0582 + 0846 Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern that can have significant adverse impacts on organizations. @@ -172354,7 +194750,7 @@ function add_audit_rule() fi } -if [[ "$OSCAP_BOOTC_BUILD" == "YES" ]] ; then +if { rpm --quiet -q kernel rpm-ostree bootc && ! rpm --quiet -q openshift-kubelet && { [ -f "/run/.containerenv" ] || [ -f "/.containerenv" ]; }; } ; then PRIV_CMDS=$(find / -perm /6000 -type f -not -path "/sysroot/*" 2>/dev/null) for PRIV_CMD in $PRIV_CMDS; do add_audit_rule $PRIV_CMD @@ -172548,18 +194944,23 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - at - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 AU-2(d) AU-12(c) AC-6(9) @@ -172578,12 +194979,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/at -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -172910,16 +195314,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/at +- name: Ensure auditd Collects Information on the Use of Privileged Commands - at + - Perform remediation of Audit rules for /usr/bin/at block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -172928,43 +195333,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/at -F perm=x -F auid>=1000 @@ -172976,7 +195382,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -172986,12 +195392,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173000,17 +195406,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset (?:-k @@ -173022,7 +195429,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173054,15 +195461,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - chage - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -173097,11 +195510,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -173131,14 +195539,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -173149,19 +195557,19 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-000468-GPOS-00212 - SRG-OS-000471-GPOS-00215 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 - OL09-00-000550 - SV-271537r1092494_rule + 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-000468-GPOS-00212 + SRG-OS-000471-GPOS-00215 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 + OL09-00-000550 + SV-271537r1092494_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -173176,12 +195584,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chage -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -173511,16 +195922,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chage +- name: Ensure auditd Collects Information on the Use of Privileged Commands - chage + - Perform remediation of Audit rules for /usr/bin/chage block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173529,43 +195941,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chage -F perm=x -F @@ -173577,7 +195990,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173587,12 +196000,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -173601,17 +196014,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset @@ -173623,7 +196037,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -173658,15 +196072,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - chsh - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -173701,11 +196121,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -173735,14 +196150,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -173753,15 +196168,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - OL09-00-000565 - SV-271540r1092500_rule + 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-APP-000495-CTR-001235 + OL09-00-000565 + SV-271540r1092500_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -173776,12 +196191,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/chsh -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -174111,16 +196529,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/chsh +- name: Ensure auditd Collects Information on the Use of Privileged Commands - chsh + - Perform remediation of Audit rules for /usr/bin/chsh block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174129,43 +196548,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chsh -F perm=x -F @@ -174177,7 +196597,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174187,12 +196607,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174201,17 +196621,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset @@ -174223,7 +196644,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174258,15 +196679,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - crontab - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -174301,11 +196728,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -174344,15 +196766,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - OL09-00-000570 - SV-271541r1092502_rule + 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-APP-000495-CTR-001235 + OL09-00-000570 + SV-271541r1092502_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -174367,12 +196789,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/crontab -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -174701,16 +197126,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/crontab +- name: Ensure auditd Collects Information on the Use of Privileged Commands - crontab + - Perform remediation of Audit rules for /usr/bin/crontab block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174719,43 +197145,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/crontab -F perm=x @@ -174767,7 +197194,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174777,12 +197204,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -174791,17 +197218,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset @@ -174813,7 +197241,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -174847,15 +197275,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -174890,11 +197324,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -174924,14 +197353,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -174942,16 +197371,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000575 - SV-271542r1092504_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000575 + SV-271542r1092504_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -174966,12 +197395,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/gpasswd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -175301,16 +197733,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/gpasswd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + - Perform remediation of Audit rules for /usr/bin/gpasswd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175319,43 +197752,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/gpasswd -F perm=x @@ -175367,7 +197801,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175377,12 +197811,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175391,17 +197825,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset @@ -175413,7 +197848,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175448,41 +197883,42 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - kmod - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-3 AU-3.1 AU-12(a) AU-12.1(ii) AU-12.1(iv)AU-12(c) MA-4(1)(a) - 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-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-APP-000495-CTR-001235 - SRG-APP-000504-CTR-001280 + 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-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-APP-000495-CTR-001235 + SRG-APP-000504-CTR-001280 R73 - OL09-00-000695 - SV-271566r1092552_rule + OL09-00-000695 + SV-271566r1092552_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -175493,12 +197929,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/kmod -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -175828,16 +198267,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/kmod +- name: Ensure auditd Collects Information on the Use of Privileged Commands - kmod + - Perform remediation of Audit rules for /usr/bin/kmod block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175846,43 +198286,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F @@ -175894,7 +198335,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175904,12 +198345,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -175918,17 +198359,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset @@ -175940,7 +198382,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -175975,35 +198417,36 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - mount - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 AU-2(d) AU-12(c) AC-6(9) CM-6(a) - 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-APP-000029-CTR-000085 - OL09-00-000630 - SV-271553r1092526_rule + 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-APP-000029-CTR-000085 + OL09-00-000630 + SV-271553r1092526_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -176018,12 +198461,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/mount -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -176351,16 +198797,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/mount +- name: Ensure auditd Collects Information on the Use of Privileged Commands - mount + - Perform remediation of Audit rules for /usr/bin/mount block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176369,43 +198816,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/mount -F perm=x -F @@ -176417,7 +198865,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -176427,12 +198875,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176441,17 +198889,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset @@ -176463,7 +198912,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -176496,15 +198945,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -176539,11 +198994,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -176573,14 +199023,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -176591,16 +199041,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000580 - SV-271543r1092506_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000580 + SV-271543r1092506_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -176615,12 +199065,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/newgrp -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -176950,16 +199403,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/newgrp +- name: Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + - Perform remediation of Audit rules for /usr/bin/newgrp block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -176968,43 +199422,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/newgrp -F perm=x -F @@ -177016,7 +199471,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177026,12 +199481,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -177040,17 +199495,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset @@ -177062,7 +199518,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177097,18 +199553,22 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/sbin/pam_timestamp_check --F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: --a always,exit -F path=/usr/sbin/pam_timestamp_check --F perm=x -F auid>=1000 -F auid!=unset -F key=privileged +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 12 @@ -177142,11 +199602,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -177185,16 +199640,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000585 - SV-271544r1092508_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000585 + SV-271544r1092508_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -177209,12 +199664,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/pam_timestamp_check -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -177543,16 +200001,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/pam_timestamp_check +- name: Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + - Perform remediation of Audit rules for /usr/sbin/pam_timestamp_check block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset @@ -177562,43 +200021,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/pam_timestamp_check @@ -177610,7 +200070,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177620,12 +200080,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset @@ -177635,17 +200095,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 @@ -177657,7 +200118,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -177691,15 +200152,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - passwd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -177734,11 +200201,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -177768,14 +200230,14 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -177786,16 +200248,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000590 - SV-271545r1092510_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000590 + SV-271545r1092510_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -177810,12 +200272,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/passwd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -178145,16 +200610,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/passwd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - passwd + - Perform remediation of Audit rules for /usr/bin/passwd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178163,43 +200629,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/passwd -F perm=x -F @@ -178211,7 +200678,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178221,12 +200688,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178235,17 +200702,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset @@ -178257,7 +200725,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178292,15 +200760,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -178335,11 +200809,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -178378,15 +200847,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - OL09-00-000595 - SV-271546r1092512_rule + 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-APP-000495-CTR-001235 + OL09-00-000595 + SV-271546r1092512_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -178401,12 +200870,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/postdrop -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -178735,16 +201207,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/postdrop +- name: Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + - Perform remediation of Audit rules for /usr/sbin/postdrop block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178753,43 +201226,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postdrop -F perm=x @@ -178801,7 +201275,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178811,12 +201285,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -178825,17 +201299,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset @@ -178847,7 +201322,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -178881,15 +201356,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -178924,11 +201405,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -178967,15 +201443,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - OL09-00-000600 - SV-271547r1092514_rule + 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-APP-000495-CTR-001235 + OL09-00-000600 + SV-271547r1092514_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -178990,12 +201466,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/postqueue -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -179324,16 +201803,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/postqueue +- name: Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + - Perform remediation of Audit rules for /usr/sbin/postqueue block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179342,43 +201822,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postqueue -F perm=x @@ -179390,7 +201871,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179400,12 +201881,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179414,17 +201895,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset @@ -179436,7 +201918,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179470,31 +201952,32 @@ fi Record Any Attempts to Run ssh-agent - At a minimum, the audit system should collect any execution attempt -of the ssh-agent command for all users and root. If the auditd -daemon is configured to use the augenrules program to read audit rules -during daemon startup (the default), add the following lines to a file with suffix -.rules in the directory /etc/audit/rules.d: --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following lines to -/etc/audit/audit.rules file: --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - 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-APP-000495-CTR-001235 - OL09-00-000605 - SV-271548r1092516_rule + 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-APP-000495-CTR-001235 + OL09-00-000605 + SV-271548r1092516_rule Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify @@ -179505,12 +201988,15 @@ information system (e.g., module or policy filter). # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/ssh-agent -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -179834,16 +202320,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/ssh-agent +- name: Record Any Attempts to Run ssh-agent - Perform remediation of Audit rules + for /usr/bin/ssh-agent block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179852,43 +202339,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/ssh-agent -F perm=x @@ -179900,7 +202388,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179910,12 +202398,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -179924,17 +202412,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset @@ -179946,7 +202435,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -179975,15 +202464,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -180018,11 +202513,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -180061,16 +202551,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000610 - SV-271549r1092518_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000610 + SV-271549r1092518_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -180085,12 +202575,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/libexec/openssh/ssh-keysign -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -180419,16 +202912,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/libexec/openssh/ssh-keysign +- name: Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + - Perform remediation of Audit rules for /usr/libexec/openssh/ssh-keysign block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset @@ -180438,43 +202932,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/libexec/openssh/ssh-keysign @@ -180486,7 +202981,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -180496,12 +202991,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset @@ -180511,17 +203006,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 @@ -180533,7 +203029,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -180567,15 +203063,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - su - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -180610,11 +203112,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -180653,20 +203150,20 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-0003 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-OS-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-OS-000755-GPOS-00220 - OL09-00-000540 - SV-271535r1092490_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-00033 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-OS-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 + OL09-00-000540 + SV-271535r1092490_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -180681,12 +203178,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/su -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -181015,16 +203515,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/su +- name: Ensure auditd Collects Information on the Use of Privileged Commands - su + - Perform remediation of Audit rules for /usr/bin/su block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181033,43 +203534,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/su -F perm=x -F auid>=1000 @@ -181081,7 +203583,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181091,12 +203593,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181105,17 +203607,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset (?:-k @@ -181127,7 +203630,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181161,15 +203664,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - sudo - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -181204,11 +203713,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -181247,20 +203751,20 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-000466-GPOS-00210 - SRG-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - SRG-OS-000755-GPOS-00220 + 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-000466-GPOS-00210 + SRG-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + SRG-OS-000755-GPOS-00220 R33 - OL09-00-000670 - SV-271561r1092542_rule + OL09-00-000670 + SV-271561r1092542_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -181275,12 +203779,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/sudo -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -181609,16 +204116,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/sudo +- name: Ensure auditd Collects Information on the Use of Privileged Commands - sudo + - Perform remediation of Audit rules for /usr/bin/sudo block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181627,43 +204135,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F @@ -181675,7 +204184,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181685,12 +204194,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -181699,17 +204208,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset @@ -181721,7 +204231,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -181755,15 +204265,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -181798,11 +204314,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -181841,16 +204352,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - SRG-OS-000755-GPOS-00220 - OL09-00-000615 - SV-271550r1092520_rule + 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-APP-000495-CTR-001235 + SRG-OS-000755-GPOS-00220 + OL09-00-000615 + SV-271550r1092520_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -181865,12 +204376,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/sudoedit -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -182199,16 +204713,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/sudoedit +- name: Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + - Perform remediation of Audit rules for /usr/bin/sudoedit block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182217,43 +204732,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudoedit -F perm=x @@ -182265,7 +204781,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182275,12 +204791,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182289,17 +204805,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset @@ -182311,7 +204828,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182345,15 +204862,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - umount - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -182388,10 +204911,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -182430,15 +204949,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - OL09-00-000705 - SV-271568r1092556_rule + 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-APP-000029-CTR-000085 + OL09-00-000705 + SV-271568r1092556_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -182453,12 +204972,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/bin/umount -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -182787,16 +205309,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/bin/umount +- name: Ensure auditd Collects Information on the Use of Privileged Commands - umount + - Perform remediation of Audit rules for /usr/bin/umount block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182805,43 +205328,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/umount -F perm=x -F @@ -182853,7 +205377,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182863,12 +205387,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -182877,17 +205401,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset @@ -182899,7 +205424,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -182933,15 +205458,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -182976,11 +205507,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -183010,15 +205536,15 @@ form to /etc/audit/audit.rules: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 - CIP-007-3 R6.5 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 + CIP-007-3 R6.5 AC-2(4) AU-2(d) AU-3 @@ -183035,16 +205561,16 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000029-CTR-000085 - SRG-APP-000495-CTR-001235 - OL09-00-000620 - SV-271551r1092522_rule + 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-APP-000029-CTR-000085 + SRG-APP-000495-CTR-001235 + OL09-00-000620 + SV-271551r1092522_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -183059,12 +205585,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/unix_chkpwd -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -183400,16 +205929,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/unix_chkpwd +- name: Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + - Perform remediation of Audit rules for /usr/sbin/unix_chkpwd block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183418,43 +205948,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_chkpwd -F perm=x @@ -183466,7 +205997,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183476,12 +206007,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183490,17 +206021,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset @@ -183512,7 +206044,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183553,32 +206085,33 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - SRG-OS-000037-GPOS-00015 - SRG-OS-000042-GPOS-00020 - SRG-OS-000062-GPOS-00031 - SRG-OS-000064-GPOS-00033 - SRG-OS-000392-GPOS-00172 - SRG-OS-000462-GPOS-00206 - SRG-OS-000471-GPOS-00215 - SRG-APP-000495-CTR-001235 - OL09-00-000535 - SV-271534r1092488_rule + SRG-OS-000037-GPOS-00015 + SRG-OS-000042-GPOS-00020 + SRG-OS-000062-GPOS-00031 + SRG-OS-000064-GPOS-00033 + SRG-OS-000392-GPOS-00172 + SRG-OS-000462-GPOS-00206 + SRG-OS-000471-GPOS-00215 + SRG-APP-000495-CTR-001235 + OL09-00-000535 + SV-271534r1092488_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -183593,12 +206126,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/unix_update -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -183922,16 +206458,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/unix_update +- name: Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + - Perform remediation of Audit rules for /usr/sbin/unix_update block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -183940,43 +206477,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_update -F perm=x @@ -183988,7 +206526,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -183998,12 +206536,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184012,17 +206550,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset @@ -184034,7 +206573,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184063,15 +206602,21 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged 1 @@ -184106,11 +206651,6 @@ form to /etc/audit/audit.rules: MEA01.05 MEA02.01 3.1.7 - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -184149,15 +206689,15 @@ form to /etc/audit/audit.rules: DE.CM-7 ID.SC-4 PR.PT-1 - 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-APP-000495-CTR-001235 - OL09-00-000625 - SV-271552r1092524_rule + 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-APP-000495-CTR-001235 + OL09-00-000625 + SV-271552r1092524_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -184172,12 +206712,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/userhelper -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -184506,16 +207049,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/userhelper +- name: Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + - Perform remediation of Audit rules for /usr/sbin/userhelper block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184524,43 +207068,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/userhelper -F perm=x @@ -184572,7 +207117,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184582,12 +207127,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -184596,17 +207141,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset @@ -184618,7 +207164,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -184652,33 +207198,34 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - usermod - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CCI-000130 - CCI-000135 - CCI-000169 - CCI-002884 - 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-000466-GPOS-00210 - SRG-APP-000495-CTR-001235 - SRG-APP-000499-CTR-001255 - OL09-00-000675 - SV-271562r1092544_rule + 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-000466-GPOS-00210 + SRG-APP-000495-CTR-001235 + SRG-APP-000499-CTR-001255 + OL09-00-000675 + SV-271562r1092544_rule Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. @@ -184693,12 +207240,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/usermod -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -185022,16 +207572,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/usermod +- name: Ensure auditd Collects Information on the Use of Privileged Commands - usermod + - Perform remediation of Audit rules for /usr/sbin/usermod block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185040,43 +207591,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usermod -F perm=x @@ -185088,7 +207640,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185098,12 +207650,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185112,17 +207664,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset @@ -185134,7 +207687,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185163,26 +207716,31 @@ fi Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl - At a minimum, the audit system should collect the execution of -privileged commands for all users and root. If the auditd daemon is -configured to use the augenrules program to read audit rules during -daemon startup (the default), add a line of the following form to a file with -suffix .rules in the directory /etc/audit/rules.d: + + + +At a minimum, the audit system should collect the execution of privileged +commands for all users and root. + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add +a line of the following form to a file with suffix .rules +in the directory /etc/audit/rules.d: -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add a line of the following -form to /etc/audit/audit.rules: +utility to read audit rules during daemon startup, add a line of the +following form to /etc/audit/audit.rules: -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - CCI-000172 - CIP-004-6 R2.2.2 - CIP-004-6 R2.2.3 - CIP-007-3 R.1.3 - CIP-007-3 R5 - CIP-007-3 R5.1.1 - CIP-007-3 R5.1.3 - CIP-007-3 R5.2.1 - CIP-007-3 R5.2.3 + CIP-004-6 R2.2.2 + CIP-004-6 R2.2.3 + CIP-007-3 R.1.3 + CIP-007-3 R5 + CIP-007-3 R5.1.1 + CIP-007-3 R5.1.3 + CIP-007-3 R5.2.1 + CIP-007-3 R5.2.3 AC-2(4) AU-2(d) AU-12(c) @@ -185202,12 +207760,15 @@ unusual activity. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -ACTION_ARCH_FILTERS="-a always,exit" +# Retrieve hardware architecture of the underlying system OTHER_FILTERS="-F path=/usr/sbin/usernetctl -F perm=x" AUID_FILTERS="-F auid>=1000 -F auid!=unset" SYSCALL="" KEY="privileged" SYSCALL_GROUPING="" + + +ACTION_ARCH_FILTERS="-a always,exit" # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' unset syscall_a unset syscall_grouping @@ -185535,16 +208096,17 @@ fi - no_reboot_needed - restrict_strategy -- name: Perform remediation of Audit rules for /usr/sbin/usernetctl +- name: Ensure auditd Collects Information on the Use of Privileged Commands - usernetctl + - Perform remediation of Audit rules for /usr/sbin/usernetctl block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185553,43 +208115,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/privileged.rules - set_fact: audit_file="/etc/audit/rules.d/privileged.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usernetctl -F perm=x @@ -185601,7 +208164,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185611,12 +208174,12 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: [] syscall_grouping: [] - name: Check existence of in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset (-k\s+|-F\s+key=)\S+\s*$ @@ -185625,17 +208188,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset @@ -185647,7 +208211,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit{{ syscalls | join(',') }} -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged @@ -185751,8 +208315,6 @@ not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -185825,6 +208387,7 @@ not required. See an example of multiple combined syscalls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -186191,7 +208754,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -186219,7 +208782,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186228,7 +208791,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186237,43 +208800,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186284,7 +208848,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186293,7 +208857,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186302,7 +208866,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186311,17 +208875,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186332,7 +208897,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186363,7 +208928,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186371,7 +208936,7 @@ fi - settimeofday - name: Check existence of adjtimex in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186380,43 +208945,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186427,7 +208993,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186436,7 +209002,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - adjtimex syscall_grouping: @@ -186445,7 +209011,7 @@ fi - stime - name: Check existence of adjtimex in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -186454,17 +209020,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -186475,7 +209042,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -186576,8 +209143,6 @@ desired, but is not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -186650,6 +209215,7 @@ desired, but is not required. See an example of multiple combined syscalls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -187004,7 +209570,7 @@ fi - restrict_strategy - name: Set architecture for audit tasks - set_fact: + ansible.builtin.set_fact: audit_arch: b64 when: - '"audit" in ansible_facts.packages' @@ -187032,13 +209598,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187047,43 +209613,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/time-change.rules - set_fact: audit_file="/etc/audit/rules.d/time-change.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/time-change.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187094,7 +209661,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187104,13 +209671,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187119,17 +209686,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187140,7 +209708,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187172,13 +209740,13 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187187,43 +209755,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/time-change.rules - set_fact: audit_file="/etc/audit/rules.d/time-change.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/time-change.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187234,7 +209803,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187244,13 +209813,13 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - clock_settime syscall_grouping: [] - name: Check existence of clock_settime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* -F a0=0x0 (-k\s+|-F\s+key=)\S+\s*$ @@ -187259,17 +209828,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F a0=0x0 (?:-k |-F key=)\w+) @@ -187280,7 +209850,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F a0=0x0 -F key=time-change @@ -187382,8 +209952,6 @@ not required. See an example of multiple combined syscalls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -187455,6 +210023,7 @@ not required. See an example of multiple combined syscalls: RS.AN-1 RS.AN-4 Req-10.4.2.b + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -187849,7 +210418,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -187858,7 +210427,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -187867,43 +210436,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -187914,7 +210484,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -187923,7 +210493,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -187932,7 +210502,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -187941,17 +210511,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -187962,7 +210533,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -187993,7 +210564,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -188002,7 +210573,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188011,43 +210582,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188058,7 +210630,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188067,7 +210639,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - settimeofday syscall_grouping: @@ -188076,7 +210648,7 @@ fi - stime - name: Check existence of settimeofday in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b64(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188085,17 +210657,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b64)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188106,7 +210679,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b64 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188211,8 +210784,6 @@ required. See an example of multiple combined system calls: MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -188285,6 +210856,7 @@ required. See an example of multiple combined system calls: RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -188655,7 +211227,7 @@ fi block: - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - stime syscall_grouping: @@ -188664,7 +211236,7 @@ fi - stime - name: Check existence of stime in /etc/audit/rules.d/ - find: + ansible.builtin.find: paths: /etc/audit/rules.d contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188673,43 +211245,44 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Reset syscalls found per file - set_fact: + ansible.builtin.set_fact: syscalls_per_file: {} found_paths_dict: {} - name: Declare syscalls found per file - set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path + ansible.builtin.set_fact: syscalls_per_file="{{ syscalls_per_file | combine( {item.files[0].path :[item.item] + syscalls_per_file.get(item.files[0].path, []) } ) }}" loop: '{{ find_command.results | selectattr(''matched'') | list }}' - name: Declare files where syscalls were found - set_fact: found_paths="{{ find_command.results | map(attribute='files') | flatten - | map(attribute='path') | list }}" + ansible.builtin.set_fact: found_paths="{{ find_command.results | map(attribute='files') + | flatten | map(attribute='path') | list }}" - name: Count occurrences of syscalls in paths - set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, + ansible.builtin.set_fact: found_paths_dict="{{ found_paths_dict | combine({ item:1+found_paths_dict.get(item, 0) }) }}" loop: '{{ find_command.results | map(attribute=''files'') | flatten | map(attribute=''path'') | list }}' - name: Get path with most syscalls - set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') + ansible.builtin.set_fact: audit_file="{{ (found_paths_dict | dict2items() | sort(attribute='value') | last).key }}" when: found_paths | length >= 1 - name: No file with syscall found, set path to /etc/audit/rules.d/audit_time_rules.rules - set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/audit_time_rules.rules" when: found_paths | length == 0 - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188720,7 +211293,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188729,7 +211302,7 @@ fi when: syscalls_found | length == 0 - name: Declare list of syscalls - set_fact: + ansible.builtin.set_fact: syscalls: - stime syscall_grouping: @@ -188738,7 +211311,7 @@ fi - stime - name: Check existence of stime in /etc/audit/audit.rules - find: + ansible.builtin.find: paths: /etc/audit contains: -a always,exit -F arch=b32(( -S |,)\w+)*(( -S |,){{ item }})+(( -S |,)\w+)* (-k\s+|-F\s+key=)\S+\s*$ @@ -188747,17 +211320,18 @@ fi loop: '{{ (syscall_grouping + syscalls) | unique }}' - name: Set path to /etc/audit/audit.rules - set_fact: audit_file="/etc/audit/audit.rules" + ansible.builtin.set_fact: audit_file="/etc/audit/audit.rules" - name: Declare found syscalls - set_fact: syscalls_found="{{ find_command.results | selectattr('matched') | map(attribute='item') - | list }}" + ansible.builtin.set_fact: syscalls_found="{{ find_command.results | selectattr('matched') + | map(attribute='item') | list }}" - name: Declare missing syscalls - set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) }}" + ansible.builtin.set_fact: missing_syscalls="{{ syscalls | difference(syscalls_found) + }}" - name: Replace the audit rule in {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' regexp: (-a always,exit -F arch=b32)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( (?:-k |-F key=)\w+) @@ -188768,7 +211342,7 @@ fi when: syscalls_found | length > 0 and missing_syscalls | length > 0 - name: Add the audit rule to {{ audit_file }} - lineinfile: + ansible.builtin.lineinfile: path: '{{ audit_file }}' line: -a always,exit -F arch=b32 -S {{ syscalls | join(',') }} -F key=audit_time_rules create: true @@ -188806,18 +211380,23 @@ fi Record Attempts to Alter the localtime File - If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the default), -add the following line to a file with suffix .rules in the directory -/etc/audit/rules.d: + + + + +If the auditd daemon is configured to use the augenrules +program to read audit rules during daemon startup (the default), add the +following lines to a file with suffix .rules in the +directory /etc/audit/rules.d: + -w /etc/localtime -p wa -k audit_time_rules + If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, add the following line to -/etc/audit/audit.rules file: +utility to read audit rules during daemon startup, add the following lines to +/etc/audit/audit.rules: + -w /etc/localtime -p wa -k audit_time_rules -The -k option allows for the specification of a key in string form that can -be used for better reporting capability through ausearch and aureport and -should always be used. + 1 11 12 @@ -188863,8 +211442,6 @@ should always be used. MEA01.05 MEA02.01 3.1.7 - CCI-001487 - CCI-000169 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -188937,6 +211514,7 @@ should always be used. RS.AN-4 Req-10.4.2.b R73 + 0582 10.6.3 10.6 Arbitrary changes to the system time can be used to obfuscate @@ -188947,6 +211525,12 @@ to the system time should be audited. if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then # Perform the remediation for both possible tools: 'auditctl' and 'augenrules' + + + + + + # Create a list of audit *.rules files that should be inspected for presence and correctness # of a particular audit rule. The scheme is as follows: # @@ -188970,7 +211554,9 @@ files_to_inspect+=('/etc/audit/audit.rules') for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/localtime" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -188978,7 +211564,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/localtime $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -188994,12 +211582,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/localtime$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/localtime -p wa -k audit_time_rules" >> "$audit_rules_file" + fi done # Create a list of audit *.rules files that should be inspected for presence and correctness @@ -189018,8 +211610,10 @@ files_to_inspect=() # If the audit is 'augenrules', then check if rule is already defined # If rule is defined, add '/etc/audit/rules.d/*.rules' to list of files for inspection. # If rule isn't defined, add '/etc/audit/rules.d/audit_time_rules.rules' to list of files for inspection. + readarray -t matches < <(grep -HP "[\s]*-w[\s]+/etc/localtime" /etc/audit/rules.d/*.rules) + # For each of the matched entries for match in "${matches[@]}" do @@ -189047,7 +211641,9 @@ fi for audit_rules_file in "${files_to_inspect[@]}" do # Check if audit watch file system object rule for given path already present + if grep -q -P -- "^[\s]*-w[\s]+/etc/localtime" "$audit_rules_file" + then # Rule is found => verify yet if existing rule definition contains # all of the required access type bits @@ -189055,7 +211651,9 @@ do # Define BRE whitespace class shortcut sp="[[:space:]]" # Extract current permission access types (e.g. -p [r|w|x|a] values) from audit rule + current_access_bits=$(sed -ne "s#$sp*-w$sp\+/etc/localtime $sp\+-p$sp\+\([rxwa]\{1,4\}\).*#\1#p" "$audit_rules_file") + # Split required access bits string into characters array # (to check bit's presence for one bit at a time) for access_bit in $(echo "wa" | grep -o .) @@ -189071,12 +211669,16 @@ do done # Propagate the updated rule's access bits (original + the required # ones) back into the /etc/audit/audit.rules file for that rule + sed -i "s#\($sp*-w$sp\+/etc/localtime$sp\+-p$sp\+\)\([rxwa]\{1,4\}\)\(.*\)#\1$current_access_bits\3#" "$audit_rules_file" + else # Rule isn't present yet. Append it at the end of $audit_rules_file file # with proper key + echo "-w /etc/localtime -p wa -k audit_time_rules" >> "$audit_rules_file" + fi done @@ -189104,8 +211706,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/localtime already exists in /etc/audit/rules.d/ - find: +- name: Record Attempts to Alter the localtime File - Check if watch rule for /etc/localtime + already exists in /etc/audit/rules.d/ + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^\s*-w\s+/etc/localtime\s+-p\s+wa(\s|$)+ patterns: '*.rules' @@ -189130,8 +211733,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Search /etc/audit/rules.d for other rules with specified key audit_time_rules - find: +- name: Record Attempts to Alter the localtime File - Search /etc/audit/rules.d for + other rules with specified key audit_time_rules + ansible.builtin.find: paths: /etc/audit/rules.d contains: ^.*(?:-F key=|-k\s+)audit_time_rules$ patterns: '*.rules' @@ -189158,8 +211762,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use /etc/audit/rules.d/audit_time_rules.rules as the recipient for the rule - set_fact: +- name: Record Attempts to Alter the localtime File - Use /etc/audit/rules.d/audit_time_rules.rules + as the recipient for the rule + ansible.builtin.set_fact: all_files: - /etc/audit/rules.d/audit_time_rules.rules when: @@ -189184,8 +211789,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Use matched file as the recipient for the rule - set_fact: +- name: Record Attempts to Alter the localtime File - Use matched file as the recipient + for the rule + ansible.builtin.set_fact: all_files: - '{{ find_watch_key.files | map(attribute=''path'') | list | first }}' when: @@ -189210,8 +211816,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/localtime in /etc/audit/rules.d/ - lineinfile: +- name: Record Attempts to Alter the localtime File - Add watch rule for /etc/localtime + in /etc/audit/rules.d/ + ansible.builtin.lineinfile: path: '{{ all_files[0] }}' line: -w /etc/localtime -p wa -k audit_time_rules create: true @@ -189238,8 +211845,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Check if watch rule for /etc/localtime already exists in /etc/audit/audit.rules - find: +- name: Record Attempts to Alter the localtime File - Check if watch rule for /etc/localtime + already exists in /etc/audit/audit.rules + ansible.builtin.find: paths: /etc/audit/ contains: ^\s*-w\s+/etc/localtime\s+-p\s+wa(\s|$)+ patterns: audit.rules @@ -189264,8 +211872,9 @@ fi - no_reboot_needed - restrict_strategy -- name: Add watch rule for /etc/localtime in /etc/audit/audit.rules - lineinfile: +- name: Record Attempts to Alter the localtime File - Add watch rule for /etc/localtime + in /etc/audit/audit.rules + ansible.builtin.lineinfile: line: -w /etc/localtime -p wa -k audit_time_rules state: present dest: /etc/audit/audit.rules @@ -189360,6 +211969,16 @@ normally. ignore single|halt single|halt + single|halt + + + The percentage remaining in disk space before prompting admin_space_left_action + The setting for admin_space_left as a percentage in /etc/audit/auditd.conf + 5 + 25 + 50 + 75 + 5 Action for auditd to take when disk errors @@ -189377,7 +211996,10 @@ for remediations the first value will be taken' syslog|single|halt syslog|single|halt syslog|single|halt + syslog|single|halt + syslog|single|halt syslog|single|halt + syslog|single|halt Action for auditd to take when disk is full @@ -189396,7 +212018,10 @@ for remediations the first value will be taken' syslog|single|halt syslog|single|halt halt|single + halt|single + halt|single halt|single + halt|single Auditd priority for flushing data to disk @@ -189465,6 +212090,7 @@ for remediations the first value will be taken' ignore email|exec|single|halt email|exec|single|halt + email|exec|single|halt The percentage remaining in disk space before prompting space_left_action @@ -189501,12 +212127,10 @@ following command: $ sudo df -h /var/log/audit/ /dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - CCI-001849 - CCI-001851 - SRG-OS-000341-GPOS-00132 - SRG-OS-000342-GPOS-00133 - OL09-00-000850 - SV-271596r1091500_rule + SRG-OS-000341-GPOS-00132 + SRG-OS-000342-GPOS-00133 + OL09-00-000850 + SV-271596r1091500_rule Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information systems with limited audit storage capacity. @@ -189549,7 +212173,6 @@ Restart the auditd service: DSS05.07 MEA02.01 3.3.1 - CCI-001851 164.308(a)(1)(ii)(D) 164.308(a)(5)(ii)(B) 164.308(a)(5)(ii)(C) @@ -189591,12 +212214,12 @@ Restart the auditd service: RS.AN-1 RS.AN-4 Req-10.5.3 - SRG-OS-000479-GPOS-00224 - SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + SRG-OS-000342-GPOS-00133 10.3.3 10.3 - OL09-00-000855 - SV-271597r1092586_rule + OL09-00-000855 + SV-271597r1092586_rule The auditd service does not include the ability to send audit records to a centralized server for management directly. It does, however, include a plug-in for audit event multiplexor (audispd) to pass audit records @@ -189652,7 +212275,7 @@ fi - no_reboot_needed - name: Enable syslog plugin - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/plugins.d/syslog.conf regexp: ^active line: active = yes @@ -189728,7 +212351,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -189768,14 +212390,14 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 Taking appropriate action in case of disk errors will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -189837,7 +212459,7 @@ fi - always - name: Configure auditd Disk Error Action on Disk Error - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_error_action = {{ var_auditd_disk_error_action.split('|')[0] }} regexp: ^\s*disk_error_action\s*=\s*.*$ @@ -189909,7 +212531,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -189949,9 +212570,9 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - OL09-00-000760 - SV-271579r1091449_rule + SRG-OS-000047-GPOS-00023 + OL09-00-000760 + SV-271579r1091449_rule Taking appropriate action in case of disk errors will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190007,7 +212628,7 @@ fi - always - name: Configure auditd Disk Error Action on Disk Error - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_error_action = {{ var_auditd_disk_error_action }} regexp: ^\s*disk_error_action\s*=\s*.*$ @@ -190082,7 +212703,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -190122,7 +212742,7 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 + SRG-OS-000047-GPOS-00023 Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190179,7 +212799,7 @@ fi - always - name: Configure auditd Disk Full Action when Disk Space Is Full - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_full_action = {{ var_auditd_disk_full_action.split('|')[0] }} regexp: ^\s*disk_full_action\s*=\s*.*$ @@ -190251,7 +212871,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.04 DSS05.07 MEA02.01 - CCI-000140 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -190291,9 +212910,9 @@ determined. Details regarding all possible values for ACTION ar PR.PT-1 RS.AN-1 RS.AN-4 - SRG-OS-000047-GPOS-00023 - OL09-00-000765 - SV-271580r1091452_rule + SRG-OS-000047-GPOS-00023 + OL09-00-000765 + SV-271580r1091452_rule Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records. # Remediation is applicable only in certain platforms @@ -190349,7 +212968,7 @@ fi - always - name: Configure auditd Disk Full Action when Disk Space Is Full - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: disk_full_action = {{ var_auditd_disk_full_action }} regexp: ^\s*disk_full_action\s*=\s*.*$ @@ -190418,8 +213037,6 @@ via email for those situations: DSS05.07 MEA02.01 3.3.1 - CCI-001855 - CCI-000139 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -190449,21 +213066,21 @@ via email for those situations: A.16.1.5 A.16.1.7 A.17.2.1 - CIP-003-8 R1.3 - CIP-003-8 R3 - CIP-003-8 R3.1 - CIP-003-8 R3.2 - CIP-003-8 R3.3 - CIP-003-8 R5.1.1 - CIP-003-8 R5.3 - CIP-004-6 R2.2.3 - CIP-004-6 R2.3 - CIP-007-3 R5.1 - CIP-007-3 R5.1.2 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 + CIP-003-8 R1.3 + CIP-003-8 R3 + CIP-003-8 R3.1 + CIP-003-8 R3.2 + CIP-003-8 R3.3 + CIP-003-8 R5.1.1 + CIP-003-8 R5.3 + CIP-004-6 R2.2.3 + CIP-004-6 R2.3 + CIP-007-3 R5.1 + CIP-007-3 R5.1.2 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 IA-5(1) AU-5(a) AU-5(2) @@ -190475,10 +213092,10 @@ via email for those situations: RS.AN-1 RS.AN-4 Req-10.7.a - SRG-OS-000046-GPOS-00022 - SRG-OS-000343-GPOS-00134 - OL09-00-000825 - SV-271591r1092578_rule + SRG-OS-000046-GPOS-00022 + SRG-OS-000343-GPOS-00134 + OL09-00-000825 + SV-271591r1092578_rule Email sent to the root account is typically aliased to the administrators of the system, who can take appropriate action. # Remediation is applicable only in certain platforms @@ -190537,9 +213154,11 @@ fi tags: - always -- name: Configure auditd mail_acct Action on Low Disk Space - lineinfile: +- name: Configure auditd mail_acct Action on Low Disk Space - Configure auditd mail_acct + Action on Low Disk Space + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf + regexp: ^action_mail_acct line: action_mail_acct = {{ var_auditd_action_mail_acct }} state: present create: true @@ -190614,7 +213233,6 @@ determined. Details regarding all possible values for ACTION ar DSS05.07 MEA02.01 3.3.1 - CCI-001855 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -190656,13 +213274,11 @@ determined. Details regarding all possible values for ACTION ar RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 - OL09-00-000875 - OL09-00-000885 - SV-271601r1091515_rule - SV-271603r1092592_rule + OL09-00-000885 + SV-271603r1092592_rule Administrators should be made aware of an inability to record audit records. If a separate partition or logical volume of adequate size is used, running low on space for audit records should never occur. @@ -190705,7 +213321,6 @@ fi manager: auto tags: - CJIS-5.4.1.1 - - DISA-STIG-OL09-00-000875 - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) @@ -190729,7 +213344,7 @@ fi - always - name: Configure auditd admin_space_left Action on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: admin_space_left_action = {{ var_auditd_admin_space_left_action .split('|')[0] }} @@ -190741,7 +213356,6 @@ fi - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - CJIS-5.4.1.1 - - DISA-STIG-OL09-00-000875 - DISA-STIG-OL09-00-000885 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) @@ -190767,6 +213381,158 @@ fi + + Configure auditd admin_space_left on Low Disk Space + The auditd service can be configured to take an action +when disk space is running low but prior to running out of space completely. +Edit the file /etc/audit/auditd.conf. Add or modify the following line, +substituting PERCENTAGE appropriately: +admin_space_left = PERCENTAGE% +Set this value to +to cause the system to perform an action. + 1 + 11 + 12 + 13 + 14 + 15 + 16 + 19 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + APO11.04 + APO12.06 + APO13.01 + BAI03.05 + BAI04.04 + BAI08.02 + DSS02.02 + DSS02.04 + DSS02.07 + DSS03.01 + DSS05.04 + DSS05.07 + MEA02.01 + 4.2.3.10 + 4.3.3.3.9 + 4.3.3.5.8 + 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 2.10 + SR 2.11 + SR 2.12 + SR 2.8 + SR 2.9 + SR 6.1 + 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.16.1.4 + A.16.1.5 + A.16.1.7 + A.17.2.1 + AU-5(b) + AU-5(2) + AU-5(1) + AU-5(4) + CM-6(a) + DE.AE-3 + DE.AE-5 + PR.DS-4 + PR.PT-1 + RS.AN-1 + RS.AN-4 + Req-10.7 + SRG-OS-000343-GPOS-00134 + OL09-00-000875 + SV-271601r1091515_rule + Notifying administrators of an impending disk space problem may allow them to +take corrective action prior to any disruption. + # Remediation is applicable only in certain platforms +if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then + +var_auditd_admin_space_left_percentage='' + + +grep -q "^admin_space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \ + sed -i "s/^admin_space_left[[:space:]]*=.*$/admin_space_left = $var_auditd_admin_space_left_percentage%/g" /etc/audit/auditd.conf || \ + echo "admin_space_left = $var_auditd_admin_space_left_percentage%" >> /etc/audit/auditd.conf + +else + >&2 echo 'Remediation is not applicable, nothing was done' +fi + + - name: Gather the package facts + package_facts: + manager: auto + tags: + - DISA-STIG-OL09-00-000875 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - auditd_data_retention_admin_space_left_percentage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy +- name: XCCDF Value var_auditd_admin_space_left_percentage # promote to variable + set_fact: + var_auditd_admin_space_left_percentage: !!str + tags: + - always + +- name: Configure auditd admin_space_left on Low Disk Space + ansible.builtin.lineinfile: + dest: /etc/audit/auditd.conf + line: admin_space_left = {{ var_auditd_admin_space_left_percentage }}% + regexp: ^\s*admin_space_left\s*=\s*.*$ + state: present + create: true + when: + - '"audit" in ansible_facts.packages' + - ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) + tags: + - DISA-STIG-OL09-00-000875 + - NIST-800-53-AU-5(1) + - NIST-800-53-AU-5(2) + - NIST-800-53-AU-5(4) + - NIST-800-53-AU-5(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.7 + - auditd_data_retention_admin_space_left_percentage + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + + + + + + + + + Configure auditd flush priority The auditd service can be configured to @@ -190808,7 +213574,6 @@ fully synchronized with the log files on the disk: MEA01.05 MEA02.01 3.3.1 - CCI-001576 164.308(a)(1)(ii)(D) 164.308(a)(3)(ii)(A) 164.308(a)(5)(ii)(C) @@ -190838,13 +213603,13 @@ fully synchronized with the log files on the disk: A.14.2.7 A.15.2.1 A.15.2.2 - CIP-004-6 R2.2.3 - CIP-004-6 R3.3 - CIP-007-3 R5.2 - CIP-007-3 R5.3.1 - CIP-007-3 R5.3.2 - CIP-007-3 R5.3.3 - CIP-007-3 R6.5 + CIP-004-6 R2.2.3 + CIP-004-6 R3.3 + CIP-007-3 R5.2 + CIP-007-3 R5.3.1 + CIP-007-3 R5.3.2 + CIP-007-3 R5.3.3 + CIP-007-3 R6.5 AU-11 CM-6(a) DE.CM-1 @@ -190853,7 +213618,8 @@ fully synchronized with the log files on the disk: ID.SC-4 PR.PT-1 FAU_GEN.1 - SRG-OS-000480-GPOS-00227 + SRG-OS-000480-GPOS-00227 + 0582 Audit data should be synchronously written to disk to ensure log integrity. These parameters assure that all audit event data is fully synchronized with the log files on the disk. @@ -190914,7 +213680,7 @@ fi - always - name: Configure auditd Flush Priority - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf regexp: ^\s*flush\s*=\s*.*$ line: flush = {{ var_auditd_flush }} @@ -190983,7 +213749,6 @@ The setting is case-insensitive. DSS05.04 DSS05.07 MEA02.01 - CCI-000140 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191025,7 +213790,7 @@ The setting is case-insensitive. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000047-GPOS-00023 + SRG-OS-000047-GPOS-00023 A.3.SEC-OL6 Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by @@ -191088,7 +213853,7 @@ fi - always - name: Configure auditd max_log_file_action Upon Reaching Maximum Log Size - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: max_log_file_action = {{ var_auditd_max_log_file_action }} regexp: ^\s*max_log_file_action\s*=\s*.*$ @@ -191160,7 +213925,6 @@ occurs. This is the default. The setting is case-insensitive.DSS05.04 DSS05.07 MEA02.01 - CCI-000140 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191202,16 +213966,16 @@ occurs. This is the default. The setting is case-insensitive.RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000047-GPOS-00023 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 - OL09-00-000770 - SV-271581r1091455_rule + SRG-OS-000047-GPOS-00023 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + OL09-00-000770 + SV-271581r1091455_rule Automatically rotating logs (by setting this to rotate) minimizes the chances of the system unexpectedly running out of disk space by being overwhelmed with log data. However, for systems that must never discard @@ -191271,7 +214035,7 @@ fi - always - name: Configure auditd max_log_file_action Upon Reaching Maximum Log Size - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: max_log_file_action = {{ var_auditd_max_log_file_action }} regexp: ^\s*max_log_file_action\s*=\s*.*$ @@ -191340,7 +214104,6 @@ notify the user of an issue. DSS05.04 DSS05.07 MEA02.01 - CCI-001855 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -191381,7 +214144,7 @@ notify the user of an issue. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 Notifying administrators of an impending disk space problem may allow them to @@ -191425,7 +214188,7 @@ fi - always - name: Configure auditd space_left on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left = {{ var_auditd_space_left }} regexp: ^\s*space_left\s*=\s*.*$ @@ -191502,7 +214265,6 @@ also include suspend, single, and DSS05.07 MEA02.01 3.3.1 - CCI-001855 164.312(a)(2)(ii) 4.2.3.10 4.3.3.3.9 @@ -191544,11 +214306,11 @@ also include suspend, single, and RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 + SRG-OS-000343-GPOS-00134 10.5.1 10.5 - OL09-00-000870 - SV-271600r1091512_rule + OL09-00-000870 + SV-271600r1134858_rule Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption. # Remediation is applicable only in certain platforms @@ -191618,7 +214380,7 @@ fi - always - name: Configure auditd space_left Action on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left_action = {{ var_auditd_space_left_action.split('|')[0] }} regexp: ^\s*space_left_action\s*=\s*.*$ @@ -191691,7 +214453,6 @@ notify the user of an issue. DSS05.04 DSS05.07 MEA02.01 - CCI-001855 4.2.3.10 4.3.3.3.9 4.3.3.5.8 @@ -191732,9 +214493,9 @@ notify the user of an issue. RS.AN-1 RS.AN-4 Req-10.7 - SRG-OS-000343-GPOS-00134 - OL09-00-000865 - SV-271599r1091509_rule + SRG-OS-000343-GPOS-00134 + OL09-00-000865 + SV-271599r1134856_rule Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption. # Remediation is applicable only in certain platforms @@ -191775,7 +214536,7 @@ fi - always - name: Configure auditd space_left on Low Disk Space - lineinfile: + ansible.builtin.lineinfile: dest: /etc/audit/auditd.conf line: space_left = {{ var_auditd_space_left_percentage }}% regexp: ^\s*space_left\s*=\s*.*$ @@ -191812,18 +214573,22 @@ fi To configure Audit daemon to issue an explicit flush to disk command after writing records, set freq to in /etc/audit/auditd.conf. - CCI-000154 CM-6 FAU_GEN.1 - SRG-OS-000051-GPOS-00024 - OL09-00-000775 - SV-271582r1092574_rule + SRG-OS-000051-GPOS-00024 + 0582 + OL09-00-000775 + SV-271582r1092574_rule If option freq isn't set to , the flush to disk may happen after higher number of records, increasing the danger of audit loss. # Remediation is applicable only in certain platforms if rpm --quiet -q audit && rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then +var_auditd_freq='' + + + if [ -e "/etc/audit/auditd.conf" ] ; then LC_ALL=C sed -i "/^\s*freq\s*=\s*/Id" "/etc/audit/auditd.conf" @@ -191835,7 +214600,7 @@ sed -i -e '$a\' "/etc/audit/auditd.conf" cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak" # Insert at the end of the file -printf '%s\n' "freq = 50" >> "/etc/audit/auditd.conf" +printf '%s\n' "freq = $var_auditd_freq" >> "/etc/audit/auditd.conf" # Clean up after ourselves. rm "/etc/audit/auditd.conf.bak" @@ -191855,12 +214620,17 @@ fi - medium_severity - no_reboot_needed - restrict_strategy +- name: XCCDF Value var_auditd_freq # promote to variable + set_fact: + var_auditd_freq: !!str + tags: + - always - name: Set number of records to cause an explicit flush to audit logs block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* @@ -191870,7 +214640,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* @@ -191878,11 +214648,11 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*freq\s*=\s* - line: freq = 50 + line: freq = {{ var_auditd_freq }} state: present when: - '"audit" in ansible_facts.packages' @@ -191898,6 +214668,7 @@ fi - restrict_strategy + @@ -191909,13 +214680,12 @@ fi To configure Audit daemon to include local events in Audit logs, set local_events to yes in /etc/audit/auditd.conf. This is the default setting. - CCI-000366 - CCI-000169 CM-6 - SRG-OS-000062-GPOS-00031 - SRG-OS-000480-GPOS-00227 - OL09-00-000800 - SV-271586r1092576_rule + SRG-OS-000062-GPOS-00031 + SRG-OS-000480-GPOS-00227 + 0582 + OL09-00-000800 + SV-271586r1092576_rule If option local_events isn't set to yes only events from network will be aggregated. # Remediation is applicable only in certain platforms @@ -191957,7 +214727,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -191967,7 +214737,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -191975,7 +214745,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*local_events\s*=\s* @@ -192007,24 +214777,23 @@ fi architecture, and socket address information before writing the events to disk, set log_format to ENRICHED in /etc/audit/auditd.conf. - CCI-000366 - CCI-001487 CM-6 AU-3 FAU_GEN.1.2 - SRG-OS-000255-GPOS-00096 - SRG-OS-000480-GPOS-00227 - SRG-APP-000096-CTR-000175 - SRG-APP-000097-CTR-000180 - SRG-APP-000098-CTR-000185 - SRG-APP-000099-CTR-000190 - SRG-APP-000100-CTR-000195 - SRG-APP-000100-CTR-000200 - SRG-APP-000109-CTR-000215 - SRG-APP-000290-CTR-000670 - SRG-APP-000357-CTR-000800 - OL09-00-000835 - SV-271593r1092580_rule + SRG-OS-000255-GPOS-00096 + SRG-OS-000480-GPOS-00227 + SRG-APP-000096-CTR-000175 + SRG-APP-000097-CTR-000180 + SRG-APP-000098-CTR-000185 + SRG-APP-000099-CTR-000190 + SRG-APP-000100-CTR-000195 + SRG-APP-000100-CTR-000200 + SRG-APP-000109-CTR-000215 + SRG-APP-000290-CTR-000670 + SRG-APP-000357-CTR-000800 + 0582 + OL09-00-000835 + SV-271593r1092580_rule If option log_format isn't set to ENRICHED, the audit records will be stored in a format exactly as the kernel sends them. # Remediation is applicable only in certain platforms @@ -192067,7 +214836,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192077,7 +214846,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192085,7 +214854,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*log_format\s*=\s* @@ -192120,18 +214889,17 @@ set name_format to Whenever the variable var_auditd_name_format uses a multiple value option, for example A|B|C, the first value will be used when remediating this rule. - CCI-000132 - CCI-001851 CM-6 AU-3 FAU_GEN.1.2 - SRG-OS-000039-GPOS-00017 - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 + SRG-OS-000039-GPOS-00017 + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + 0582 10.2.2 10.2 - OL09-00-000755 - SV-271578r1092572_rule + OL09-00-000755 + SV-271578r1092572_rule If option name_format is left at its default value of none, audit events from different computers may be hard to distinguish. @@ -192207,7 +214975,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192217,7 +214985,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192225,7 +214993,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*name_format\s*=\s* @@ -192260,12 +215028,11 @@ fi The audit system should have an action setup in the event the internal event queue becomes full. To setup an overflow action edit /etc/audit/auditd.conf. Set overflow_action to one of the following values: syslog, single, halt. - CCI-001851 AU-4(1) - SRG-OS-000342-GPOS-00133 - SRG-OS-000479-GPOS-00224 - OL09-00-000860 - SV-271598r1092588_rule + SRG-OS-000342-GPOS-00133 + SRG-OS-000479-GPOS-00224 + OL09-00-000860 + SV-271598r1092588_rule The audit system should have an action setup in the event the internal event queue becomes full so that no data is lost. # Remediation is applicable only in certain platforms @@ -192307,7 +215074,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192317,7 +215084,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192325,7 +215092,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*overflow_action\s*=\s* @@ -192356,11 +215123,11 @@ fi To configure Audit daemon to write Audit logs to the disk, set write_logs to yes in /etc/audit/auditd.conf. This is the default setting. - CCI-000366 CM-6 - SRG-OS-000480-GPOS-00227 - OL09-00-000880 - SV-271602r1092590_rule + SRG-OS-000480-GPOS-00227 + 0582 + OL09-00-000880 + SV-271602r1092590_rule If write_logs isn't set to yes, the Audit logs will not be written to the disk. # Remediation is applicable only in certain platforms @@ -192402,7 +215169,7 @@ fi block: - name: Check for duplicate values - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192412,7 +215179,7 @@ fi register: dupes - name: Deduplicate values from /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192420,7 +215187,7 @@ fi when: dupes.found is defined and dupes.found > 1 - name: Insert correct line to /etc/audit/auditd.conf - lineinfile: + ansible.builtin.lineinfile: path: /etc/audit/auditd.conf create: true regexp: (?i)(?i)^\s*write_logs\s*=\s* @@ -192458,11 +215225,10 @@ deals with permissions of auditd related files. To properly set the permissions of /etc/audit/auditd.conf, run the command: $ sudo chmod 0640 /etc/audit/auditd.conf - CCI-000171 AU-12(b) - SRG-OS-000063-GPOS-00032 - OL09-00-000810 - SV-271588r1091476_rule + SRG-OS-000063-GPOS-00032 + OL09-00-000810 + SV-271588r1091476_rule Without the capability to restrict the roles and individuals that can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming @@ -192492,7 +215258,7 @@ fi - no_reboot_needed - name: Test for existence /etc/audit/auditd.conf - stat: + ansible.builtin.stat: path: /etc/audit/auditd.conf register: file_exists when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) @@ -192507,7 +215273,7 @@ fi - no_reboot_needed - name: Ensure permission u-xs,g-xws,o-xwrt on /etc/audit/auditd.conf - file: + ansible.builtin.file: path: /etc/audit/auditd.conf mode: u-xs,g-xws,o-xwrt when: @@ -192536,11 +215302,10 @@ fi To properly set the permissions of /etc/audit/rules.d/*.rules, run the command: $ sudo chmod 0600 /etc/audit/rules.d/*.rules - CCI-000171 AU-12(b) - SRG-OS-000063-GPOS-00032 - OL09-00-000805 - SV-271587r1091473_rule + SRG-OS-000063-GPOS-00032 + OL09-00-000805 + SV-271587r1091473_rule Without the capability to restrict the roles and individuals that can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming @@ -192550,7 +215315,7 @@ those responsible for one. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then -find -L /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*rules$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; +find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex '^.*rules$' -exec chmod u-xs,g-xwrs,o-xwrt {} \; else >&2 echo 'Remediation is not applicable, nothing was done' @@ -192570,7 +215335,7 @@ fi - no_reboot_needed - name: Find /etc/audit/rules.d/ file(s) - command: find -H /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type + ansible.builtin.command: find -P /etc/audit/rules.d/ -maxdepth 1 -perm /u+xs,g+xwrs,o+xwrt -type f -regextype posix-extended -regex "^.*rules$" register: files_found changed_when: false @@ -192588,7 +215353,7 @@ fi - no_reboot_needed - name: Set permissions for /etc/audit/rules.d/ file(s) - file: + ansible.builtin.file: path: '{{ item }}' mode: u-xs,g-xwrs,o-xwrt state: file @@ -192633,27 +215398,23 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 + 0582 + 0846 Unsuccessful attempts to access a file might be signs of malicious activity happening within the system. Auditing of such activities helps in their monitoring and investigation. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192688,7 +215449,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules content: | ## Unsuccessful file access (any other opens) This has to go last. @@ -192712,6 +215473,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192742,21 +215504,17 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. - 0582 - 0584 - 05885 - 0586 - 0846 - 0957 +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + 0582 + 0846 Auditing of successful attempts to access a file helps in investigation of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192790,7 +215548,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules content: | ## Successful file access (any other opens) This has to go last. @@ -192813,6 +215571,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192855,8 +215614,8 @@ Load new Audit rules into kernel by running: It might happen that Audit buffer configured by this rule is not large enough for certain use cases. If that is the case, the buffer size can be overridden by placing -b larger_buffer_size into a file within /etc/audit/rules.d directory, replacing larger_file_size with the desired value. The file name should start with a number higher than 10 and lower than 99. AU-2(a) FAU_GEN.1 - SRG-OS-000365-GPOS-00152 - SRG-OS-000475-GPOS-00220 + SRG-OS-000365-GPOS-00152 + SRG-OS-000475-GPOS-00220 Without basic configurations, audit may not perform as expected. It may not be able to correctly handle events under stressful conditions, or log events in case of failure. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -192898,7 +215657,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/10-base-config.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/10-base-config.rules content: |+ ## First rule - delete all @@ -192930,6 +215689,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/10-base-config.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -192969,21 +215729,21 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 Unsuccessful file creations might be a sign of a malicious action being performed on the system. Keeping log of such events helps in monitoring and investigation of such actions. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193026,7 +215786,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules content: | ## Unsuccessful file creation (open with O_CREAT) @@ -193058,6 +215818,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193091,15 +215852,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 Auditing of successful attempts to create a file helps in investigation of actions which happened on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193136,7 +215897,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules content: | ## Successful file creation (open with O_CREAT) @@ -193162,6 +215923,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193193,18 +215955,18 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 - SRG-APP-000501-CTR-001265 - SRG-APP-000502-CTR-001270 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 + SRG-APP-000501-CTR-001265 + SRG-APP-000502-CTR-001270 Unsuccessful attempts to delete a file might be signs of malicious activities. Auditing of such events help in monitoring and investigating of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193239,7 +216001,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules content: | ## Unsuccessful file delete @@ -193263,6 +216025,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193292,16 +216055,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-OS-000468-GPOS-00212 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-OS-000468-GPOS-00212 Auditing of successful attempts to delete a file may help in monitoring and investigation of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193334,7 +216097,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules content: | ## Successful file delete @@ -193356,6 +216119,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193386,18 +216150,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load - CCI-000162 - CCI-000163 - CCI-000164 AU-2(a) FAU_GEN.1.2 - SRG-OS-000462-GPOS-00206 - SRG-OS-000475-GPOS-00220 - SRG-OS-000057-GPOS-00027 - SRG-OS-000058-GPOS-00028 - SRG-OS-000059-GPOS-00029 - SRG-APP-000121-CTR-000255 - SRG-APP-000495-CTR-001235 + SRG-OS-000462-GPOS-00206 + SRG-OS-000475-GPOS-00220 + SRG-OS-000057-GPOS-00027 + SRG-OS-000058-GPOS-00028 + SRG-OS-000059-GPOS-00029 + SRG-APP-000121-CTR-000255 + SRG-APP-000495-CTR-001235 If modification of login UIDs is not prevented, they can be changed by unprivileged users and make auditing complicated or impossible. # Remediation is applicable only in certain platforms @@ -193430,7 +216191,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/11-loginuid.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/11-loginuid.rules content: |+ ## Make the loginuid immutable. This prevents tampering with the auid. @@ -193452,6 +216213,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/11-loginuid.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193491,21 +216253,21 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 - SRG-APP-000091-CTR-000160 - SRG-APP-000492-CTR-001220 - SRG-APP-000493-CTR-001225 - SRG-APP-000494-CTR-001230 - SRG-APP-000500-CTR-001260 - SRG-APP-000507-CTR-001295 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 + SRG-APP-000091-CTR-000160 + SRG-APP-000492-CTR-001220 + SRG-APP-000493-CTR-001225 + SRG-APP-000494-CTR-001230 + SRG-APP-000500-CTR-001260 + SRG-APP-000507-CTR-001295 Unsuccessful file modifications might be a sign of a malicious action being performed on the system. Auditing of such events helps in detection and investigation of such actions. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193548,7 +216310,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules content: | ## Unsuccessful file modifications (open for write or truncate) @@ -193580,6 +216342,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193613,15 +216376,15 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000458-GPOS-00203 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000461-GPOS-00205 + SRG-OS-000458-GPOS-00203 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000461-GPOS-00205 Auditing of successful attempts to modify a file helps in investigation of actions which happened on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193658,7 +216421,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules content: | ## Successful file modifications (open for write or truncate) @@ -193684,6 +216447,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193718,9 +216482,9 @@ Load new Audit rules into kernel by running: AU-2(a) FAU_GEN.1.1.c - SRG-OS-000471-GPOS-00216 - SRG-OS-000477-GPOS-00222 - SRG-OS-000475-GPOS-00220 + SRG-OS-000471-GPOS-00216 + SRG-OS-000477-GPOS-00222 + SRG-OS-000475-GPOS-00220 Loading of a malicious kernel module introduces a risk to the system, as the module has access to sensitive data and perform actions at the operating system kernel level. Having such events audited helps in monitoring and investigating of malicious activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193755,7 +216519,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/43-module-load.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/43-module-load.rules content: | ## These rules watch for kernel module insertion. By monitoring @@ -193780,6 +216544,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/43-module-load.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -193817,6 +216582,9 @@ The following rules configure audit as described above: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -193921,19 +216689,19 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000004-GPOS-00004 - SRG-OS-000241-GPOS-00091 - SRG-OS-000476-GPOS-00221 - SRG-OS-000327-GPOS-00127 - SRG-OS-000475-GPOS-00220 - SRG-OS-000239-GPOS-00089 - SRG-OS-000274-GPOS-00104 - SRG-OS-000275-GPOS-00105 - SRG-OS-000303-GPOS-00120 - SRG-OS-000304-GPOS-00121 + SRG-OS-000004-GPOS-00004 + SRG-OS-000241-GPOS-00091 + SRG-OS-000476-GPOS-00221 + SRG-OS-000327-GPOS-00127 + SRG-OS-000475-GPOS-00220 + SRG-OS-000239-GPOS-00089 + SRG-OS-000274-GPOS-00104 + SRG-OS-000275-GPOS-00105 + SRG-OS-000303-GPOS-00120 + SRG-OS-000304-GPOS-00121 Auditing of events listed in the description provides data for monitoring and investigation of potentially malicious events e.g. tampering with Audit logs, malicious access to files storing information about system users and groups etc. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -193952,6 +216720,9 @@ cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -194076,7 +216847,7 @@ fi - restrict_strategy - name: Put contents into /etc/audit/rules.d/30-ospp-v42.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42.rules content: |+ ## The purpose of these rules is to meet the requirements for Operating @@ -194092,6 +216863,9 @@ fi ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules + ## + ## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -194209,6 +216983,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194240,16 +217015,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Unsuccessful attempts to change an ownership of files or directories might be signs of a malicious activity. Having such events audited helps in monitoring and investigation of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194284,7 +217059,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules content: | ## Unsuccessful ownership change @@ -194308,6 +217083,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194337,17 +217113,17 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 - Auditing of successful ownership changes of files or directories helps in monitoring or investingating of activities performed on the system. + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 + Auditing of successful ownership changes of files or directories helps in monitoring or investigating of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194379,7 +217155,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules content: | ## Successful ownership change @@ -194401,6 +217177,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194432,16 +217209,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Unsuccessful attempts to change permissions of files or directories might be signs of malicious activity. Having such events audited helps in monitoring and investigation of such activities. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194476,7 +217253,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules content: | ## Unsuccessful permission change @@ -194500,6 +217277,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194529,16 +217307,16 @@ The following rules configure audit as described above: Load new Audit rules into kernel by running: augenrules --load -Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs. +Note: This rule uses a special set of Audit rules to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are aligned with your needs. AU-2(a) FAU_GEN.1.1.c - SRG-OS-000462-GPOS-00206 - SRG-OS-000463-GPOS-00207 - SRG-OS-000465-GPOS-00209 - SRG-OS-000474-GPOS-00219 - SRG-OS-000475-GPOS-00220 - SRG-OS-000466-GPOS-00210 - SRG-OS-000064-GPOS-00033 + SRG-OS-000462-GPOS-00206 + SRG-OS-000463-GPOS-00207 + SRG-OS-000465-GPOS-00209 + SRG-OS-000474-GPOS-00219 + SRG-OS-000475-GPOS-00220 + SRG-OS-000466-GPOS-00210 + SRG-OS-000064-GPOS-00033 Auditing successful file or directory permission changes helps in monitoring and investigating of activities performed on the system. # Remediation is applicable only in certain platforms if rpm --quiet -q kernel || rpm --quiet -q kernel-uek; then @@ -194571,7 +217349,7 @@ fi - name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules according to policy - copy: + ansible.builtin.copy: dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules content: | ## Successful permission change @@ -194593,6 +217371,7 @@ fi ansible.builtin.file: path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules mode: g-rwx,o-rwx + state: touch when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages) tags: - NIST-800-53-AU-2(a) @@ -194614,13 +217393,13 @@ fi - + OVALFileLinker from SCAP Security Guide - ssg: [0, 1, 76], python: 3.9.21 + ssg: [0, 1, 79], python: 3.9.23 5.11 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 @@ -194683,27 +217462,6 @@ fi - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - Oracle Linux 9 - - - Audit rules that detect changes to the system's - mandatory access controls (SELinux) in usr/share/selinux are enabled. - - - - - - - - - - - - Record Events that Modify the System's Network Environment @@ -194717,88 +217475,24 @@ fi - - - - + + + + - - - - + + + + - - - Record Attempts to Alter Process and Session Initiation Information - - Oracle Linux 9 - - - Audit rules should capture information about session initiation. - - - - - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - Oracle Linux 9 - - - Audit actions taken by system administrators on the system - /etc/sudoers. - - - - - - - - - - - - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - Oracle Linux 9 - - - Audit actions taken by system administrators on the system - /etc/sudoers.d/. - - - - - - - - - - - - Record Events When Privileged Executables Are Run @@ -194834,17 +217528,9 @@ fi Audit actions taken by system administrators on the system. - - - - - - - - - - - + + + @@ -194907,11 +217593,19 @@ fi - + + + + + - + + + + + @@ -194971,16 +217665,11 @@ fi - - - - - - - - + + + @@ -195086,6 +217775,7 @@ fi + @@ -195121,90 +217811,6 @@ fi - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - Oracle Linux 9 - - - The audit rules should be configured to log information about kernel module loading and unloading. - - - - - - - - - - - - - - - - - - - - Record Attempts to Alter Logon and Logout Events @@ -195374,26 +217980,6 @@ fi - - - Record Attempts to Alter the localtime File - - Oracle Linux 9 - - - Record attempts to alter time through /etc/localtime. - - - - - - - - - - - - Configure auditd to use audispd's syslog plugin @@ -195489,6 +218075,19 @@ fi + + + Configure auditd admin_space_left on Low Disk Space + + Oracle Linux 9 + + + admin_space_left setting in /etc/audit/auditd.conf is set to at least a certain value + + + + + Configure auditd flush priority @@ -195769,7 +218368,7 @@ fi Ensure that no other user than chrony is configured to run the chrony service - + @@ -195811,11 +218410,17 @@ fi - + + + + - + + + + @@ -195874,18 +218479,24 @@ fi - + - Ensure tftp Daemon Uses Secure Mode + Ensure tftp systemd Service Uses Secure Mode Oracle Linux 9 - + The TFTP daemon should use secure mode. - + - + + + + + + + @@ -195990,7 +218601,7 @@ fi Oracle Linux 9 - Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config + Ensure RekeyLimit is configured with the appropriate value in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -196001,7 +218612,11 @@ fi - + + + + + @@ -196026,7 +218641,9 @@ fi + + @@ -196050,6 +218667,7 @@ fi + @@ -196073,6 +218691,7 @@ fi + @@ -196096,6 +218715,7 @@ fi + @@ -196145,29 +218765,6 @@ fi - - - Use Only Strong MACs - - Oracle Linux 9 - - - Ensure only strong MAC algorithms are used - - - - - - - - - - - - - - - Certificate status checking in SSSD @@ -196252,22 +218849,6 @@ fi - - - Log USBGuard daemon audit events using Linux Audit - - Oracle Linux 9 - - - Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf - - - - - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon @@ -196303,11 +218884,11 @@ fi Ensure that the default runlevel target is set to multi-user.target. - - - - - + + + + + @@ -196590,11 +219171,6 @@ fi Account Lockouts Must Be Logged - - - - - @@ -196618,19 +219194,8 @@ fi - - - - - - - - - - - @@ -196649,11 +219214,6 @@ fi Persist lockout account after reboot - - - - - @@ -196710,15 +219270,13 @@ fi The password retry should meet minimum requirements - - - - - - - - - + + + + + + + @@ -196742,7 +219300,7 @@ fi Oracle Linux 9 - The password hashing algorithm should be set correctly in /etc/login.defs. + The password hashing algorithm should be set correctly in /usr/etc/login.defs. @@ -196872,12 +219430,17 @@ fi The requirement for a password to boot into emergency mode should be configured correctly. - - - - - - + + + + + + + + + + + @@ -196954,27 +219517,27 @@ fi - + Set Account Expiration Following Inactivity in password-auth Oracle Linux 9 - The accounts should be configured to expire automatically following password expiration. + The accounts should be configured to be disabled automatically after a period of inactivity. - + Set Account Expiration Following Inactivity in system-auth Oracle Linux 9 - The accounts should be configured to expire automatically following password expiration. + The accounts should be configured to be disabled automatically after a period of inactivity. @@ -197481,7 +220044,7 @@ fi - + Set Interactive Session Timeout @@ -197494,6 +220057,7 @@ fi + @@ -197599,7 +220163,7 @@ fi - + @@ -197722,7 +220286,7 @@ fi Oracle Linux 9 - The default umask for all users specified in /etc/login.defs + The default umask for all users specified in {{{ login_defs_path }}} @@ -197795,19 +220359,6 @@ fi - - - Set the UEFI Boot Loader Password - - Oracle Linux 9 - - - The UEFI grub2 boot loader should have password protection enabled. - - - - - Configure Low Address Space To Protect From User Allocation @@ -197965,6 +220516,8 @@ fi + + @@ -198106,22 +220659,6 @@ fi - - - NetworkManager DNS Mode Must Be Must Configured - - Oracle Linux 9 - - - Ensure 'dns' is configured with value 'default|none in section 'main' in /etc/NetworkManager/NetworkManager.conf - - - - - - - - Ensure All World-Writable Directories Are Owned by root User @@ -198235,11 +220772,17 @@ fi - + + + + - + + + + @@ -198369,34 +220912,6 @@ fi - - - Disable core dump backtraces - - Oracle Linux 9 - - - Ensure 'ProcessSizeMax' is configured with value '0 in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - - - - Disable storing core dump - - Oracle Linux 9 - - - Ensure 'Storage' is configured with value 'none in section 'Coredump' in /etc/systemd/coredump.conf - - - - - - Disable Core Dumps for All Users @@ -198501,19 +221016,6 @@ fi - - - Configure SELinux Policy - - Oracle Linux 9 - - - The SELinux policy should be set appropriately. - - - - - Ensure SELinux State is Enforcing @@ -198544,6 +221046,20 @@ fi + + + Encrypt Partitions + + Oracle Linux 9 + + + Verify all partitions are encrypted except /boot /boot/efi + + + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles @@ -198883,31 +221399,6 @@ fi - - - The Installed Operating System Is FIPS 140-2 Certified - - Oracle Linux 9 - - - - The operating system installed on the system is a certified operating system that meets FIPS 140-2 requirements. - - - - - - - - - - - - - - - - The Installed Operating System Is Vendor Supported @@ -198920,14 +221411,19 @@ fi + + + + + @@ -199153,6 +221649,30 @@ fi + + + System Wide Crypto Policy Files Must Point to FIPS Policy + + Oracle Linux 9 + + + All system wide cryptopolicy symblinks should point to FIPS policy + + + + + + + + + + + + + + + + Set kernel parameter 'crypto.fips_enabled' to 1 @@ -199252,7 +221772,6 @@ fi cryptographic hashes. - @@ -199286,6 +221805,19 @@ fi + + + Verify crypto-policies with RPM + + Oracle Linux 9 + + + Verify the crypto-policies package using the RPM database. + + + + + Verify File Hashes with RPM @@ -199531,6 +222063,20 @@ fi + + + Ensure EPEL Repository is Disabled + + Oracle Linux 9 + + + The EPEL repository should be disabled or not present on the system. + + + + + + Ensure gpgcheck Enabled In Main yum Configuration @@ -199608,6 +222154,7 @@ fi + @@ -199625,6 +222172,7 @@ fi + @@ -199642,6 +222190,7 @@ fi + @@ -199659,6 +222208,7 @@ fi + @@ -199676,6 +222226,7 @@ fi + @@ -199693,6 +222244,7 @@ fi + @@ -199710,6 +222262,7 @@ fi + @@ -199727,6 +222280,7 @@ fi + @@ -199744,6 +222298,25 @@ fi + + + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + + Oracle Linux 9 + + + The password retry should meet minimum requirements + + + + + + + + @@ -199761,6 +222334,7 @@ fi + @@ -199778,19 +222352,8 @@ fi - - - - - - - - - - - @@ -199814,19 +222377,8 @@ fi - - - - - - - - - - - @@ -199850,19 +222402,8 @@ fi - - - - - - - - - - - @@ -200340,17 +222881,21 @@ fi + + + + @@ -200368,17 +222913,21 @@ fi + + + + @@ -200424,17 +222973,21 @@ fi + + + + @@ -200452,17 +223005,21 @@ fi + + + + @@ -200480,17 +223037,21 @@ fi + + + + @@ -200508,17 +223069,21 @@ fi + + + + @@ -200551,6 +223116,26 @@ fi + + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + + Oracle Linux 9 + + + Check if actions on '/etc/cron.d/' are configured to be audited + + + + + + + + + + + + Record Any Attempts to Run chacl @@ -200767,6 +223352,34 @@ fi + + + Ensure auditd Collects File Deletion Events by User - renameat2 + + Oracle Linux 9 + + + The deletion of files should be audited. + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects File Deletion Events by User - rmdir @@ -200851,63 +223464,187 @@ fi - + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + Oracle Linux 9 + + + The audit rules should be configured to log information about kernel module loading and unloading. + + + + + + + + + + + + + + + + + + + + + Record Attempts to Alter Logon and Logout Events - faillock Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on path specified in the 'var_accounts_passwords_pam_faillock_dir' variable are configured to be audited - + - + - + Record Attempts to Alter Logon and Logout Events - lastlog Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/lastlog' are configured to be audited - + - + - + Record Attempts to Alter Logon and Logout Events - tallylog Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/tallylog' are configured to be audited - + - + + + + + + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + Oracle Linux 9 + + + Check if actions on '/etc/selinux/' are configured to be audited + + + + + + + + + + + + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + Oracle Linux 9 + + + Check if actions on '/usr/share/selinux/' are configured to be audited + + + + + + + + + @@ -201399,6 +224136,126 @@ fi + + + Record Attempts to Alter Process and Session Initiation Information btmp + + Oracle Linux 9 + + + Check if actions on '/var/log/btmp' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information utmp + + Oracle Linux 9 + + + Check if actions on '/var/run/utmp' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + + Oracle Linux 9 + + + Check if actions on '/var/log/wtmp' are configured to be audited + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + Oracle Linux 9 + + + Check if actions on '/etc/sudoers' are configured to be audited + + + + + + + + + + + + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + Oracle Linux 9 + + + Check if actions on '/etc/sudoers.d/' are configured to be audited + + + + + + + + + + + + + + + Record Attempts to Alter the localtime File + + Oracle Linux 9 + + + Check if actions on '/etc/localtime' are configured to be audited + + + + + + + + + + + + Record Unsuccessful Access Attempts to Files - creat @@ -201622,16 +224479,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/group' are configured to be audited - + - + @@ -201642,16 +224499,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/gshadow' are configured to be audited - + - + @@ -201662,16 +224519,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/security/opasswd' are configured to be audited - + - + @@ -201682,16 +224539,16 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/passwd' are configured to be audited - + - + @@ -201702,36 +224559,56 @@ fi Oracle Linux 9 - Audit user/group modification. + Check if actions on '/etc/shadow' are configured to be audited - + - + - + + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + Oracle Linux 9 + + + Check if actions on '/var/spool/cron' are configured to be audited + + + + + + + + + + + + + Record Attempts to perform maintenance activities Oracle Linux 9 - Audit rules should be configured to log successful and unsuccessful login and logout events. + Check if actions on '/var/log/sudo.log' are configured to be audited - + - + @@ -201742,7 +224619,7 @@ fi Oracle Linux 9 - Ensure 'freq' is configured with value '50' in /etc/audit/auditd.conf + Ensure 'freq' is configured with value configured through XCCDF variable var_auditd_freq' in /etc/audit/auditd.conf @@ -201788,6 +224665,50 @@ fi + + + Log USBGuard daemon audit events using Linux Audit + + Oracle Linux 9 + + + Ensure 'AuditBackend' is configured with value 'LinuxAudit' in /etc/usbguard/usbguard-daemon.conf + + + + + + + + + + + Disable core dump backtraces + + Oracle Linux 9 + + + Ensure 'ProcessSizeMax' is configured with value '0' in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + + + + Disable storing core dump + + Oracle Linux 9 + + + Ensure 'Storage' is configured with value 'none' in section 'Coredump' in /etc/systemd/coredump.conf + + + + + + Enable the GNOME3 Screen Locking On Smartcard Removal @@ -202143,7 +225064,7 @@ fi Oracle Linux 9 - Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'HostbasedAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -202155,8 +225076,9 @@ fi - - + + + @@ -202417,19 +225339,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg is group owned by 0. - - - - - Verify /boot/grub2/user.cfg Group Ownership @@ -202873,32 +225782,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg User Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg is owned by 0. - - - - - - - - Verify /boot/grub2/user.cfg User Ownership - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/user.cfg is owned by 0. - - - - - Verify User Who Owns /etc/chrony.keys File @@ -203140,7 +226023,7 @@ fi Oracle Linux 9 - This test makes sure that /var/log/syslog is owned by 104. + This test makes sure that /var/log/syslog is owned by syslog. @@ -203398,36 +226281,6 @@ fi - - - Verify the UEFI Boot Loader grub.cfg Permissions - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/grub.cfg has mode 0700. - If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - - - - Verify /boot/grub2/user.cfg Permissions - - Oracle Linux 9 - - - This test makes sure that /boot/grub2/user.cfg has mode 0700. - If the target file or directory has an extended ACL, then it will fail the mode check. - - - - - - Verify Permissions on /etc/audit/auditd.conf @@ -203768,7 +226621,7 @@ fi Oracle Linux 9 - This test makes sure that /var/log/messages has mode 0600. + This test makes sure that /var/log/messages has mode 0640. If the target file or directory has an extended ACL, then it will fail the mode check. @@ -203850,18 +226703,18 @@ fi Oracle Linux 9 - Ensure audit_backlog_limit=8192 is configured in the kernel line in /etc/default/grub. + Ensure audit_backlog_limit is configured in the kernel line in /etc/default/grub. - + - + - + @@ -205276,7 +228129,7 @@ fi - Stack Protector buffer overlow detection + Stack Protector buffer overflow detection Oracle Linux 9 @@ -205761,24 +228614,17 @@ fi - + Add nodev Option to /home Oracle Linux 9 - /home should be mounted with mount option nodev. + Home mount points should be mounted with mount option nodev. - - - - - - - - - + + @@ -206275,6 +229121,23 @@ fi + + + NetworkManager DNS Mode Must Be Must Configured + + Oracle Linux 9 + + + Ensure 'dns' is configured with value 'none|default' in section 'main' in /etc/NetworkManager/NetworkManager.conf + + + + + + + + + Install AIDE @@ -206821,32 +229684,6 @@ fi - - - Uninstall rsh-server Package - - Oracle Linux 9 - - - The RPM package rsh-server should be removed. - - - - - - - - Uninstall rsh Package - - Oracle Linux 9 - - - The RPM package rsh should be removed. - - - - - Ensure rsyslog-gnutls is installed @@ -207003,32 +229840,6 @@ fi - - - Uninstall talk-server Package - - Oracle Linux 9 - - - The RPM package talk-server should be removed. - - - - - - - - Uninstall talk Package - - Oracle Linux 9 - - - The RPM package talk should be removed. - - - - - Uninstall telnet-server Package @@ -207494,6 +230305,22 @@ fi + + + Configure SELinux Policy + + Oracle Linux 9 + + + Ensure 'SELINUXTYPE' is configured with value configured through XCCDF variable var_selinux_policy_name' in /etc/selinux/config + + + + + + + + Disable At Service (atd) @@ -207505,9 +230332,12 @@ fi - - - + + + + + + @@ -207542,9 +230372,12 @@ fi - - - + + + + + + @@ -207559,9 +230392,12 @@ fi - - - + + + + + + @@ -207616,9 +230452,12 @@ fi - - - + + + + + + @@ -207693,9 +230532,12 @@ fi - - - + + + + + + @@ -207710,9 +230552,12 @@ fi - - - + + + + + + @@ -207727,9 +230572,12 @@ fi - - - + + + + + + @@ -207784,9 +230632,12 @@ fi - - - + + + + + + @@ -207801,9 +230652,12 @@ fi - - - + + + + + + @@ -207838,9 +230692,12 @@ fi - - - + + + + + + @@ -207875,9 +230732,12 @@ fi - - - + + + + + + @@ -207892,9 +230752,12 @@ fi - - - + + + + + + @@ -207909,9 +230772,12 @@ fi - - - + + + + + + @@ -208019,9 +230885,12 @@ fi - - - + + + + + + @@ -208085,7 +230954,7 @@ fi Oracle Linux 9 - Ensure 'Protocol' is configured with value '2' in /etc/ssh/sshd_config + Ensure 'Protocol' is configured with value '2' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208097,8 +230966,9 @@ fi - - + + + @@ -208112,7 +230982,7 @@ fi Oracle Linux 9 - Ensure 'Compression' is configured with value configured in var_sshd_disable_compression variable in /etc/ssh/sshd_config + Ensure 'Compression' is configured with value configured in var_sshd_disable_compression variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208124,8 +230994,9 @@ fi - - + + + @@ -208139,7 +231010,7 @@ fi Oracle Linux 9 - Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitEmptyPasswords' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208151,8 +231022,9 @@ fi - - + + + @@ -208166,7 +231038,7 @@ fi Oracle Linux 9 - Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'GSSAPIAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208178,8 +231050,9 @@ fi - - + + + @@ -208193,7 +231066,7 @@ fi Oracle Linux 9 - Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'KerberosAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208205,8 +231078,9 @@ fi - - + + + @@ -208220,7 +231094,7 @@ fi Oracle Linux 9 - Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PubkeyAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208232,8 +231106,9 @@ fi - - + + + @@ -208247,7 +231122,7 @@ fi Oracle Linux 9 - Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'IgnoreRhosts' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208259,8 +231134,9 @@ fi - - + + + @@ -208274,7 +231150,7 @@ fi Oracle Linux 9 - Ensure 'RhostsRSAAuthentication' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'RhostsRSAAuthentication' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208286,8 +231162,9 @@ fi - - + + + @@ -208301,7 +231178,7 @@ fi Oracle Linux 9 - Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitRootLogin' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208313,8 +231190,9 @@ fi - - + + + @@ -208328,7 +231206,7 @@ fi Oracle Linux 9 - Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config + Ensure 'PermitRootLogin' is configured with value 'prohibit-password' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208340,8 +231218,9 @@ fi - - + + + @@ -208355,7 +231234,7 @@ fi Oracle Linux 9 - Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'AllowTcpForwarding' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208367,8 +231246,9 @@ fi - - + + + @@ -208382,7 +231262,7 @@ fi Oracle Linux 9 - Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'IgnoreUserKnownHosts' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208394,8 +231274,9 @@ fi - - + + + @@ -208409,7 +231290,7 @@ fi Oracle Linux 9 - Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'X11Forwarding' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208421,8 +231302,9 @@ fi - - + + + @@ -208436,7 +231318,7 @@ fi Oracle Linux 9 - Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config + Ensure 'PermitUserEnvironment' is configured with value 'no' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208448,8 +231330,9 @@ fi - - + + + @@ -208463,7 +231346,7 @@ fi Oracle Linux 9 - Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'GSSAPIAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208475,8 +231358,9 @@ fi - - + + + @@ -208490,7 +231374,7 @@ fi Oracle Linux 9 - Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'UsePAM' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208502,8 +231386,9 @@ fi - - + + + @@ -208517,7 +231402,7 @@ fi Oracle Linux 9 - Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'PubkeyAuthentication' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208529,8 +231414,9 @@ fi - - + + + @@ -208544,7 +231430,7 @@ fi Oracle Linux 9 - Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'StrictModes' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208556,8 +231442,9 @@ fi - - + + + @@ -208571,7 +231458,7 @@ fi Oracle Linux 9 - Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config + Ensure 'Banner' is configured with value '/etc/issue' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208583,8 +231470,9 @@ fi - - + + + @@ -208598,7 +231486,7 @@ fi Oracle Linux 9 - Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config + Ensure 'Banner' is configured with value '/etc/issue.net' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208610,8 +231498,9 @@ fi - - + + + @@ -208625,7 +231514,7 @@ fi Oracle Linux 9 - Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'X11Forwarding' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208637,8 +231526,9 @@ fi - - + + + @@ -208665,7 +231555,7 @@ fi Oracle Linux 9 - Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'PrintLastLog' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208677,8 +231567,9 @@ fi - - + + + @@ -208692,7 +231583,7 @@ fi Oracle Linux 9 - Ensure 'ClientAliveCountMax' is configured with value configured in var_sshd_set_keepalive variable in /etc/ssh/sshd_config + Ensure 'ClientAliveCountMax' is configured with value configured in var_sshd_set_keepalive variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208704,8 +231595,9 @@ fi - - + + + @@ -208719,7 +231611,7 @@ fi Oracle Linux 9 - Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config + Ensure 'ClientAliveCountMax' is configured with value '0' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208731,8 +231623,9 @@ fi - - + + + @@ -208746,7 +231639,7 @@ fi Oracle Linux 9 - Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config + Ensure 'LogLevel' is configured with value 'INFO' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208758,8 +231651,9 @@ fi - - + + + @@ -208773,7 +231667,7 @@ fi Oracle Linux 9 - Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config + Ensure 'LogLevel' is configured with value 'VERBOSE' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208785,8 +231679,9 @@ fi - - + + + @@ -208800,7 +231695,7 @@ fi Oracle Linux 9 - Ensure 'UsePrivilegeSeparation' is configured with value configured in var_sshd_priv_separation variable in /etc/ssh/sshd_config + Ensure 'UsePrivilegeSeparation' is configured with value configured in var_sshd_priv_separation variable in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208812,8 +231707,9 @@ fi - - + + + @@ -208827,7 +231723,7 @@ fi Oracle Linux 9 - Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config + Ensure 'X11UseLocalhost' is configured with value 'yes' in /etc/ssh/sshd_config or in /etc/ssh/sshd_config.d @@ -208839,8 +231735,9 @@ fi - - + + + @@ -208867,7 +231764,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults noexec configuration @@ -208880,7 +231777,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults requiretty configuration @@ -208893,7 +231790,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults use_pty configuration @@ -208906,7 +231803,7 @@ fi Oracle Linux 9 - Checks sudoers Defaults {{ OPTION }} configuration + Checks sudoers Defaults logfile configuration @@ -210102,7 +232999,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210116,7 +233013,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210129,7 +233026,7 @@ fi - Drop Gratuitious ARP frames on All IPv4 Interfaces + Drop Gratuitous ARP frames on All IPv4 Interfaces Oracle Linux 9 @@ -210297,10 +233194,10 @@ fi Oracle Linux 9 - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system runtime. + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to the appropriate value in the system runtime. - + @@ -210310,13 +233207,13 @@ fi Oracle Linux 9 - The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to 1 or 2 in the system configuration. + The kernel 'net.ipv4.conf.all.rp_filter' parameter should be set to the appropriate value in the system configuration. - + - + @@ -210542,7 +233439,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -210556,7 +233453,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -210569,7 +233466,7 @@ fi - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default Oracle Linux 9 @@ -212162,7 +235059,7 @@ fi - Record Any Attempts to Run semanage + Test if auditctl is in use for audit rules Oracle Linux 9 @@ -212175,7 +235072,7 @@ fi - Record Any Attempts to Run semanage + Test if augenrules is enabled for audit rules Oracle Linux 9 @@ -212199,18 +235096,18 @@ fi - + - + - + - + @@ -212228,18 +235125,18 @@ fi - + - + - + - + @@ -212285,6 +235182,10 @@ fi + + + + @@ -212315,6 +235216,22 @@ fi + + + AlmaLinux OS 9 + + Oracle Linux 9 + + + + The operating system installed on the system is AlmaLinux OS 9 + + + + + + + Oracle Linux 7 @@ -212382,21 +235299,25 @@ fi - + - Red Hat Enterprise Linux CoreOS + Red Hat Enterprise Linux 10 Oracle Linux 9 - - + + The operating system installed on the system is - Red Hat Enterprise Linux CoreOS release 4 + Red Hat Enterprise Linux 10 - - - + + + + + + + @@ -212494,6 +235415,25 @@ fi + + + SUSE Linux Enterprise 16 + + Oracle Linux 9 + + + + The operating system installed on the system is SUSE Linux Enterprise Server 16. + + + + + + + + + + SUSE Linux Enterprise Micro @@ -212516,6 +235456,25 @@ fi + + + SUSE Linux Enterprise Micro + + Oracle Linux 9 + + + + + The operating system installed on the system is + SUSE Linux Micro. + + + + + + + + Ubuntu @@ -212531,49 +235490,19 @@ fi - + - Ubuntu 16.04 LTS + Ubuntu 24.04 LTS Oracle Linux 9 - - - The operating system installed on the system is Ubuntu 16.04 LTS + + + The operating system installed on the system is Ubuntu 24.04 LTS - + - - - - - - Ubuntu 18.04 LTS - - Oracle Linux 9 - - - - The operating system installed on the system is Ubuntu 18.04 LTS - - - - - - - - - Ubuntu 20.04 LTS - - Oracle Linux 9 - - - - The operating system installed on the system is Ubuntu 20.04 LTS - - - - + @@ -212803,65 +235732,29 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -212887,18 +235780,6 @@ fi - - - - - - - - - - - - @@ -212937,11 +235818,17 @@ fi - - + + - - + + + + + + + + @@ -212966,14 +235853,6 @@ fi - - - - - - - - @@ -213006,42 +235885,6 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -213108,12 +235951,6 @@ fi - - - - - - @@ -213157,6 +235994,10 @@ fi + + + + @@ -213259,7 +236100,7 @@ fi - + @@ -213275,6 +236116,9 @@ fi + + + @@ -213299,9 +236143,15 @@ fi - - - + + + + + + + + + @@ -213325,7 +236175,7 @@ fi - + @@ -213354,11 +236204,28 @@ fi + + + + + + + + + + + + + + + + + @@ -213367,6 +236234,11 @@ fi + + + + + @@ -213375,6 +236247,11 @@ fi + + + + + @@ -213383,6 +236260,11 @@ fi + + + + + @@ -213401,10 +236283,6 @@ fi - - - - @@ -213441,21 +236319,17 @@ fi - - - - - - - - - + + - - + + - - + + + + + @@ -213613,71 +236487,33 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -213685,9 +236521,6 @@ fi - - - @@ -213702,22 +236535,11 @@ fi - - - - - - - - - - - @@ -213775,6 +236597,9 @@ fi + + + @@ -214029,6 +236854,10 @@ fi + + + + @@ -214136,9 +236965,6 @@ fi - - - @@ -214246,6 +237072,12 @@ fi + + + + + + @@ -214263,7 +237095,7 @@ fi - + @@ -214305,13 +237137,6 @@ fi - - - - - - - @@ -214352,6 +237177,9 @@ fi + + + @@ -214401,22 +237229,6 @@ fi - - - - - - - - - - - - - - - - @@ -214425,7 +237237,7 @@ fi - + @@ -214462,10 +237274,6 @@ fi - - - - @@ -214482,6 +237290,12 @@ fi + + + + + + @@ -214556,6 +237370,7 @@ fi + @@ -214688,6 +237503,54 @@ fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -214759,6 +237622,9 @@ fi + + + @@ -214852,6 +237718,13 @@ fi + + + + + + + @@ -214872,6 +237745,9 @@ fi + + + @@ -214879,6 +237755,9 @@ fi + + + @@ -214886,6 +237765,9 @@ fi + + + @@ -214893,6 +237775,9 @@ fi + + + @@ -214900,6 +237785,9 @@ fi + + + @@ -214908,6 +237796,9 @@ fi + + + @@ -214915,6 +237806,9 @@ fi + + + @@ -214922,6 +237816,9 @@ fi + + + @@ -214929,13 +237826,30 @@ fi + + + + + + + + + + + + + + + + + @@ -214943,123 +237857,52 @@ fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -215232,6 +238075,18 @@ fi + + + + + + + + + + + + @@ -215244,6 +238099,18 @@ fi + + + + + + + + + + + + @@ -215268,6 +238135,18 @@ fi + + + + + + + + + + + + @@ -215280,6 +238159,18 @@ fi + + + + + + + + + + + + @@ -215292,6 +238183,18 @@ fi + + + + + + + + + + + + @@ -215304,6 +238207,18 @@ fi + + + + + + + + + + + + @@ -215316,6 +238231,12 @@ fi + + + + + + @@ -215388,6 +238309,18 @@ fi + + + + + + + + + + + + @@ -215424,23 +238357,71 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -215592,6 +238573,42 @@ fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -215736,41 +238753,47 @@ fi - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - + + + + + + + + @@ -215791,6 +238814,29 @@ fi + + + + + + + + + + + + + + + + + + + + + + + @@ -215932,6 +238978,10 @@ fi + + + + @@ -216043,9 +239093,6 @@ fi - - - @@ -216151,12 +239198,6 @@ fi - - - - - - @@ -216280,12 +239321,6 @@ fi - - - - - - @@ -216386,15 +239421,15 @@ fi - + - + - + @@ -217360,20 +240395,10 @@ fi - - - + + + - - - - - - - - - - @@ -217664,6 +240689,17 @@ fi + + + + + + + + + + + @@ -217790,12 +240826,6 @@ fi - - - - - - @@ -217832,12 +240862,6 @@ fi - - - - - - @@ -217865,9 +240889,6 @@ fi - - - @@ -217960,6 +240981,13 @@ fi + + + + + + + @@ -217968,6 +240996,10 @@ fi + + + + @@ -217994,6 +241026,10 @@ fi + + + + @@ -218005,6 +241041,10 @@ fi + + + + @@ -218046,6 +241086,10 @@ fi + + + + @@ -218102,6 +241146,10 @@ fi + + + + @@ -218113,6 +241161,10 @@ fi + + + + @@ -218124,6 +241176,10 @@ fi + + + + @@ -218165,6 +241221,10 @@ fi + + + + @@ -218176,6 +241236,10 @@ fi + + + + @@ -218202,6 +241266,10 @@ fi + + + + @@ -218228,6 +241296,10 @@ fi + + + + @@ -218239,6 +241311,10 @@ fi + + + + @@ -218250,6 +241326,10 @@ fi + + + + @@ -218325,6 +241405,10 @@ fi + + + + @@ -218369,6 +241453,10 @@ fi + + + + @@ -218380,6 +241468,10 @@ fi + + + + @@ -218391,6 +241483,10 @@ fi + + + + @@ -218402,6 +241498,10 @@ fi + + + + @@ -218413,6 +241513,10 @@ fi + + + + @@ -218424,6 +241528,10 @@ fi + + + + @@ -218435,6 +241543,10 @@ fi + + + + @@ -218446,6 +241558,10 @@ fi + + + + @@ -218457,6 +241573,10 @@ fi + + + + @@ -218468,6 +241588,10 @@ fi + + + + @@ -218479,6 +241603,10 @@ fi + + + + @@ -218490,6 +241618,10 @@ fi + + + + @@ -218501,6 +241633,10 @@ fi + + + + @@ -218512,6 +241648,10 @@ fi + + + + @@ -218523,6 +241663,10 @@ fi + + + + @@ -218534,6 +241678,10 @@ fi + + + + @@ -218545,6 +241693,10 @@ fi + + + + @@ -218556,6 +241708,10 @@ fi + + + + @@ -218567,6 +241723,10 @@ fi + + + + @@ -218578,6 +241738,10 @@ fi + + + + @@ -218589,6 +241753,10 @@ fi + + + + @@ -218603,6 +241771,10 @@ fi + + + + @@ -218614,6 +241786,10 @@ fi + + + + @@ -218625,6 +241801,10 @@ fi + + + + @@ -218636,6 +241816,10 @@ fi + + + + @@ -218647,6 +241831,10 @@ fi + + + + @@ -218658,6 +241846,10 @@ fi + + + + @@ -218669,6 +241861,10 @@ fi + + + + @@ -219159,23 +242355,20 @@ fi - + - - + - - + - - + @@ -219795,29 +242988,29 @@ fi - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -219840,6 +243033,13 @@ fi + + + + + + + @@ -219847,6 +243047,12 @@ fi + + + + + + @@ -219863,13 +243069,17 @@ fi - - - - - - - + + + + + + + + + + + @@ -219939,6 +243149,22 @@ fi + + + + + + + + + + + + + + + + @@ -219951,20 +243177,22 @@ fi + + + + + + + + - - - - - - - - + + @@ -220050,106 +243278,46 @@ fi ^\-w[\s]+/etc/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/usr/share/selinux/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/issue[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/issue\.net[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/hosts[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + /etc/audit/audit.rules ^\-w[\s]+/etc/sysconfig/network[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/run/utmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/btmp\s+\-p\s+wa\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w\s+/var/log/wtmp\s+\-p\s+wa\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/?[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+-S[\s]+execve[\s]+-C[\s]+uid!=euid[\s]+-F[\s]+euid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -220190,26 +243358,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+-S[\s]+execve[\s]+-C[\s]+gid!=egid[\s]+-F[\s]+egid=0[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^\-w[\s]+/etc/sudoers\.d/[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - ^/etc/audit/rules\.d/.*\.rules$ ^\-f\s+(\d)\s*$ @@ -220270,15 +243418,25 @@ fi ^\-w[\s]+/etc/security/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ - - 1 + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 - - /etc/audit/audit.rules - - 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b64[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 @@ -220323,18 +243481,6 @@ fi oval:ssg-state_not_mode_0700:ste:1 - - - /var/log/audit - - oval:ssg-state_not_mode_0750:ste:1 - - - - - - oval:ssg-state_not_mode_0750:ste:1 - oval:ssg-state_group_owner_not_root_var_log_audit:ste:1 @@ -220385,66 +243531,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount[\s]+|([\s]+|[,])umount([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - 1 - ^(?!/proc(/.*|$)).*$ oval:ssg-state_audit_rules_privileged_commands_dev_partitons:ste:1 @@ -220560,16 +243646,6 @@ fi ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+arch=b32.*(-S[\s]+stime[\s]+|([\s]+|[,])stime([\s]+|[,])).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - ^/etc/audit/rules\.d/.*\.rules$ - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - - - /etc/audit/audit.rules - ^[\s]*-w[\s]+\/etc\/localtime[\s]+-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - 1 - /etc/audit/plugins.d/syslog.conf ^[ ]*active[ ]+=[ ]+yes[ ]*$ @@ -220598,13 +243674,18 @@ fi /etc/audit/auditd.conf ^[ ]*action_mail_acct[ ]+=[ ]+(\S+)[ ]*$ - 1 + 1 /etc/audit/auditd.conf ^[ ]*admin_space_left_action[ ]+=[ ]+(\S+)[ ]*$ 1 + + /etc/audit/auditd.conf + ^[\s]*admin_space_left[\s]+=[\s]+(\d+)%[\s]*$ + 1 + /etc/audit/auditd.conf ^[ ]*flush[ ]+=[ ]+(\S+)[ ]*$ @@ -220740,12 +243821,12 @@ fi 0 - ^/etc/chrony\.(conf|d/.+\.conf)$ + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ ^[\s]*server.*$ 1 - - ^/etc/chrony\.(conf|d/.+\.conf)$ + + ^(/etc/chrony\.conf|/etc/chrony\.d/.+\.conf)$ ^[\s]+pool.*$ 1 @@ -220759,6 +243840,9 @@ fi ^\s*group:\s+(.*)$ 1 + + nss-altfiles + /etc/chrony.keys oval:ssg-state_file_groupowner_etc_chrony_keys_uid_chrony:ste:1 @@ -220766,7 +243850,7 @@ fi /etc/group - ^chrony:\w+:(\w+):.* + ^chrony:[\w!]+:(\w+):.* 1 @@ -220782,7 +243866,7 @@ fi /usr/lib/group - ^chrony:\w+:(\w+):.* + ^chrony:[\w!]+:(\w+):.* 1 @@ -220813,9 +243897,15 @@ fi / .shosts - - /etc/xinetd.d/tftp - ^[\s]*server_args[\s]+=[\s]+.*?-s[\s]+([/\.\w]+).*$ + + /etc/systemd/system/tftp.service.d + .*\.conf$ + ^\s*ExecStart=\s*(?:.*\n)*?(\s*ExecStart=.+)$ + 1 + + + /usr/lib/systemd/system/tftp.service + ^\s*ExecStart\s*=\s*/\S+\s+-s\s+(/\S+).*$ 1 @@ -220912,14 +244002,37 @@ fi ^[\s]*RekeyLimit[\s]+(.*)$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[\s]*RekeyLimit[\s]+(.*)$ + 1 + /etc/ssh/sshd_config ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + + + /etc/ssh/sshd_config + (?i)^\s*Include\s+(.*)$ + 1 + + + + ^[\s]*(?i)ClientAliveInterval[\s]+(\d+)[\s]*(?:#.*)?$ + 1 + oval:ssg-object_sshd_idle_timeout:obj:1 + oval:ssg-object_sshd_idle_timeout_config_dir:obj:1 @@ -220927,9 +244040,16 @@ fi ^[\s]*(?i)LoginGraceTime[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LoginGraceTime(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_login_grace_time:obj:1 + oval:ssg-obj_sshd_set_login_grace_time_config_dir:obj:1 @@ -220937,9 +244057,16 @@ fi ^[\s]*(?i)MaxAuthTries[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)MaxAuthTries(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_max_auth_tries:obj:1 + oval:ssg-obj_sshd_set_max_auth_tries_config_dir:obj:1 @@ -220947,9 +244074,16 @@ fi ^[\s]*(?i)MaxSessions[\s]+(\d+)[\s]*(?:#.*)?$ 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)MaxSessions(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-object_sshd_max_sessions:obj:1 + oval:ssg-obj_sshd_set_max_sessions_config_dir:obj:1 @@ -220975,14 +244109,6 @@ fi ^[ \t]*(?i)match(?-i)\s+\S+ 1 - - oval:ssg-var_sshd_config_strong_macs:var:1 - - - /etc/ssh/sshd_config - ^[\s]*(?i)MACs(?-i)[\s]+([\w,-@]+)+[\s]*(?:#.*)?$ - 1 - ^/etc/sssd/(sssd|conf\.d/.*)\.conf$ ^[\s]*\[sssd](?:[^\n\[]*\n+)+?[\s]*certificate_verification\s*=\s*ocsp_dgst=(\w+)$ @@ -221028,21 +244154,16 @@ fi ^[\s]*\[domain\/[^]]*](?:[^\n\[\]]*\n+)+?[\s]*ldap_id_use_start_tls[ \t]*=[ \t]*((?i)\w+)[ \t]*$ 1 - - /etc/usbguard/usbguard-daemon.conf - ^[ \t]*AuditBackend=(.+?)[ \t]*(?:$|#) - 1 - - - ^/etc/usbguard/usbguard-daemon.conf - - + xorg-x11-server-Xorg - + + xorg-x11-server-common + + xorg-x11-server-utils - + xorg-x11-server-Xwayland @@ -221115,7 +244236,7 @@ fi /etc/pam.d/postlogin - ^\s*session\s+.*\s+pam_lastlog\.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$ + ^\s*session\s+.*\s+pam_lastlog.so\b(?!.*\ssilent\s).*\sshowfailed\s.*$ 1 @@ -221149,7 +244270,7 @@ fi 1 - /etc/pam.d/password-auth|/etc/pam.d/system-auth|/etc/security/faillock.conf + /etc/security/faillock.conf ^\s*(?:auth.*pam_faillock\.so.*)?dir\s*=\s*(\S+) 1 @@ -221250,26 +244371,6 @@ fi 1 - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/system-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - - - ^/etc/pam.d/password-auth$ - - 1 - ^/etc/pam.d/system-auth$ @@ -221297,19 +244398,13 @@ fi 1 oval:ssg-state_pam_faillock_dir_parameter_not_default_value:ste:1 - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_system_auth:var:1 - - - oval:ssg-var_faillock_dir_set_both_preauth_authfail_password_auth:var:1 - /etc/security/faillock.conf 1 - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^enforce_for_root$ 1 @@ -221333,11 +244428,6 @@ fi ^\s*password\s+(?:(?:required)|(?:requisite))\s+pam_pwquality\.so.*retry=([0-9]*).*$ 1 - - /etc/security/pwquality.conf - ^[\s]*retry[\s]*=[\s]*(\d+)(?:[\s]|$) - 1 - /etc/libuser.conf ^[\s]*crypt_style[\s]*=[\s]*(\w*)[\s]*$ @@ -221416,6 +244506,12 @@ fi ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency 1 + + /etc/systemd/system/emergency.service.d + ^.*\.conf$ + ^ExecStart=\-/usr/lib/systemd/systemd-sulogin-shell[\s]+emergency + 1 + /usr/lib/systemd/system/emergency.target ^Requires=.*emergency\.service @@ -221601,7 +244697,7 @@ fi ^/etc/pam.d/password-auth$ - ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so.*rounds=([0-9]*).*$ + ^\s*password\s+(?:(?:sufficient)|(?:required))\s+pam_unix\.so[^#]*rounds=([0-9]*).*$ 1 @@ -222107,7 +245203,7 @@ fi /boot/grub2/grub.cfg - ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)"$ + ^[\s]*set[\s]+superusers="(?i)\b(?!(?:root|admin|administrator)\b)(\w+)".*\n[\s]*export[\s]+superusers[\s]*$ 1 @@ -222115,11 +245211,6 @@ fi ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ 1 - - /boot/grub2/user.cfg - ^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$ - 1 - ^/boot/config-.*$ ^CONFIG_DEFAULT_MMAP_MIN_ADDR="?(.*?)"?$ @@ -222149,7 +245240,7 @@ fi /etc/rsyslog.conf - (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + (?ms)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ 1 @@ -222161,18 +245252,18 @@ fi /etc/rsyslog.d ^.*$ - (?m)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ + (?ms)^\s*cron\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfile"\s*.*(?i)\bfile\b(?-i)="/var/log/cron"\s*.*\)\s*$ 1 /etc/rsyslog.conf - (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + (?ms)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ 1 /etc/rsyslog.d ^.*$ - (?m)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ + (?ms)^[\s]*\*\.\*[\s]+(/var/log/messages|action\(\s*.*(?i:\btype\b)="omfile"\s*.*(?i:\bfile\b)="/var/log/messages"\s*\))\s*(?:#.*)?$ 1 @@ -222182,7 +245273,7 @@ fi /etc/rsyslog.conf - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ 1 @@ -222194,7 +245285,7 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverAuthMode\b(?-i)="x509/name".*\)\s*$ 1 @@ -222204,7 +245295,7 @@ fi /etc/rsyslog.conf - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ 1 @@ -222216,7 +245307,7 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ + (?ms)^\s*action\(.*(?i)\btype\b(?-i)="omfwd".*(?i)\bStreamDriverMode\b(?-i)="1".*\)\s*$ 1 @@ -222226,7 +245317,7 @@ fi /etc/rsyslog.conf - ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + (?ms)^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ 1 @@ -222238,22 +245329,22 @@ fi /etc/rsyslog.d ^.*conf$ - ^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ + (?ms)^\s*global\(.*(?i)\bDefaultNetStreamDriver\b(?-i)="gtls".*\)\s*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*auth\.\*.*$ + ^[^#\n]*auth(,\w+)*\.\*[^\n]*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*authpriv\.\*.*$ + ^[^#\n]*authpriv(,\w+)*\.\*[^\n]*$ 1 ^/etc/rsyslog\.(conf|d/.+\.conf)$ - ^[^#]*daemon\.\*.*$ + ^[^#\n]*daemon(,\w+)*\.\*[^\n]*$ 1 @@ -222296,6 +245387,17 @@ fi ^\*\.\*[\s]+(?:@|\:omrelp\:) 1 + + /etc/rsyslog.conf + (?ms)^\s*\*\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfwd"\s*.*(?i)\btarget\b(?-i)="\S+"\s*.*\)\s*$ + 1 + + + /etc/rsyslog.d + ^.+\.conf$ + (?ms)^\s*\*\.\*\s+action\(\s*.*(?i)\btype\b(?-i)="omfwd"\s*.*(?i)\btarget\b(?-i)="\S+"\s*.*\)\s*$ + 1 + ^/etc/rsyslog\.(conf|d/.+\.conf)$ @@ -222373,14 +245475,6 @@ fi ^wl.*$ - - /etc/NetworkManager/NetworkManager.conf - ^\s*\[main\].*(?:\n\s*[^[\s].*)*\ndns=([^#]*).*$ - 1 - - - ^/etc/NetworkManager/NetworkManager.conf - / @@ -222537,6 +245631,9 @@ fi ^\s*group:\s+(.*)$ 1 + + nss-altfiles + .* @@ -222554,6 +245651,7 @@ fi ^\/s?bin|^\/usr\/s?bin|^\/usr\/local\/s?bin ^.*$ oval:ssg-state_groupowner_system_commands_dirs_not_root_or_system_account:ste:1 + oval:ssg-state_groupowner_system_commands_dirs_symlink:ste:1 ^\/(|s)bin|^\/usr\/(|local\/)(|s)bin|^\/usr\/libexec @@ -222642,37 +245740,15 @@ fi ^[[:blank:]]*kernel.core_pattern[[:blank:]]*=[[:blank:]]*(.*)$ 1 - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)ProcessSizeMax(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - - - /etc/systemd/coredump.conf.d - .*\.conf$ - ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*(?i)Storage(?-i)[ \t]*=[ \t]*(.+?)[ \t]*(?:$|#) - 1 - /etc/security/limits.conf - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\S]+) 1 /etc/security/limits.d ^.*\.conf$ - ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\d]+) + ^[\s]*\*[\s]+(?:hard|-)[\s]+core[\s]+([\S]+) 1 @@ -222682,7 +245758,7 @@ fi 1 - /boot/grub2/grub.cfg + /etc/default/grub [\s]*noexec[\s]*=[\s]*off 1 @@ -222737,11 +245813,6 @@ fi ^SELINUX=(.*)$ 1 - - /etc/selinux/config - ^SELINUXTYPE=([\w]*)[\s]*$ - 1 - /etc/selinux/config ^SELINUX=(.*)$ @@ -222760,6 +245831,17 @@ fi ^.*\.(.*)$ 1 + + ^(?!\/boot(?:\/efi)?$).* + oval:ssg-state_encrypted_partitions:ste:1 + oval:ssg-state_non_temporary_partitions:ste:1 + oval:ssg-state_non_pseudo_file_systems:ste:1 + + + /etc/crypttab + ^\s*(\S+) + 1 + /etc/dconf/db/local @@ -223055,7 +246137,7 @@ fi /etc/crypto-policies/back-ends/opensshserver.config ^(?!#).*Ciphers\s+([^\s']+).*$ - 1 + -1 /etc/crypto-policies/back-ends/openssh.config @@ -223064,8 +246146,8 @@ fi /etc/crypto-policies/back-ends/opensshserver.config - ^(?!#).*(-oMACs=\S+).+$ - 1 + ^(?!#).*MACs\s+([^\s']+).*$ + -1 ^mfetpd.*$ @@ -223092,12 +246174,48 @@ fi /etc/system-fips + + /etc/crypto-policies/back-ends/bind.config + + + /etc/crypto-policies/back-ends/gnutls.config + + + /etc/crypto-policies/back-ends/java.config + + + /etc/crypto-policies/back-ends/javasystem.config + + + /etc/crypto-policies/back-ends/krb5.config + + + /etc/crypto-policies/back-ends/libreswan.config + + + /etc/crypto-policies/back-ends/libssh.config + + + /etc/crypto-policies/back-ends/openssh.config + + + /etc/crypto-policies/back-ends/opensshserver.config + + + /etc/crypto-policies/back-ends/opensslcnf.config + + + /etc/crypto-policies/back-ends/openssl.config + + + /etc/crypto-policies/back-ends/openssl_fips.config + crypto.fips_enabled /etc/aide.conf - ^database=file:@@{DBDIR}/([a-z.]+)$ + ^database=file:(?:@@{DBDIR})?/(?:[a-z.]+/)*([a-z.]+)$ 1 @@ -223110,37 +246228,37 @@ fi /etc/aide.conf - ^\/usr\/sbin\/auditctl\s+([^\n]+)$ + ^(?:/usr)?/sbin/auditctl\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/auditd\s+([^\n]+)$ + ^(?:/usr)?/sbin/auditd\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/ausearch\s+([^\n]+)$ + ^(?:/usr)?/sbin/ausearch\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/aureport\s+([^\n]+)$ + ^(?:/usr)?/sbin/aureport\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/autrace\s+([^\n]+)$ + ^(?:/usr)?/sbin/autrace\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/rsyslogd\s+([^\n]+)$ + ^(?:/usr)?/sbin/rsyslogd\s+([^\n]+)$ 1 /etc/aide.conf - ^/usr/sbin/augenrules\s+([^\n]+)$ + ^(?:/usr)?/sbin/augenrules\s+([^\n]+)$ 1 @@ -223201,6 +246319,15 @@ fi ^(?!ALLXTRAHASHES)[A-Z][a-zA-Z_]*[\s]*=[\s]*([a-zA-Z0-9\+]*)$ 1 + + crypto-policies + .* + .* + .* + .* + .* + oval:ssg-state_rpm_verify_crypto_policies:ste:1 + .* @@ -223363,6 +246490,16 @@ fi ^/etc/dnf/automatic.conf + + ^/etc/yum\.repos\.d/.*\.repo$ + (?i)^\s*\[[^\]]*epel[^\]]*\] + 1 + + + ^/etc/yum\.repos\.d/.*\.repo$ + (?i)(?:^\s*\[[^\]]*epel[^\]]*\][\s\S]*?)^\s*enabled\s*=\s*(\S+) + 1 + /etc/yum.conf ^\s*gpgcheck\s*=\s*(1|True|yes)\s*$ @@ -223387,8 +246524,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdcredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdcredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*dcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223397,8 +246539,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdictcheck\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdictcheck\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*dictcheck[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223407,8 +246554,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bdifok\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bdifok\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*difok[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223417,8 +246569,13 @@ fi ^\s*password.*pam_pwquality\.so.*\blcredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\blcredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*lcredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223427,8 +246584,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bmaxclassrepeat\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*maxclassrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223437,8 +246599,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bmaxrepeat\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*maxrepeat[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223447,8 +246614,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bminclass\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bminclass\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*minclass[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223457,8 +246629,13 @@ fi ^\s*password.*pam_pwquality\.so.*\bminlen\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bminlen\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*minlen[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223467,18 +246644,43 @@ fi ^\s*password.*pam_pwquality\.so.*\bocredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bocredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*ocredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 + + /etc/pam.d/system-auth + ^\s*password.*pam_pwquality\.so.*\bretry\b + 1 + + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bretry\b + 1 + + + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ + ^\s*retry[\s]*=[\s]*(-?\d+)(?:[\s]|$) + 1 + /etc/pam.d/system-auth ^\s*password.*pam_pwquality\.so.*\bucredit\b 1 + + /etc/pam.d/password-auth + ^\s*password.*pam_pwquality\.so.*\bucredit\b + 1 + - ^/etc/security/pwquality\.conf$ + ^/etc/security/pwquality\.conf(\.d/[^/]+\.conf)?$ ^\s*ucredit[\s]*=[\s]*(-?\d+)(?:[\s]|$) 1 @@ -223487,31 +246689,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223532,31 +246714,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223577,31 +246739,11 @@ fi 1 - - /etc/pam.d/system-auth - - 1 - /etc/pam.d/password-auth 1 - - /etc/pam.d/password-auth - - 1 - - - /etc/pam.d/system-auth - - 1 - - - /etc/pam.d/password-auth - - 1 - /etc/pam.d/system-auth @@ -223719,7 +246861,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/init(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223729,7 +246871,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/poweroff(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223739,7 +246881,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/reboot(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223749,7 +246891,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/shutdown(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -223893,6 +247035,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fremovexattr[\s]+|([\s]+|[,])fremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223913,6 +247075,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+fsetxattr[\s]+|([\s]+|[,])fsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lchown[\s]+|([\s]+|[,])lchown([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223953,6 +247135,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lremovexattr[\s]+|([\s]+|[,])lremovexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223973,6 +247175,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+lsetxattr[\s]+|([\s]+|[,])lsetxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -223993,6 +247215,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+removexattr[\s]+|([\s]+|[,])removexattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224013,6 +247255,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setxattr[\s]+|([\s]+|[,])setxattr([\s]+|[,])))(?:.*-F\s+auid=0[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224033,13 +247295,23 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+umount2[\s]+|([\s]+|[,])umount2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224049,7 +247321,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chcon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224059,7 +247331,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/restorecon(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224069,7 +247341,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/semanage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224079,7 +247351,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/setfacl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224089,7 +247361,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setfiles(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224099,7 +247371,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/setsebool(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224109,7 +247381,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/seunshare(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224153,6 +247425,26 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat[\s]+|([\s]+|[,])renameat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+renameat2[\s]+|([\s]+|[,])renameat2([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+rmdir[\s]+|([\s]+|[,])rmdir([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ @@ -224213,34 +247505,114 @@ fi ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+unlinkat[\s]+|([\s]+|[,])unlinkat([\s]+|[,])))(?:.*-F\s+auid>=1000[\s]+)(?:.*-F\s+auid!=(?:4294967295|unset)[\s]+).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - - /etc/audit/audit.rules - - 1 - - + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+delete_module[\s]+|([\s]+|[,])delete_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + ^/etc/audit/rules\.d/.*\.rules$ - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + /etc/audit/audit.rules - + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+finit_module[\s]+|([\s]+|[,])finit_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + /etc/audit/audit.rules + ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+init_module[\s]+|([\s]+|[,])init_module([\s]+|[,]))).*(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295))\s+(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + 1 @@ -224269,7 +247641,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/at(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224279,7 +247651,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chage(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224289,7 +247661,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/chsh(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224299,7 +247671,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/crontab(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224309,7 +247681,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/gpasswd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224319,7 +247691,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/kmod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224329,7 +247701,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/mount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224339,7 +247711,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/newgrp(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224349,7 +247721,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/pam_timestamp_check(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224359,7 +247731,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/passwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224369,7 +247741,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postdrop(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224379,7 +247751,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/postqueue(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224389,7 +247761,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/ssh-agent(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224399,7 +247771,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/libexec\/openssh\/ssh-keysign(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224409,7 +247781,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/su(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224419,7 +247791,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudo(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224429,7 +247801,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/sudoedit(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224439,7 +247811,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/bin\/umount(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224449,7 +247821,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_chkpwd(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224459,7 +247831,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/unix_update(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224469,7 +247841,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/userhelper(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224479,7 +247851,7 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usermod(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -224489,10 +247861,70 @@ fi 1 - /etc/audit/audit.rules + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+-F[\s]+path=\/usr\/sbin\/usernetctl(?:[\s]+-F[\s]+perm=x)[\s]+-F[\s]+auid>=1000[\s]+-F[\s]+auid!=(?:4294967295|unset|-1)[\s]+(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + + 1 + ^/etc/audit/rules\.d/.*\.rules$ @@ -224733,64 +248165,74 @@ fi 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/group[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/gshadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/security\/opasswd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/passwd[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 /etc/audit/audit.rules - ^\-w[\s]+\/etc\/shadow[\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + 1 - + ^/etc/audit/rules\.d/.*\.rules$ - + 1 - + /etc/audit/audit.rules - + + 1 + + + ^/etc/audit/rules\.d/.*\.rules$ + + 1 + + + /etc/audit/audit.rules + 1 @@ -224818,6 +248260,36 @@ fi ^[ \t]*(?i)write_logs(?-i)[ \t]*=[ \t]* 1 + + /etc/usbguard/usbguard-daemon.conf + ^[ \\t]*AuditBackend=(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/usbguard/usbguard-daemon.conf + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*ProcessSizeMax\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*ProcessSizeMax\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*Storage\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/systemd/coredump.conf.d + .*\.conf$ + ^\s*\[Coredump\].*(?:\n\s*[^[\s].*)*\n^[ \t]*Storage\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + /etc/dconf/db/local.d/ ^.*$ @@ -224834,99 +248306,99 @@ fi /lib - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /lib64 - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /usr/lib - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_2:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /usr/lib64 - oval:ssg-symlink_file_groupownerdir_group_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_gid_0_3:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdir_group_ownership_library_dirs_0_0:ste:1 /bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/local/bin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_4:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /usr/local/sbin - oval:ssg-symlink_file_ownerdir_ownership_binary_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_binary_dirs_uid_0_5:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_binary_dirs_0_0:ste:1 /lib - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /lib64 - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /usr/lib - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 /usr/lib64 - oval:ssg-symlink_file_ownerdir_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownerdir_ownership_library_dirs_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdir_ownership_library_dirs_0_0:ste:1 @@ -224998,107 +248470,173 @@ fi oval:ssg-exclude_symlinks_dir_permissions_library_dirs:ste:1 oval:ssg-state_file_permissionsdir_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 - - /etc/ipsec.d - - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_ipsecd_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_ipsecd_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_ipsecd_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_ipsecd_root_gid_usr:obj:1 + + + + /etc/ipsec.d + + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_ipsecd_0_root:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_iptables_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_iptables_root_gid_usr:obj:1 + + /etc/iptables - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_iptables_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_iptables_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_iptables_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_nftables_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_nftables_root_gid_usr:obj:1 + + /etc/nftables - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_nftables_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_nftables_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_nftables_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_selinux_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_selinux_root_gid_usr:obj:1 + + /etc/selinux - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_selinux_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_selinux_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_selinux_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sudoersd_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sudoersd_root_gid_usr:obj:1 + + /etc/sudoers.d - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sudoersd_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_sudoersd_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sudoersd_0_root:ste:1 - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sysctld_root_gid_etc:obj:1 + oval:ssg-object_file_groupownerdirectory_groupowner_etc_sysctld_root_gid_usr:obj:1 + + /etc/sysctl.d - oval:ssg-symlink_file_groupownerdirectory_groupowner_etc_sysctld_uid_root:ste:1 - oval:ssg-state_file_groupownerdirectory_groupowner_etc_sysctld_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerdirectory_groupowner_etc_sysctld_0_root:ste:1 - - /etc/group - ^root:\w+:(\w+):.* - 1 - /etc/ipsec.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_ipsecd_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_ipsecd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_ipsecd_0_0:ste:1 /etc/iptables - oval:ssg-symlink_file_ownerdirectory_owner_etc_iptables_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_iptables_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_iptables_0_0:ste:1 /etc/nftables - oval:ssg-symlink_file_ownerdirectory_owner_etc_nftables_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_nftables_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_nftables_0_0:ste:1 /etc/selinux - oval:ssg-symlink_file_ownerdirectory_owner_etc_selinux_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_selinux_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_selinux_0_0:ste:1 /etc/sudoers.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_sudoersd_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_sudoersd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sudoersd_0_0:ste:1 /etc/sysctl.d - oval:ssg-symlink_file_ownerdirectory_owner_etc_sysctld_uid_0:ste:1 - oval:ssg-state_file_ownerdirectory_owner_etc_sysctld_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerdirectory_owner_etc_sysctld_0_0:ste:1 /etc/ipsec.d @@ -225151,10 +248689,16 @@ fi ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)HostbasedAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_disable_host_auth:obj:1 - oval:ssg-obj_disable_host_auth_sshd_included_files:obj:1 + oval:ssg-obj_disable_host_auth_config_dir:obj:1 @@ -225162,73 +248706,73 @@ fi /sbin/auditctl - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/aureport - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/ausearch - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_2:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/autrace - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_3:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/auditd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_4:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/rsyslogd - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_5:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/augenrules - oval:ssg-symlink_file_groupownerfile_audit_tools_group_ownership_uid_0:ste:1 - oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_gid_0_6:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerfile_audit_tools_group_ownership_0_0:ste:1 /sbin/auditctl - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/aureport - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/ausearch - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_2:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/autrace - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_3:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/auditd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_4:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/rsyslogd - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_5:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/augenrules - oval:ssg-symlink_file_ownerfile_audit_tools_ownership_uid_0:ste:1 - oval:ssg-state_file_ownerfile_audit_tools_ownership_uid_0_6:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownerfile_audit_tools_ownership_0_0:ste:1 /sbin/auditctl @@ -225270,458 +248814,523 @@ fi /etc/at.allow - oval:ssg-symlink_file_groupowner_at_allow_uid_0:ste:1 - oval:ssg-state_file_groupowner_at_allow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_at_allow_0_0:ste:1 /etc/group- - oval:ssg-symlink_file_groupowner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_group_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_group_0_0:ste:1 /etc/gshadow- - oval:ssg-symlink_file_groupowner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_gshadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_gshadow_0_0:ste:1 /etc/passwd- - oval:ssg-symlink_file_groupowner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_passwd_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_passwd_0_0:ste:1 /etc/shadow- - oval:ssg-symlink_file_groupowner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_backup_etc_shadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_backup_etc_shadow_0_0:ste:1 /etc/cron.allow - oval:ssg-symlink_file_groupowner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_allow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_allow_0_0:ste:1 /etc/cron.d - oval:ssg-symlink_file_groupowner_cron_d_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_d_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_d_0_0:ste:1 /etc/cron.daily - oval:ssg-symlink_file_groupowner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_daily_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_daily_0_0:ste:1 /etc/cron.deny - oval:ssg-symlink_file_groupowner_cron_deny_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_deny_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_deny_0_0:ste:1 /etc/cron.hourly - oval:ssg-symlink_file_groupowner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_hourly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_hourly_0_0:ste:1 /etc/cron.monthly - oval:ssg-symlink_file_groupowner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_monthly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_monthly_0_0:ste:1 /etc/cron.weekly - oval:ssg-symlink_file_groupowner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_groupowner_cron_weekly_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_cron_weekly_0_0:ste:1 /etc/crontab - oval:ssg-symlink_file_groupowner_crontab_uid_0:ste:1 - oval:ssg-state_file_groupowner_crontab_gid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_groupowner_efi_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_efi_grub2_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_crontab_0_0:ste:1 /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_efi_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_efi_user_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_efi_user_cfg_0_0:ste:1 - - /etc/crypttab - oval:ssg-symlink_file_groupowner_etc_crypttab_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_crypttab_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_crypttab_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_crypttab_root_gid_usr:obj:1 + + + + /etc/crypttab + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_crypttab_0_root:ste:1 + /etc/group - oval:ssg-symlink_file_groupowner_etc_group_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_group_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_group_0_0:ste:1 /etc/gshadow - oval:ssg-symlink_file_groupowner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_gshadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_gshadow_0_0:ste:1 - - /etc/ipsec.conf - oval:ssg-symlink_file_groupowner_etc_ipsec_conf_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_ipsec_conf_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_ipsec_conf_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_ipsec_conf_root_gid_usr:obj:1 + + + + /etc/ipsec.conf + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_conf_0_root:ste:1 + + + /etc/group + ^root:\w+:(\w+):.* + 1 + + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_ipsec_secrets_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_ipsec_secrets_root_gid_usr:obj:1 + + /etc/ipsec.secrets - oval:ssg-symlink_file_groupowner_etc_ipsec_secrets_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_ipsec_secrets_gid_root_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_ipsec_secrets_0_root:ste:1 - - /etc/group - ^root:\w+:(\w+):.* - 1 - /etc/issue.net - oval:ssg-symlink_file_groupowner_etc_issue_net_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_issue_net_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_issue_net_0_0:ste:1 /etc/passwd - oval:ssg-symlink_file_groupowner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_passwd_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_passwd_0_0:ste:1 - - /etc/sestatus.conf - oval:ssg-symlink_file_groupowner_etc_sestatus_conf_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_sestatus_conf_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_sestatus_conf_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_sestatus_conf_root_gid_usr:obj:1 + + + + /etc/sestatus.conf + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_sestatus_conf_0_root:ste:1 + /etc/shadow - oval:ssg-symlink_file_groupowner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_shadow_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_shadow_0_0:ste:1 /etc/shells - oval:ssg-symlink_file_groupowner_etc_shells_uid_0:ste:1 - oval:ssg-state_file_groupowner_etc_shells_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_shells_0_0:ste:1 - - /etc/sudoers - oval:ssg-symlink_file_groupowner_etc_sudoers_uid_root:ste:1 - oval:ssg-state_file_groupowner_etc_sudoers_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_etc_sudoers_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_etc_sudoers_root_gid_usr:obj:1 + + + + /etc/sudoers + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_etc_sudoers_0_root:ste:1 + /boot/grub2/grub.cfg - oval:ssg-symlink_file_groupowner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_grub2_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_grub2_cfg_0_0:ste:1 /etc/ssh/sshd_config - oval:ssg-symlink_file_groupowner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_groupowner_sshd_config_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_sshd_config_0_0:ste:1 - - /boot - ^.*System\.map.*$ - oval:ssg-symlink_file_groupowner_systemmap_uid_root:ste:1 - oval:ssg-state_file_groupowner_systemmap_gid_root_0:ste:1 - - + /etc/group ^root:\w+:(\w+):.* 1 + + /usr/lib/group + ^root:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupowner_systemmap_root_gid_etc:obj:1 + oval:ssg-object_file_groupowner_systemmap_root_gid_usr:obj:1 + + + + /boot + ^.*System\.map.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_systemmap_0_root:ste:1 + /boot/grub2/user.cfg - oval:ssg-symlink_file_groupowner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_groupowner_user_cfg_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_user_cfg_0_0:ste:1 /var/log - oval:ssg-symlink_file_groupowner_var_log_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_0_0:ste:1 /var/log/messages - oval:ssg-symlink_file_groupowner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_groupowner_var_log_messages_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_messages_0_0:ste:1 /var/log/syslog - oval:ssg-symlink_file_groupowner_var_log_syslog_uid_4:ste:1 - oval:ssg-state_file_groupowner_var_log_syslog_gid_4_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupowner_var_log_syslog_0_4:ste:1 /etc/audit ^.*audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_0_0:ste:1 /etc/audit/rules.d ^.*\.rules$ - oval:ssg-symlink_file_groupownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_groupownership_audit_configuration_gid_0_1:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_audit_configuration_0_0:ste:1 - - /etc/ssh - ^.*_key$ - oval:ssg-symlink_file_groupownership_sshd_private_key_uid_ssh_keys:ste:1 - oval:ssg-state_file_groupownership_sshd_private_key_gid_ssh_keys_0:ste:1 - - + /etc/group ^ssh_keys:\w+:(\w+):.* 1 + + /usr/lib/group + ^ssh_keys:\w+:(\w+):.* + 1 + + + + oval:ssg-object_file_groupownership_sshd_private_key_ssh_keys_gid_etc:obj:1 + oval:ssg-object_file_groupownership_sshd_private_key_ssh_keys_gid_usr:obj:1 + + + + /etc/ssh + ^.*_key$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_sshd_private_key_0_ssh_keys:ste:1 + /etc/ssh ^.*\.pub$ - oval:ssg-symlink_file_groupownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_groupownership_sshd_pub_key_gid_0_0:ste:1 + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownership_sshd_pub_key_0_0:ste:1 /etc/group- - oval:ssg-symlink_file_owner_backup_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_group_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_group_0_0:ste:1 /etc/gshadow- - oval:ssg-symlink_file_owner_backup_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_gshadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_gshadow_0_0:ste:1 /etc/passwd- - oval:ssg-symlink_file_owner_backup_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_passwd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_passwd_0_0:ste:1 /etc/shadow- - oval:ssg-symlink_file_owner_backup_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_backup_etc_shadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_backup_etc_shadow_0_0:ste:1 /etc/cron.allow - oval:ssg-symlink_file_owner_cron_allow_uid_0:ste:1 - oval:ssg-state_file_owner_cron_allow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_allow_0_0:ste:1 /etc/cron.d - oval:ssg-symlink_file_owner_cron_d_uid_0:ste:1 - oval:ssg-state_file_owner_cron_d_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_d_0_0:ste:1 /etc/cron.daily - oval:ssg-symlink_file_owner_cron_daily_uid_0:ste:1 - oval:ssg-state_file_owner_cron_daily_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_daily_0_0:ste:1 /etc/cron.deny - oval:ssg-symlink_file_owner_cron_deny_uid_0:ste:1 - oval:ssg-state_file_owner_cron_deny_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_deny_0_0:ste:1 /etc/cron.hourly - oval:ssg-symlink_file_owner_cron_hourly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_hourly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_hourly_0_0:ste:1 /etc/cron.monthly - oval:ssg-symlink_file_owner_cron_monthly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_monthly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_monthly_0_0:ste:1 /etc/cron.weekly - oval:ssg-symlink_file_owner_cron_weekly_uid_0:ste:1 - oval:ssg-state_file_owner_cron_weekly_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_cron_weekly_0_0:ste:1 /etc/crontab - oval:ssg-symlink_file_owner_crontab_uid_0:ste:1 - oval:ssg-state_file_owner_crontab_uid_0_0:ste:1 - - - /boot/grub2/grub.cfg - oval:ssg-symlink_file_owner_efi_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_efi_grub2_cfg_uid_0_0:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-symlink_file_owner_efi_user_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_efi_user_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_crontab_0_0:ste:1 /etc/chrony.keys - oval:ssg-symlink_file_owner_etc_chrony_keys_uid_0:ste:1 - oval:ssg-state_file_owner_etc_chrony_keys_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_chrony_keys_0_0:ste:1 /etc/crypttab - oval:ssg-symlink_file_owner_etc_crypttab_uid_0:ste:1 - oval:ssg-state_file_owner_etc_crypttab_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_crypttab_0_0:ste:1 /etc/group - oval:ssg-symlink_file_owner_etc_group_uid_0:ste:1 - oval:ssg-state_file_owner_etc_group_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_group_0_0:ste:1 /etc/gshadow - oval:ssg-symlink_file_owner_etc_gshadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_gshadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_gshadow_0_0:ste:1 /etc/ipsec.conf - oval:ssg-symlink_file_owner_etc_ipsec_conf_uid_0:ste:1 - oval:ssg-state_file_owner_etc_ipsec_conf_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_ipsec_conf_0_0:ste:1 /etc/ipsec.secrets - oval:ssg-symlink_file_owner_etc_ipsec_secrets_uid_0:ste:1 - oval:ssg-state_file_owner_etc_ipsec_secrets_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_ipsec_secrets_0_0:ste:1 /etc/issue.net - oval:ssg-symlink_file_owner_etc_issue_net_uid_0:ste:1 - oval:ssg-state_file_owner_etc_issue_net_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_issue_net_0_0:ste:1 /etc/passwd - oval:ssg-symlink_file_owner_etc_passwd_uid_0:ste:1 - oval:ssg-state_file_owner_etc_passwd_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_passwd_0_0:ste:1 /etc/sestatus.conf - oval:ssg-symlink_file_owner_etc_sestatus_conf_uid_0:ste:1 - oval:ssg-state_file_owner_etc_sestatus_conf_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_sestatus_conf_0_0:ste:1 /etc/shadow - oval:ssg-symlink_file_owner_etc_shadow_uid_0:ste:1 - oval:ssg-state_file_owner_etc_shadow_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_shadow_0_0:ste:1 /etc/shells - oval:ssg-symlink_file_owner_etc_shells_uid_0:ste:1 - oval:ssg-state_file_owner_etc_shells_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_shells_0_0:ste:1 /etc/sudoers - oval:ssg-symlink_file_owner_etc_sudoers_uid_0:ste:1 - oval:ssg-state_file_owner_etc_sudoers_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_etc_sudoers_0_0:ste:1 /boot/grub2/grub.cfg - oval:ssg-symlink_file_owner_grub2_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_grub2_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_grub2_cfg_0_0:ste:1 /etc/ssh/sshd_config - oval:ssg-symlink_file_owner_sshd_config_uid_0:ste:1 - oval:ssg-state_file_owner_sshd_config_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_sshd_config_0_0:ste:1 /boot ^.*System\.map.*$ - oval:ssg-symlink_file_owner_systemmap_uid_0:ste:1 - oval:ssg-state_file_owner_systemmap_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_systemmap_0_0:ste:1 /boot/grub2/user.cfg - oval:ssg-symlink_file_owner_user_cfg_uid_0:ste:1 - oval:ssg-state_file_owner_user_cfg_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_user_cfg_0_0:ste:1 /var/log - oval:ssg-symlink_file_owner_var_log_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_0_0:ste:1 /var/log/messages - oval:ssg-symlink_file_owner_var_log_messages_uid_0:ste:1 - oval:ssg-state_file_owner_var_log_messages_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_messages_0_0:ste:1 + + syslog + /var/log/syslog - oval:ssg-symlink_file_owner_var_log_syslog_uid_104:ste:1 - oval:ssg-state_file_owner_var_log_syslog_uid_104_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_owner_var_log_syslog_0_syslog:ste:1 /etc/audit ^.*audit(\.rules|d\.conf)$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_audit_configuration_0_0:ste:1 /etc/audit/rules.d ^.*\.rules$ - oval:ssg-symlink_file_ownership_audit_configuration_uid_0:ste:1 - oval:ssg-state_file_ownership_audit_configuration_uid_0_1:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_audit_configuration_0_0:ste:1 /lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_0:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_1:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /usr/lib - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_2:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /usr/lib64 - ^.*$ - oval:ssg-symlink_file_ownership_library_dirs_uid_0:ste:1 - oval:ssg-state_file_ownership_library_dirs_uid_0_3:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_library_dirs_0_0:ste:1 /etc/ssh ^.*_key$ - oval:ssg-symlink_file_ownership_sshd_private_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_private_key_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_sshd_private_key_0_0:ste:1 /etc/ssh ^.*\.pub$ - oval:ssg-symlink_file_ownership_sshd_pub_key_uid_0:ste:1 - oval:ssg-state_file_ownership_sshd_pub_key_uid_0_0:ste:1 + oval:ssg-symlink_file_owner:ste:1 + oval:ssg-state_file_ownership_sshd_pub_key_0_0:ste:1 /etc/at.allow @@ -225800,16 +249409,6 @@ fi oval:ssg-exclude_symlinks__crontab:ste:1 oval:ssg-state_file_permissions_crontab_0_mode_0600or_stricter_:ste:1 - - /boot/grub2/grub.cfg - oval:ssg-exclude_symlinks__efi_grub2_cfg:ste:1 - oval:ssg-state_file_permissions_efi_grub2_cfg_0_mode_0700or_stricter_:ste:1 - - - /boot/grub2/user.cfg - oval:ssg-exclude_symlinks__efi_user_cfg:ste:1 - oval:ssg-state_file_permissions_efi_user_cfg_0_mode_0700or_stricter_:ste:1 - /etc/audit/auditd.conf oval:ssg-exclude_symlinks__etc_audit_auditd:ste:1 @@ -225889,28 +249488,28 @@ fi /lib - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_0_mode_7755or_stricter_:ste:1 /lib64 - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_1_mode_7755or_stricter_:ste:1 /usr/lib - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_2_mode_7755or_stricter_:ste:1 /usr/lib64 - ^.*$ + ^.*\.so.*$ oval:ssg-exclude_symlinks__library_dirs:ste:1 oval:ssg-state_file_permissions_library_dirs_3_mode_7755or_stricter_:ste:1 @@ -225950,7 +249549,7 @@ fi /var/log/messages oval:ssg-exclude_symlinks__var_log_messages:ste:1 - oval:ssg-state_file_permissions_var_log_messages_0_mode_0600or_stricter_:ste:1 + oval:ssg-state_file_permissions_var_log_messages_0_mode_0640or_stricter_:ste:1 /var/log/syslog @@ -227318,14 +250917,17 @@ fi - - /home - - - /etc/fstab - ^[\s]*(?!#)[\S]+[\s]+/home[\s]+[\S]+[\s]+([\S]+) + + /etc/passwd + 1 + + / + + + + /etc/passwd @@ -227545,6 +251147,20 @@ fi ^[\s]*(?!#)[\S]+[\s]+/var/tmp[\s]+[\S]+[\s]+([\S]+) 1 + + /etc/NetworkManager/NetworkManager.conf + ^\s*\[main\].*(?:\n\s*[^[\s].*)*\n^[ \t]*dns\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + /etc/NetworkManager/conf.d + .*\.conf$ + ^\s*\[main\].*(?:\n\s*[^[\s].*)*\n^[ \t]*dns\h*=\h*(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/NetworkManager/NetworkManager.conf + aide @@ -227671,12 +251287,6 @@ fi rng-tools - - rsh-server - - - rsh - rsyslog-gnutls @@ -227713,12 +251323,6 @@ fi syslog-ng - - talk-server - - - talk - telnet-server @@ -227746,9 +251350,6 @@ fi vsftpd - - xorg-x11-server-common - /dev/shm @@ -227776,30 +251377,30 @@ fi /lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_0:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_1:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /usr/lib - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_2:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /usr/lib64 - ^.*$ - oval:ssg-symlink_file_groupownerroot_permissions_syslibrary_files_uid_0:ste:1 - oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_gid_0_3:ste:1 + ^.*\.so.*$ + oval:ssg-symlink_file_groupowner:ste:1 + oval:ssg-state_file_groupownerroot_permissions_syslibrary_files_0_0:ste:1 /etc/rsyslog.conf @@ -227922,6 +251523,14 @@ fi ssh_sysadm_login + + /etc/selinux/config + ^SELINUXTYPE=(.+?)[ \t]*(?:$|#) + 1 + + + ^/etc/selinux/config + ^atd\.(service|socket)$ ActiveState @@ -228308,10 +251917,16 @@ fi ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Protocol(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_allow_only_protocol2:obj:1 - oval:ssg-obj_sshd_allow_only_protocol2_sshd_included_files:obj:1 + oval:ssg-obj_sshd_allow_only_protocol2_config_dir:obj:1 @@ -228329,10 +251944,16 @@ fi ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Compression(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_compression:obj:1 - oval:ssg-obj_sshd_disable_compression_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_compression_config_dir:obj:1 @@ -228350,10 +251971,16 @@ fi ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitEmptyPasswords(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_empty_passwords:obj:1 - oval:ssg-obj_sshd_disable_empty_passwords_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_empty_passwords_config_dir:obj:1 @@ -228371,10 +251998,16 @@ fi ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_disable_gssapi_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_gssapi_auth_config_dir:obj:1 @@ -228392,10 +252025,16 @@ fi ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)KerberosAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_kerb_auth:obj:1 - oval:ssg-obj_sshd_disable_kerb_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_kerb_auth_config_dir:obj:1 @@ -228413,10 +252052,16 @@ fi ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_disable_pubkey_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_pubkey_auth_config_dir:obj:1 @@ -228434,10 +252079,16 @@ fi ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)IgnoreRhosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_rhosts:obj:1 - oval:ssg-obj_sshd_disable_rhosts_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_rhosts_config_dir:obj:1 @@ -228455,10 +252106,16 @@ fi ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)RhostsRSAAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_rhosts_rsa:obj:1 - oval:ssg-obj_sshd_disable_rhosts_rsa_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_rhosts_rsa_config_dir:obj:1 @@ -228476,10 +252133,16 @@ fi ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_root_login:obj:1 - oval:ssg-obj_sshd_disable_root_login_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_root_login_config_dir:obj:1 @@ -228497,10 +252160,16 @@ fi ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitRootLogin(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_root_password_login:obj:1 - oval:ssg-obj_sshd_disable_root_password_login_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_root_password_login_config_dir:obj:1 @@ -228518,10 +252187,16 @@ fi ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)AllowTcpForwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_tcp_forwarding:obj:1 - oval:ssg-obj_sshd_disable_tcp_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_tcp_forwarding_config_dir:obj:1 @@ -228539,10 +252214,16 @@ fi ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)IgnoreUserKnownHosts(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_user_known_hosts:obj:1 - oval:ssg-obj_sshd_disable_user_known_hosts_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_user_known_hosts_config_dir:obj:1 @@ -228560,10 +252241,16 @@ fi ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_disable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_disable_x11_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_disable_x11_forwarding_config_dir:obj:1 @@ -228581,10 +252268,16 @@ fi ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PermitUserEnvironment(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_do_not_permit_user_env:obj:1 - oval:ssg-obj_sshd_do_not_permit_user_env_sshd_included_files:obj:1 + oval:ssg-obj_sshd_do_not_permit_user_env_config_dir:obj:1 @@ -228602,10 +252295,16 @@ fi ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)GSSAPIAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_gssapi_auth:obj:1 - oval:ssg-obj_sshd_enable_gssapi_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_gssapi_auth_config_dir:obj:1 @@ -228623,10 +252322,16 @@ fi ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)UsePAM(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_pam:obj:1 - oval:ssg-obj_sshd_enable_pam_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_pam_config_dir:obj:1 @@ -228644,10 +252349,16 @@ fi ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PubkeyAuthentication(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_pubkey_auth:obj:1 - oval:ssg-obj_sshd_enable_pubkey_auth_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_pubkey_auth_config_dir:obj:1 @@ -228665,10 +252376,16 @@ fi ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)StrictModes(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_strictmodes:obj:1 - oval:ssg-obj_sshd_enable_strictmodes_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_strictmodes_config_dir:obj:1 @@ -228686,10 +252403,16 @@ fi ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_warning_banner:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_config_dir:obj:1 @@ -228707,10 +252430,16 @@ fi ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)Banner(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_warning_banner_net:obj:1 - oval:ssg-obj_sshd_enable_warning_banner_net_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_warning_banner_net_config_dir:obj:1 @@ -228728,10 +252457,16 @@ fi ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11Forwarding(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_enable_x11_forwarding:obj:1 - oval:ssg-obj_sshd_enable_x11_forwarding_sshd_included_files:obj:1 + oval:ssg-obj_sshd_enable_x11_forwarding_config_dir:obj:1 @@ -228754,10 +252489,16 @@ fi ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)PrintLastLog(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_print_last_log:obj:1 - oval:ssg-obj_sshd_print_last_log_sshd_included_files:obj:1 + oval:ssg-obj_sshd_print_last_log_config_dir:obj:1 @@ -228775,10 +252516,16 @@ fi ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_keepalive:obj:1 - oval:ssg-obj_sshd_set_keepalive_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_keepalive_config_dir:obj:1 @@ -228796,10 +252543,16 @@ fi ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)ClientAliveCountMax(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_keepalive_0:obj:1 - oval:ssg-obj_sshd_set_keepalive_0_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_keepalive_0_config_dir:obj:1 @@ -228817,10 +252570,16 @@ fi ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_loglevel_info:obj:1 - oval:ssg-obj_sshd_set_loglevel_info_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_loglevel_info_config_dir:obj:1 @@ -228838,10 +252597,16 @@ fi ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)LogLevel(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_set_loglevel_verbose:obj:1 - oval:ssg-obj_sshd_set_loglevel_verbose_sshd_included_files:obj:1 + oval:ssg-obj_sshd_set_loglevel_verbose_config_dir:obj:1 @@ -228859,10 +252624,16 @@ fi ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)UsePrivilegeSeparation(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_use_priv_separation:obj:1 - oval:ssg-obj_sshd_use_priv_separation_sshd_included_files:obj:1 + oval:ssg-obj_sshd_use_priv_separation_config_dir:obj:1 @@ -228880,10 +252651,16 @@ fi ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) 1 + + /etc/ssh/sshd_config.d + .*\.conf$ + ^[ \t]*(?i)X11UseLocalhost(?-i)[ \t]+(.+?)[ \t]*(?:$|#) + 1 + oval:ssg-obj_sshd_x11_use_localhost:obj:1 - oval:ssg-obj_sshd_x11_use_localhost_sshd_included_files:obj:1 + oval:ssg-obj_sshd_x11_use_localhost_config_dir:obj:1 @@ -228893,22 +252670,22 @@ fi ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\bnoexec.*$ + ^[\s]*Defaults\b[^!\n]*\bnoexec.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\brequiretty.*$ + ^[\s]*Defaults\b[^!\n]*\brequiretty.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\buse_pty.*$ + ^[\s]*Defaults\b[^!\n]*\buse_pty.*$ 1 ^/etc/sudoers(|\.d/.*)$ - ^[\s]*Defaults[\s]*[^!]\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$ + ^[\s]*Defaults\b[^!\n]*\blogfile\s*=\s*(?:"?([^",\s]+)"?).*$ 1 @@ -232852,42 +256629,42 @@ fi ^(ExecStartPost=\-\/sbin\/augenrules.*$|Requires=augenrules.service) 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+setdomainname[\s]+|([\s]+|[,])setdomainname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + ^/etc/audit/rules\.d/.*\.rules$ ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 - + /etc/audit/audit.rules ^[\s]*-a[\s]+always,exit[\s]+(?:.*-F[\s]+arch=b64[\s]+)(?:.*(-S[\s]+sethostname[\s]+|([\s]+|[,])sethostname([\s]+|[,]))).*(-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ 1 @@ -232919,6 +256696,12 @@ fi openshift-kubelet + + /run/ostree-booted + + + /ostree + /etc/default/grub ^\s*GRUB_DISABLE_RECOVERY=(.*)$ @@ -232929,6 +256712,14 @@ fi ^([\s]*server[\s]+.+$){2,}$ 1 + + /etc/almalinux-release + + + /etc/almalinux-release + ^AlmaLinux release 9.[0-9]+ .*$ + 1 + oraclelinux-release @@ -232939,14 +256730,13 @@ fi oraclelinux-release - - /etc/os-release - ^ID="(\w+)"$ - 1 - - - /etc/os-release - ^VERSION_ID="(\d)\.\d+"$ + + + redhat-release + + + /etc/redhat-release + ^Red Hat Enterprise Linux release (\d)\.\d+$ 1 @@ -232996,6 +256786,16 @@ fi SLE_HPC-release + + + SLES-release + + + SLES_SAP-release + + + sle-ha-release + SUSE-MicroOS-release @@ -233003,6 +256803,10 @@ fi SLE-Micro-release + + + SL-Micro-release + /etc/lsb-release @@ -233011,19 +256815,9 @@ fi ^DISTRIB_ID=Ubuntu$ 1 - + /etc/lsb-release - ^DISTRIB_CODENAME=xenial$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=bionic$ - 1 - - - /etc/lsb-release - ^DISTRIB_CODENAME=focal$ + ^DISTRIB_CODENAME=noble$ 1 @@ -233074,15 +256868,6 @@ fi 0 - - true - true - true - true - true - true - true - true true @@ -233187,6 +256972,9 @@ fi + + + @@ -233256,8 +257044,8 @@ fi - - + + \s*ExecStart\s*=\s*\S+\s+-s\s+\S+.* symbolic link @@ -233271,7 +257059,6 @@ fi false false false - false false false false @@ -233335,9 +257122,6 @@ fi - - - @@ -233365,9 +257149,6 @@ fi (?i)true - - ^LinuxAudit$ - /etc/systemd/system/default.target ^(/usr)?/lib/systemd/system/multi-user.target$ @@ -233419,12 +257200,6 @@ fi /var/run/faillock - - 2 - - - 2 - @@ -233475,13 +257250,13 @@ fi - + 0 - + 0 @@ -233627,6 +257402,9 @@ fi + + 1 + ^(nobody|nfsnobody)$ @@ -233643,7 +257421,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ regular @@ -233665,7 +257443,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ ^\/[^\/\n]*\/[^\/\n]{1,}.*$ @@ -233735,7 +257513,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ ^(nobody|nfsnobody)$ @@ -233757,7 +257535,7 @@ fi ^(nobody|nfsnobody)$ - ^/sbin/nologin$ + ^(?:/usr)?/sbin/nologin$ directory @@ -233848,9 +257626,6 @@ fi UP - - ^.*\bdefault|none\b.*$ - 0 true @@ -233944,6 +257719,9 @@ fi 1000 + + symbolic link + 0 @@ -233956,6 +257734,7 @@ fi ^/dev/.*$ + ^(?!afs$|autofs$|ceph$|cifs$|smb3$|smbfs$|sshfs$|ncpfs$|ncp$|nfs$|nfs4$|gfs$|gfs2$|glusterfs$|gpfs$|pvfs2$|ocfs2$|lustre$|davfs$|fuse\.sshfs$).+ nodev @@ -233977,18 +257756,6 @@ fi - - ^(?i)0(?-i)$ - - - ^(?i)0(?-i)$ - - - ^(?i)none(?-i)$ - - - ^(?i)none(?-i)$ - 0 @@ -234010,9 +257777,6 @@ fi ^(enforcing|permissive)$ - - - @@ -234025,6 +257789,16 @@ fi ^(x86_64|aarch64|ppc64le|s390x|.*-amd64)$ + + + + + bind + + + .+ + iso9660 + @@ -234034,6 +257808,9 @@ fi + + 0 + @@ -234083,7 +257860,7 @@ fi - + fips @@ -234092,8 +257869,44 @@ fi ^(?:.*\s)?fips=1(?:\s.*)?$ - ^FIPS(:OSPP)?$ + ^FIPS(:(OSPP|STIG))?$ + + /usr/share/crypto-policies/FIPS/bind.txt + + + /usr/share/crypto-policies/FIPS/gnutls.txt + + + /usr/share/crypto-policies/FIPS/java.txt + + + /usr/share/crypto-policies/FIPS/javasystem.txt + + + /usr/share/crypto-policies/FIPS/krb5.txt + + + /usr/share/crypto-policies/FIPS/libreswan.txt + + + /usr/share/crypto-policies/FIPS/libssh.txt + + + /usr/share/crypto-policies/FIPS/openssh.txt + + + /usr/share/crypto-policies/FIPS/opensshserver.txt + + + /usr/share/crypto-policies/FIPS/opensslcnf.txt + + + /usr/share/crypto-policies/FIPS/openssl.txt + + + /usr/share/crypto-policies/FIPS/openssl_fips.txt + 1 @@ -234109,6 +257922,17 @@ fi ^.*xattrs.*$ + + fail + fail + fail + fail + fail + fail + fail + fail + fail + fail false @@ -234130,6 +257954,9 @@ fi ^security$ + + ^(0|[Ff]alse|[Nn]o)$ + 629e59ec 8d8b756f @@ -234168,6 +257995,12 @@ fi + + + + + 0 + @@ -234309,6 +258142,9 @@ fi ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -234441,7 +258277,7 @@ fi - ^(?i)50(?-i)$ + ^(?i)yes(?-i)$ @@ -234452,59 +258288,38 @@ fi ^(?i)yes(?-i)$ + + ^LinuxAudit$ + + + ^0$ + + + ^0$ + + + ^none$ + + + ^none$ + ^'lock-screen'$ - - 0 + + - - 0 - - - 0 - - - 0 - - + symbolic link - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - + symbolic link - - 0 + + - - 0 - - - 0 - - - 0 - - - symbolic link + + false @@ -234570,77 +258385,41 @@ fi symbolic link - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link + + false @@ -234722,53 +258501,14 @@ fi ^no$ - - 0 + + ^no$ + + + - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link + + false @@ -234822,458 +258562,215 @@ fi symbolic link - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 0 + + - - symbolic link + + - - 4 + + - - symbolic link + + - - 0 + + - - 0 + + - - symbolic link + + - - - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 104 - - - symbolic link - - - 0 - - - 0 - - - symbolic link - - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link - - - 0 - - - symbolic link - - - 0 - - - symbolic link + + false @@ -235473,34 +258970,6 @@ fi symbolic link - - false - false - false - false - false - false - false - false - false - - - symbolic link - - - false - false - false - false - false - false - false - false - false - - - symbolic link - false false @@ -235818,12 +259287,11 @@ fi symbolic link - + false false false false - false false false false @@ -235860,7 +259328,7 @@ fi .*rescue\.conf$ - ^(?:.*\s)?audit_backlog_limit=8192(?:\s.*)?$ + .*rescue\.conf$ @@ -236409,13 +259877,9 @@ fi grpquota - - nodev + + nodev - - 1 - nodev - noexec @@ -236574,20 +260038,14 @@ fi 1 nosuid - - 0 - - - 0 - - - 0 - - - 0 - - - symbolic link + + ^none|default$ + + + ^none|default$ + + + (?:file="[^\s;]+"|\$IncludeConfig[\s]+[^\s;]+|\/dev\/.*) @@ -236673,12 +260131,18 @@ fi + + + inactive|failed masked + + not-found + auditd.service @@ -236694,12 +260158,18 @@ fi masked + + not-found + inactive|failed masked + + not-found + chronyd.service @@ -236724,6 +260194,9 @@ fi masked + + not-found + fapolicyd.service @@ -236757,18 +260230,27 @@ fi masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + pcscd.service @@ -236793,12 +260275,18 @@ fi masked + + not-found + inactive|failed masked + + not-found + rngd.service @@ -236814,6 +260302,9 @@ fi masked + + not-found + rsyslog.service @@ -236829,18 +260320,27 @@ fi masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + sshd.service @@ -236886,6 +260386,9 @@ fi masked + + not-found + ufw.service @@ -236910,11 +260413,17 @@ fi ^2$ + + ^2$ + - + - + + + + ^no$ @@ -236922,125 +260431,188 @@ fi ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^prohibit-password$ ^prohibit-password$ + + ^prohibit-password$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^no$ ^no$ + + ^no$ + ^no$ ^no$ + + ^no$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + ^/etc/issue$ ^/etc/issue$ + + ^/etc/issue$ + ^/etc/issue.net$ ^/etc/issue.net$ + + ^/etc/issue.net$ + ^yes$ ^yes$ + + ^yes$ + ^yes$ ^yes$ + + ^yes$ + - + - + + + + ^0$ @@ -237048,23 +260620,35 @@ fi ^0$ + + ^0$ + ^INFO$ ^INFO$ + + ^INFO$ + ^VERBOSE$ ^VERBOSE$ + + ^VERBOSE$ + - + - + + + + ^yes$ @@ -237072,6 +260656,9 @@ fi ^yes$ + + ^yes$ + @@ -237273,17 +260860,11 @@ fi 0 - - 1 + + - - 2 - - - 1 - - - 2 + + @@ -237537,6 +261118,10 @@ fi active + + /ostree + symbolic link + ^(true|"true")$ @@ -237552,11 +261137,14 @@ fi unix - - rhcos - - - 4 + + unix + + + ^10.*$ + + + 10 unix @@ -237609,6 +261197,18 @@ fi ^15.*$ + + unix + + + ^16.*$ + + + ^16.*$ + + + ^16.*$ + unix @@ -237618,6 +261218,12 @@ fi ^5.*$ + + unix + + + ^6.*$ + 1 @@ -237651,9 +261257,6 @@ fi - - ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+dir=/var/log/audit/)[\s]+(?:-F[\s]+perm=r)[\s]+(?:-F\s+auid>=1000[\s]+)(?:-F\s+auid!=(unset|4294967295)[\s]+)(?:-k[\s]+|-F[\s]+key=)[\S]+[\s]*$ - @@ -237726,6 +261329,7 @@ fi + @@ -237773,7 +261377,6 @@ fi - @@ -237813,6 +261416,18 @@ fi + + + ^(/etc/ssh/(?!/))? + + + + + + + + + @@ -237835,17 +261450,6 @@ fi - - - - - - - - - - - @@ -237882,10 +261486,10 @@ fi - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) @@ -237900,20 +261504,20 @@ fi - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) ^\s*password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so.*$ - + ^\s*password\b.*\bpam_pwhistory\.so\b.*\bremember=([0-9]*).*$ - + ^\s*remember\s*=\s*([0-9]+) @@ -237922,12 +261526,6 @@ fi ^[\s]*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*even_deny_root @@ -237950,24 +261548,6 @@ fi - - - - - - - - - - - - - - - - - - @@ -238014,6 +261594,7 @@ fi + @@ -238126,7 +261707,9 @@ fi - + + + @@ -238201,7 +261784,9 @@ fi - + + + @@ -238251,7 +261836,9 @@ fi - + + + @@ -238478,8 +262065,13 @@ fi - + + + /dev/mapper/ + + + @@ -238517,12 +262109,6 @@ fi - - - -oMACs= - - - @@ -238551,12 +262137,6 @@ fi ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*deny=([0-9]+) @@ -238567,12 +262147,6 @@ fi ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*fail_interval=([0-9]+) @@ -238580,44 +262154,101 @@ fi ^[\s]*fail_interval[\s]*=[\s]*([0-9]+) - ^\s*auth\N+pam_unix\.so - - ^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail - - - ^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so - ^[\s]*auth[\s]+.+[\s]+pam_faillock.so[\s]+[^\n]*unlock_time=([0-9]+) ^[\s]*unlock_time[\s]*=[\s]*([0-9]+) - + + + + ^\-w[\s]+ + \/etc\/cron.d\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - - + + ^\-w[\s]+ \/var\/log\/lastlog [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - + ^\-w[\s]+ \/var\/log\/tallylog [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ + \/etc\/selinux\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/usr\/share\/selinux\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/log\/btmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/run\/utmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/log\/wtmp + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/sudoers + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/sudoers.d\/ + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/localtime + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + ^[\s]*-a[\s]+always,exit[\s]+(?:-F[\s]+arch=b32[\s]+)(?:.*(-S[\s]+creat[\s]+|([\s]+|[,])creat([\s]+|[,])))(?:(?!-F[\s]+a\d&).)* @@ -238840,30 +262471,100 @@ fi - + + + ^\-w[\s]+ + \/etc\/group + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/gshadow + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/security\/opasswd + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/passwd + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/etc\/shadow + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + + + ^\-w[\s]+ + \/var\/spool\/cron + [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ + + + ^\-w[\s]+ \/var\/log\/sudo.log [\s]+\-p[\s]+\b([rx]*w[rx]*a[rx]*|[rx]*a[rx]*w[rx]*)\b.*$ - - + + + 0 - - + + 0 - - + + 0 - - + + - - + + - - + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 @@ -238877,27 +262578,230 @@ fi - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 - - + + 0 + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 4 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + ^(?:.*\s)?audit_backlog_limit= + + (?:\s.*)?$ + + + ^(?:.*\s)?l1tf= @@ -239993,6 +263897,16 @@ fi + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( + + ).*?:.* + + + + + ^(?:(?!nobody).*)?:.*?:[1-9]\d{3,}:.*?:.*?:( @@ -240084,6 +263998,9 @@ fi [\s]+[/\w]+[\s]+[\w]+[\s]+([^\s]+)(?:[\s]+[\d]+){2}$ + + 0 + @@ -240149,6 +264066,7 @@ fi + ^(/etc/ssh/(?!/))? @@ -240161,9 +264079,6 @@ fi - - - @@ -240417,9 +264332,6 @@ fi - - - @@ -240469,9 +264381,6 @@ fi - - - @@ -240504,6 +264413,7 @@ fi + @@ -240582,3644 +264492,19 @@ fi - + build_shorthand.py from SCAP Security Guide - ssg: 0.1.76 + ssg: 0.1.79 2.0 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 - - Ensure gpgcheck Enabled In Main yum Configuration + + Set Account Expiration Following Inactivity in password-auth - ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd - - ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 - - - - Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 - - - - Verify Permissions On /etc/nftables Directory - - ocil:ssg-directory_permissions_etc_nftables_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive - - ocil:ssg-accounts_users_home_files_permissions_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg User Ownership - - ocil:ssg-file_owner_grub2_cfg_action:testaction:1 - - - - Configure the confidence in TPM for entropy - - ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in login.defs - - ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 - - - - Uninstall talk-server Package - - ocil:ssg-package_talk-server_removed_action:testaction:1 - - - - Disable vsyscall emulate execution only - - ocil:ssg-kernel_config_legacy_vsyscall_xonly_action:testaction:1 - - - - Disable RDS Support - - ocil:ssg-kernel_module_rds_disabled_action:testaction:1 - - - - Configure System to Forward All Mail through a specific host - - ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 - - - - Verify Group Who Owns cron.monthly - - ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 - - - - Ensure tftp Daemon Uses Secure Mode - - ocil:ssg-tftpd_uses_secure_mode_action:testaction:1 - - - - Ensure '/etc/system-fips' exists - - ocil:ssg-etc_system_fips_exists_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lchown - - ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 - - - - Uninstall squid Package - - ocil:ssg-package_squid_removed_action:testaction:1 - - - - Disable vsyscalls - - ocil:ssg-grub2_vsyscall_argument_action:testaction:1 - - - - Sign kernel modules with SHA-512 - - ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 - - - - Disable IPv6 Addressing on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 - - - - Configure SSSD LDAP Backend to Use TLS For All Transactions - - ocil:ssg-sssd_ldap_start_tls_action:testaction:1 - - - - Add noexec Option to Removable Media Partitions - - ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 - - - - Verify Group Who Owns /etc/sysctl.d Directory - - ocil:ssg-directory_groupowner_etc_sysctld_action:testaction:1 - - - - Verify Group Who Owns /etc/sudoers File - - ocil:ssg-file_groupowner_etc_sudoers_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/libuser.conf - - ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Symlinks - - ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.d Directory - - ocil:ssg-directory_permissions_etc_ipsecd_action:testaction:1 - - - - Ensure that System Accounts Do Not Run a Shell Upon Login - - ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 - - - - Add nodev Option to /var/log - - ocil:ssg-mount_option_var_log_nodev_action:testaction:1 - - - - Ensure cron Is Logging To Rsyslog - - ocil:ssg-rsyslog_cron_logging_action:testaction:1 - - - - Install dnf-automatic Package - - ocil:ssg-package_dnf-automatic_installed_action:testaction:1 - - - - Limit the Number of Concurrent Login Sessions Allowed Per User - - ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 - - - - Ensure yum Removes Previous Package Versions - - ocil:ssg-clean_components_post_updating_action:testaction:1 - - - - Uninstall DHCP Server Package - - ocil:ssg-package_dhcp_removed_action:testaction:1 - - - - Verify Permissions on System.map Files - - ocil:ssg-file_permissions_systemmap_action:testaction:1 - - - - Enable use of Berkeley Packet Filter with seccomp - - ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 - - - - Require Authentication for Emergency Systemd Target - - ocil:ssg-require_emergency_target_auth_action:testaction:1 - - - - Set SSH Client Alive Count Max - - ocil:ssg-sshd_set_keepalive_action:testaction:1 - - - - Add nodev Option to Non-Root Local Partitions - - ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 - - - - User Initialization Files Must Not Run World-Writable Programs - - ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 - - - - All Interactive Users Must Have A Home Directory Defined - - ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 - - - - Configure Accepting Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 - - - - Add nodev Option to /tmp - - ocil:ssg-mount_option_tmp_nodev_action:testaction:1 - - - - Uninstall rsh Package - - ocil:ssg-package_rsh_removed_action:testaction:1 - - - - Add nosuid Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 - - - - Verify the SSH Private Key Files Have a Passcode - - ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 - - - - Ensure SELinux is Not Disabled - - ocil:ssg-selinux_not_disabled_action:testaction:1 - - - - Install the cron service - - ocil:ssg-package_cron_installed_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Characters - - ocil:ssg-accounts_password_pam_difok_action:testaction:1 - - - - Enable seccomp to safely compute untrusted bytecode - - ocil:ssg-kernel_config_seccomp_action:testaction:1 - - - - Require Credential Prompting for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_user_cfg_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Ownership - - ocil:ssg-dir_ownership_library_dirs_action:testaction:1 - - - - Verify the system-wide library files in directories -"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. - - ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 - - - - Enable ExecShield via sysctl - - ocil:ssg-sysctl_kernel_exec_shield_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/shadow - - ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Have a Valid Owner - - ocil:ssg-accounts_users_home_files_ownership_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters - - ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 - - - - The Chronyd service is enabled - - ocil:ssg-service_chronyd_enabled_action:testaction:1 - - - - Install firewalld Package - - ocil:ssg-package_firewalld_installed_action:testaction:1 - - - - Verify Permissions On /etc/sudoers.d Directory - - ocil:ssg-directory_permissions_etc_sudoersd_action:testaction:1 - - - - Set GNOME3 Screensaver Inactivity Timeout - - ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 - - - - Record Events that Modify User/Group Information - - ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 - - - - Verify Permissions on SSH Server config file - - ocil:ssg-file_permissions_sshd_config_action:testaction:1 - - - - Ensure Authentication Required for Single User Mode - - ocil:ssg-ensure_root_password_configured_action:testaction:1 - - - - Authorize Human Interface Devices and USB hubs in USBGuard daemon - - ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 - - - - Ensure /tmp Located On Separate Partition - - ocil:ssg-partition_for_tmp_action:testaction:1 - - - - Enable the OpenSSH Service - - ocil:ssg-service_sshd_enabled_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg Permissions - - ocil:ssg-file_permissions_grub2_cfg_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 - - - - Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 - - - - Configure auditing of successful permission changes - - ocil:ssg-audit_perm_change_success_action:testaction:1 - - - - Disable Bluetooth Kernel Module - - ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 - - - - Install libselinux Package - - ocil:ssg-package_libselinux_installed_action:testaction:1 - - - - Verify User Who Owns gshadow File - - ocil:ssg-file_owner_etc_gshadow_action:testaction:1 - - - - Uninstall net-snmp Package - - ocil:ssg-package_net-snmp_removed_action:testaction:1 - - - - Remove ftp Package - - ocil:ssg-package_ftp_removed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - poweroff - - ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 - - - - Restrict unprivileged access to the kernel syslog - - ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 - - - - Verify Group Who Owns Backup gshadow File - - ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 - - - - Verify User Who Owns /var/log/messages File - - ocil:ssg-file_owner_var_log_messages_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount2 - - ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 - - - - Ensure All Files Are Owned by a Group - - ocil:ssg-file_permissions_ungroupowned_action:testaction:1 - - - - Add nosuid Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 - - - - Audit Configuration Files Permissions are 640 or More Restrictive - - ocil:ssg-file_permissions_audit_configuration_action:testaction:1 - - - - Verify Permissions on /etc/audit/rules.d/*.rules - - ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 - - - - Ensure a dedicated group owns sudo - - ocil:ssg-sudo_dedicated_group_action:testaction:1 - - - - Ensure /srv Located On Separate Partition - - ocil:ssg-partition_for_srv_action:testaction:1 - - - - Randomize the address of the kernel image (KASLR) - - ocil:ssg-kernel_config_randomize_base_action:testaction:1 - - - - Enable checks on notifier call chains - - ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 - - - - Set Interval For Counting Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Different Categories - - ocil:ssg-accounts_password_pam_minclass_action:testaction:1 - - - - Record Events that Modify the System's Network Environment - - ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Screensaver Settings - - ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 - - - - Disable the authlogin_nsswitch_use_ldap SELinux Boolean - - ocil:ssg-sebool_authlogin_nsswitch_use_ldap_action:testaction:1 - - - - Make sure that the dconf databases are up-to-date with regards to respective keyfiles - - ocil:ssg-dconf_db_up_to_date_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchmod - - ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 - - - - Verify All Account Password Hashes are Shadowed - - ocil:ssg-accounts_password_all_shadowed_action:testaction:1 - - - - Allow Only SSH Protocol 2 - - ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 - - - - Deactivate Wireless Network Interfaces - - ocil:ssg-wireless_disable_interfaces_action:testaction:1 - - - - Configure auditing of successful file creations - - ocil:ssg-audit_create_success_action:testaction:1 - - - - Install cryptsetup Package - - ocil:ssg-package_cryptsetup-luks_installed_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Activation - - ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 - - - - Install the opensc Package For Multifactor Authentication - - ocil:ssg-package_opensc_installed_action:testaction:1 - - - - Only Authorized Local User Accounts Exist on Operating System - - ocil:ssg-accounts_authorized_local_users_action:testaction:1 - - - - Direct root Logins Not Allowed - - ocil:ssg-no_direct_root_logins_action:testaction:1 - - - - Enable GSSAPI Authentication - - ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Root - - ocil:ssg-file_ownership_audit_configuration_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading - init_module - - ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 - - - - Set Existing Passwords Warning Age - - ocil:ssg-accounts_password_set_warn_age_existing_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chown - - ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 - - - - Uninstall nfs-utils Package - - ocil:ssg-package_nfs-utils_removed_action:testaction:1 - - - - Verify that system commands directories have root ownership - - ocil:ssg-dir_system_commands_root_owned_action:testaction:1 - - - - Verify User Who Owns group File - - ocil:ssg-file_owner_etc_group_action:testaction:1 - - - - Uninstall cyrus-imapd Package - - ocil:ssg-package_cyrus-imapd_removed_action:testaction:1 - - - - Encrypt Partitions - - ocil:ssg-encrypt_partitions_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - renameat - - ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 - - - - Add usrquota Option to /home - - ocil:ssg-mount_option_home_usrquota_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - usermod - - ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 - - - - Disable the selinuxuser_execstack SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 - - - - Ensure SELinux Not Disabled in /etc/default/grub - - ocil:ssg-grub2_enable_selinux_action:testaction:1 - - - - Record Access Events to Audit Log Directory - - ocil:ssg-directory_access_var_log_audit_action:testaction:1 - - - - Disable the uvcvideo module - - ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 - - - - Assign Expiration Date to Temporary Accounts - - ocil:ssg-account_temp_expire_date_action:testaction:1 - - - - Record Events When Privileged Executables Are Run - - ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 - - - - Set Default ip6tables Policy for Incoming Packets - - ocil:ssg-set_ip6tables_default_rule_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 - - - - Record Any Attempts to Run setsebool - - ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 - - - - Verify that Shared Library Files Have Restrictive Permissions - - ocil:ssg-file_permissions_library_dirs_action:testaction:1 - - - - Restrict Virtual Console Root Logins - - ocil:ssg-securetty_root_login_console_only_action:testaction:1 - - - - Enable Randomized Layout of Virtual Address Space - - ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 - - - - Set Existing Passwords Maximum Age - - ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 - - - - Add nosuid Option to /tmp - - ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 - - - - Disable X11 Forwarding - - ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 - - - - Enable Use of Privilege Separation - - ocil:ssg-sshd_use_priv_separation_action:testaction:1 - - - - Ensure that /etc/at.deny does not exist - - ocil:ssg-file_at_deny_not_exist_action:testaction:1 - - - - Install sudo Package - - ocil:ssg-package_sudo_installed_action:testaction:1 - - - - Restrict usage of ptrace to descendant processes - - ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 - - - - Set SSH MaxSessions limit - - ocil:ssg-sshd_set_max_sessions_action:testaction:1 - - - - Verify Group Who Owns Crontab - - ocil:ssg-file_groupowner_crontab_action:testaction:1 - - - - Verify Group Who Owns /etc/shells File - - ocil:ssg-file_groupowner_etc_shells_action:testaction:1 - - - - Verify Owner on cron.weekly - - ocil:ssg-file_owner_cron_weekly_action:testaction:1 - - - - Randomize layout of sensitive kernel structures - - ocil:ssg-kernel_config_gcc_plugin_randstruct_action:testaction:1 - - - - Remove the OpenSSH Server Package - - ocil:ssg-package_openssh-server_removed_action:testaction:1 - - - - Disable IEEE 1394 (FireWire) Support - - ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 - - - - Disable rlogin Service - - ocil:ssg-service_rlogin_disabled_action:testaction:1 - - - - Disable support for /proc/kkcore - - ocil:ssg-kernel_config_proc_kcore_action:testaction:1 - - - - Verify Group Who Owns passwd File - - ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 - - - - Configure auditing of successful file modifications - - ocil:ssg-audit_modify_success_action:testaction:1 - - - - Enable Dracut FIPS Module - - ocil:ssg-enable_dracut_fips_module_action:testaction:1 - - - - Verify User Who Owns /etc/sudoers File - - ocil:ssg-file_owner_etc_sudoers_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly in /etc/profile - - ocil:ssg-accounts_umask_etc_profile_action:testaction:1 - - - - Enable Encrypted X11 Forwarding - - ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 - - - - Prevent Unrestricted Mail Relaying - - ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 - - - - Ensure the audit Subsystem is Installed - - ocil:ssg-package_audit_installed_action:testaction:1 - - - - Set Password Hashing Rounds in /etc/login.defs - - ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 - - - - Configure Firewalld to Trust Loopback Traffic - - ocil:ssg-firewalld_loopback_traffic_trusted_action:testaction:1 - - - - Verify Owner on cron.monthly - - ocil:ssg-file_owner_cron_monthly_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 - - - - Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 - - - - Do not allow usercopy whitelist violations to fallback to object size - - ocil:ssg-kernel_config_hardened_usercopy_fallback_action:testaction:1 - - - - Record Any Attempts to Run semanage - - ocil:ssg-audit_rules_execution_semanage_action:testaction:1 - - - - Ensure Sudo Logfile Exists - sudo logfile - - ocil:ssg-sudo_custom_logfile_action:testaction:1 - - - - Disable Core Dumps for All Users - - ocil:ssg-disable_users_coredumps_action:testaction:1 - - - - Configure file name of core dumps - - ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/passwd - - ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 - - - - Generate some entropy during boot and runtime - - ocil:ssg-kernel_config_gcc_plugin_latent_entropy_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config - - ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 - - - - Enable the kerberos_enabled SELinux Boolean - - ocil:ssg-sebool_kerberos_enabled_action:testaction:1 - - - - Verify Permissions on Backup passwd File - - ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 - - - - Disable graphical user interface - - ocil:ssg-xwindows_remove_packages_action:testaction:1 - - - - Record Any Attempts to Run seunshare - - ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 - - - - Ensure invoking users password for privilege escalation when using sudo - - ocil:ssg-sudoers_validate_passwd_action:testaction:1 - - - - Add nodev Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 - - - - Enable checks on linked list manipulation - - ocil:ssg-kernel_config_debug_list_action:testaction:1 - - - - Verify Group Who Owns /etc/chrony.keys File - - ocil:ssg-file_groupowner_etc_chrony_keys_action:testaction:1 - - - - Kernel panic oops - - ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 - - - - Disable loading and unloading of kernel modules - - ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 - - - - Ensure /var/log Located On Separate Partition - - ocil:ssg-partition_for_var_log_action:testaction:1 - - - - Verify Group Who Owns group File - - ocil:ssg-file_groupowner_etc_group_action:testaction:1 - - - - Disable network management of chrony daemon - - ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 - - - - Ensure gnutls-utils is installed - - ocil:ssg-package_gnutls-utils_installed_action:testaction:1 - - - - Disable debug-shell SystemD Service - - ocil:ssg-service_debug-shell_disabled_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config - - ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 - - - - Randomize the kernel memory sections - - ocil:ssg-kernel_config_randomize_memory_action:testaction:1 - - - - Disable the IPv6 protocol - - ocil:ssg-kernel_config_ipv6_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - umount - - ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 - - - - Enable syslog-ng Service - - ocil:ssg-service_syslogng_enabled_action:testaction:1 - - - - Disable the selinuxuser_execheap SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 - - - - Configure Libreswan to use System Crypto Policy - - ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 - - - - Enable the selinuxuser_execmod SELinux Boolean - - ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 - - - - Verify User Who Owns Backup gshadow File - - ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 - - - - Disable Mounting of cramfs - - ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chsh - - ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 - - - - Verify Group Who Owns /etc/iptables Directory - - ocil:ssg-directory_groupowner_etc_iptables_action:testaction:1 - - - - Install the pcsc-lite package - - ocil:ssg-package_pcsc-lite_installed_action:testaction:1 - - - - Ensure No Device Files are Unlabeled by SELinux - - ocil:ssg-selinux_all_devicefiles_labeled_action:testaction:1 - - - - zero-init everything passed by reference - - ocil:ssg-kernel_config_gcc_plugin_structleak_byref_all_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module - - ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 - - - - Ensure PAM Displays Last Logon/Access Notification - - ocil:ssg-display_login_attempts_action:testaction:1 - - - - Configure Multiple DNS Servers in /etc/resolv.conf - - ocil:ssg-network_configure_name_resolution_action:testaction:1 - - - - Configure Microarchitectural Data Sampling mitigation - - ocil:ssg-grub2_mds_argument_action:testaction:1 - - - - Install AIDE - - ocil:ssg-package_aide_installed_action:testaction:1 - - - - Install rear Package - - ocil:ssg-package_rear_installed_action:testaction:1 - - - - Add noexec Option to /home - - ocil:ssg-mount_option_home_noexec_action:testaction:1 - - - - Verify Group Who Owns /var/log/messages File - - ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 - - - - Set Default firewalld Zone for Incoming Packets - - ocil:ssg-set_firewalld_default_zone_action:testaction:1 - - - - Verify Only Root Has UID 0 - - ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 - - - - Verify that System Executables Have Restrictive Permissions - - ocil:ssg-file_permissions_binary_dirs_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - userhelper - - ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 - - - - Ensure syslog-ng is Installed - - ocil:ssg-package_syslogng_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd - - ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - - ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 - - - - Verify /boot/grub2/user.cfg User Ownership - - ocil:ssg-file_owner_user_cfg_action:testaction:1 - - - - Disable the use of user namespaces - - ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 - - - - Configure dnf-automatic to Install Available Updates Automatically - - ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 - - - - Configure auditd mail_acct Action on Low Disk Space - - ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 - - - - Ensure McAfee Endpoint Security for Linux (ENSL) is running - - ocil:ssg-agent_mfetpd_running_action:testaction:1 - - - - Disable legacy (BSD) PTY support - - ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rename - - ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 - - - - Add nosuid Option to Removable Media Partitions - - ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 - - - - Ensure auditd Collects Information on Exporting to Media (successful) - - ocil:ssg-audit_rules_media_export_action:testaction:1 - - - - Verify Owner on cron.hourly - - ocil:ssg-file_owner_cron_hourly_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Permissions - - ocil:ssg-file_permissions_efi_user_cfg_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - passwd - - ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 - - - - Ensure SELinux State is Enforcing - - ocil:ssg-selinux_state_action:testaction:1 - - - - Limit Password Reuse: system-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 - - - - Log USBGuard daemon audit events using Linux Audit - - ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 - - - - Verify Permissions on cron.monthly - - ocil:ssg-file_permissions_cron_monthly_action:testaction:1 - - - - Disable the 32-bit vDSO - - ocil:ssg-kernel_config_compat_vdso_action:testaction:1 - - - - Configure Firewalld to Use the Nftables Backend - - ocil:ssg-firewalld-backend_action:testaction:1 - - - - Verify Group Ownership of System Login Banner for Remote Connections - - ocil:ssg-file_groupowner_etc_issue_net_action:testaction:1 - - - - Ensure tmp.mount Unit Is Enabled - - ocil:ssg-systemd_tmp_mount_enabled_action:testaction:1 - - - - Add nosuid Option to /boot/efi - - ocil:ssg-mount_option_boot_efi_nosuid_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - setxattr - - ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 - - - - Verify Group Who Owns /etc/selinux Directory - - ocil:ssg-directory_groupowner_etc_selinux_action:testaction:1 - - - - Configure SELinux Policy - - ocil:ssg-selinux_policytype_action:testaction:1 - - - - Disable vsyscall mapping - - ocil:ssg-kernel_config_legacy_vsyscall_none_action:testaction:1 - - - - Verify nftables Service is Disabled - - ocil:ssg-service_nftables_disabled_action:testaction:1 - - - - Verify User Who Owns passwd File - - ocil:ssg-file_owner_etc_passwd_action:testaction:1 - - - - Configure immutable Audit login UIDs - - ocil:ssg-audit_immutable_login_uids_action:testaction:1 - - - - All GIDs referenced in /etc/passwd must be defined in /etc/group - - ocil:ssg-gid_passwd_group_same_action:testaction:1 - - - - Ensure Logrotate Runs Periodically - - ocil:ssg-ensure_logrotate_activated_action:testaction:1 - - - - Uninstall setroubleshoot-server Package - - ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 - - - - Add nodev Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 - - - - Set Account Expiration Following Inactivity - - ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign - - ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 - - - - Audit Tools Must Have a Mode of 0755 or Less Permissive - - ocil:ssg-file_audit_tools_permissions_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.conf File - - ocil:ssg-file_groupowner_etc_ipsec_conf_action:testaction:1 - - - - Record Attempts to perform maintenance activities - - ocil:ssg-audit_sudo_log_events_action:testaction:1 - - - - Disable mutable hooks - - ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 - - - - Enforce usage of pam_wheel for su authentication - - ocil:ssg-use_pam_wheel_for_su_action:testaction:1 - - - - Disable KDump Kernel Crash Analyzer (kdump) - - ocil:ssg-service_kdump_disabled_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 - - - - Disable GNOME3 Automount running - - ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 - - - - Ensure Logs Sent To Remote Host - - ocil:ssg-rsyslog_remote_loghost_action:testaction:1 - - - - Ensure All SUID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 - - - - Verify User Who Owns /var/log/syslog File - - ocil:ssg-file_owner_var_log_syslog_action:testaction:1 - - - - Verify Group Who Owns gshadow File - - ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 - - - - Prevent Login to Accounts With Empty Password - - ocil:ssg-no_empty_passwords_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - reboot - - ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 - - - - Verify Group Who Owns /var/log/syslog File - - ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 - - - - Ensure All User Initialization Files Have Mode 0740 Or Less Permissive - - ocil:ssg-file_permission_user_init_files_action:testaction:1 - - - - Record Attempts to Alter Time Through clock_settime - - ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 - - - - Disable merging of slabs with similar size - - ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 - - - - Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config - - ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 - - - - Set Boot Loader Password in grub2 - - ocil:ssg-grub2_password_action:testaction:1 - - - - Verify Permissions on /var/log/syslog File - - ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 - - - - Verify Group Who Owns /etc/cron.allow file - - ocil:ssg-file_groupowner_cron_allow_action:testaction:1 - - - - Configure dnf-automatic to Install Only Security Updates - - ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 - - - - Harden the operation of the BPF just-in-time compiler - - ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 - - - - Set SSH Client Alive Interval - - ocil:ssg-sshd_set_idle_timeout_action:testaction:1 - - - - Verify User Who Owns Backup passwd File - - ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - removexattr - - ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 - - - - Ensure System Log Files Have Correct Permissions - - ocil:ssg-rsyslog_files_permissions_action:testaction:1 - - - - Ensure the Default C Shell Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 - - - - Disable kernel support for MISC binaries - - ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 - - - - Configure Polyinstantiation of /tmp Directories - - ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.secrets File - - ocil:ssg-file_groupowner_etc_ipsec_secrets_action:testaction:1 - - - - Shutdown System When Auditing Failures Occur - - ocil:ssg-audit_rules_system_shutdown_action:testaction:1 - - - - Make the kernel text and rodata read-only - - ocil:ssg-kernel_config_strict_kernel_rwx_action:testaction:1 - - - - Avoid speculative indirect branches in kernel - - ocil:ssg-kernel_config_retpoline_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - password-auth - - ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 - - - - Verify that Shared Library Files Have Root Ownership - - ocil:ssg-file_ownership_library_dirs_action:testaction:1 - - - - Enable Smartcards in SSSD - - ocil:ssg-sssd_enable_smartcards_action:testaction:1 - - - - Verify ufw Enabled - - ocil:ssg-service_ufw_enabled_action:testaction:1 - - - - System Audit Logs Must Have Mode 0640 or Less Permissive - - ocil:ssg-file_permissions_var_log_audit_action:testaction:1 - - - - Ensure /var/tmp Located On Separate Partition - - ocil:ssg-partition_for_var_tmp_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check - - ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlinkat - - ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 - - - - Enable SSH Server firewalld Firewall Exception - - ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 - - - - Ensure No World-Writable Files Exist - - ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 - - - - Configure Response Mode of ARP Requests for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 - - - - Resolve information before writing to audit logs - - ocil:ssg-auditd_log_format_action:testaction:1 - - - - Set GNOME3 Screensaver Lock Delay After Activation Period - - ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 - - - - Restrict Access to Kernel Message Buffer - - ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 - - - - Disable Accepting Router Advertisements on all IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - - ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 - - - - Ensure /var/log/audit Located On Separate Partition - - ocil:ssg-partition_for_var_log_audit_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Hardlinks - - ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 - - - - Ensure gpgcheck Enabled for Local Packages - - ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 - - - - Enable the USBGuard Service - - ocil:ssg-service_usbguard_enabled_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls in usr/share - - ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 - - - - Configure SSSD to Expire Offline Credentials - - ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 - - - - Set number of Password Hashing Rounds - system-auth - - ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 - - - - Enable checks on credential management - - ocil:ssg-kernel_config_debug_credentials_action:testaction:1 - - - - Verify and Correct Ownership with RPM - - ocil:ssg-rpm_verify_ownership_action:testaction:1 - - - - Disable snmpd Service - - ocil:ssg-service_snmpd_disabled_action:testaction:1 - - - - Verify File Hashes with RPM - - ocil:ssg-rpm_verify_hashes_action:testaction:1 - - - - Verify Group Who Owns SSH Server config file - - ocil:ssg-file_groupowner_sshd_config_action:testaction:1 - - - - Install crypto-policies package - - ocil:ssg-package_crypto-policies_installed_action:testaction:1 - - - - Ensure SMEP is not disabled during boot - - ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 - - - - Install audispd-plugins Package - - ocil:ssg-package_audispd-plugins_installed_action:testaction:1 - - - - Enable SLUB/SLAB allocator poisoning - - ocil:ssg-grub2_slub_debug_argument_action:testaction:1 - - - - Verify User Who Owns Backup shadow File - - ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 - - - - User a virtually-mapped stack - - ocil:ssg-kernel_config_vmap_stack_action:testaction:1 - - - - Verify Group Who Owns /var/log Directory - - ocil:ssg-file_groupowner_var_log_action:testaction:1 - - - - Harden SSH client Crypto Policy - - ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 - - - - Verify Permissions on Backup gshadow File - - ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 - - - - Ensure All-Squashing Disabled On All Exports - - ocil:ssg-no_all_squash_exports_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - - ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 - - - - Disable GSSAPI Authentication - - ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 - - - - Enable TCP/IP syncookie support - - ocil:ssg-kernel_config_syn_cookies_action:testaction:1 - - - - Verify User Who Owns Backup group File - - ocil:ssg-file_owner_backup_etc_group_action:testaction:1 - - - - Set type of computer node name logging in audit logs - - ocil:ssg-auditd_name_format_action:testaction:1 - - - - Disable telnet Service - - ocil:ssg-service_telnet_disabled_action:testaction:1 - - - - Verify Permissions On /etc/selinux Directory - - ocil:ssg-directory_permissions_etc_selinux_action:testaction:1 - - - - Disallow kernel profiling by unprivileged users - - ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lremovexattr - - ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 - - - - Enable SSH Warning Banner - - ocil:ssg-sshd_enable_warning_banner_action:testaction:1 - - - - Audit Tools Must Be Owned by Root - - ocil:ssg-file_audit_tools_ownership_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - unlink - - ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 - - - - Configure Logind to terminate idle sessions after certain time of inactivity - - ocil:ssg-logind_session_timeout_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_action:testaction:1 - - - - Enable the GNOME3 Screen Locking On Smartcard Removal - - ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 - - - - Record Events that Modify the System's Mandatory Access Controls - - ocil:ssg-audit_rules_mac_modification_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.secrets File - - ocil:ssg-file_permissions_etc_ipsec_secrets_action:testaction:1 - - - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 - - - - Disable SSH Root Login - - ocil:ssg-sshd_disable_root_login_action:testaction:1 - - - - Verify Group Ownership on SSH Server Public *.pub Key Files - - ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 - - - - Configure auditing of unsuccessful file accesses - - ocil:ssg-audit_access_failed_action:testaction:1 - - - - Add noexec Option to /var - - ocil:ssg-mount_option_var_noexec_action:testaction:1 - - - - Remove telnet Clients - - ocil:ssg-package_telnet_removed_action:testaction:1 - - - - Set SSH Daemon LogLevel to VERBOSE - - ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 - - - - Configure Denying Router Solicitations on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 - - - - Make the module text and rodata read-only - - ocil:ssg-kernel_config_strict_module_rwx_action:testaction:1 - - - - Set Root Account Password Maximum Age - - ocil:ssg-accounts_password_set_max_life_root_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 - - - - Disable SSH TCP Forwarding - - ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 - - - - Verify Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 - - - - SSSD Has a Correct Trust Anchor - - ocil:ssg-sssd_has_trust_anchor_action:testaction:1 - - - - Set Password Maximum Consecutive Repeating Characters - - ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty - - ocil:ssg-sudo_add_use_pty_action:testaction:1 - - - - Configure the secure_mode_insmod SELinux Boolean - - ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 - - - - Configure auditing of loading and unloading of kernel modules - - ocil:ssg-audit_module_load_action:testaction:1 - - - - Verify Permissions on SSH Server Private *_key Key Files - - ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 - - - - Configure System to Forward All Mail For The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 - - - - Verify Group Who Owns cron.d - - ocil:ssg-file_groupowner_cron_d_action:testaction:1 - - - - Use Centralized and Automated Authentication - - ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 - - - - Verify Permissions on /etc/cron.allow file - - ocil:ssg-file_permissions_cron_allow_action:testaction:1 - - - - Don't target root user in the sudoers file - - ocil:ssg-sudoers_no_root_target_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - mount - - ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 - - - - Install policycoreutils Package - - ocil:ssg-package_policycoreutils_installed_action:testaction:1 - - - - Prefer to use a 64-bit Operating System when supported - - ocil:ssg-prefer_64bit_os_action:testaction:1 - - - - Configure Notification of Post-AIDE Scan Details - - ocil:ssg-aide_scan_notification_action:testaction:1 - - - - Modify the System Login Banner for Remote Connections - - ocil:ssg-banner_etc_issue_net_action:testaction:1 - - - - Configure System to Forward All Mail From Postmaster to The Root Account - - ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 - - - - The Chrony package is installed - - ocil:ssg-package_chrony_installed_action:testaction:1 - - - - Configure maximum number of process identifiers - - ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 - - - - Verify Permissions on /var/log Directory - - ocil:ssg-file_permissions_var_log_action:testaction:1 - - - - Poison kernel stack before returning from syscalls - - ocil:ssg-kernel_config_gcc_plugin_stackleak_action:testaction:1 - - - - Enable FIPS Mode - - ocil:ssg-enable_fips_mode_action:testaction:1 - - - - Ensure There Are No Accounts With Blank or Null Passwords - - ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 - - - - Ensure All Files Are Owned by a User - - ocil:ssg-no_files_unowned_by_user_action:testaction:1 - - - - Install usbguard Package - - ocil:ssg-package_usbguard_installed_action:testaction:1 - - - - Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC - - ocil:ssg-sudo_add_noexec_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postqueue - - ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 - - - - Install scap-security-guide Package - - ocil:ssg-package_scap-security-guide_installed_action:testaction:1 - - - - Disable storing core dumps - - ocil:ssg-sysctl_kernel_core_pattern_empty_string_action:testaction:1 - - - - Limit CPU consumption of the Perf system - - ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 - - - - Set the Boot Loader Admin Username to a Non-Default Value - - ocil:ssg-grub2_admin_username_action:testaction:1 - - - - Configure auditing of unsuccessful file deletions - - ocil:ssg-audit_delete_failed_action:testaction:1 - - - - Ensure PAM password complexity module is enabled in password-auth - - ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 - - - - Explicit arguments in sudo specifications - - ocil:ssg-sudoers_explicit_command_args_action:testaction:1 - - - - Disable Avahi Server Software - - ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 - - - - Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty - - ocil:ssg-ensure_pam_wheel_group_empty_action:testaction:1 - - - - Disable storing core dumps - - ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/gshadow - - ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 - - - - Prevent remote hosts from connecting to the proxy display - - ocil:ssg-sshd_x11_use_localhost_action:testaction:1 - - - - Add noexec Option to /dev/shm - - ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 - - - - Kernel panic timeout - - ocil:ssg-kernel_config_panic_timeout_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 - - - - Verify User Who Owns /etc/chrony.keys File - - ocil:ssg-file_owner_etc_chrony_keys_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fremovexattr - - ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/group - - ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 - - - - Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 - - - - Enable the pcscd Service - - ocil:ssg-service_pcscd_enabled_action:testaction:1 - - - - Enable poison of pages after freeing - - ocil:ssg-kernel_config_page_poisoning_action:testaction:1 - - - - Verify Permissions on passwd File - - ocil:ssg-file_permissions_etc_passwd_action:testaction:1 - - - - Set PAM''s Password Hashing Algorithm - - ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 - - - - Configure Backups of User Data - - ocil:ssg-configure_user_data_backups_action:testaction:1 - - - - Only the VDSM User Can Use sudo NOPASSWD - - ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 - - - - Ensure rsyslog-gnutls is installed - - ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 - - - - Configure auditd to use audispd's syslog plugin - - ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 - - - - Verify Permissions on Backup group File - - ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 - - - - Verify User Who Owns System.map Files - - ocil:ssg-file_owner_systemmap_action:testaction:1 - - - - Add noexec Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 - - - - Disable Squid - - ocil:ssg-service_squid_disabled_action:testaction:1 - - - - Verify Permissions on crontab - - ocil:ssg-file_permissions_crontab_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate - - ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 - - - - System Audit Logs Must Be Group Owned By Root - - ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 - - - - The operating system must restrict privilege elevation to authorized personnel - - ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - init - - ocil:ssg-audit_privileged_commands_init_action:testaction:1 - - - - Verify Group Who Owns Backup group File - - ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 - - - - Configure BIND to use System Crypto Policy - - ocil:ssg-configure_bind_crypto_policy_action:testaction:1 - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_accept_default_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - newgrp - - ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on Regular files - - ocil:ssg-sysctl_fs_protected_regular_action:testaction:1 - - - - Enable auditd Service - - ocil:ssg-service_auditd_enabled_action:testaction:1 - - - - Ensure rsyncd service is disabled - - ocil:ssg-service_rsyncd_disabled_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.d Directory - - ocil:ssg-directory_owner_etc_ipsecd_action:testaction:1 - - - - Disable kexec system call - - ocil:ssg-kernel_config_kexec_action:testaction:1 - - - - Ensure auditd Collects File Deletion Events by User - rmdir - - ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 - - - - Record attempts to alter time through adjtimex - - ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 - - - - Disable SSH Support for User Known Hosts - - ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 - - - - Verify User Who Owns /var/log Directory - - ocil:ssg-file_owner_var_log_action:testaction:1 - - - - Ensure that chronyd is running under chrony user account - - ocil:ssg-chronyd_run_as_chrony_user_action:testaction:1 - - - - Enable PAM - - ocil:ssg-sshd_enable_pam_action:testaction:1 - - - - Disable Postfix Network Listening - - ocil:ssg-postfix_network_listening_disabled_action:testaction:1 - - - - Verify User Who Owns /etc/sestatus.conf File - - ocil:ssg-file_owner_etc_sestatus_conf_action:testaction:1 - - - - Configure auditd Disk Error Action on Disk Error - - ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 - - - - Configure Time Service Maxpoll Interval - - ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 - - - - Add noexec Option to /tmp - - ocil:ssg-mount_option_tmp_noexec_action:testaction:1 - - - - Disable the ssh_sysadm_login SELinux Boolean - - ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - - ocil:ssg-audit_rules_privileged_commands_action:testaction:1 - - - - Verify Group Who Owns System.map Files - - ocil:ssg-file_groupowner_systemmap_action:testaction:1 - - - - Mount Remote Filesystems with noexec - - ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 - - - - Ensure SSH MaxStartups is configured - - ocil:ssg-sshd_set_maxstartups_action:testaction:1 - - - - Chrony Configure Pool and Server - - ocil:ssg-chronyd_configure_pool_and_server_action:testaction:1 - - - - Verify Group Who Owns /etc/nftables Directory - - ocil:ssg-directory_groupowner_etc_nftables_action:testaction:1 - - - - Verify Group Who Owns cron.daily - - ocil:ssg-file_groupowner_cron_daily_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - unix_update - - ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 - - - - Configure auditd space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 - - - - Disable Modprobe Loading of USB Storage Driver - - ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 - - - - Set number of Password Hashing Rounds - password-auth - - ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 - - - - Configure auditing of unsuccessful file modifications - - ocil:ssg-audit_modify_failed_action:testaction:1 - - - - Add noexec Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 - - - - Do not allow ACPI methods to be inserted/replaced at run time - - ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 - - - - Disable SSH root Login with a Password (Insecure) - - ocil:ssg-sshd_disable_root_password_login_action:testaction:1 - - - - Ensure the Default Umask is Set Correctly For Interactive Users - - ocil:ssg-accounts_umask_interactive_users_action:testaction:1 - - - - Add noexec Option to /boot - - ocil:ssg-mount_option_boot_noexec_action:testaction:1 - - - - Install the SSSD Package - - ocil:ssg-package_sssd_installed_action:testaction:1 - - - - Enable dnf-automatic Timer - - ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 - - - - Verify Permissions On /etc/crypttab File - - ocil:ssg-file_permissions_etc_crypttab_action:testaction:1 - - - - Configure auditing of unsuccessful ownership changes - - ocil:ssg-audit_owner_change_failed_action:testaction:1 - - - - All Interactive Users Home Directories Must Exist - - ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 - - - - Generate USBGuard Policy - - ocil:ssg-usbguard_generate_policy_action:testaction:1 - - - - Enable module signature verification - - ocil:ssg-kernel_config_module_sig_action:testaction:1 - - - - Disable Compression Or Set Compression to delayed - - ocil:ssg-sshd_disable_compression_action:testaction:1 - - - - Ensure No Daemons are Unconfined by SELinux - - ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 - - - - Ensure All World-Writable Directories Are Owned by root User - - ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 - - - - Record Attempts to Alter Time Through stime - - ocil:ssg-audit_rules_time_stime_action:testaction:1 - - - - Record Any Attempts to Run chcon - - ocil:ssg-audit_rules_execution_chcon_action:testaction:1 - - - - Disable acquiring, saving, and processing core dumps - - ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 - - - - Add nosuid Option to /home - - ocil:ssg-mount_option_home_nosuid_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate Group - - ocil:ssg-rsyslog_files_groupownership_action:testaction:1 - - - - Verify Permissions On /etc/iptables Directory - - ocil:ssg-directory_permissions_etc_iptables_action:testaction:1 - - - - Configure auditd flush priority - - ocil:ssg-auditd_data_retention_flush_action:testaction:1 - - - - Add nosuid Option to /var - - ocil:ssg-mount_option_var_nosuid_action:testaction:1 - - - - Enable checks on scatter-gather (SG) table operations - - ocil:ssg-kernel_config_debug_sg_action:testaction:1 - - - - Warn on W+X mappings found at boot - - ocil:ssg-kernel_config_debug_wx_action:testaction:1 - - - - Do Not Allow SSH Environment Options - - ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 - - - - Configure auditing of successful file accesses - - ocil:ssg-audit_access_success_action:testaction:1 - - - - Ensure All Groups on the System Have Unique Group ID - - ocil:ssg-group_unique_id_action:testaction:1 - - - - The s-nail Package Is Installed - - ocil:ssg-package_s-nail_installed_action:testaction:1 - - - - Verify ownership of System Login Banner for Remote Connections - - ocil:ssg-file_owner_etc_issue_net_action:testaction:1 - - - - Ensure Rsyslog Authenticates Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.secrets File - - ocil:ssg-file_owner_etc_ipsec_secrets_action:testaction:1 - - - - Enable Kernel Parameter to Enforce DAC on FIFOs - - ocil:ssg-sysctl_fs_protected_fifos_action:testaction:1 - - - - Ensure /var Located On Separate Partition - - ocil:ssg-partition_for_var_action:testaction:1 - - - - Verify User Who Owns /etc/ipsec.conf File - - ocil:ssg-file_owner_etc_ipsec_conf_action:testaction:1 - - - - Add nosuid Option to /var/log/audit - - ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD - - ocil:ssg-sudo_remove_nopasswd_action:testaction:1 - - - - Add nodev Option to /var/tmp - - ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 - - - - Set Password Hashing Algorithm in /etc/login.defs - - ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 - - - - Disable the Automounter - - ocil:ssg-service_autofs_disabled_action:testaction:1 - - - - Verify permissions on System Login Banner for Remote Connections - - ocil:ssg-file_permissions_etc_issue_net_action:testaction:1 - - - - Disable Graphical Environment Startup By Setting Default Target - - ocil:ssg-xwindows_runlevel_target_action:testaction:1 - - - - Disable Ctrl-Alt-Del Burst Action - - ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 - - - - Remove the X Windows Package Group - - ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 - - - - Add noexec Option to /var/log - - ocil:ssg-mount_option_var_log_noexec_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - chmod - - ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - lsetxattr - - ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - openat - - ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 - - - - Verify Permissions On /etc/sudoers File - - ocil:ssg-file_permissions_etc_sudoers_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg Group Ownership - - ocil:ssg-file_groupowner_efi_grub2_cfg_action:testaction:1 - - - - Ensure Software Patches Installed - - ocil:ssg-security_patches_up_to_date_action:testaction:1 - - - - Perform general configuration of Audit for OSPP - - ocil:ssg-audit_ospp_general_action:testaction:1 - - - - Enable cron Service - - ocil:ssg-service_crond_enabled_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 - - - - Verify Permissions on cron.d - - ocil:ssg-file_permissions_cron_d_action:testaction:1 - - - - Ensure rsyslog is Installed - - ocil:ssg-package_rsyslog_installed_action:testaction:1 - - - - Add nodev Option to /var - - ocil:ssg-mount_option_var_nodev_action:testaction:1 - - - - Record attempts to alter time through settimeofday - - ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 - - - - Specify the hash to use when signing modules - - ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 - - - - Disable Accepting Packets Routed Between Local Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 - - - - Require Authentication for Single User Mode - - ocil:ssg-require_singleuser_auth_action:testaction:1 - - - - Enable GNOME3 Login Warning Banner - - ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class - - ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 - - - - Set the UEFI Boot Loader Password - - ocil:ssg-grub2_uefi_password_action:testaction:1 - - - - Configure TLS for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 - - - - Verify Permissions on cron.weekly - - ocil:ssg-file_permissions_cron_weekly_action:testaction:1 - - - - Ensure Rsyslog Encrypts Off-Loaded Audit Records - - ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 - - - - Enable the File Access Policy Service - - ocil:ssg-service_fapolicyd_enabled_action:testaction:1 - - - - Uninstall rsh-server Package - - ocil:ssg-package_rsh-server_removed_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fsetxattr - - ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 - - - - Disable compatibility with brk() - - ocil:ssg-kernel_config_compat_brk_action:testaction:1 - - - - Randomize slab freelist - - ocil:ssg-kernel_config_slab_freelist_random_action:testaction:1 - - - - Uninstall Sendmail Package - - ocil:ssg-package_sendmail_removed_action:testaction:1 - - - - Configure auditd Disk Full Action when Disk Space Is Full - - ocil:ssg-auditd_data_disk_full_action_action:testaction:1 - - - - Require Re-Authentication When Using the sudo Command - - ocil:ssg-sudo_require_reauthentication_action:testaction:1 - - - - Require Encryption for Remote Access in GNOME3 - - ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 - - - - Verify Group Who Owns /etc/at.allow file - - ocil:ssg-file_groupowner_at_allow_action:testaction:1 - - - - Disable SSH Access via Empty Passwords - - ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 - - - - Ensure Users Re-Authenticate for Privilege Escalation - sudo - - ocil:ssg-sudo_require_authentication_action:testaction:1 - - - - Verify Permissions on gshadow File - - ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 - - - - Enable Certmap in SSSD - - ocil:ssg-sssd_enable_certmap_action:testaction:1 - - - - Disable hibernation - - ocil:ssg-kernel_config_hibernation_action:testaction:1 - - - - Disable the GNOME3 Login Restart and Shutdown Buttons - - ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 - - - - Configure L1 Terminal Fault mitigations - - ocil:ssg-grub2_l1tf_argument_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default - - ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - crontab - - ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 - - - - Limit Users' SSH Access - - ocil:ssg-sshd_limit_user_access_action:testaction:1 - - - - Ensure All SGID Executables Are Authorized - - ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 - - - - Enable randomization of the page allocator - - ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 - - - - Configure GNOME3 DConf User Profile - - ocil:ssg-enable_dconf_user_profile_action:testaction:1 - - - - Enable GNOME3 Screensaver Idle Activation - - ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 - - - - Enable authselect - - ocil:ssg-enable_authselect_action:testaction:1 - - - - Disable x86 vsyscall emulation - - ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 - - - - Ensure System is Not Acting as a Network Sniffer - - ocil:ssg-network_sniffer_disabled_action:testaction:1 - - - - Ensure that /etc/cron.deny does not exist - - ocil:ssg-file_cron_deny_not_exist_action:testaction:1 - - - - Install nftables Package - - ocil:ssg-package_nftables_installed_action:testaction:1 - - - - Verify Group Who Owns cron.hourly - - ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 - - - - Disable Odd Job Daemon (oddjobd) - - ocil:ssg-service_oddjobd_disabled_action:testaction:1 - - - - Ensure all users last password change date is in the past - - ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 - - - - Uninstall tftp-server Package - - ocil:ssg-package_tftp-server_removed_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 - - - - Verify that Shared Library Directories Have Root Group Ownership - - ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 - - - - Configure AIDE to Verify the Audit Tools - - ocil:ssg-aide_check_audit_tools_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Loading and Unloading - - ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 - - - - Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems - - ocil:ssg-configured_firewalld_default_deny_action:testaction:1 - - - - Audit Tools Must Be Group-owned by Root - - ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 - - - - Verify Permissions on /etc/shells File - - ocil:ssg-file_permissions_etc_shells_action:testaction:1 - - - - Verify Permissions on SSH Server Public *.pub Key Files - - ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 - - - - Ensure SSH LoginGraceTime is configured - - ocil:ssg-sshd_set_login_grace_time_action:testaction:1 - - - - Ensure Log Files Are Owned By Appropriate User - - ocil:ssg-rsyslog_files_ownership_action:testaction:1 - - - - Enable Postfix Service - - ocil:ssg-service_postfix_enabled_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - faillock - - ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 - - - - The Installed Operating System Is Vendor Supported - - ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 - - - - Ensure that User Home Directories are not Group-Writable or World-Readable - - ocil:ssg-file_permissions_home_dirs_action:testaction:1 - - - - Verify Permissions On /etc/sysctl.d Directory - - ocil:ssg-directory_permissions_etc_sysctld_action:testaction:1 - - - - Verify Owner on SSH Server config file - - ocil:ssg-file_owner_sshd_config_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg Permissions - - ocil:ssg-file_permissions_efi_grub2_cfg_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - shutdown - - ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 - - - - Verify firewalld Enabled - - ocil:ssg-service_firewalld_enabled_action:testaction:1 - - - - Record Any Attempts to Run chacl - - ocil:ssg-audit_rules_execution_chacl_action:testaction:1 - - - - Uninstall quagga Package - - ocil:ssg-package_quagga_removed_action:testaction:1 - - - - Disable chrony daemon from acting as server - - ocil:ssg-chronyd_client_only_action:testaction:1 - - - - Record Any Attempts to Run ssh-agent - - ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 - - - - Certificate status checking in SSSD - - ocil:ssg-sssd_certificate_verification_action:testaction:1 - - - - Verify Group Who Owns /etc/sestatus.conf File - - ocil:ssg-file_groupowner_etc_sestatus_conf_action:testaction:1 - - - - Uninstall talk Package - - ocil:ssg-package_talk_removed_action:testaction:1 - - - - Harden common str/mem functions against buffer overflows - - ocil:ssg-kernel_config_fortify_source_action:testaction:1 - - - - Disallow merge of slab caches - - ocil:ssg-kernel_config_slab_merge_default_action:testaction:1 - - - - Force frequent session key renegotiation - - ocil:ssg-sshd_rekey_limit_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open_by_handle_at - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 - - - - Verify Permissions on cron.hourly - - ocil:ssg-file_permissions_cron_hourly_action:testaction:1 - - - - Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - - ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 - - - - Set number of records to cause an explicit flush to audit logs - - ocil:ssg-auditd_freq_action:testaction:1 - - - - Enable automatic signing of all modules - - ocil:ssg-kernel_config_module_sig_all_action:testaction:1 - - - - Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 - - - - Install OpenSSH client software - - ocil:ssg-package_openssh-clients_installed_action:testaction:1 - - - - Unmap kernel when running in userspace (aka KAISER) - - ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 - - - - Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server - - ocil:ssg-sssd_ldap_configure_tls_reqcert_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words - - ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 - - - - Verify /boot/grub2/user.cfg User Ownership - - ocil:ssg-file_owner_efi_user_cfg_action:testaction:1 - - - - Detect stack corruption on calls to schedule() - - ocil:ssg-kernel_config_sched_stack_end_check_action:testaction:1 - - - - Ensure logrotate is Installed - - ocil:ssg-package_logrotate_installed_action:testaction:1 - - - - Enable poison without sanity check - - ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 - - - - Ensure Users Cannot Change GNOME3 Session Idle Settings - - ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 - - - - Verify Permissions on Backup shadow File - - ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 - - - - Configure Firewalld to Restrict Loopback Traffic - - ocil:ssg-firewalld_loopback_traffic_restricted_action:testaction:1 - - - - Configure the polyinstantiation_enabled SELinux Boolean - - ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 - - - - Specify module signing key to use - - ocil:ssg-kernel_config_module_sig_key_action:testaction:1 - - - - Build and Test AIDE Database - - ocil:ssg-aide_build_database_action:testaction:1 - - - - Verify Group Who Owns /etc/sudoers.d Directory - - ocil:ssg-directory_groupowner_etc_sudoersd_action:testaction:1 - - - - Uninstall vsftpd Package - - ocil:ssg-package_vsftpd_removed_action:testaction:1 + ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 @@ -244228,1600 +264513,22 @@ fi ocil:ssg-account_disable_inactivity_system_auth_action:testaction:1 - - Set Account Expiration Following Inactivity in password-auth + + Set Account Expiration Following Inactivity - ocil:ssg-account_disable_inactivity_password_auth_action:testaction:1 + ocil:ssg-account_disable_post_pw_expiration_action:testaction:1 - - Set kernel parameter 'crypto.fips_enabled' to 1 + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/password-auth File. - ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 + ocil:ssg-account_password_pam_faillock_password_auth_action:testaction:1 - - Verify Owner on crontab + + Configure the Use of the pam_faillock.so Module in the /etc/pam.d/system-auth File. - ocil:ssg-file_owner_crontab_action:testaction:1 - - - - Verify that System Executable Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Length - - ocil:ssg-accounts_password_pam_minlen_action:testaction:1 - - - - Verify Group Who Owns /etc/ipsec.d Directory - - ocil:ssg-directory_groupowner_etc_ipsecd_action:testaction:1 - - - - Verify User Who Owns /etc/cron.allow file - - ocil:ssg-file_owner_cron_allow_action:testaction:1 - - - - Configure the root Account for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 - - - - Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - creat - - ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 - - - - Harden memory copies between kernel and userspace - - ocil:ssg-kernel_config_hardened_usercopy_action:testaction:1 - - - - Disable GNOME3 Automount Opening - - ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 - - - - Disable PubkeyAuthentication Authentication - - ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 - - - - Configure auditd admin_space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 - - - - Enforce Usage of pam_wheel with Group Parameter for su Authentication - - ocil:ssg-use_pam_wheel_group_for_su_action:testaction:1 - - - - Account Lockouts Must Persist - - ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 - - - - Lock Accounts Must Persist - - ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 - - - - Configure kernel to zero out memory before allocation - - ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 - - - - Use Only Strong MACs - - ocil:ssg-sshd_use_strong_macs_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - umount - - ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 - - - - Extend Audit Backlog Limit for the Audit Daemon - - ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 - - - - The Postfix package is installed - - ocil:ssg-package_postfix_installed_action:testaction:1 - - - - Trigger a kernel BUG when data corruption is detected - - ocil:ssg-kernel_config_bug_on_data_corruption_action:testaction:1 - - - - Verify Group Who Owns cron.deny - - ocil:ssg-file_groupowner_cron_deny_action:testaction:1 - - - - Disable Access to Network bpf() Syscall From Unprivileged Processes - - ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 - - - - Disallow magic SysRq key - - ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 - - - - Enable systemd-journald Service - - ocil:ssg-service_systemd-journald_enabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Special Characters - - ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 - - - - Ensure that Users Path Contains Only Local Directories - - ocil:ssg-accounts_user_home_paths_only_action:testaction:1 - - - - System Audit Logs Must Have Mode 0750 or Less Permissive - - ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 - - - - Configure Low Address Space To Protect From User Allocation - - ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 - - - - Disable GNOME3 Automounting - - ocil:ssg-dconf_gnome_disable_automount_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - open - - ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 - - - - Disable Host-Based Authentication - - ocil:ssg-disable_host_auth_action:testaction:1 - - - - System Audit Logs Must Be Owned By Root - - ocil:ssg-file_ownership_var_log_audit_action:testaction:1 - - - - Add nosuid Option to /boot - - ocil:ssg-mount_option_boot_nosuid_action:testaction:1 - - - - Write Audit Logs to the Disk - - ocil:ssg-auditd_write_logs_action:testaction:1 - - - - Configure auditd space_left Action on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 - - - - Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 - - - - Configure ARP filtering for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 - - - - Require modules to be validly signed - - ocil:ssg-kernel_config_module_sig_force_action:testaction:1 - - - - Verify that System Executables Have Root Ownership - - ocil:ssg-file_ownership_binary_dirs_action:testaction:1 - - - - Limit Password Reuse - - ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 - - - - Disable vsyscall emulation - - ocil:ssg-kernel_config_legacy_vsyscall_emulate_action:testaction:1 - - - - Configure auditing of unsuccessful file creations - - ocil:ssg-audit_create_failed_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Group Ownership - - ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 - - - - Ensure Oracle Linux GPG Key Installed - - ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 - - - - Include Local Events in Audit Logs - - ocil:ssg-auditd_local_events_action:testaction:1 - - - - Stack Protector buffer overlow detection - - ocil:ssg-kernel_config_stackprotector_action:testaction:1 - - - - Add grpquota Option to /home - - ocil:ssg-mount_option_home_grpquota_action:testaction:1 - - - - Limit Password Reuse: password-auth - - ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 - - - - Install the OpenSSH Server Package - - ocil:ssg-package_openssh-server_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - postdrop - - ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ - - ocil:ssg-audit_rules_sudoers_d_action:testaction:1 - - - - Disable Kernel Parameter for IPv6 Forwarding - - ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 - - - - Record Attempts to Alter the localtime File - - ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 - - - - Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_forwarding_action:testaction:1 - - - - Install fapolicyd Package - - ocil:ssg-package_fapolicyd_installed_action:testaction:1 - - - - Set the GNOME3 Login Warning Banner Text - - ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 - - - - Enforce Spectre v2 mitigation - - ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces By Default - - ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 - - - - Prevent applications from mapping low portion of virtual memory - - ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 - - - - Verify Permissions On /etc/ipsec.conf File - - ocil:ssg-file_permissions_etc_ipsec_conf_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 - - - - Force initialization of variables containing userspace addresses - - ocil:ssg-kernel_config_gcc_plugin_structleak_action:testaction:1 - - - - Emulate Privileged Access Never (PAN) - - ocil:ssg-kernel_config_arm64_sw_ttbr0_pan_action:testaction:1 - - - - Disable IPv6 Addressing on IPv6 Interfaces by Default - - ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 - - - - Add nosuid Option to /srv - - ocil:ssg-mount_option_srv_nosuid_action:testaction:1 - - - - Disable the GNOME3 Login User List - - ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 - - - - Disable IA32 emulation - - ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 - - - - Disable Recovery Booting - - ocil:ssg-grub2_disable_recovery_action:testaction:1 - - - - Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server - - ocil:ssg-rsyslog_nolisten_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique Names - - ocil:ssg-account_unique_name_action:testaction:1 - - - - Verify Group Who Owns cron.weekly - - ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 - - - - Install Smart Card Packages For Multifactor Authentication - - ocil:ssg-install_smartcard_packages_action:testaction:1 - - - - Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config - - ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 - - - - Verify /boot/grub2/grub.cfg Group Ownership - - ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 - - - - Enable Kernel Page-Table Isolation (KPTI) - - ocil:ssg-grub2_pti_argument_action:testaction:1 - - - - Verify No netrc Files Exist - - ocil:ssg-no_netrc_files_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - tallylog - - ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 - - - - System Audit Directories Must Be Group Owned By Root - - ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 - - - - All Interactive User Home Directories Must Have mode 0750 Or Less Permissive - - ocil:ssg-file_permissions_home_directories_action:testaction:1 - - - - Ensure nss-tools is installed - - ocil:ssg-package_nss-tools_installed_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - at - - ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 - - - - Verify Group Ownership on SSH Server Private *_key Key Files - - ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 - - - - Disable SSH Server If Possible - - ocil:ssg-service_sshd_disabled_action:testaction:1 - - - - Configure Polyinstantiation of /var/tmp Directories - - ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 - - - - Verify Owner on cron.daily - - ocil:ssg-file_owner_cron_daily_action:testaction:1 - - - - Enable logrotate Timer - - ocil:ssg-timer_logrotate_enabled_action:testaction:1 - - - - All Interactive User Home Directories Must Be Group-Owned By The Primary Group - - ocil:ssg-file_groupownership_home_directories_action:testaction:1 - - - - Set Default iptables Policy for Incoming Packets - - ocil:ssg-set_iptables_default_rule_action:testaction:1 - - - - Remove Rsh Trust Files - - ocil:ssg-no_rsh_trust_files_action:testaction:1 - - - - Verify that All World-Writable Directories Have Sticky Bits Set - - ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 - - - - Configure Auto Configuration on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 - - - - Remove the kernel mapping in user mode - - ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - kmod - - ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 - - - - Uninstall telnet-server Package - - ocil:ssg-package_telnet-server_removed_action:testaction:1 - - - - Verify User Who Owns /etc/selinux Directory - - ocil:ssg-directory_owner_etc_selinux_action:testaction:1 - - - - Install openscap-scanner Package - - ocil:ssg-package_openscap-scanner_installed_action:testaction:1 - - - - Ensure the Logon Failure Delay is Set Correctly in login.defs - - ocil:ssg-accounts_logon_fail_delay_action:testaction:1 - - - - Ensure auditd Collects Information on Kernel Module Unloading - delete_module - - ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 - - - - Verify User Who Owns shadow File - - ocil:ssg-file_owner_etc_shadow_action:testaction:1 - - - - Verify User Who Owns /etc/crypttab File - - ocil:ssg-file_owner_etc_crypttab_action:testaction:1 - - - - Verify Permissions On /etc/chrony.keys File - - ocil:ssg-file_permissions_etc_chrony_keys_action:testaction:1 - - - - Verify that Shared Library Directories Have Restrictive Permissions - - ocil:ssg-dir_permissions_library_dirs_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchown - - ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 - - - - Disable At Service (atd) - - ocil:ssg-service_atd_disabled_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - /etc/sudoers - - ocil:ssg-audit_rules_sudoers_action:testaction:1 - - - - Strong Stack Protector - - ocil:ssg-kernel_config_stackprotector_strong_action:testaction:1 - - - - Configure the Firewalld Ports - - ocil:ssg-configure_firewalld_ports_action:testaction:1 - - - - Install policycoreutils-python-utils package - - ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 - - - - Configure AIDE to Use FIPS 140-2 for Validating Hashes - - ocil:ssg-aide_use_fips_hashes_action:testaction:1 - - - - Remove Host-Based Authentication Files - - ocil:ssg-no_host_based_files_action:testaction:1 - - - - Ensure SMAP is not disabled during boot - - ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 - - - - Verify iptables Enabled - - ocil:ssg-service_iptables_enabled_action:testaction:1 - - - - Enable different security models - - ocil:ssg-kernel_config_security_action:testaction:1 - - - - Disable CAN Support - - ocil:ssg-kernel_module_can_disabled_action:testaction:1 - - - - Perform full reference count validation - - ocil:ssg-kernel_config_refcount_full_action:testaction:1 - - - - Enable rsyslog Service - - ocil:ssg-service_rsyslog_enabled_action:testaction:1 - - - - Restrict Serial Port Root Logins - - ocil:ssg-restrict_serial_port_logins_action:testaction:1 - - - - Appropriate Action Must be Setup When the Internal Audit Event Queue is Full - - ocil:ssg-auditd_overflow_action_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - su - - ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 - - - - Configure SNMP Service to Use Only SNMPv3 or Newer - - ocil:ssg-snmpd_use_newer_protocol_action:testaction:1 - - - - Disable Accepting ICMP Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 - - - - Verify User Who Owns /etc/sudoers.d Directory - - ocil:ssg-directory_owner_etc_sudoersd_action:testaction:1 - - - - Ensure that System Accounts Are Locked - - ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 - - - - Enable SSH Print Last Log - - ocil:ssg-sshd_print_last_log_action:testaction:1 - - - - Mount Remote Filesystems with nosuid - - ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 - - - - Verify that System Executable Have Root Ownership - - ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 - - - - Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces - - ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 - - - - Configure session renegotiation for SSH client - - ocil:ssg-ssh_client_rekey_limit_action:testaction:1 - - - - Configure SSH to use System Crypto Policy - - ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 - - - - Make the auditd Configuration Immutable - - ocil:ssg-audit_rules_immutable_action:testaction:1 - - - - Configure PAM in SSSD Services - - ocil:ssg-sssd_enable_pam_services_action:testaction:1 - - - - Set Password Minimum Length in login.defs - - ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 - - - - Verify Permissions on /etc/at.allow file - - ocil:ssg-file_permissions_at_allow_action:testaction:1 - - - - Verify Group Who Owns /etc/crypttab File - - ocil:ssg-file_groupowner_etc_crypttab_action:testaction:1 - - - - Harden slab freelist metadata - - ocil:ssg-kernel_config_slab_freelist_hardened_action:testaction:1 - - - - Kernel panic on oops - - ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 - - - - Set Default iptables Policy for Forwarded Packets - - ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 - - - - Enable support for BUG() - - ocil:ssg-kernel_config_bug_action:testaction:1 - - - - Verify Group Who Owns shadow File - - ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 - - - - Disable XDMCP in GDM - - ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 - - - - Set SSH Client Alive Count Max to zero - - ocil:ssg-sshd_set_keepalive_0_action:testaction:1 - - - - Disable Network Router Discovery Daemon (rdisc) - - ocil:ssg-service_rdisc_disabled_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Enforce for root User - - ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 - - - - Uninstall tuned Package - - ocil:ssg-package_tuned_removed_action:testaction:1 - - - - Modify the System Message of the Day Banner - - ocil:ssg-banner_etc_motd_action:testaction:1 - - - - Verify Permissions on /etc/audit/auditd.conf - - ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 - - - - Enable NX or XD Support in the BIOS - - ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 - - - - Configure Periodic Execution of AIDE - - ocil:ssg-aide_periodic_cron_checking_action:testaction:1 - - - - Ensure All Accounts on the System Have Unique User IDs - - ocil:ssg-account_unique_id_action:testaction:1 - - - - Uninstall bind Package - - ocil:ssg-package_bind_removed_action:testaction:1 - - - - Ensure /dev/shm is configured - - ocil:ssg-partition_for_dev_shm_action:testaction:1 - - - - Disable the LDT (local descriptor table) - - ocil:ssg-kernel_config_modify_ldt_syscall_action:testaction:1 - - - - Record Any Attempts to Run setfiles - - ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 - - - - Enable the auditadm_exec_content SELinux Boolean - - ocil:ssg-sebool_auditadm_exec_content_action:testaction:1 - - - - Install McAfee Endpoint Security for Linux (ENSL) - - ocil:ssg-package_mcafeetp_installed_action:testaction:1 - - - - Verify Any Configured IPSec Tunnel Connections - - ocil:ssg-libreswan_approved_tunnels_action:testaction:1 - - - - Implement Blank Screensaver - - ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 - - - - Uninstall gssproxy Package - - ocil:ssg-package_gssproxy_removed_action:testaction:1 - - - - NetworkManager DNS Mode Must Be Must Configured - - ocil:ssg-networkmanager_dns_mode_action:testaction:1 - - - - Add nosuid Option to /opt - - ocil:ssg-mount_option_opt_nosuid_action:testaction:1 - - - - Ensure that Root's Path Does Not Include World or Group-Writable Directories - - ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 - - - - Set Lockout Time for Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 - - - - Enable Yama support - - ocil:ssg-kernel_config_security_yama_action:testaction:1 - - - - Configure OpenSSL library to use System Crypto Policy - - ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 - - - - System Audit Directories Must Be Owned By Root - - ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 - - - - User Initialization Files Must Be Owned By the Primary User - - ocil:ssg-accounts_user_dot_user_ownership_action:testaction:1 - - - - Configure Kerberos to use System Crypto Policy - - ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 - - - - Drop Gratuitious ARP frames on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 - - - - Configure AIDE to Verify Access Control Lists (ACLs) - - ocil:ssg-aide_verify_acls_action:testaction:1 - - - - Enable Auditing for Processes Which Start Prior to the Audit Daemon - - ocil:ssg-grub2_audit_argument_action:testaction:1 - - - - Modify the System Login Banner - - ocil:ssg-banner_etc_issue_action:testaction:1 - - - - Disable ATM Support - - ocil:ssg-kernel_module_atm_disabled_action:testaction:1 - - - - Configure CA certificate for rsyslog remote logging - - ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 - - - - Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) - - ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 - - - - Configure auditing of unsuccessful permission changes - - ocil:ssg-audit_perm_change_failed_action:testaction:1 - - - - Disable Kernel Image Loading - - ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 - - - - Ensure the Default Bash Umask is Set Correctly - - ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 - - - - Verify Root Has A Primary GID 0 - - ocil:ssg-accounts_root_gid_zero_action:testaction:1 - - - - Configure auditd space_left on Low Disk Space - - ocil:ssg-auditd_data_retention_space_left_action:testaction:1 - - - - Remove tftp Daemon - - ocil:ssg-package_tftp_removed_action:testaction:1 - - - - Disable SSH Support for Rhosts RSA Authentication - - ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 - - - - Verify Permissions on cron.daily - - ocil:ssg-file_permissions_cron_daily_action:testaction:1 - - - - Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 - - - - Configure a Sufficiently Large Partition for Audit Logs - - ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 - - - - Verify that system commands files are group owned by root or a system account - - ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 - - - - Uninstall dovecot Package - - ocil:ssg-package_dovecot_removed_action:testaction:1 - - - - Verify Permissions on group File - - ocil:ssg-file_permissions_etc_group_action:testaction:1 - - - - Ensure remote access methods are monitored in Rsyslog - - ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 - - - - Verify that system commands directories have root as a group owner - - ocil:ssg-dir_system_commands_group_root_owned_action:testaction:1 - - - - Verify User Who Owns /etc/iptables Directory - - ocil:ssg-directory_owner_etc_iptables_action:testaction:1 - - - - Disable Core Dumps for SUID programs - - ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 - - - - Audit Configuration Files Must Be Owned By Group root - - ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 - - - - Disable Kerberos Authentication - - ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 - - - - Disable storing core dump - - ocil:ssg-coredump_disable_storage_action:testaction:1 - - - - Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - chage - - ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 - - - - Disable IPv6 Networking Support Automatic Loading - - ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 - - - - Set Kernel Parameter to Increase Local Port Range - - ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 - - - - Enable the Hardware RNG Entropy Gatherer Service - - ocil:ssg-service_rngd_enabled_action:testaction:1 - - - - Enable the SSSD Service - - ocil:ssg-service_sssd_enabled_action:testaction:1 - - - - Disable TIPC Support - - ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 - - - - Account Lockouts Must Be Logged - - ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 - - - - Lock Accounts After Failed Password Attempts - - ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 - - - - Remove User Host-Based Authentication Files - - ocil:ssg-no_user_host_based_files_action:testaction:1 - - - - Record Any Attempts to Run setfacl - - ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 - - - - Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 - - - - Disable core dump backtraces - - ocil:ssg-coredump_disable_backtraces_action:testaction:1 - - - - Configure immutable Audit login UIDs - - ocil:ssg-audit_rules_immutable_login_uids_action:testaction:1 - - - - Restrict Exposed Kernel Pointer Addresses Access - - ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 - - - - Enable Use of Strict Mode Checking - - ocil:ssg-sshd_enable_strictmodes_action:testaction:1 - - - - Verify Owner on cron.deny - - ocil:ssg-file_owner_cron_deny_action:testaction:1 - - - - Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 - - - - Set Password Warning Age - - ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 - - - - Use Kerberos Security on All Exports - - ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 - - - - Verify Group Who Owns Backup passwd File - - ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 - - - - Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 - - - - Mount Remote Filesystems with nodev - - ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 - - - - Ensure gpgcheck Enabled for All yum Package Repositories - - ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 - - - - Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty - - ocil:ssg-sudo_add_requiretty_action:testaction:1 - - - - Configure the deny_execmem SELinux Boolean - - ocil:ssg-sebool_deny_execmem_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - truncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 - - - - Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 - - ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 - - - - Verify and Correct File Permissions with RPM - - ocil:ssg-rpm_verify_permissions_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudo - - ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 - - - - Force kernel panic on uncorrected MCEs - - ocil:ssg-grub2_mce_argument_action:testaction:1 - - - - Install rng-tools Package - - ocil:ssg-package_rng-tools_installed_action:testaction:1 - - - - Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 - - - - Disable SSH Support for .rhosts Files - - ocil:ssg-sshd_disable_rhosts_action:testaction:1 - - - - Set Interactive Session Timeout - - ocil:ssg-accounts_tmout_action:testaction:1 - - - - Set LogLevel to INFO - - ocil:ssg-sshd_set_loglevel_info_action:testaction:1 - - - - Configure auditing of successful ownership changes - - ocil:ssg-audit_owner_change_success_action:testaction:1 - - - - Distribute the SSH Server configuration to multiple files in a config directory. - - ocil:ssg-sshd_use_directory_configuration_action:testaction:1 - - - - Record Events that Modify User/Group Information - /etc/security/opasswd - - ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 - - - - Verify Permissions On /etc/sestatus.conf File - - ocil:ssg-file_permissions_etc_sestatus_conf_action:testaction:1 - - - - Configure AIDE to Verify Extended Attributes - - ocil:ssg-aide_verify_ext_attributes_action:testaction:1 - - - - Set Existing Passwords Minimum Age - - ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 - - - - Configure auditd max_log_file_action Upon Reaching Maximum Log Size - - ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 - - - - Configure System Cryptography Policy - - ocil:ssg-configure_crypto_policy_action:testaction:1 - - - - Record Attempts to Alter Logon and Logout Events - lastlog - - ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 - - - - IOMMU configuration directive - - ocil:ssg-grub2_enable_iommu_force_action:testaction:1 - - - - Disable /dev/kmem virtual device support - - ocil:ssg-kernel_config_devkmem_action:testaction:1 - - - - Ensure Chrony is only configured with the server directive - - ocil:ssg-chronyd_server_directive_action:testaction:1 - - - - Verify Permissions on /var/log/messages File - - ocil:ssg-file_permissions_var_log_messages_action:testaction:1 - - - - Set Password Minimum Age - - ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 - - - - Install libreswan Package - - ocil:ssg-package_libreswan_installed_action:testaction:1 - - - - Ensure debug-shell service is not enabled during boot - - ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 - - - - Prevent non-Privileged Users from Modifying Network Interfaces using nmcli - - ocil:ssg-network_nmcli_permissions_action:testaction:1 - - - - Add nodev Option to /boot - - ocil:ssg-mount_option_boot_nodev_action:testaction:1 - - - - Ensure PAM Enforces Password Requirements - Minimum Digit Characters - - ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 - - - - Enable Public Key Authentication - - ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 - - - - Configure Kernel Parameter for Accepting Secure Redirects By Default - - ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 - - - - Configure basic parameters of Audit system - - ocil:ssg-audit_basic_configuration_action:testaction:1 - - - - Add nodev Option to /home - - ocil:ssg-mount_option_home_nodev_action:testaction:1 - - - - Enable GNOME3 Screensaver Lock After Idle Period - - ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 - - - - Enable page allocator poisoning - - ocil:ssg-grub2_page_poison_argument_action:testaction:1 - - - - Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit - - ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 - - - - Disable SCTP Support - - ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 - - - - Ensure auditd Collects System Administrator Actions - - ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 - - - - Record Events that Modify the System's Discretionary Access Controls - fchownat - - ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 - - - - Verify Owner on cron.d - - ocil:ssg-file_owner_cron_d_action:testaction:1 - - - - A remote time server for Chrony is configured - - ocil:ssg-chronyd_specify_remote_server_action:testaction:1 - - - - All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group - - ocil:ssg-accounts_users_home_files_groupownership_action:testaction:1 + ocil:ssg-account_password_pam_faillock_system_auth_action:testaction:1 @@ -245830,136 +264537,46 @@ fi ocil:ssg-account_password_selinux_faillock_dir_action:testaction:1 - - Verify Who Owns /etc/shells File + + Account Lockouts Must Be Logged - ocil:ssg-file_owner_etc_shells_action:testaction:1 + ocil:ssg-account_passwords_pam_faillock_audit_action:testaction:1 - - Verify All Account Password Hashes are Shadowed with SHA512 + + Account Lockouts Must Persist - ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 + ocil:ssg-account_passwords_pam_faillock_dir_action:testaction:1 - - Disable GDM Automatic Login + + Assign Expiration Date to Temporary Accounts - ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 + ocil:ssg-account_temp_expire_date_action:testaction:1 - - Set Password Maximum Age + + Ensure All Accounts on the System Have Unique User IDs - ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 + ocil:ssg-account_unique_id_action:testaction:1 - - Record Events that Modify the System's Discretionary Access Controls - fchmodat + + Ensure All Accounts on the System Have Unique Names - ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 + ocil:ssg-account_unique_name_action:testaction:1 - - Don't define allowed commands in sudoers by means of exclusion + + Use Centralized and Automated Authentication - ocil:ssg-sudoers_no_command_negation_action:testaction:1 + ocil:ssg-account_use_centralized_automated_auth_action:testaction:1 - - Enable SLUB debugging support + + Only Authorized Local User Accounts Exist on Operating System - ocil:ssg-kernel_config_slub_debug_action:testaction:1 - - - - Verify that Interactive Boot is Disabled - - ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 - - - - Verify /boot/grub2/user.cfg Permissions - - ocil:ssg-file_permissions_user_cfg_action:testaction:1 - - - - Verify Permissions on shadow File - - ocil:ssg-file_permissions_etc_shadow_action:testaction:1 - - - - Configure auditing of successful file deletions - - ocil:ssg-audit_delete_success_action:testaction:1 - - - - Uninstall iprutils Package - - ocil:ssg-package_iprutils_removed_action:testaction:1 - - - - Limit sampling frequency of the Perf system - - ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 - - - - Configure opensc Smart Card Drivers - - ocil:ssg-configure_opensc_card_drivers_action:testaction:1 - - - - Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces - - ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 - - - - Set existing passwords a period of inactivity before they been locked - - ocil:ssg-accounts_set_post_pw_existing_action:testaction:1 - - - - Disable kernel debugfs - - ocil:ssg-kernel_config_debug_fs_action:testaction:1 - - - - Verify the UEFI Boot Loader grub.cfg User Ownership - - ocil:ssg-file_owner_efi_grub2_cfg_action:testaction:1 - - - - Record Any Attempts to Run restorecon - - ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 - - - - Record Unsuccessful Access Attempts to Files - ftruncate - - ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 - - - - Uninstall setroubleshoot-plugins Package - - ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 - - - - Disable DCCP Support - - ocil:ssg-kernel_module_dccp_disabled_action:testaction:1 + ocil:ssg-accounts_authorized_local_users_action:testaction:1 @@ -245968,40 +264585,142 @@ fi ocil:ssg-accounts_have_homedir_login_defs_action:testaction:1 - - Set SSH authentication attempt limit + + Ensure the Logon Failure Delay is Set Correctly in login.defs - ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 + ocil:ssg-accounts_logon_fail_delay_action:testaction:1 - - Add nodev Option to Removable Media Partitions + + Limit the Number of Concurrent Login Sessions Allowed Per User - ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 + ocil:ssg-accounts_max_concurrent_login_sessions_action:testaction:1 - - User Initialization Files Must Be Group-Owned By The Primary Group + + Set Password Maximum Age - ocil:ssg-accounts_user_dot_group_ownership_action:testaction:1 + ocil:ssg-accounts_maximum_age_login_defs_action:testaction:1 - - Verify User Who Owns /etc/nftables Directory + + Set Password Minimum Age - ocil:ssg-directory_owner_etc_nftables_action:testaction:1 + ocil:ssg-accounts_minimum_age_login_defs_action:testaction:1 - - Verify Group Who Owns Backup shadow File + + Verify Only Root Has UID 0 - ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 + ocil:ssg-accounts_no_uid_except_zero_action:testaction:1 - - Use zero for poisoning instead of debugging value + + Verify All Account Password Hashes are Shadowed - ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 + ocil:ssg-accounts_password_all_shadowed_action:testaction:1 + + + + Verify All Account Password Hashes are Shadowed with SHA512 + + ocil:ssg-accounts_password_all_shadowed_sha512_action:testaction:1 + + + + Ensure all users last password change date is in the past + + ocil:ssg-accounts_password_last_change_is_in_past_action:testaction:1 + + + + Set Password Minimum Length in login.defs + + ocil:ssg-accounts_password_minlen_login_defs_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Digit Characters + + ocil:ssg-accounts_password_pam_dcredit_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Prevent the Use of Dictionary Words + + ocil:ssg-accounts_password_pam_dictcheck_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Characters + + ocil:ssg-accounts_password_pam_difok_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Enforce for root User + + ocil:ssg-accounts_password_pam_enforce_root_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters + + ocil:ssg-accounts_password_pam_lcredit_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class + + ocil:ssg-accounts_password_pam_maxclassrepeat_action:testaction:1 + + + + Set Password Maximum Consecutive Repeating Characters + + ocil:ssg-accounts_password_pam_maxrepeat_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Different Categories + + ocil:ssg-accounts_password_pam_minclass_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Length + + ocil:ssg-accounts_password_pam_minlen_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Minimum Special Characters + + ocil:ssg-accounts_password_pam_ocredit_action:testaction:1 + + + + Limit Password Reuse: password-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_action:testaction:1 + + + + Limit Password Reuse: system-auth + + ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_action:testaction:1 + + + + Ensure PAM password complexity module is enabled in password-auth + + ocil:ssg-accounts_password_pam_pwquality_password_auth_action:testaction:1 + + + + Ensure PAM Enforces Password Requirements - Authentication Retry Prompts Permitted Per-Session in /etc/security/pwquality.conf + + ocil:ssg-accounts_password_pam_pwquality_retry_action:testaction:1 @@ -246016,52 +264735,784 @@ fi ocil:ssg-accounts_password_pam_retry_action:testaction:1 - - Disable the authlogin_radius SELinux Boolean + + Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters - ocil:ssg-sebool_authlogin_radius_action:testaction:1 + ocil:ssg-accounts_password_pam_ucredit_action:testaction:1 - - Verify User Who Owns /etc/sysctl.d Directory + + Limit Password Reuse - ocil:ssg-directory_owner_etc_sysctld_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_remember_action:testaction:1 - - Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + Set number of Password Hashing Rounds - password-auth - ocil:ssg-fapolicy_default_deny_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_rounds_password_auth_action:testaction:1 - - Add nosuid Option to /var/log + + Set number of Password Hashing Rounds - system-auth - ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 + ocil:ssg-accounts_password_pam_unix_rounds_system_auth_action:testaction:1 - - Ensure /home Located On Separate Partition + + Set Existing Passwords Maximum Age - ocil:ssg-partition_for_home_action:testaction:1 + ocil:ssg-accounts_password_set_max_life_existing_action:testaction:1 - - Mount Remote Filesystems with Kerberos Security + + Set Root Account Password Maximum Age - ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 + ocil:ssg-accounts_password_set_max_life_root_action:testaction:1 - - Configure Speculative Store Bypass Mitigation + + Set Existing Passwords Minimum Age - ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 + ocil:ssg-accounts_password_set_min_life_existing_action:testaction:1 - - Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + Set Existing Passwords Warning Age - ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 + ocil:ssg-accounts_password_set_warn_age_existing_action:testaction:1 + + + + Set Password Warning Age + + ocil:ssg-accounts_password_warn_age_login_defs_action:testaction:1 + + + + Account Lockouts Must Be Logged + + ocil:ssg-accounts_passwords_pam_faillock_audit_action:testaction:1 + + + + Lock Accounts After Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_action:testaction:1 + + + + Configure the root Account for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_deny_root_action:testaction:1 + + + + Lock Accounts Must Persist + + ocil:ssg-accounts_passwords_pam_faillock_dir_action:testaction:1 + + + + Set Interval For Counting Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_interval_action:testaction:1 + + + + Set Lockout Time for Failed Password Attempts + + ocil:ssg-accounts_passwords_pam_faillock_unlock_time_action:testaction:1 + + + + Configure Polyinstantiation of /tmp Directories + + ocil:ssg-accounts_polyinstantiated_tmp_action:testaction:1 + + + + Configure Polyinstantiation of /var/tmp Directories + + ocil:ssg-accounts_polyinstantiated_var_tmp_action:testaction:1 + + + + Verify Root Has A Primary GID 0 + + ocil:ssg-accounts_root_gid_zero_action:testaction:1 + + + + Ensure that Root's Path Does Not Include World or Group-Writable Directories + + ocil:ssg-accounts_root_path_dirs_no_write_action:testaction:1 + + + + Set existing passwords a period of inactivity before they been locked + + ocil:ssg-accounts_set_post_pw_existing_action:testaction:1 + + + + Set Interactive Session Timeout + + ocil:ssg-accounts_tmout_action:testaction:1 + + + + Ensure the Default Bash Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_bashrc_action:testaction:1 + + + + Ensure the Default C Shell Umask is Set Correctly + + ocil:ssg-accounts_umask_etc_csh_cshrc_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in login.defs + + ocil:ssg-accounts_umask_etc_login_defs_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly in /etc/profile + + ocil:ssg-accounts_umask_etc_profile_action:testaction:1 + + + + Ensure the Default Umask is Set Correctly For Interactive Users + + ocil:ssg-accounts_umask_interactive_users_action:testaction:1 + + + + User Initialization Files Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_user_dot_group_ownership_action:testaction:1 + + + + User Initialization Files Must Not Run World-Writable Programs + + ocil:ssg-accounts_user_dot_no_world_writable_programs_action:testaction:1 + + + + User Initialization Files Must Be Owned By the Primary User + + ocil:ssg-accounts_user_dot_user_ownership_action:testaction:1 + + + + Ensure that Users Path Contains Only Local Directories + + ocil:ssg-accounts_user_home_paths_only_action:testaction:1 + + + + All Interactive Users Must Have A Home Directory Defined + + ocil:ssg-accounts_user_interactive_home_directory_defined_action:testaction:1 + + + + All Interactive Users Home Directories Must Exist + + ocil:ssg-accounts_user_interactive_home_directory_exists_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary Group + + ocil:ssg-accounts_users_home_files_groupownership_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have a Valid Owner + + ocil:ssg-accounts_users_home_files_ownership_action:testaction:1 + + + + All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive + + ocil:ssg-accounts_users_home_files_permissions_action:testaction:1 + + + + Ensure McAfee Endpoint Security for Linux (ENSL) is running + + ocil:ssg-agent_mfetpd_running_action:testaction:1 + + + + Build and Test AIDE Database + + ocil:ssg-aide_build_database_action:testaction:1 + + + + Configure AIDE to Verify the Audit Tools + + ocil:ssg-aide_check_audit_tools_action:testaction:1 + + + + Configure Periodic Execution of AIDE + + ocil:ssg-aide_periodic_cron_checking_action:testaction:1 + + + + Configure Notification of Post-AIDE Scan Details + + ocil:ssg-aide_scan_notification_action:testaction:1 + + + + Configure AIDE to Use FIPS 140-2 for Validating Hashes + + ocil:ssg-aide_use_fips_hashes_action:testaction:1 + + + + Configure AIDE to Verify Access Control Lists (ACLs) + + ocil:ssg-aide_verify_acls_action:testaction:1 + + + + Configure AIDE to Verify Extended Attributes + + ocil:ssg-aide_verify_ext_attributes_action:testaction:1 + + + + Configure auditing of unsuccessful file accesses + + ocil:ssg-audit_access_failed_action:testaction:1 + + + + Configure auditing of successful file accesses + + ocil:ssg-audit_access_success_action:testaction:1 + + + + Configure basic parameters of Audit system + + ocil:ssg-audit_basic_configuration_action:testaction:1 + + + + Configure auditing of unsuccessful file creations + + ocil:ssg-audit_create_failed_action:testaction:1 + + + + Configure auditing of successful file creations + + ocil:ssg-audit_create_success_action:testaction:1 + + + + Configure auditing of unsuccessful file deletions + + ocil:ssg-audit_delete_failed_action:testaction:1 + + + + Configure auditing of successful file deletions + + ocil:ssg-audit_delete_success_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_immutable_login_uids_action:testaction:1 + + + + Configure auditing of unsuccessful file modifications + + ocil:ssg-audit_modify_failed_action:testaction:1 + + + + Configure auditing of successful file modifications + + ocil:ssg-audit_modify_success_action:testaction:1 + + + + Configure auditing of loading and unloading of kernel modules + + ocil:ssg-audit_module_load_action:testaction:1 + + + + Perform general configuration of Audit for OSPP + + ocil:ssg-audit_ospp_general_action:testaction:1 + + + + Configure auditing of unsuccessful ownership changes + + ocil:ssg-audit_owner_change_failed_action:testaction:1 + + + + Configure auditing of successful ownership changes + + ocil:ssg-audit_owner_change_success_action:testaction:1 + + + + Configure auditing of unsuccessful permission changes + + ocil:ssg-audit_perm_change_failed_action:testaction:1 + + + + Configure auditing of successful permission changes + + ocil:ssg-audit_perm_change_success_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - init + + ocil:ssg-audit_privileged_commands_init_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - poweroff + + ocil:ssg-audit_privileged_commands_poweroff_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - reboot + + ocil:ssg-audit_privileged_commands_reboot_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - shutdown + + ocil:ssg-audit_privileged_commands_shutdown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chmod + + ocil:ssg-audit_rules_dac_modification_chmod_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - chown + + ocil:ssg-audit_rules_dac_modification_chown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmod + + ocil:ssg-audit_rules_dac_modification_fchmod_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchmodat + + ocil:ssg-audit_rules_dac_modification_fchmodat_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchown + + ocil:ssg-audit_rules_dac_modification_fchown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fchownat + + ocil:ssg-audit_rules_dac_modification_fchownat_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fremovexattr + + ocil:ssg-audit_rules_dac_modification_fremovexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - fsetxattr + + ocil:ssg-audit_rules_dac_modification_fsetxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lchown + + ocil:ssg-audit_rules_dac_modification_lchown_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lremovexattr + + ocil:ssg-audit_rules_dac_modification_lremovexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - lsetxattr + + ocil:ssg-audit_rules_dac_modification_lsetxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - removexattr + + ocil:ssg-audit_rules_dac_modification_removexattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - setxattr + + ocil:ssg-audit_rules_dac_modification_setxattr_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount + + ocil:ssg-audit_rules_dac_modification_umount_action:testaction:1 + + + + Record Events that Modify the System's Discretionary Access Controls - umount2 + + ocil:ssg-audit_rules_dac_modification_umount2_action:testaction:1 + + + + Ensure auditd Collects Changes to Cron Jobs - /etc/cron.d/ + + ocil:ssg-audit_rules_etc_cron_d_action:testaction:1 + + + + Record Any Attempts to Run chacl + + ocil:ssg-audit_rules_execution_chacl_action:testaction:1 + + + + Record Any Attempts to Run chcon + + ocil:ssg-audit_rules_execution_chcon_action:testaction:1 + + + + Record Any Attempts to Run restorecon + + ocil:ssg-audit_rules_execution_restorecon_action:testaction:1 + + + + Record Any Attempts to Run semanage + + ocil:ssg-audit_rules_execution_semanage_action:testaction:1 + + + + Record Any Attempts to Run setfacl + + ocil:ssg-audit_rules_execution_setfacl_action:testaction:1 + + + + Record Any Attempts to Run setfiles + + ocil:ssg-audit_rules_execution_setfiles_action:testaction:1 + + + + Record Any Attempts to Run setsebool + + ocil:ssg-audit_rules_execution_setsebool_action:testaction:1 + + + + Record Any Attempts to Run seunshare + + ocil:ssg-audit_rules_execution_seunshare_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User + + ocil:ssg-audit_rules_file_deletion_events_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rename + + ocil:ssg-audit_rules_file_deletion_events_rename_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - renameat + + ocil:ssg-audit_rules_file_deletion_events_renameat_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - rmdir + + ocil:ssg-audit_rules_file_deletion_events_rmdir_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlink + + ocil:ssg-audit_rules_file_deletion_events_unlink_action:testaction:1 + + + + Ensure auditd Collects File Deletion Events by User - unlinkat + + ocil:ssg-audit_rules_file_deletion_events_unlinkat_action:testaction:1 + + + + Make the auditd Configuration Immutable + + ocil:ssg-audit_rules_immutable_action:testaction:1 + + + + Configure immutable Audit login UIDs + + ocil:ssg-audit_rules_immutable_login_uids_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading + + ocil:ssg-audit_rules_kernel_module_loading_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Unloading - delete_module + + ocil:ssg-audit_rules_kernel_module_loading_delete_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_module + + ocil:ssg-audit_rules_kernel_module_loading_finit_action:testaction:1 + + + + Ensure auditd Collects Information on Kernel Module Loading - init_module + + ocil:ssg-audit_rules_kernel_module_loading_init_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - faillock + + ocil:ssg-audit_rules_login_events_faillock_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - lastlog + + ocil:ssg-audit_rules_login_events_lastlog_action:testaction:1 + + + + Record Attempts to Alter Logon and Logout Events - tallylog + + ocil:ssg-audit_rules_login_events_tallylog_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls + + ocil:ssg-audit_rules_mac_modification_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls (/etc/selinux) + + ocil:ssg-audit_rules_mac_modification_etc_selinux_action:testaction:1 + + + + Record Events that Modify the System's Mandatory Access Controls in usr/share + + ocil:ssg-audit_rules_mac_modification_usr_share_action:testaction:1 + + + + Ensure auditd Collects Information on Exporting to Media (successful) + + ocil:ssg-audit_rules_media_export_action:testaction:1 + + + + Record Events that Modify the System's Network Environment + + ocil:ssg-audit_rules_networkconfig_modification_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands + + ocil:ssg-audit_rules_privileged_commands_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - at + + ocil:ssg-audit_rules_privileged_commands_at_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chage + + ocil:ssg-audit_rules_privileged_commands_chage_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - chsh + + ocil:ssg-audit_rules_privileged_commands_chsh_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - crontab + + ocil:ssg-audit_rules_privileged_commands_crontab_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - gpasswd + + ocil:ssg-audit_rules_privileged_commands_gpasswd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - kmod + + ocil:ssg-audit_rules_privileged_commands_kmod_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - mount + + ocil:ssg-audit_rules_privileged_commands_mount_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - newgrp + + ocil:ssg-audit_rules_privileged_commands_newgrp_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_check + + ocil:ssg-audit_rules_privileged_commands_pam_timestamp_check_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - passwd + + ocil:ssg-audit_rules_privileged_commands_passwd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postdrop + + ocil:ssg-audit_rules_privileged_commands_postdrop_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - postqueue + + ocil:ssg-audit_rules_privileged_commands_postqueue_action:testaction:1 + + + + Record Any Attempts to Run ssh-agent + + ocil:ssg-audit_rules_privileged_commands_ssh_agent_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysign + + ocil:ssg-audit_rules_privileged_commands_ssh_keysign_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - su + + ocil:ssg-audit_rules_privileged_commands_su_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudo + + ocil:ssg-audit_rules_privileged_commands_sudo_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - sudoedit + + ocil:ssg-audit_rules_privileged_commands_sudoedit_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - umount + + ocil:ssg-audit_rules_privileged_commands_umount_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwd + + ocil:ssg-audit_rules_privileged_commands_unix_chkpwd_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - unix_update + + ocil:ssg-audit_rules_privileged_commands_unix_update_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - userhelper + + ocil:ssg-audit_rules_privileged_commands_userhelper_action:testaction:1 + + + + Ensure auditd Collects Information on the Use of Privileged Commands - usermod + + ocil:ssg-audit_rules_privileged_commands_usermod_action:testaction:1 @@ -246070,4853 +265521,4486 @@ fi ocil:ssg-audit_rules_privileged_commands_usernetctl_action:testaction:1 + + Record Attempts to Alter Process and Session Initiation Information btmp + + ocil:ssg-audit_rules_session_events_btmp_action:testaction:1 + + + + Record Attempts to Alter Process and Session Initiation Information utmp + + ocil:ssg-audit_rules_session_events_utmp_action:testaction:1 + + + + Record Attempts to Alter Process and Session Initiation Information wtmp + + ocil:ssg-audit_rules_session_events_wtmp_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers + + ocil:ssg-audit_rules_sudoers_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions - /etc/sudoers.d/ + + ocil:ssg-audit_rules_sudoers_d_action:testaction:1 + + + + Record Events When Privileged Executables Are Run + + ocil:ssg-audit_rules_suid_privilege_function_action:testaction:1 + + + + Ensure auditd Collects System Administrator Actions + + ocil:ssg-audit_rules_sysadmin_actions_action:testaction:1 + + + + Shutdown System When Auditing Failures Occur + + ocil:ssg-audit_rules_system_shutdown_action:testaction:1 + + + + Record attempts to alter time through adjtimex + + ocil:ssg-audit_rules_time_adjtimex_action:testaction:1 + + + + Record Attempts to Alter Time Through clock_settime + + ocil:ssg-audit_rules_time_clock_settime_action:testaction:1 + + + + Record attempts to alter time through settimeofday + + ocil:ssg-audit_rules_time_settimeofday_action:testaction:1 + + + + Record Attempts to Alter Time Through stime + + ocil:ssg-audit_rules_time_stime_action:testaction:1 + + + + Record Attempts to Alter the localtime File + + ocil:ssg-audit_rules_time_watch_localtime_action:testaction:1 + + + + Ensure auditd Collects Unauthorized Access Attempts to Files (unsuccessful) + + ocil:ssg-audit_rules_unsuccessful_file_modification_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - creat + + ocil:ssg-audit_rules_unsuccessful_file_modification_creat_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - ftruncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_ftruncate_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - open_by_handle_at + + ocil:ssg-audit_rules_unsuccessful_file_modification_open_by_handle_at_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - openat + + ocil:ssg-audit_rules_unsuccessful_file_modification_openat_action:testaction:1 + + + + Record Unsuccessful Access Attempts to Files - truncate + + ocil:ssg-audit_rules_unsuccessful_file_modification_truncate_action:testaction:1 + + + + Record Events that Modify User/Group Information + + ocil:ssg-audit_rules_usergroup_modification_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/group + + ocil:ssg-audit_rules_usergroup_modification_group_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/gshadow + + ocil:ssg-audit_rules_usergroup_modification_gshadow_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/security/opasswd + + ocil:ssg-audit_rules_usergroup_modification_opasswd_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/passwd + + ocil:ssg-audit_rules_usergroup_modification_passwd_action:testaction:1 + + + + Record Events that Modify User/Group Information - /etc/shadow + + ocil:ssg-audit_rules_usergroup_modification_shadow_action:testaction:1 + + + + Ensure auditd Collects Changes to Cron Jobs - /var/spool/cron + + ocil:ssg-audit_rules_var_spool_cron_action:testaction:1 + + + + Record Attempts to perform maintenance activities + + ocil:ssg-audit_sudo_log_events_action:testaction:1 + + + + Configure a Sufficiently Large Partition for Audit Logs + + ocil:ssg-auditd_audispd_configure_sufficiently_large_partition_action:testaction:1 + + + + Configure auditd to use audispd's syslog plugin + + ocil:ssg-auditd_audispd_syslog_plugin_activated_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_action:testaction:1 + + + + Configure auditd Disk Error Action on Disk Error + + ocil:ssg-auditd_data_disk_error_action_stig_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_action:testaction:1 + + + + Configure auditd Disk Full Action when Disk Space Is Full + + ocil:ssg-auditd_data_disk_full_action_stig_action:testaction:1 + + + + Configure auditd mail_acct Action on Low Disk Space + + ocil:ssg-auditd_data_retention_action_mail_acct_action:testaction:1 + + + + Configure auditd admin_space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_admin_space_left_action_action:testaction:1 + + + + Configure auditd admin_space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_admin_space_left_percentage_action:testaction:1 + + + + Configure auditd flush priority + + ocil:ssg-auditd_data_retention_flush_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_action:testaction:1 + + + + Configure auditd max_log_file_action Upon Reaching Maximum Log Size + + ocil:ssg-auditd_data_retention_max_log_file_action_stig_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action:testaction:1 + + + + Configure auditd space_left Action on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_action_action:testaction:1 + + + + Configure auditd space_left on Low Disk Space + + ocil:ssg-auditd_data_retention_space_left_percentage_action:testaction:1 + + + + Set number of records to cause an explicit flush to audit logs + + ocil:ssg-auditd_freq_action:testaction:1 + + + + Include Local Events in Audit Logs + + ocil:ssg-auditd_local_events_action:testaction:1 + + + + Resolve information before writing to audit logs + + ocil:ssg-auditd_log_format_action:testaction:1 + + + + Set type of computer node name logging in audit logs + + ocil:ssg-auditd_name_format_action:testaction:1 + + + + Appropriate Action Must be Setup When the Internal Audit Event Queue is Full + + ocil:ssg-auditd_overflow_action_action:testaction:1 + + + + Write Audit Logs to the Disk + + ocil:ssg-auditd_write_logs_action:testaction:1 + + + + Modify the System Login Banner + + ocil:ssg-banner_etc_issue_action:testaction:1 + + + + Modify the System Login Banner for Remote Connections + + ocil:ssg-banner_etc_issue_net_action:testaction:1 + + + + Modify the System Message of the Day Banner + + ocil:ssg-banner_etc_motd_action:testaction:1 + + + + Enable NX or XD Support in the BIOS + + ocil:ssg-bios_enable_execution_restrictions_action:testaction:1 + + + + Disable chrony daemon from acting as server + + ocil:ssg-chronyd_client_only_action:testaction:1 + + + + Chrony Configure Pool and Server + + ocil:ssg-chronyd_configure_pool_and_server_action:testaction:1 + + + + Disable network management of chrony daemon + + ocil:ssg-chronyd_no_chronyc_network_action:testaction:1 + + + + Configure Time Service Maxpoll Interval + + ocil:ssg-chronyd_or_ntpd_set_maxpoll_action:testaction:1 + + + + Ensure that chronyd is running under chrony user account + + ocil:ssg-chronyd_run_as_chrony_user_action:testaction:1 + + + + Ensure Chrony is only configured with the server directive + + ocil:ssg-chronyd_server_directive_action:testaction:1 + + + + A remote time server for Chrony is configured + + ocil:ssg-chronyd_specify_remote_server_action:testaction:1 + + + + Ensure yum Removes Previous Package Versions + + ocil:ssg-clean_components_post_updating_action:testaction:1 + + + + Configure BIND to use System Crypto Policy + + ocil:ssg-configure_bind_crypto_policy_action:testaction:1 + + + + Configure System Cryptography Policy + + ocil:ssg-configure_crypto_policy_action:testaction:1 + + + + Configure the Firewalld Ports + + ocil:ssg-configure_firewalld_ports_action:testaction:1 + + + + Configure Kerberos to use System Crypto Policy + + ocil:ssg-configure_kerberos_crypto_policy_action:testaction:1 + + + + Configure Libreswan to use System Crypto Policy + + ocil:ssg-configure_libreswan_crypto_policy_action:testaction:1 + + + + Configure opensc Smart Card Drivers + + ocil:ssg-configure_opensc_card_drivers_action:testaction:1 + + + + Configure OpenSSL library to use System Crypto Policy + + ocil:ssg-configure_openssl_crypto_policy_action:testaction:1 + + + + Configure SSH to use System Crypto Policy + + ocil:ssg-configure_ssh_crypto_policy_action:testaction:1 + + + + Log USBGuard daemon audit events using Linux Audit + + ocil:ssg-configure_usbguard_auditbackend_action:testaction:1 + + + + Configure Backups of User Data + + ocil:ssg-configure_user_data_backups_action:testaction:1 + + + + Firewalld Must Employ a Deny-all, Allow-by-exception Policy for Allowing Connections to Other Systems + + ocil:ssg-configured_firewalld_default_deny_action:testaction:1 + + + + Disable core dump backtraces + + ocil:ssg-coredump_disable_backtraces_action:testaction:1 + + + + Disable storing core dump + + ocil:ssg-coredump_disable_storage_action:testaction:1 + + + + Make sure that the dconf databases are up-to-date with regards to respective keyfiles + + ocil:ssg-dconf_db_up_to_date_action:testaction:1 + + + + Enable GNOME3 Login Warning Banner + + ocil:ssg-dconf_gnome_banner_enabled_action:testaction:1 + + + + Disable GNOME3 Automounting + + ocil:ssg-dconf_gnome_disable_automount_action:testaction:1 + + + + Disable GNOME3 Automount Opening + + ocil:ssg-dconf_gnome_disable_automount_open_action:testaction:1 + + + + Disable GNOME3 Automount running + + ocil:ssg-dconf_gnome_disable_autorun_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Key Sequence in GNOME3 + + ocil:ssg-dconf_gnome_disable_ctrlaltdel_reboot_action:testaction:1 + + + + Disable the GNOME3 Login Restart and Shutdown Buttons + + ocil:ssg-dconf_gnome_disable_restart_shutdown_action:testaction:1 + + + + Disable the GNOME3 Login User List + + ocil:ssg-dconf_gnome_disable_user_list_action:testaction:1 + + + + Enable the GNOME3 Screen Locking On Smartcard Removal + + ocil:ssg-dconf_gnome_lock_screen_on_smartcard_removal_action:testaction:1 + + + + Set the GNOME3 Login Warning Banner Text + + ocil:ssg-dconf_gnome_login_banner_text_action:testaction:1 + + + + Require Credential Prompting for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_credential_prompt_action:testaction:1 + + + + Require Encryption for Remote Access in GNOME3 + + ocil:ssg-dconf_gnome_remote_access_encryption_action:testaction:1 + + + + Enable GNOME3 Screensaver Idle Activation + + ocil:ssg-dconf_gnome_screensaver_idle_activation_enabled_action:testaction:1 + + + + Set GNOME3 Screensaver Inactivity Timeout + + ocil:ssg-dconf_gnome_screensaver_idle_delay_action:testaction:1 + + + + Set GNOME3 Screensaver Lock Delay After Activation Period + + ocil:ssg-dconf_gnome_screensaver_lock_delay_action:testaction:1 + + + + Enable GNOME3 Screensaver Lock After Idle Period + + ocil:ssg-dconf_gnome_screensaver_lock_enabled_action:testaction:1 + + + + Implement Blank Screensaver + + ocil:ssg-dconf_gnome_screensaver_mode_blank_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Screensaver Settings + + ocil:ssg-dconf_gnome_screensaver_user_locks_action:testaction:1 + + + + Ensure Users Cannot Change GNOME3 Session Idle Settings + + ocil:ssg-dconf_gnome_session_idle_user_locks_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Group Ownership + + ocil:ssg-dir_group_ownership_library_dirs_action:testaction:1 + + + + Verify that System Executable Have Root Ownership + + ocil:ssg-dir_ownership_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Directories Have Root Ownership + + ocil:ssg-dir_ownership_library_dirs_action:testaction:1 + + + + Verify that System Executable Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Directories Have Restrictive Permissions + + ocil:ssg-dir_permissions_library_dirs_action:testaction:1 + + + + Ensure All World-Writable Directories Are Owned by root User + + ocil:ssg-dir_perms_world_writable_root_owned_action:testaction:1 + + + + Verify that All World-Writable Directories Have Sticky Bits Set + + ocil:ssg-dir_perms_world_writable_sticky_bits_action:testaction:1 + + + + Verify that system commands directories have root as a group owner + + ocil:ssg-dir_system_commands_group_root_owned_action:testaction:1 + + + + Verify that system commands directories have root ownership + + ocil:ssg-dir_system_commands_root_owned_action:testaction:1 + + + + Record Access Events to Audit Log Directory + + ocil:ssg-directory_access_var_log_audit_action:testaction:1 + + + + System Audit Directories Must Be Group Owned By Root + + ocil:ssg-directory_group_ownership_var_log_audit_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_groupowner_etc_ipsecd_action:testaction:1 + + + + Verify Group Who Owns /etc/iptables Directory + + ocil:ssg-directory_groupowner_etc_iptables_action:testaction:1 + + + + Verify Group Who Owns /etc/nftables Directory + + ocil:ssg-directory_groupowner_etc_nftables_action:testaction:1 + + + + Verify Group Who Owns /etc/selinux Directory + + ocil:ssg-directory_groupowner_etc_selinux_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_groupowner_etc_sudoersd_action:testaction:1 + + + + Verify Group Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_groupowner_etc_sysctld_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.d Directory + + ocil:ssg-directory_owner_etc_ipsecd_action:testaction:1 + + + + Verify User Who Owns /etc/iptables Directory + + ocil:ssg-directory_owner_etc_iptables_action:testaction:1 + + + + Verify User Who Owns /etc/nftables Directory + + ocil:ssg-directory_owner_etc_nftables_action:testaction:1 + + + + Verify User Who Owns /etc/selinux Directory + + ocil:ssg-directory_owner_etc_selinux_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers.d Directory + + ocil:ssg-directory_owner_etc_sudoersd_action:testaction:1 + + + + Verify User Who Owns /etc/sysctl.d Directory + + ocil:ssg-directory_owner_etc_sysctld_action:testaction:1 + + + + System Audit Directories Must Be Owned By Root + + ocil:ssg-directory_ownership_var_log_audit_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.d Directory + + ocil:ssg-directory_permissions_etc_ipsecd_action:testaction:1 + + + + Verify Permissions On /etc/iptables Directory + + ocil:ssg-directory_permissions_etc_iptables_action:testaction:1 + + + + Verify Permissions On /etc/nftables Directory + + ocil:ssg-directory_permissions_etc_nftables_action:testaction:1 + + + + Verify Permissions On /etc/selinux Directory + + ocil:ssg-directory_permissions_etc_selinux_action:testaction:1 + + + + Verify Permissions On /etc/sudoers.d Directory + + ocil:ssg-directory_permissions_etc_sudoersd_action:testaction:1 + + + + Verify Permissions On /etc/sysctl.d Directory + + ocil:ssg-directory_permissions_etc_sysctld_action:testaction:1 + + + + System Audit Logs Must Have Mode 0750 or Less Permissive + + ocil:ssg-directory_permissions_var_log_audit_action:testaction:1 + + + + Disable Ctrl-Alt-Del Burst Action + + ocil:ssg-disable_ctrlaltdel_burstaction_action:testaction:1 + + + + Disable Ctrl-Alt-Del Reboot Activation + + ocil:ssg-disable_ctrlaltdel_reboot_action:testaction:1 + + + + Disable Host-Based Authentication + + ocil:ssg-disable_host_auth_action:testaction:1 + + + + Disable Core Dumps for All Users + + ocil:ssg-disable_users_coredumps_action:testaction:1 + + Disallow Configuration to Bypass Password Requirements for Privilege Escalation ocil:ssg-disallow_bypass_password_sudo_action:testaction:1 + + Ensure PAM Displays Last Logon/Access Notification + + ocil:ssg-display_login_attempts_action:testaction:1 + + + + Configure dnf-automatic to Install Available Updates Automatically + + ocil:ssg-dnf-automatic_apply_updates_action:testaction:1 + + + + Configure dnf-automatic to Install Only Security Updates + + ocil:ssg-dnf-automatic_security_updates_only_action:testaction:1 + + + + Enable authselect + + ocil:ssg-enable_authselect_action:testaction:1 + + + + Configure GNOME3 DConf User Profile + + ocil:ssg-enable_dconf_user_profile_action:testaction:1 + + + + Enable Dracut FIPS Module + + ocil:ssg-enable_dracut_fips_module_action:testaction:1 + + + + Enable FIPS Mode + + ocil:ssg-enable_fips_mode_action:testaction:1 + + + + Encrypt Partitions + + ocil:ssg-encrypt_partitions_action:testaction:1 + + + + Ensure EPEL Repository is Disabled + + ocil:ssg-ensure_epel_repos_disabled_action:testaction:1 + + + + Ensure gpgcheck Enabled In Main yum Configuration + + ocil:ssg-ensure_gpgcheck_globally_activated_action:testaction:1 + + + + Ensure gpgcheck Enabled for Local Packages + + ocil:ssg-ensure_gpgcheck_local_packages_action:testaction:1 + + + + Ensure gpgcheck Enabled for All yum Package Repositories + + ocil:ssg-ensure_gpgcheck_never_disabled_action:testaction:1 + + + + Ensure Logrotate Runs Periodically + + ocil:ssg-ensure_logrotate_activated_action:testaction:1 + + + + Ensure Oracle Linux GPG Key Installed + + ocil:ssg-ensure_oracle_gpgkey_installed_action:testaction:1 + + + + Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty + + ocil:ssg-ensure_pam_wheel_group_empty_action:testaction:1 + + + + Ensure Authentication Required for Single User Mode + + ocil:ssg-ensure_root_password_configured_action:testaction:1 + + + + Ensure '/etc/system-fips' exists + + ocil:ssg-etc_system_fips_exists_action:testaction:1 + + + + Configure Fapolicy Module to Employ a Deny-all, Permit-by-exception Policy to Allow the Execution of Authorized Software Programs. + + ocil:ssg-fapolicy_default_deny_action:testaction:1 + + + + Ensure that /etc/at.deny does not exist + + ocil:ssg-file_at_deny_not_exist_action:testaction:1 + + + + Audit Tools Must Be Group-owned by Root + + ocil:ssg-file_audit_tools_group_ownership_action:testaction:1 + + + + Audit Tools Must Be Owned by Root + + ocil:ssg-file_audit_tools_ownership_action:testaction:1 + + + + Audit Tools Must Have a Mode of 0755 or Less Permissive + + ocil:ssg-file_audit_tools_permissions_action:testaction:1 + + + + Ensure that /etc/cron.deny does not exist + + ocil:ssg-file_cron_deny_not_exist_action:testaction:1 + + + + System Audit Logs Must Be Group Owned By Root + + ocil:ssg-file_group_ownership_var_log_audit_action:testaction:1 + + + + Verify Group Who Owns /etc/at.allow file + + ocil:ssg-file_groupowner_at_allow_action:testaction:1 + + + + Verify Group Who Owns Backup group File + + ocil:ssg-file_groupowner_backup_etc_group_action:testaction:1 + + + + Verify Group Who Owns Backup gshadow File + + ocil:ssg-file_groupowner_backup_etc_gshadow_action:testaction:1 + + + + Verify Group Who Owns Backup passwd File + + ocil:ssg-file_groupowner_backup_etc_passwd_action:testaction:1 + + + + Verify User Who Owns Backup shadow File + + ocil:ssg-file_groupowner_backup_etc_shadow_action:testaction:1 + + + + Verify Group Who Owns /etc/cron.allow file + + ocil:ssg-file_groupowner_cron_allow_action:testaction:1 + + + + Verify Group Who Owns cron.d + + ocil:ssg-file_groupowner_cron_d_action:testaction:1 + + + + Verify Group Who Owns cron.daily + + ocil:ssg-file_groupowner_cron_daily_action:testaction:1 + + + + Verify Group Who Owns cron.deny + + ocil:ssg-file_groupowner_cron_deny_action:testaction:1 + + + + Verify Group Who Owns cron.hourly + + ocil:ssg-file_groupowner_cron_hourly_action:testaction:1 + + + + Verify Group Who Owns cron.monthly + + ocil:ssg-file_groupowner_cron_monthly_action:testaction:1 + + + + Verify Group Who Owns cron.weekly + + ocil:ssg-file_groupowner_cron_weekly_action:testaction:1 + + + + Verify Group Who Owns Crontab + + ocil:ssg-file_groupowner_crontab_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_efi_user_cfg_action:testaction:1 + + + + Verify Group Who Owns /etc/chrony.keys File + + ocil:ssg-file_groupowner_etc_chrony_keys_action:testaction:1 + + + + Verify Group Who Owns /etc/crypttab File + + ocil:ssg-file_groupowner_etc_crypttab_action:testaction:1 + + + + Verify Group Who Owns group File + + ocil:ssg-file_groupowner_etc_group_action:testaction:1 + + + + Verify Group Who Owns gshadow File + + ocil:ssg-file_groupowner_etc_gshadow_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.conf File + + ocil:ssg-file_groupowner_etc_ipsec_conf_action:testaction:1 + + + + Verify Group Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_groupowner_etc_ipsec_secrets_action:testaction:1 + + + + Verify Group Ownership of System Login Banner for Remote Connections + + ocil:ssg-file_groupowner_etc_issue_net_action:testaction:1 + + + + Verify Group Who Owns passwd File + + ocil:ssg-file_groupowner_etc_passwd_action:testaction:1 + + + + Verify Group Who Owns /etc/sestatus.conf File + + ocil:ssg-file_groupowner_etc_sestatus_conf_action:testaction:1 + + + + Verify Group Who Owns shadow File + + ocil:ssg-file_groupowner_etc_shadow_action:testaction:1 + + + + Verify Group Who Owns /etc/shells File + + ocil:ssg-file_groupowner_etc_shells_action:testaction:1 + + + + Verify Group Who Owns /etc/sudoers File + + ocil:ssg-file_groupowner_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Group Ownership + + ocil:ssg-file_groupowner_grub2_cfg_action:testaction:1 + + + + Verify Group Who Owns SSH Server config file + + ocil:ssg-file_groupowner_sshd_config_action:testaction:1 + + + + Verify Group Who Owns System.map Files + + ocil:ssg-file_groupowner_systemmap_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Group Ownership + + ocil:ssg-file_groupowner_user_cfg_action:testaction:1 + + + + Verify Group Who Owns /var/log Directory + + ocil:ssg-file_groupowner_var_log_action:testaction:1 + + + + Verify Group Who Owns /var/log/messages File + + ocil:ssg-file_groupowner_var_log_messages_action:testaction:1 + + + + Verify Group Who Owns /var/log/syslog File + + ocil:ssg-file_groupowner_var_log_syslog_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Group root + + ocil:ssg-file_groupownership_audit_configuration_action:testaction:1 + + + + All Interactive User Home Directories Must Be Group-Owned By The Primary Group + + ocil:ssg-file_groupownership_home_directories_action:testaction:1 + + + + Verify Group Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_groupownership_sshd_private_key_action:testaction:1 + + + + Verify Group Ownership on SSH Server Public *.pub Key Files + + ocil:ssg-file_groupownership_sshd_pub_key_action:testaction:1 + + + + Verify that system commands files are group owned by root or a system account + + ocil:ssg-file_groupownership_system_commands_dirs_action:testaction:1 + + + + Verify User Who Owns Backup group File + + ocil:ssg-file_owner_backup_etc_group_action:testaction:1 + + + + Verify User Who Owns Backup gshadow File + + ocil:ssg-file_owner_backup_etc_gshadow_action:testaction:1 + + + + Verify User Who Owns Backup passwd File + + ocil:ssg-file_owner_backup_etc_passwd_action:testaction:1 + + + + Verify Group Who Owns Backup shadow File + + ocil:ssg-file_owner_backup_etc_shadow_action:testaction:1 + + + + Verify User Who Owns /etc/cron.allow file + + ocil:ssg-file_owner_cron_allow_action:testaction:1 + + + + Verify Owner on cron.d + + ocil:ssg-file_owner_cron_d_action:testaction:1 + + + + Verify Owner on cron.daily + + ocil:ssg-file_owner_cron_daily_action:testaction:1 + + + + Verify Owner on cron.deny + + ocil:ssg-file_owner_cron_deny_action:testaction:1 + + + + Verify Owner on cron.hourly + + ocil:ssg-file_owner_cron_hourly_action:testaction:1 + + + + Verify Owner on cron.monthly + + ocil:ssg-file_owner_cron_monthly_action:testaction:1 + + + + Verify Owner on cron.weekly + + ocil:ssg-file_owner_cron_weekly_action:testaction:1 + + + + Verify Owner on crontab + + ocil:ssg-file_owner_crontab_action:testaction:1 + + + + Verify User Who Owns /etc/chrony.keys File + + ocil:ssg-file_owner_etc_chrony_keys_action:testaction:1 + + + + Verify User Who Owns /etc/crypttab File + + ocil:ssg-file_owner_etc_crypttab_action:testaction:1 + + + + Verify User Who Owns group File + + ocil:ssg-file_owner_etc_group_action:testaction:1 + + + + Verify User Who Owns gshadow File + + ocil:ssg-file_owner_etc_gshadow_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.conf File + + ocil:ssg-file_owner_etc_ipsec_conf_action:testaction:1 + + + + Verify User Who Owns /etc/ipsec.secrets File + + ocil:ssg-file_owner_etc_ipsec_secrets_action:testaction:1 + + + + Verify ownership of System Login Banner for Remote Connections + + ocil:ssg-file_owner_etc_issue_net_action:testaction:1 + + + + Verify User Who Owns passwd File + + ocil:ssg-file_owner_etc_passwd_action:testaction:1 + + + + Verify User Who Owns /etc/sestatus.conf File + + ocil:ssg-file_owner_etc_sestatus_conf_action:testaction:1 + + + + Verify User Who Owns shadow File + + ocil:ssg-file_owner_etc_shadow_action:testaction:1 + + + + Verify Who Owns /etc/shells File + + ocil:ssg-file_owner_etc_shells_action:testaction:1 + + + + Verify User Who Owns /etc/sudoers File + + ocil:ssg-file_owner_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg User Ownership + + ocil:ssg-file_owner_grub2_cfg_action:testaction:1 + + + + Verify Owner on SSH Server config file + + ocil:ssg-file_owner_sshd_config_action:testaction:1 + + + + Verify User Who Owns System.map Files + + ocil:ssg-file_owner_systemmap_action:testaction:1 + + + + Verify /boot/grub2/user.cfg User Ownership + + ocil:ssg-file_owner_user_cfg_action:testaction:1 + + + + Verify User Who Owns /var/log Directory + + ocil:ssg-file_owner_var_log_action:testaction:1 + + + + Verify User Who Owns /var/log/messages File + + ocil:ssg-file_owner_var_log_messages_action:testaction:1 + + + + Verify User Who Owns /var/log/syslog File + + ocil:ssg-file_owner_var_log_syslog_action:testaction:1 + + + + Audit Configuration Files Must Be Owned By Root + + ocil:ssg-file_ownership_audit_configuration_action:testaction:1 + + + + Verify that System Executables Have Root Ownership + + ocil:ssg-file_ownership_binary_dirs_action:testaction:1 + + + + Verify that Shared Library Files Have Root Ownership + + ocil:ssg-file_ownership_library_dirs_action:testaction:1 + + + + Verify Ownership on SSH Server Private *_key Key Files + + ocil:ssg-file_ownership_sshd_private_key_action:testaction:1 + + Verify Ownership on SSH Server Public *.pub Key Files ocil:ssg-file_ownership_sshd_pub_key_action:testaction:1 + + System Audit Logs Must Be Owned By Root + + ocil:ssg-file_ownership_var_log_audit_action:testaction:1 + + + + Ensure All User Initialization Files Have Mode 0740 Or Less Permissive + + ocil:ssg-file_permission_user_init_files_action:testaction:1 + + + + Verify Permissions on /etc/at.allow file + + ocil:ssg-file_permissions_at_allow_action:testaction:1 + + + + Audit Configuration Files Permissions are 640 or More Restrictive + + ocil:ssg-file_permissions_audit_configuration_action:testaction:1 + + + + Verify Permissions on Backup group File + + ocil:ssg-file_permissions_backup_etc_group_action:testaction:1 + + + + Verify Permissions on Backup gshadow File + + ocil:ssg-file_permissions_backup_etc_gshadow_action:testaction:1 + + + + Verify Permissions on Backup passwd File + + ocil:ssg-file_permissions_backup_etc_passwd_action:testaction:1 + + + + Verify Permissions on Backup shadow File + + ocil:ssg-file_permissions_backup_etc_shadow_action:testaction:1 + + + + Verify that System Executables Have Restrictive Permissions + + ocil:ssg-file_permissions_binary_dirs_action:testaction:1 + + + + Verify Permissions on /etc/cron.allow file + + ocil:ssg-file_permissions_cron_allow_action:testaction:1 + + + + Verify Permissions on cron.d + + ocil:ssg-file_permissions_cron_d_action:testaction:1 + + + + Verify Permissions on cron.daily + + ocil:ssg-file_permissions_cron_daily_action:testaction:1 + + + + Verify Permissions on cron.hourly + + ocil:ssg-file_permissions_cron_hourly_action:testaction:1 + + + + Verify Permissions on cron.monthly + + ocil:ssg-file_permissions_cron_monthly_action:testaction:1 + + + + Verify Permissions on cron.weekly + + ocil:ssg-file_permissions_cron_weekly_action:testaction:1 + + + + Verify Permissions on crontab + + ocil:ssg-file_permissions_crontab_action:testaction:1 + + + + Verify Permissions on /etc/audit/auditd.conf + + ocil:ssg-file_permissions_etc_audit_auditd_action:testaction:1 + + + + Verify Permissions on /etc/audit/rules.d/*.rules + + ocil:ssg-file_permissions_etc_audit_rulesd_action:testaction:1 + + + + Verify Permissions On /etc/chrony.keys File + + ocil:ssg-file_permissions_etc_chrony_keys_action:testaction:1 + + + + Verify Permissions On /etc/crypttab File + + ocil:ssg-file_permissions_etc_crypttab_action:testaction:1 + + + + Verify Permissions on group File + + ocil:ssg-file_permissions_etc_group_action:testaction:1 + + + + Verify Permissions on gshadow File + + ocil:ssg-file_permissions_etc_gshadow_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.conf File + + ocil:ssg-file_permissions_etc_ipsec_conf_action:testaction:1 + + + + Verify Permissions On /etc/ipsec.secrets File + + ocil:ssg-file_permissions_etc_ipsec_secrets_action:testaction:1 + + + + Verify permissions on System Login Banner for Remote Connections + + ocil:ssg-file_permissions_etc_issue_net_action:testaction:1 + + + + Verify Permissions on passwd File + + ocil:ssg-file_permissions_etc_passwd_action:testaction:1 + + + + Verify Permissions On /etc/sestatus.conf File + + ocil:ssg-file_permissions_etc_sestatus_conf_action:testaction:1 + + + + Verify Permissions on shadow File + + ocil:ssg-file_permissions_etc_shadow_action:testaction:1 + + + + Verify Permissions on /etc/shells File + + ocil:ssg-file_permissions_etc_shells_action:testaction:1 + + + + Verify Permissions On /etc/sudoers File + + ocil:ssg-file_permissions_etc_sudoers_action:testaction:1 + + + + Verify /boot/grub2/grub.cfg Permissions + + ocil:ssg-file_permissions_grub2_cfg_action:testaction:1 + + + + All Interactive User Home Directories Must Have mode 0750 Or Less Permissive + + ocil:ssg-file_permissions_home_directories_action:testaction:1 + + + + Ensure that User Home Directories are not Group-Writable or World-Readable + + ocil:ssg-file_permissions_home_dirs_action:testaction:1 + + + + Verify that Shared Library Files Have Restrictive Permissions + + ocil:ssg-file_permissions_library_dirs_action:testaction:1 + + + + Verify Permissions on SSH Server config file + + ocil:ssg-file_permissions_sshd_config_action:testaction:1 + + + + Verify Permissions on SSH Server Private *_key Key Files + + ocil:ssg-file_permissions_sshd_private_key_action:testaction:1 + + + + Verify Permissions on SSH Server Public *.pub Key Files + + ocil:ssg-file_permissions_sshd_pub_key_action:testaction:1 + + + + Verify Permissions on System.map Files + + ocil:ssg-file_permissions_systemmap_action:testaction:1 + + + + Ensure All SGID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_sgid_action:testaction:1 + + + + Ensure All SUID Executables Are Authorized + + ocil:ssg-file_permissions_unauthorized_suid_action:testaction:1 + + + + Ensure No World-Writable Files Exist + + ocil:ssg-file_permissions_unauthorized_world_writable_action:testaction:1 + + + + Ensure All Files Are Owned by a Group + + ocil:ssg-file_permissions_ungroupowned_action:testaction:1 + + + + Verify /boot/grub2/user.cfg Permissions + + ocil:ssg-file_permissions_user_cfg_action:testaction:1 + + + + Verify Permissions on /var/log Directory + + ocil:ssg-file_permissions_var_log_action:testaction:1 + + + + System Audit Logs Must Have Mode 0640 or Less Permissive + + ocil:ssg-file_permissions_var_log_audit_action:testaction:1 + + + + Verify Permissions on /var/log/messages File + + ocil:ssg-file_permissions_var_log_messages_action:testaction:1 + + + + Verify Permissions on /var/log/syslog File + + ocil:ssg-file_permissions_var_log_syslog_action:testaction:1 + + + + System Wide Crypto Policy Files Must Point to FIPS Policy + + ocil:ssg-fips_crypto_policy_symlinks_action:testaction:1 + + + + Configure Firewalld to Use the Nftables Backend + + ocil:ssg-firewalld-backend_action:testaction:1 + + + + Configure Firewalld to Restrict Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_restricted_action:testaction:1 + + + + Configure Firewalld to Trust Loopback Traffic + + ocil:ssg-firewalld_loopback_traffic_trusted_action:testaction:1 + + + + Enable SSH Server firewalld Firewall Exception + + ocil:ssg-firewalld_sshd_port_enabled_action:testaction:1 + + + + All GIDs referenced in /etc/passwd must be defined in /etc/group + + ocil:ssg-gid_passwd_group_same_action:testaction:1 + + + + Disable GDM Automatic Login + + ocil:ssg-gnome_gdm_disable_automatic_login_action:testaction:1 + + + + Disable XDMCP in GDM + + ocil:ssg-gnome_gdm_disable_xdmcp_action:testaction:1 + + + + Ensure All Groups on the System Have Unique Group ID + + ocil:ssg-group_unique_id_action:testaction:1 + + + + Set the Boot Loader Admin Username to a Non-Default Value + + ocil:ssg-grub2_admin_username_action:testaction:1 + + + + Enable Auditing for Processes Which Start Prior to the Audit Daemon + + ocil:ssg-grub2_audit_argument_action:testaction:1 + + + + Extend Audit Backlog Limit for the Audit Daemon + + ocil:ssg-grub2_audit_backlog_limit_argument_action:testaction:1 + + + + Verify that Interactive Boot is Disabled + + ocil:ssg-grub2_disable_interactive_boot_action:testaction:1 + + + + Disable Recovery Booting + + ocil:ssg-grub2_disable_recovery_action:testaction:1 + + + + IOMMU configuration directive + + ocil:ssg-grub2_enable_iommu_force_action:testaction:1 + + + + Ensure SELinux Not Disabled in /etc/default/grub + + ocil:ssg-grub2_enable_selinux_action:testaction:1 + + + + Configure kernel to zero out memory before allocation + + ocil:ssg-grub2_init_on_alloc_argument_action:testaction:1 + + + + Configure L1 Terminal Fault mitigations + + ocil:ssg-grub2_l1tf_argument_action:testaction:1 + + + + Force kernel panic on uncorrected MCEs + + ocil:ssg-grub2_mce_argument_action:testaction:1 + + + + Configure Microarchitectural Data Sampling mitigation + + ocil:ssg-grub2_mds_argument_action:testaction:1 + + + + Ensure SMAP is not disabled during boot + + ocil:ssg-grub2_nosmap_argument_absent_action:testaction:1 + + + + Ensure SMEP is not disabled during boot + + ocil:ssg-grub2_nosmep_argument_absent_action:testaction:1 + + + + Enable randomization of the page allocator + + ocil:ssg-grub2_page_alloc_shuffle_argument_action:testaction:1 + + + + Enable page allocator poisoning + + ocil:ssg-grub2_page_poison_argument_action:testaction:1 + + + + Set Boot Loader Password in grub2 + + ocil:ssg-grub2_password_action:testaction:1 + + + + Enable Kernel Page-Table Isolation (KPTI) + + ocil:ssg-grub2_pti_argument_action:testaction:1 + + + + Configure the confidence in TPM for entropy + + ocil:ssg-grub2_rng_core_default_quality_argument_action:testaction:1 + + + + Disable merging of slabs with similar size + + ocil:ssg-grub2_slab_nomerge_argument_action:testaction:1 + + + + Enable SLUB/SLAB allocator poisoning + + ocil:ssg-grub2_slub_debug_argument_action:testaction:1 + + + + Configure Speculative Store Bypass Mitigation + + ocil:ssg-grub2_spec_store_bypass_disable_argument_action:testaction:1 + + + + Enforce Spectre v2 mitigation + + ocil:ssg-grub2_spectre_v2_argument_action:testaction:1 + + + + Ensure debug-shell service is not enabled during boot + + ocil:ssg-grub2_systemd_debug-shell_argument_absent_action:testaction:1 + + + + Disable vsyscalls + + ocil:ssg-grub2_vsyscall_argument_action:testaction:1 + + + + Harden SSH client Crypto Policy + + ocil:ssg-harden_ssh_client_crypto_policy_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140 Validated Ciphers: openssh.config + + ocil:ssg-harden_sshd_ciphers_openssh_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated Ciphers: opensshserver.config + + ocil:ssg-harden_sshd_ciphers_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Client to Use FIPS 140-2 Validated MACs: openssh.config + + ocil:ssg-harden_sshd_macs_openssh_conf_crypto_policy_action:testaction:1 + + + + Configure SSH Server to Use FIPS 140-2 Validated MACs: opensshserver.config + + ocil:ssg-harden_sshd_macs_opensshserver_conf_crypto_policy_action:testaction:1 + + + + Install Smart Card Packages For Multifactor Authentication + + ocil:ssg-install_smartcard_packages_action:testaction:1 + + + + The Installed Operating System Is Vendor Supported + + ocil:ssg-installed_OS_is_vendor_supported_action:testaction:1 + + + + Do not allow ACPI methods to be inserted/replaced at run time + + ocil:ssg-kernel_config_acpi_custom_method_action:testaction:1 + + + + Emulate Privileged Access Never (PAN) + + ocil:ssg-kernel_config_arm64_sw_ttbr0_pan_action:testaction:1 + + + + Disable kernel support for MISC binaries + + ocil:ssg-kernel_config_binfmt_misc_action:testaction:1 + + + + Enable support for BUG() + + ocil:ssg-kernel_config_bug_action:testaction:1 + + + + Trigger a kernel BUG when data corruption is detected + + ocil:ssg-kernel_config_bug_on_data_corruption_action:testaction:1 + + + + Disable compatibility with brk() + + ocil:ssg-kernel_config_compat_brk_action:testaction:1 + + + + Disable the 32-bit vDSO + + ocil:ssg-kernel_config_compat_vdso_action:testaction:1 + + + + Enable checks on credential management + + ocil:ssg-kernel_config_debug_credentials_action:testaction:1 + + + + Disable kernel debugfs + + ocil:ssg-kernel_config_debug_fs_action:testaction:1 + + + + Enable checks on linked list manipulation + + ocil:ssg-kernel_config_debug_list_action:testaction:1 + + + + Enable checks on notifier call chains + + ocil:ssg-kernel_config_debug_notifiers_action:testaction:1 + + + + Enable checks on scatter-gather (SG) table operations + + ocil:ssg-kernel_config_debug_sg_action:testaction:1 + + + + Warn on W+X mappings found at boot + + ocil:ssg-kernel_config_debug_wx_action:testaction:1 + + + + Configure Low Address Space To Protect From User Allocation + + ocil:ssg-kernel_config_default_mmap_min_addr_action:testaction:1 + + + + Disable /dev/kmem virtual device support + + ocil:ssg-kernel_config_devkmem_action:testaction:1 + + + + Harden common str/mem functions against buffer overflows + + ocil:ssg-kernel_config_fortify_source_action:testaction:1 + + + + Generate some entropy during boot and runtime + + ocil:ssg-kernel_config_gcc_plugin_latent_entropy_action:testaction:1 + + + + Randomize layout of sensitive kernel structures + + ocil:ssg-kernel_config_gcc_plugin_randstruct_action:testaction:1 + + + + Poison kernel stack before returning from syscalls + + ocil:ssg-kernel_config_gcc_plugin_stackleak_action:testaction:1 + + + + Force initialization of variables containing userspace addresses + + ocil:ssg-kernel_config_gcc_plugin_structleak_action:testaction:1 + + + + zero-init everything passed by reference + + ocil:ssg-kernel_config_gcc_plugin_structleak_byref_all_action:testaction:1 + + + + Harden memory copies between kernel and userspace + + ocil:ssg-kernel_config_hardened_usercopy_action:testaction:1 + + + + Do not allow usercopy whitelist violations to fallback to object size + + ocil:ssg-kernel_config_hardened_usercopy_fallback_action:testaction:1 + + + + Disable hibernation + + ocil:ssg-kernel_config_hibernation_action:testaction:1 + + + + Disable IA32 emulation + + ocil:ssg-kernel_config_ia32_emulation_action:testaction:1 + + + + Disable the IPv6 protocol + + ocil:ssg-kernel_config_ipv6_action:testaction:1 + + + + Disable kexec system call + + ocil:ssg-kernel_config_kexec_action:testaction:1 + + + + Disable legacy (BSD) PTY support + + ocil:ssg-kernel_config_legacy_ptys_action:testaction:1 + + + + Disable vsyscall emulation + + ocil:ssg-kernel_config_legacy_vsyscall_emulate_action:testaction:1 + + + + Disable vsyscall mapping + + ocil:ssg-kernel_config_legacy_vsyscall_none_action:testaction:1 + + + + Disable vsyscall emulate execution only + + ocil:ssg-kernel_config_legacy_vsyscall_xonly_action:testaction:1 + + + + Disable the LDT (local descriptor table) + + ocil:ssg-kernel_config_modify_ldt_syscall_action:testaction:1 + + + + Enable module signature verification + + ocil:ssg-kernel_config_module_sig_action:testaction:1 + + + + Enable automatic signing of all modules + + ocil:ssg-kernel_config_module_sig_all_action:testaction:1 + + + + Require modules to be validly signed + + ocil:ssg-kernel_config_module_sig_force_action:testaction:1 + + + + Specify the hash to use when signing modules + + ocil:ssg-kernel_config_module_sig_hash_action:testaction:1 + + + + Specify module signing key to use + + ocil:ssg-kernel_config_module_sig_key_action:testaction:1 + + + + Sign kernel modules with SHA-512 + + ocil:ssg-kernel_config_module_sig_sha512_action:testaction:1 + + + + Enable poison of pages after freeing + + ocil:ssg-kernel_config_page_poisoning_action:testaction:1 + + + + Enable poison without sanity check + + ocil:ssg-kernel_config_page_poisoning_no_sanity_action:testaction:1 + + + + Use zero for poisoning instead of debugging value + + ocil:ssg-kernel_config_page_poisoning_zero_action:testaction:1 + + + + Remove the kernel mapping in user mode + + ocil:ssg-kernel_config_page_table_isolation_action:testaction:1 + + + + Kernel panic oops + + ocil:ssg-kernel_config_panic_on_oops_action:testaction:1 + + + + Kernel panic timeout + + ocil:ssg-kernel_config_panic_timeout_action:testaction:1 + + + + Disable support for /proc/kkcore + + ocil:ssg-kernel_config_proc_kcore_action:testaction:1 + + + + Randomize the address of the kernel image (KASLR) + + ocil:ssg-kernel_config_randomize_base_action:testaction:1 + + + + Randomize the kernel memory sections + + ocil:ssg-kernel_config_randomize_memory_action:testaction:1 + + + + Perform full reference count validation + + ocil:ssg-kernel_config_refcount_full_action:testaction:1 + + + + Avoid speculative indirect branches in kernel + + ocil:ssg-kernel_config_retpoline_action:testaction:1 + + + + Detect stack corruption on calls to schedule() + + ocil:ssg-kernel_config_sched_stack_end_check_action:testaction:1 + + + + Enable seccomp to safely compute untrusted bytecode + + ocil:ssg-kernel_config_seccomp_action:testaction:1 + + + + Enable use of Berkeley Packet Filter with seccomp + + ocil:ssg-kernel_config_seccomp_filter_action:testaction:1 + + + + Enable different security models + + ocil:ssg-kernel_config_security_action:testaction:1 + + + + Restrict unprivileged access to the kernel syslog + + ocil:ssg-kernel_config_security_dmesg_restrict_action:testaction:1 + + + + Disable mutable hooks + + ocil:ssg-kernel_config_security_writable_hooks_action:testaction:1 + + + + Enable Yama support + + ocil:ssg-kernel_config_security_yama_action:testaction:1 + + + + Harden slab freelist metadata + + ocil:ssg-kernel_config_slab_freelist_hardened_action:testaction:1 + + + + Randomize slab freelist + + ocil:ssg-kernel_config_slab_freelist_random_action:testaction:1 + + + + Disallow merge of slab caches + + ocil:ssg-kernel_config_slab_merge_default_action:testaction:1 + + + + Enable SLUB debugging support + + ocil:ssg-kernel_config_slub_debug_action:testaction:1 + + + + Stack Protector buffer overflow detection + + ocil:ssg-kernel_config_stackprotector_action:testaction:1 + + + + Strong Stack Protector + + ocil:ssg-kernel_config_stackprotector_strong_action:testaction:1 + + + + Make the kernel text and rodata read-only + + ocil:ssg-kernel_config_strict_kernel_rwx_action:testaction:1 + + + + Make the module text and rodata read-only + + ocil:ssg-kernel_config_strict_module_rwx_action:testaction:1 + + + + Enable TCP/IP syncookie support + + ocil:ssg-kernel_config_syn_cookies_action:testaction:1 + + + + Unmap kernel when running in userspace (aka KAISER) + + ocil:ssg-kernel_config_unmap_kernel_at_el0_action:testaction:1 + + + + User a virtually-mapped stack + + ocil:ssg-kernel_config_vmap_stack_action:testaction:1 + + + + Disable x86 vsyscall emulation + + ocil:ssg-kernel_config_x86_vsyscall_emulation_action:testaction:1 + + + + Disable ATM Support + + ocil:ssg-kernel_module_atm_disabled_action:testaction:1 + + + + Disable Bluetooth Kernel Module + + ocil:ssg-kernel_module_bluetooth_disabled_action:testaction:1 + + + + Disable CAN Support + + ocil:ssg-kernel_module_can_disabled_action:testaction:1 + + + + Disable Mounting of cramfs + + ocil:ssg-kernel_module_cramfs_disabled_action:testaction:1 + + + + Disable DCCP Support + + ocil:ssg-kernel_module_dccp_disabled_action:testaction:1 + + + + Disable IEEE 1394 (FireWire) Support + + ocil:ssg-kernel_module_firewire-core_disabled_action:testaction:1 + + + + Disable IPv6 Networking Support Automatic Loading + + ocil:ssg-kernel_module_ipv6_option_disabled_action:testaction:1 + + + + Disable RDS Support + + ocil:ssg-kernel_module_rds_disabled_action:testaction:1 + + + + Disable SCTP Support + + ocil:ssg-kernel_module_sctp_disabled_action:testaction:1 + + + + Disable TIPC Support + + ocil:ssg-kernel_module_tipc_disabled_action:testaction:1 + + + + Disable Modprobe Loading of USB Storage Driver + + ocil:ssg-kernel_module_usb-storage_disabled_action:testaction:1 + + + + Disable the uvcvideo module + + ocil:ssg-kernel_module_uvcvideo_disabled_action:testaction:1 + + + + Verify Any Configured IPSec Tunnel Connections + + ocil:ssg-libreswan_approved_tunnels_action:testaction:1 + + + + Configure Logind to terminate idle sessions after certain time of inactivity + + ocil:ssg-logind_session_timeout_action:testaction:1 + + + + Add nosuid Option to /boot/efi + + ocil:ssg-mount_option_boot_efi_nosuid_action:testaction:1 + + + + Add nodev Option to /boot + + ocil:ssg-mount_option_boot_nodev_action:testaction:1 + + + + Add noexec Option to /boot + + ocil:ssg-mount_option_boot_noexec_action:testaction:1 + + + + Add nosuid Option to /boot + + ocil:ssg-mount_option_boot_nosuid_action:testaction:1 + + + + Add nodev Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nodev_action:testaction:1 + + + + Add noexec Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_noexec_action:testaction:1 + + + + Add nosuid Option to /dev/shm + + ocil:ssg-mount_option_dev_shm_nosuid_action:testaction:1 + + + + Add grpquota Option to /home + + ocil:ssg-mount_option_home_grpquota_action:testaction:1 + + + + Add nodev Option to /home + + ocil:ssg-mount_option_home_nodev_action:testaction:1 + + + + Add noexec Option to /home + + ocil:ssg-mount_option_home_noexec_action:testaction:1 + + + + Add nosuid Option to /home + + ocil:ssg-mount_option_home_nosuid_action:testaction:1 + + + + Add usrquota Option to /home + + ocil:ssg-mount_option_home_usrquota_action:testaction:1 + + + + Mount Remote Filesystems with Kerberos Security + + ocil:ssg-mount_option_krb_sec_remote_filesystems_action:testaction:1 + + + + Add nodev Option to Non-Root Local Partitions + + ocil:ssg-mount_option_nodev_nonroot_local_partitions_action:testaction:1 + + + + Mount Remote Filesystems with nodev + + ocil:ssg-mount_option_nodev_remote_filesystems_action:testaction:1 + + + + Add nodev Option to Removable Media Partitions + + ocil:ssg-mount_option_nodev_removable_partitions_action:testaction:1 + + + + Mount Remote Filesystems with noexec + + ocil:ssg-mount_option_noexec_remote_filesystems_action:testaction:1 + + + + Add noexec Option to Removable Media Partitions + + ocil:ssg-mount_option_noexec_removable_partitions_action:testaction:1 + + + + Mount Remote Filesystems with nosuid + + ocil:ssg-mount_option_nosuid_remote_filesystems_action:testaction:1 + + + + Add nosuid Option to Removable Media Partitions + + ocil:ssg-mount_option_nosuid_removable_partitions_action:testaction:1 + + + + Add nosuid Option to /opt + + ocil:ssg-mount_option_opt_nosuid_action:testaction:1 + + + + Add nosuid Option to /srv + + ocil:ssg-mount_option_srv_nosuid_action:testaction:1 + + + + Add nodev Option to /tmp + + ocil:ssg-mount_option_tmp_nodev_action:testaction:1 + + + + Add noexec Option to /tmp + + ocil:ssg-mount_option_tmp_noexec_action:testaction:1 + + + + Add nosuid Option to /tmp + + ocil:ssg-mount_option_tmp_nosuid_action:testaction:1 + + + + Add nodev Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nodev_action:testaction:1 + + + + Add noexec Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_noexec_action:testaction:1 + + + + Add nosuid Option to /var/log/audit + + ocil:ssg-mount_option_var_log_audit_nosuid_action:testaction:1 + + + + Add nodev Option to /var/log + + ocil:ssg-mount_option_var_log_nodev_action:testaction:1 + + + + Add noexec Option to /var/log + + ocil:ssg-mount_option_var_log_noexec_action:testaction:1 + + + + Add nosuid Option to /var/log + + ocil:ssg-mount_option_var_log_nosuid_action:testaction:1 + + + + Add nodev Option to /var + + ocil:ssg-mount_option_var_nodev_action:testaction:1 + + + + Add noexec Option to /var + + ocil:ssg-mount_option_var_noexec_action:testaction:1 + + + + Add nosuid Option to /var + + ocil:ssg-mount_option_var_nosuid_action:testaction:1 + + + + Add nodev Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nodev_action:testaction:1 + + + + Add noexec Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_noexec_action:testaction:1 + + + + Add nosuid Option to /var/tmp + + ocil:ssg-mount_option_var_tmp_nosuid_action:testaction:1 + + + + Configure Multiple DNS Servers in /etc/resolv.conf + + ocil:ssg-network_configure_name_resolution_action:testaction:1 + + + + Prevent non-Privileged Users from Modifying Network Interfaces using nmcli + + ocil:ssg-network_nmcli_permissions_action:testaction:1 + + + + Ensure System is Not Acting as a Network Sniffer + + ocil:ssg-network_sniffer_disabled_action:testaction:1 + + + + NetworkManager DNS Mode Must Be Must Configured + + ocil:ssg-networkmanager_dns_mode_action:testaction:1 + + + + Ensure All-Squashing Disabled On All Exports + + ocil:ssg-no_all_squash_exports_action:testaction:1 + + + + Direct root Logins Not Allowed + + ocil:ssg-no_direct_root_logins_action:testaction:1 + + + + Prevent Login to Accounts With Empty Password + + ocil:ssg-no_empty_passwords_action:testaction:1 + + + + Ensure There Are No Accounts With Blank or Null Passwords + + ocil:ssg-no_empty_passwords_etc_shadow_action:testaction:1 + + + + Ensure All Files Are Owned by a User + + ocil:ssg-no_files_unowned_by_user_action:testaction:1 + + + + Remove Host-Based Authentication Files + + ocil:ssg-no_host_based_files_action:testaction:1 + + + + Verify No netrc Files Exist + + ocil:ssg-no_netrc_files_action:testaction:1 + + + + Ensure that System Accounts Are Locked + + ocil:ssg-no_password_auth_for_systemaccounts_action:testaction:1 + + + + Remove Rsh Trust Files + + ocil:ssg-no_rsh_trust_files_action:testaction:1 + + + + Ensure that System Accounts Do Not Run a Shell Upon Login + + ocil:ssg-no_shelllogin_for_systemaccounts_action:testaction:1 + + + + Remove User Host-Based Authentication Files + + ocil:ssg-no_user_host_based_files_action:testaction:1 + + + + Install AIDE + + ocil:ssg-package_aide_installed_action:testaction:1 + + + + Install audispd-plugins Package + + ocil:ssg-package_audispd-plugins_installed_action:testaction:1 + + + + Ensure the audit Subsystem is Installed + + ocil:ssg-package_audit_installed_action:testaction:1 + + + + Uninstall bind Package + + ocil:ssg-package_bind_removed_action:testaction:1 + + + + The Chrony package is installed + + ocil:ssg-package_chrony_installed_action:testaction:1 + + + + Install the cron service + + ocil:ssg-package_cron_installed_action:testaction:1 + + + + Install crypto-policies package + + ocil:ssg-package_crypto-policies_installed_action:testaction:1 + + + + Install cryptsetup Package + + ocil:ssg-package_cryptsetup-luks_installed_action:testaction:1 + + + + Uninstall cyrus-imapd Package + + ocil:ssg-package_cyrus-imapd_removed_action:testaction:1 + + + + Uninstall DHCP Server Package + + ocil:ssg-package_dhcp_removed_action:testaction:1 + + + + Install dnf-automatic Package + + ocil:ssg-package_dnf-automatic_installed_action:testaction:1 + + + + Uninstall dovecot Package + + ocil:ssg-package_dovecot_removed_action:testaction:1 + + + + Install fapolicyd Package + + ocil:ssg-package_fapolicyd_installed_action:testaction:1 + + + + Install firewalld Package + + ocil:ssg-package_firewalld_installed_action:testaction:1 + + + + Remove ftp Package + + ocil:ssg-package_ftp_removed_action:testaction:1 + + + + Ensure gnutls-utils is installed + + ocil:ssg-package_gnutls-utils_installed_action:testaction:1 + + + + Uninstall gssproxy Package + + ocil:ssg-package_gssproxy_removed_action:testaction:1 + + + + Uninstall iprutils Package + + ocil:ssg-package_iprutils_removed_action:testaction:1 + + + + Install libreswan Package + + ocil:ssg-package_libreswan_installed_action:testaction:1 + + + + Install libselinux Package + + ocil:ssg-package_libselinux_installed_action:testaction:1 + + + + Ensure logrotate is Installed + + ocil:ssg-package_logrotate_installed_action:testaction:1 + + + + Install McAfee Endpoint Security for Linux (ENSL) + + ocil:ssg-package_mcafeetp_installed_action:testaction:1 + + + + Uninstall net-snmp Package + + ocil:ssg-package_net-snmp_removed_action:testaction:1 + + + + Uninstall nfs-utils Package + + ocil:ssg-package_nfs-utils_removed_action:testaction:1 + + + + Install nftables Package + + ocil:ssg-package_nftables_installed_action:testaction:1 + + + + Ensure nss-tools is installed + + ocil:ssg-package_nss-tools_installed_action:testaction:1 + + + + Install the opensc Package For Multifactor Authentication + + ocil:ssg-package_opensc_installed_action:testaction:1 + + + + Install openscap-scanner Package + + ocil:ssg-package_openscap-scanner_installed_action:testaction:1 + + + + Install OpenSSH client software + + ocil:ssg-package_openssh-clients_installed_action:testaction:1 + + + + Install the OpenSSH Server Package + + ocil:ssg-package_openssh-server_installed_action:testaction:1 + + + + Remove the OpenSSH Server Package + + ocil:ssg-package_openssh-server_removed_action:testaction:1 + + + + Install the pcsc-lite package + + ocil:ssg-package_pcsc-lite_installed_action:testaction:1 + + + + Install policycoreutils-python-utils package + + ocil:ssg-package_policycoreutils-python-utils_installed_action:testaction:1 + + + + Install policycoreutils Package + + ocil:ssg-package_policycoreutils_installed_action:testaction:1 + + + + The Postfix package is installed + + ocil:ssg-package_postfix_installed_action:testaction:1 + + + + Uninstall quagga Package + + ocil:ssg-package_quagga_removed_action:testaction:1 + + + + Install rear Package + + ocil:ssg-package_rear_installed_action:testaction:1 + + + + Install rng-tools Package + + ocil:ssg-package_rng-tools_installed_action:testaction:1 + + + + Ensure rsyslog-gnutls is installed + + ocil:ssg-package_rsyslog-gnutls_installed_action:testaction:1 + + + + Ensure rsyslog is Installed + + ocil:ssg-package_rsyslog_installed_action:testaction:1 + + + + The s-nail Package Is Installed + + ocil:ssg-package_s-nail_installed_action:testaction:1 + + + + Install scap-security-guide Package + + ocil:ssg-package_scap-security-guide_installed_action:testaction:1 + + + + Uninstall Sendmail Package + + ocil:ssg-package_sendmail_removed_action:testaction:1 + + + + Uninstall setroubleshoot-plugins Package + + ocil:ssg-package_setroubleshoot-plugins_removed_action:testaction:1 + + + + Uninstall setroubleshoot-server Package + + ocil:ssg-package_setroubleshoot-server_removed_action:testaction:1 + + + + Uninstall squid Package + + ocil:ssg-package_squid_removed_action:testaction:1 + + + + Install the SSSD Package + + ocil:ssg-package_sssd_installed_action:testaction:1 + + + + Install sudo Package + + ocil:ssg-package_sudo_installed_action:testaction:1 + + + + Ensure syslog-ng is Installed + + ocil:ssg-package_syslogng_installed_action:testaction:1 + + + + Uninstall telnet-server Package + + ocil:ssg-package_telnet-server_removed_action:testaction:1 + + + + Remove telnet Clients + + ocil:ssg-package_telnet_removed_action:testaction:1 + + + + Uninstall tftp-server Package + + ocil:ssg-package_tftp-server_removed_action:testaction:1 + + + + Remove tftp Daemon + + ocil:ssg-package_tftp_removed_action:testaction:1 + + + + Uninstall tuned Package + + ocil:ssg-package_tuned_removed_action:testaction:1 + + + + Install usbguard Package + + ocil:ssg-package_usbguard_installed_action:testaction:1 + + + + Uninstall vsftpd Package + + ocil:ssg-package_vsftpd_removed_action:testaction:1 + + + + Remove the X Windows Package Group + + ocil:ssg-package_xorg-x11-server-common_removed_action:testaction:1 + + + + Ensure /dev/shm is configured + + ocil:ssg-partition_for_dev_shm_action:testaction:1 + + + + Ensure /home Located On Separate Partition + + ocil:ssg-partition_for_home_action:testaction:1 + + + + Ensure /srv Located On Separate Partition + + ocil:ssg-partition_for_srv_action:testaction:1 + + + + Ensure /tmp Located On Separate Partition + + ocil:ssg-partition_for_tmp_action:testaction:1 + + + + Ensure /var Located On Separate Partition + + ocil:ssg-partition_for_var_action:testaction:1 + + + + Ensure /var/log Located On Separate Partition + + ocil:ssg-partition_for_var_log_action:testaction:1 + + + + Ensure /var/log/audit Located On Separate Partition + + ocil:ssg-partition_for_var_log_audit_action:testaction:1 + + + + Ensure /var/tmp Located On Separate Partition + + ocil:ssg-partition_for_var_tmp_action:testaction:1 + + + + Configure System to Forward All Mail For The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_action:testaction:1 + + + + Configure System to Forward All Mail From Postmaster to The Root Account + + ocil:ssg-postfix_client_configure_mail_alias_postmaster_action:testaction:1 + + + + Configure System to Forward All Mail through a specific host + + ocil:ssg-postfix_client_configure_relayhost_action:testaction:1 + + + + Disable Postfix Network Listening + + ocil:ssg-postfix_network_listening_disabled_action:testaction:1 + + + + Prevent Unrestricted Mail Relaying + + ocil:ssg-postfix_prevent_unrestricted_relay_action:testaction:1 + + + + Prefer to use a 64-bit Operating System when supported + + ocil:ssg-prefer_64bit_os_action:testaction:1 + + + + Require Authentication for Emergency Systemd Target + + ocil:ssg-require_emergency_target_auth_action:testaction:1 + + + + Require Authentication for Single User Mode + + ocil:ssg-require_singleuser_auth_action:testaction:1 + + + + Restrict Serial Port Root Logins + + ocil:ssg-restrict_serial_port_logins_action:testaction:1 + + + + Verify the system-wide library files in directories +"/lib", "/lib64", "/usr/lib/" and "/usr/lib64" are group-owned by root. + + ocil:ssg-root_permissions_syslibrary_files_action:testaction:1 + + + + Verify crypto-policies with RPM + + ocil:ssg-rpm_verify_crypto_policies_action:testaction:1 + + + + Verify File Hashes with RPM + + ocil:ssg-rpm_verify_hashes_action:testaction:1 + + + + Verify and Correct Ownership with RPM + + ocil:ssg-rpm_verify_ownership_action:testaction:1 + + + + Verify and Correct File Permissions with RPM + + ocil:ssg-rpm_verify_permissions_action:testaction:1 + + + + Ensure cron Is Logging To Rsyslog + + ocil:ssg-rsyslog_cron_logging_action:testaction:1 + + + + Ensure Rsyslog Authenticates Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdriverauthmode_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_actionsendstreamdrivermode_action:testaction:1 + + + + Ensure Rsyslog Encrypts Off-Loaded Audit Records + + ocil:ssg-rsyslog_encrypt_offload_defaultnetstreamdriver_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate Group + + ocil:ssg-rsyslog_files_groupownership_action:testaction:1 + + + + Ensure Log Files Are Owned By Appropriate User + + ocil:ssg-rsyslog_files_ownership_action:testaction:1 + + + + Ensure System Log Files Have Correct Permissions + + ocil:ssg-rsyslog_files_permissions_action:testaction:1 + + + + Ensure rsyslog Does Not Accept Remote Messages Unless Acting As Log Server + + ocil:ssg-rsyslog_nolisten_action:testaction:1 + + + + Ensure remote access methods are monitored in Rsyslog + + ocil:ssg-rsyslog_remote_access_monitoring_action:testaction:1 + + + + Ensure Logs Sent To Remote Host + + ocil:ssg-rsyslog_remote_loghost_action:testaction:1 + + + + Configure TLS for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_action:testaction:1 + + + + Configure CA certificate for rsyslog remote logging + + ocil:ssg-rsyslog_remote_tls_cacert_action:testaction:1 + + + + Enable the auditadm_exec_content SELinux Boolean + + ocil:ssg-sebool_auditadm_exec_content_action:testaction:1 + + + + Disable the authlogin_nsswitch_use_ldap SELinux Boolean + + ocil:ssg-sebool_authlogin_nsswitch_use_ldap_action:testaction:1 + + + + Disable the authlogin_radius SELinux Boolean + + ocil:ssg-sebool_authlogin_radius_action:testaction:1 + + + + Configure the deny_execmem SELinux Boolean + + ocil:ssg-sebool_deny_execmem_action:testaction:1 + + + + Enable the kerberos_enabled SELinux Boolean + + ocil:ssg-sebool_kerberos_enabled_action:testaction:1 + + + + Configure the polyinstantiation_enabled SELinux Boolean + + ocil:ssg-sebool_polyinstantiation_enabled_action:testaction:1 + + + + Configure the secure_mode_insmod SELinux Boolean + + ocil:ssg-sebool_secure_mode_insmod_action:testaction:1 + + + + Disable the selinuxuser_execheap SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execheap_action:testaction:1 + + + + Enable the selinuxuser_execmod SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execmod_action:testaction:1 + + + + Disable the selinuxuser_execstack SELinux Boolean + + ocil:ssg-sebool_selinuxuser_execstack_action:testaction:1 + + + + Disable the ssh_sysadm_login SELinux Boolean + + ocil:ssg-sebool_ssh_sysadm_login_action:testaction:1 + + + + Ensure that Secure Boot is enabled + + ocil:ssg-secure_boot_enabled_action:testaction:1 + + + + Restrict Virtual Console Root Logins + + ocil:ssg-securetty_root_login_console_only_action:testaction:1 + + + + Ensure Software Patches Installed + + ocil:ssg-security_patches_up_to_date_action:testaction:1 + + + + Ensure No Device Files are Unlabeled by SELinux + + ocil:ssg-selinux_all_devicefiles_labeled_action:testaction:1 + + + + Ensure No Daemons are Unconfined by SELinux + + ocil:ssg-selinux_confinement_of_daemons_action:testaction:1 + + + + Ensure SELinux is Not Disabled + + ocil:ssg-selinux_not_disabled_action:testaction:1 + + + + Configure SELinux Policy + + ocil:ssg-selinux_policytype_action:testaction:1 + + + + Ensure SELinux State is Enforcing + + ocil:ssg-selinux_state_action:testaction:1 + + + + Disable At Service (atd) + + ocil:ssg-service_atd_disabled_action:testaction:1 + + + + Enable auditd Service + + ocil:ssg-service_auditd_enabled_action:testaction:1 + + + + Disable the Automounter + + ocil:ssg-service_autofs_disabled_action:testaction:1 + + + + Disable Avahi Server Software + + ocil:ssg-service_avahi-daemon_disabled_action:testaction:1 + + + + The Chronyd service is enabled + + ocil:ssg-service_chronyd_enabled_action:testaction:1 + + + + Enable cron Service + + ocil:ssg-service_crond_enabled_action:testaction:1 + + + + Disable debug-shell SystemD Service + + ocil:ssg-service_debug-shell_disabled_action:testaction:1 + + + + Enable the File Access Policy Service + + ocil:ssg-service_fapolicyd_enabled_action:testaction:1 + + + + Verify firewalld Enabled + + ocil:ssg-service_firewalld_enabled_action:testaction:1 + + + + Verify iptables Enabled + + ocil:ssg-service_iptables_enabled_action:testaction:1 + + + + Disable KDump Kernel Crash Analyzer (kdump) + + ocil:ssg-service_kdump_disabled_action:testaction:1 + + + + Verify nftables Service is Disabled + + ocil:ssg-service_nftables_disabled_action:testaction:1 + + + + Disable Odd Job Daemon (oddjobd) + + ocil:ssg-service_oddjobd_disabled_action:testaction:1 + + + + Enable the pcscd Service + + ocil:ssg-service_pcscd_enabled_action:testaction:1 + + + + Enable Postfix Service + + ocil:ssg-service_postfix_enabled_action:testaction:1 + + + + Disable Network Router Discovery Daemon (rdisc) + + ocil:ssg-service_rdisc_disabled_action:testaction:1 + + + + Disable rlogin Service + + ocil:ssg-service_rlogin_disabled_action:testaction:1 + + + + Enable the Hardware RNG Entropy Gatherer Service + + ocil:ssg-service_rngd_enabled_action:testaction:1 + + + + Ensure rsyncd service is disabled + + ocil:ssg-service_rsyncd_disabled_action:testaction:1 + + + + Enable rsyslog Service + + ocil:ssg-service_rsyslog_enabled_action:testaction:1 + + + + Disable snmpd Service + + ocil:ssg-service_snmpd_disabled_action:testaction:1 + + + + Disable Squid + + ocil:ssg-service_squid_disabled_action:testaction:1 + + + + Disable SSH Server If Possible + + ocil:ssg-service_sshd_disabled_action:testaction:1 + + + + Enable the OpenSSH Service + + ocil:ssg-service_sshd_enabled_action:testaction:1 + + + + Enable the SSSD Service + + ocil:ssg-service_sssd_enabled_action:testaction:1 + + + + Enable syslog-ng Service + + ocil:ssg-service_syslogng_enabled_action:testaction:1 + + + + Disable acquiring, saving, and processing core dumps + + ocil:ssg-service_systemd-coredump_disabled_action:testaction:1 + + + + Enable systemd-journald Service + + ocil:ssg-service_systemd-journald_enabled_action:testaction:1 + + + + Disable telnet Service + + ocil:ssg-service_telnet_disabled_action:testaction:1 + + + + Verify ufw Enabled + + ocil:ssg-service_ufw_enabled_action:testaction:1 + + + + Enable the USBGuard Service + + ocil:ssg-service_usbguard_enabled_action:testaction:1 + + + + Set Default firewalld Zone for Incoming Packets + + ocil:ssg-set_firewalld_default_zone_action:testaction:1 + + + + Set Default ip6tables Policy for Incoming Packets + + ocil:ssg-set_ip6tables_default_rule_action:testaction:1 + + + + Set Default iptables Policy for Incoming Packets + + ocil:ssg-set_iptables_default_rule_action:testaction:1 + + + + Set Default iptables Policy for Forwarded Packets + + ocil:ssg-set_iptables_default_rule_forward_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/libuser.conf + + ocil:ssg-set_password_hashing_algorithm_libuserconf_action:testaction:1 + + + + Set Password Hashing Algorithm in /etc/login.defs + + ocil:ssg-set_password_hashing_algorithm_logindefs_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm - password-auth + + ocil:ssg-set_password_hashing_algorithm_passwordauth_action:testaction:1 + + + + Set PAM''s Password Hashing Algorithm + + ocil:ssg-set_password_hashing_algorithm_systemauth_action:testaction:1 + + + + Set Password Hashing Rounds in /etc/login.defs + + ocil:ssg-set_password_hashing_min_rounds_logindefs_action:testaction:1 + + + + Configure SNMP Service to Use Only SNMPv3 or Newer + + ocil:ssg-snmpd_use_newer_protocol_action:testaction:1 + + + + Configure session renegotiation for SSH client + + ocil:ssg-ssh_client_rekey_limit_action:testaction:1 + + + + Verify the SSH Private Key Files Have a Passcode + + ocil:ssg-ssh_keys_passphrase_protected_action:testaction:1 + + + + Allow Only SSH Protocol 2 + + ocil:ssg-sshd_allow_only_protocol2_action:testaction:1 + + + + Disable Compression Or Set Compression to delayed + + ocil:ssg-sshd_disable_compression_action:testaction:1 + + + + Disable SSH Access via Empty Passwords + + ocil:ssg-sshd_disable_empty_passwords_action:testaction:1 + + + + Disable GSSAPI Authentication + + ocil:ssg-sshd_disable_gssapi_auth_action:testaction:1 + + + + Disable Kerberos Authentication + + ocil:ssg-sshd_disable_kerb_auth_action:testaction:1 + + + + Disable PubkeyAuthentication Authentication + + ocil:ssg-sshd_disable_pubkey_auth_action:testaction:1 + + + + Disable SSH Support for .rhosts Files + + ocil:ssg-sshd_disable_rhosts_action:testaction:1 + + + + Disable SSH Support for Rhosts RSA Authentication + + ocil:ssg-sshd_disable_rhosts_rsa_action:testaction:1 + + + + Disable SSH Root Login + + ocil:ssg-sshd_disable_root_login_action:testaction:1 + + + + Disable SSH root Login with a Password (Insecure) + + ocil:ssg-sshd_disable_root_password_login_action:testaction:1 + + + + Disable SSH TCP Forwarding + + ocil:ssg-sshd_disable_tcp_forwarding_action:testaction:1 + + + + Disable SSH Support for User Known Hosts + + ocil:ssg-sshd_disable_user_known_hosts_action:testaction:1 + + + + Disable X11 Forwarding + + ocil:ssg-sshd_disable_x11_forwarding_action:testaction:1 + + + + Do Not Allow SSH Environment Options + + ocil:ssg-sshd_do_not_permit_user_env_action:testaction:1 + + + + Enable GSSAPI Authentication + + ocil:ssg-sshd_enable_gssapi_auth_action:testaction:1 + + + + Enable PAM + + ocil:ssg-sshd_enable_pam_action:testaction:1 + + + + Enable Public Key Authentication + + ocil:ssg-sshd_enable_pubkey_auth_action:testaction:1 + + + + Enable Use of Strict Mode Checking + + ocil:ssg-sshd_enable_strictmodes_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_action:testaction:1 + + + + Enable SSH Warning Banner + + ocil:ssg-sshd_enable_warning_banner_net_action:testaction:1 + + + + Enable Encrypted X11 Forwarding + + ocil:ssg-sshd_enable_x11_forwarding_action:testaction:1 + + + + Limit Users' SSH Access + + ocil:ssg-sshd_limit_user_access_action:testaction:1 + + + + Enable SSH Print Last Log + + ocil:ssg-sshd_print_last_log_action:testaction:1 + + + + Force frequent session key renegotiation + + ocil:ssg-sshd_rekey_limit_action:testaction:1 + + + + Set SSH Client Alive Interval + + ocil:ssg-sshd_set_idle_timeout_action:testaction:1 + + + + Set SSH Client Alive Count Max + + ocil:ssg-sshd_set_keepalive_action:testaction:1 + + + + Set SSH Client Alive Count Max to zero + + ocil:ssg-sshd_set_keepalive_0_action:testaction:1 + + + + Ensure SSH LoginGraceTime is configured + + ocil:ssg-sshd_set_login_grace_time_action:testaction:1 + + + + Set LogLevel to INFO + + ocil:ssg-sshd_set_loglevel_info_action:testaction:1 + + + + Set SSH Daemon LogLevel to VERBOSE + + ocil:ssg-sshd_set_loglevel_verbose_action:testaction:1 + + + + Set SSH authentication attempt limit + + ocil:ssg-sshd_set_max_auth_tries_action:testaction:1 + + + + Set SSH MaxSessions limit + + ocil:ssg-sshd_set_max_sessions_action:testaction:1 + + + + Ensure SSH MaxStartups is configured + + ocil:ssg-sshd_set_maxstartups_action:testaction:1 + + + + Distribute the SSH Server configuration to multiple files in a config directory. + + ocil:ssg-sshd_use_directory_configuration_action:testaction:1 + + + + Enable Use of Privilege Separation + + ocil:ssg-sshd_use_priv_separation_action:testaction:1 + + + + Prevent remote hosts from connecting to the proxy display + + ocil:ssg-sshd_x11_use_localhost_action:testaction:1 + + + + Certificate status checking in SSSD + + ocil:ssg-sssd_certificate_verification_action:testaction:1 + + + + Enable Certmap in SSSD + + ocil:ssg-sssd_enable_certmap_action:testaction:1 + + + + Configure PAM in SSSD Services + + ocil:ssg-sssd_enable_pam_services_action:testaction:1 + + + + Enable Smartcards in SSSD + + ocil:ssg-sssd_enable_smartcards_action:testaction:1 + + + + SSSD Has a Correct Trust Anchor + + ocil:ssg-sssd_has_trust_anchor_action:testaction:1 + + + + Configure SSSD LDAP Backend Client to Demand a Valid Certificate from the Server + + ocil:ssg-sssd_ldap_configure_tls_reqcert_action:testaction:1 + + + + Configure SSSD LDAP Backend to Use TLS For All Transactions + + ocil:ssg-sssd_ldap_start_tls_action:testaction:1 + + + + Configure SSSD to Expire Offline Credentials + + ocil:ssg-sssd_offline_cred_expiration_action:testaction:1 + + + + Ensure Privileged Escalated Commands Cannot Execute Other Commands - sudo NOEXEC + + ocil:ssg-sudo_add_noexec_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo requiretty + + ocil:ssg-sudo_add_requiretty_action:testaction:1 + + + + Ensure Only Users Logged In To Real tty Can Execute Sudo - sudo use_pty + + ocil:ssg-sudo_add_use_pty_action:testaction:1 + + + + Ensure Sudo Logfile Exists - sudo logfile + + ocil:ssg-sudo_custom_logfile_action:testaction:1 + + + + Ensure a dedicated group owns sudo + + ocil:ssg-sudo_dedicated_group_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate + + ocil:ssg-sudo_remove_no_authenticate_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWD + + ocil:ssg-sudo_remove_nopasswd_action:testaction:1 + + + + Ensure Users Re-Authenticate for Privilege Escalation - sudo + + ocil:ssg-sudo_require_authentication_action:testaction:1 + + + + Require Re-Authentication When Using the sudo Command + + ocil:ssg-sudo_require_reauthentication_action:testaction:1 + + + + The operating system must restrict privilege elevation to authorized personnel + + ocil:ssg-sudo_restrict_privilege_elevation_to_authorized_action:testaction:1 + + + + Only the VDSM User Can Use sudo NOPASSWD + + ocil:ssg-sudo_vdsm_nopasswd_action:testaction:1 + + + + Explicit arguments in sudo specifications + + ocil:ssg-sudoers_explicit_command_args_action:testaction:1 + + + + Don't define allowed commands in sudoers by means of exclusion + + ocil:ssg-sudoers_no_command_negation_action:testaction:1 + + + + Don't target root user in the sudoers file + + ocil:ssg-sudoers_no_root_target_action:testaction:1 + + + + Ensure invoking users password for privilege escalation when using sudo + + ocil:ssg-sudoers_validate_passwd_action:testaction:1 + + + + Set kernel parameter 'crypto.fips_enabled' to 1 + + ocil:ssg-sysctl_crypto_fips_enabled_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on FIFOs + + ocil:ssg-sysctl_fs_protected_fifos_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Hardlinks + + ocil:ssg-sysctl_fs_protected_hardlinks_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Regular files + + ocil:ssg-sysctl_fs_protected_regular_action:testaction:1 + + + + Enable Kernel Parameter to Enforce DAC on Symlinks + + ocil:ssg-sysctl_fs_protected_symlinks_action:testaction:1 + + + + Disable Core Dumps for SUID programs + + ocil:ssg-sysctl_fs_suid_dumpable_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_action:testaction:1 + + + + Disable storing core dumps + + ocil:ssg-sysctl_kernel_core_pattern_empty_string_action:testaction:1 + + + + Configure file name of core dumps + + ocil:ssg-sysctl_kernel_core_uses_pid_action:testaction:1 + + + + Restrict Access to Kernel Message Buffer + + ocil:ssg-sysctl_kernel_dmesg_restrict_action:testaction:1 + + + + Enable ExecShield via sysctl + + ocil:ssg-sysctl_kernel_exec_shield_action:testaction:1 + + + + Disable Kernel Image Loading + + ocil:ssg-sysctl_kernel_kexec_load_disabled_action:testaction:1 + + + + Restrict Exposed Kernel Pointer Addresses Access + + ocil:ssg-sysctl_kernel_kptr_restrict_action:testaction:1 + + + + Disable loading and unloading of kernel modules + + ocil:ssg-sysctl_kernel_modules_disabled_action:testaction:1 + + + + Kernel panic on oops + + ocil:ssg-sysctl_kernel_panic_on_oops_action:testaction:1 + + + + Limit CPU consumption of the Perf system + + ocil:ssg-sysctl_kernel_perf_cpu_time_max_percent_action:testaction:1 + + + + Limit sampling frequency of the Perf system + + ocil:ssg-sysctl_kernel_perf_event_max_sample_rate_action:testaction:1 + + + + Disallow kernel profiling by unprivileged users + + ocil:ssg-sysctl_kernel_perf_event_paranoid_action:testaction:1 + + + + Configure maximum number of process identifiers + + ocil:ssg-sysctl_kernel_pid_max_action:testaction:1 + + + + Enable Randomized Layout of Virtual Address Space + + ocil:ssg-sysctl_kernel_randomize_va_space_action:testaction:1 + + + + Disallow magic SysRq key + + ocil:ssg-sysctl_kernel_sysrq_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_action:testaction:1 + + + + Disable Access to Network bpf() Syscall From Unprivileged Processes + + ocil:ssg-sysctl_kernel_unprivileged_bpf_disabled_accept_default_action:testaction:1 + + + + Restrict usage of ptrace to descendant processes + + ocil:ssg-sysctl_kernel_yama_ptrace_scope_action:testaction:1 + + + + Harden the operation of the BPF just-in-time compiler + + ocil:ssg-sysctl_net_core_bpf_jit_harden_action:testaction:1 + + + + Disable Accepting Packets Routed Between Local Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_local_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_accept_source_route_action:testaction:1 + + + + Configure ARP filtering for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_filter_action:testaction:1 + + + + Configure Response Mode of ARP Requests for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_arp_ignore_action:testaction:1 + + + + Drop Gratuitous ARP frames on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_drop_gratuitous_arp_action:testaction:1 + + + + Disable Kernel Parameter for IPv4 Forwarding on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_forwarding_action:testaction:1 + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_log_martians_action:testaction:1 + + + + Prevent Routing External Traffic to Local Loopback on All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_route_localnet_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_rp_filter_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_secure_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_send_redirects_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects for All IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_all_shared_media_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_accept_source_route_action:testaction:1 + + + + Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_log_martians_action:testaction:1 + + + + Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_rp_filter_action:testaction:1 + + + + Configure Kernel Parameter for Accepting Secure Redirects By Default + + ocil:ssg-sysctl_net_ipv4_conf_default_secure_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_send_redirects_action:testaction:1 + + + + Configure Sending and Accepting Shared Media Redirects by Default + + ocil:ssg-sysctl_net_ipv4_conf_default_shared_media_action:testaction:1 + + + + Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_echo_ignore_broadcasts_action:testaction:1 + + + + Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_icmp_ignore_bogus_error_responses_action:testaction:1 + + + + Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_ip_forward_action:testaction:1 + + + + Set Kernel Parameter to Increase Local Port Range + + ocil:ssg-sysctl_net_ipv4_ip_local_port_range_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP RFC 1337 on IPv4 Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_rfc1337_action:testaction:1 + + + + Enable Kernel Parameter to Use TCP Syncookies on Network Interfaces + + ocil:ssg-sysctl_net_ipv4_tcp_syncookies_action:testaction:1 + + + + Configure Accepting Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_defrtr_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_pinfo_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_action:testaction:1 + + + + Disable Accepting ICMP Redirects for All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_accept_source_route_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_autoconf_action:testaction:1 + + + + Disable IPv6 Addressing on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_disable_ipv6_action:testaction:1 + + + + Disable Kernel Parameter for IPv6 Forwarding + + ocil:ssg-sysctl_net_ipv6_conf_all_forwarding_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_max_addresses_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_all_router_solicitations_action:testaction:1 + + + + Disable Accepting Router Advertisements on all IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_action:testaction:1 + + + + Configure Accepting Default Router in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_defrtr_action:testaction:1 + + + + Configure Accepting Prefix Information in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_pinfo_action:testaction:1 + + + + Configure Accepting Router Preference in Router Advertisements on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_action:testaction:1 + + + + Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_redirects_action:testaction:1 + + + + Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_accept_source_route_action:testaction:1 + + + + Configure Auto Configuration on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_autoconf_action:testaction:1 + + + + Disable IPv6 Addressing on IPv6 Interfaces by Default + + ocil:ssg-sysctl_net_ipv6_conf_default_disable_ipv6_action:testaction:1 + + + + Configure Maximum Number of Autoconfigured Addresses on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_max_addresses_action:testaction:1 + + + + Configure Denying Router Solicitations on All IPv6 Interfaces By Default + + ocil:ssg-sysctl_net_ipv6_conf_default_router_solicitations_action:testaction:1 + + + + Disable the use of user namespaces + + ocil:ssg-sysctl_user_max_user_namespaces_action:testaction:1 + + + + Prevent applications from mapping low portion of virtual memory + + ocil:ssg-sysctl_vm_mmap_min_addr_action:testaction:1 + + + + Ensure tmp.mount Unit Is Enabled + + ocil:ssg-systemd_tmp_mount_enabled_action:testaction:1 + + + + Ensure tftp systemd Service Uses Secure Mode + + ocil:ssg-tftp_uses_secure_mode_systemd_action:testaction:1 + + + + Enable dnf-automatic Timer + + ocil:ssg-timer_dnf-automatic_enabled_action:testaction:1 + + + + Enable logrotate Timer + + ocil:ssg-timer_logrotate_enabled_action:testaction:1 + + + + Authorize Human Interface Devices and USB hubs in USBGuard daemon + + ocil:ssg-usbguard_allow_hid_and_hub_action:testaction:1 + + + + Generate USBGuard Policy + + ocil:ssg-usbguard_generate_policy_action:testaction:1 + + + + Use Kerberos Security on All Exports + + ocil:ssg-use_kerberos_security_all_exports_action:testaction:1 + + + + Enforce usage of pam_wheel for su authentication + + ocil:ssg-use_pam_wheel_for_su_action:testaction:1 + + + + Enforce Usage of pam_wheel with Group Parameter for su Authentication + + ocil:ssg-use_pam_wheel_group_for_su_action:testaction:1 + + + + Deactivate Wireless Network Interfaces + + ocil:ssg-wireless_disable_interfaces_action:testaction:1 + + + + Disable graphical user interface + + ocil:ssg-xwindows_remove_packages_action:testaction:1 + + + + Disable Graphical Environment Startup By Setting Default Target + + ocil:ssg-xwindows_runlevel_target_action:testaction:1 + + - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -250932,7 +270016,7 @@ fi FAIL - + PASS @@ -250940,7 +270024,7 @@ fi FAIL - + PASS @@ -250948,2111 +270032,7 @@ fi FAIL - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -253068,7 +270048,7 @@ fi FAIL - + PASS @@ -253076,7 +270056,7 @@ fi FAIL - + PASS @@ -253084,7 +270064,7 @@ fi FAIL - + PASS @@ -253092,7 +270072,7 @@ fi FAIL - + PASS @@ -253100,7 +270080,7 @@ fi FAIL - + PASS @@ -253108,7 +270088,7 @@ fi FAIL - + PASS @@ -253116,127 +270096,7 @@ fi FAIL - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - - - PASS - - - FAIL - - - + PASS @@ -253252,7 +270112,7 @@ fi FAIL - + PASS @@ -253260,7 +270120,7 @@ fi FAIL - + PASS @@ -253268,7 +270128,7 @@ fi FAIL - + PASS @@ -253276,7 +270136,7 @@ fi FAIL - + PASS @@ -253284,7 +270144,7 @@ fi FAIL - + PASS @@ -253292,7 +270152,143 @@ fi FAIL - + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + PASS @@ -253316,7 +270312,7 @@ fi FAIL - + PASS @@ -253324,7 +270320,7 @@ fi FAIL - + PASS @@ -253332,7 +270328,7 @@ fi FAIL - + PASS @@ -253340,7 +270336,7 @@ fi FAIL - + PASS @@ -253348,7 +270344,7 @@ fi FAIL - + PASS @@ -253356,7 +270352,7 @@ fi FAIL - + PASS @@ -253364,7 +270360,7 @@ fi FAIL - + PASS @@ -253372,7 +270368,983 @@ fi FAIL - + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + PASS @@ -253388,6 +271360,1030 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + PASS @@ -253396,6 +272392,782 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + PASS @@ -253404,317 +273176,4311 @@ fi FAIL + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + + + + PASS + + + FAIL + + - - Verify that yum verifies the signature of packages from a repository prior to install with the following command: + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify the inactive setting, run the following command: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +The output should indicate the inactive configuration option is set +to an appropriate integer between 1 and +; and should appear +before the pam_unix.so module as shown in the example below: +$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth +auth required pam_lastlog.so inactive= +auth sufficient pam_unix.so + Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? + + + + To verify the INACTIVE setting, run the following command: +$ grep "INACTIVE" /etc/default/useradd +The output should indicate the INACTIVE configuration option is set +to an appropriate integer as shown in the example below: +$ grep "INACTIVE" /etc/default/useradd +INACTIVE= + Is it the case that the value of INACTIVE is greater than the expected value or is -1? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: -$ grep gpgcheck /etc/yum.conf +$ sudo grep pam_faillock.so /etc/pam.d/password-auth -gpgcheck=1 +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? + + + + Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: -If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates that is approved by the organization? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: +$ sudo grep pam_faillock.so /etc/pam.d/system-auth -$ sudo auditctl -l | grep unix_chkpwd +auth required pam_faillock.so preauth +auth required pam_faillock.so authfail +account required pam_faillock.so + Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? + + + + If the system does not have SELinux enabled and enforcing a targeted policy, or if the +pam_faillock.so module is not configured for use, this requirement is not applicable. --a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.log_martians -1. +Verify the location of the non-default tally directory for the pam_faillock.so module with +the following command: - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/nftables, -run the command: -$ ls -l /etc/nftables -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/nftables does not have unix mode 0700? - - - - To verify all files and directories contained in interactive user home -directory, excluding local initialization files, have a mode of 0750, -run the following command: -$ sudo ls -lLR /home/USER - Is it the case that home directory files or folders have incorrect permissions? - - - - To check the ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/grub.cfg does not have an owner of root? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes rng_core.default_quality=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' -The command should not return any output. - Is it the case that trust on hardware random number generator is not configured appropriately? - - - - Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: +$ sudo grep -w dir /etc/security/faillock.conf -# grep -i umask /etc/login.defs +dir = /var/log/faillock -UMASK - Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? - - - - Run the following command to determine if the talk-server package is installed: -$ rpm -q talk-server - Is it the case that the package is installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - -If the system is configured to prevent the loading of the rds kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. +Check the security context type of the non-default tally directory with the following command: -These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. +$ sudo ls -Zd /var/log/faillock -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r rds /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +unconfined_u:object_r:faillog_t:s0 /var/log/faillock + Is it the case that the security context type of the non-default tally directory is not "faillog_t"? - - Run the following command to ensure postfix routes mail to this system: -$ grep relayhost /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it is not? - - - - To check the group ownership of /etc/cron.monthly, -run the command: -$ ls -lL /etc/cron.monthly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.monthly does not have a group owner of root? - - - - Verify the TFTP daemon is configured to operate in secure mode. + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: -Check if a TFTP server is installed with the following command: +$ sudo grep audit /etc/security/faillock.conf -$ sudo dnf list --installed tftp-server +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: -tftp-server.x86_64 5.2-35.el9.x86_64 +$ sudo grep 'dir =' /etc/security/faillock.conf +dir = /var/log/faillock + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? + + + + Verify that temporary accounts have been provisioned with an expiration date +of 72 hours. For every temporary account, run the following command to +obtain its account aging and expiration information: +$ sudo chage -l temporary_account_name +Verify each of these accounts has an expiration date set within 72 hours or +as documented. + Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? + + + + Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. -If a TFTP server is not installed, this is Not Applicable. +Check that the operating system contains no duplicate UIDs for interactive users with the following command: +$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd + Is it the case that output is produced and the accounts listed are interactive user accounts? + + + + To verify all accounts have unique names, run the following command: +$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d +No output should be returned. + Is it the case that a line is returned? + + + + Verify that the system is integrated with a centralized authentication mechanism +such as as Active Directory, Kerberos, Directory Server, etc. that has +automated account mechanisms in place. + Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? + + + + To verify that there are no unauthorized local user accounts, run the following command: +$ less /etc/passwd +Inspect the results, and if unauthorized local user accounts exist, remove them by running +the following command: +$ sudo userdel unauthorized_user + Is it the case that there are unauthorized local user accounts on the system? + + + + Verify all local interactive users on Oracle Linux 9 are assigned a home +directory upon creation with the following command: +$ grep -i create_home /etc/login.defs +CREATE_HOME yes + Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? + + + + Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: -If a TFTP server is installed, check for the server arguments with the following command: - -$ systemctl cat tftp | grep ExecStart= -ExecStart=/usr/sbin/in.tftpd -s - Is it the case that 'the "ExecStart" line does not have a "-s" option, and a subdirectory is not assigned'? - - - - To verify /etc/system-fips exists, run the following command: -ls -l /etc/system-fips -The output should be similar to the following: --rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips - Is it the case that /etc/system-fips does not exist? - - - - To determine if the system is configured to audit calls to the -lchown system call, run the following command: -$ sudo grep "lchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Run the following command to determine if the squid package is installed: -$ rpm -q squid - Is it the case that the package is installed? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes vsyscall=none, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' -The command should not return any output. - Is it the case that vsyscalls are enabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.all.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps all network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled on all network interfaces? - - - - If the system is not using TLS, set the ldap_id_use_start_tls option -in /etc/sssd/sssd.conf to true. - Is it the case that the 'ldap_id_use_start_tls' option is not set to 'true'? - - - - To verify that binaries cannot be directly executed from removable media, run the following command: -$ grep -v noexec /etc/fstab -The resulting output will show partitions which do not have the noexec flag. Verify all partitions -in the output are not removable media. - Is it the case that removable media partitions are present? - - - - To check the group ownership of /etc/sysctl.d, -run the command: -$ ls -lL /etc/sysctl.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sysctl.d does not have a group owner of root? - - - - To check the group ownership of /etc/sudoers, -run the command: -$ ls -lL /etc/sudoers -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sudoers does not have a group owner of root? - - - - The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i crypt_style /etc/libuser.conf - -crypt_style = - Is it the case that crypt_style is not set to sha512? - - - - The runtime status of the fs.protected_symlinks kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_symlinks -1. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/ipsec.d, -run the command: -$ ls -l /etc/ipsec.d -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/ipsec.d does not have unix mode 0700? - - - - To obtain a listing of all users, their UIDs, and their shells, run the command: -$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd -Identify the system accounts from this listing. These will primarily be the accounts with UID -numbers less than 1000, other than root. - Is it the case that any system account other than root has a login shell? - - - - Verify the nodev option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nodev . . . - - Is it the case that the "/var/log" file system does not have the "nodev" option set? - - - - Verify that cron is logging to rsyslog, -run the following command: -grep -rni "cron\.\*" /etc/rsyslog.* -cron.* /var/log/cron -or -cron.* action(type="omfile" file="/var/log/cron") - Is it the case that cron is not logging to rsyslog? - - - - Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic - Is it the case that the package is not installed? +$ sudo grep -i "FAIL_DELAY" /etc/login.defs +FAIL_DELAY + Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? @@ -253731,158 +277497,92 @@ operational requirement for all domains that have the "maxlogins" item assigned'? - - Verify Oracle Linux 9 removes all software components after updated versions have been installed. + + Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: +$ grep -i pass_max_days /etc/login.defs -$ grep clean_requirements_on_remove /etc/yum.conf -clean_requirements_on_remove=1 - Is it the case that '"clean_requirements_on_remove" is not set to "1"'? +PASS_MAX_DAYS + Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? - - Run the following command to determine if the dhcp-server package is installed: -$ rpm -q dhcp-server - Is it the case that the package is installed? - - - - To check the permissions of /boot/System.map*, -run the command: -$ ls -l /boot/System.map* -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/System.map* does not have unix mode -rw-------? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP_FILTER /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if authentication is required for emergency mode, run the following command: -$ grep sulogin /usr/lib/systemd/system/emergency.service -The output should be similar to the following, and the line must begin with -ExecStart and /usr/lib/systemd/systemd-sulogin-shell. - ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + + Verify Oracle Linux 9 enforces 24 hours/one day as the minimum password lifetime for new user accounts. -Then, check if the emergency target requires the emergency service: -Run the following command: -$ sudo grep Requires /usr/lib/systemd/system/emergency.target -The output should be the following: -Requires=emergency.service +Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: -Then, check if there is no custom emergency target configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.target /etc/systemd/system/ -The output should be empty. +$ grep -i pass_min_days /etc/login.defs -Then, check if there is no custom emergency service configured in systemd configuration. -Run the following command: -$ sudo grep -r emergency.service /etc/systemd/system/ -The output should be empty. - Is it the case that the output is different? +PASS_MIN_DAYS + Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? - - To ensure ClientAliveInterval is set correctly, run the following command: -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveCountMax -For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when -the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout -functionality completely. -If the option is set to a number greater than 0, then the session will be disconnected after -ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. - Is it the case that it is commented out or not configured properly? + + Verify that only the "root" account has a UID "0" assignment with the +following command: +$ awk -F: '$3 == 0 {print $1}' /etc/passwd +root + Is it the case that any accounts other than "root" have a UID of "0"? - - To verify the nodev option is configured for non-root local partitions, run the following command: -$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' -The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. - - Is it the case that some mounts appear among output lines? + + To check that no password hashes are stored in +/etc/passwd, run the following command: +awk '!/\S:x|\*/ {print}' /etc/passwd +If it produces any output, then a password hash is +stored in /etc/passwd. + Is it the case that any stored hashes are found in /etc/passwd? - - Verify that local initialization files do not execute world-writable programs with the following command: + + Verify that the interactive user account passwords are using a strong +password hash with the following command: -Note: The example will be for a system that is configured to create user home directories in the "/home" directory. +$ sudo cut -d: -f2 /etc/shadow -$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; - Is it the case that any local initialization files are found to reference world-writable files? +$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ + +Password hashes ! or * indicate inactive accounts not +available for logon and are not evaluated. + Is it the case that any interactive user password hash does not begin with "$6"? - - Verify that interactive users on the system have a home directory assigned with the following command: - -$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd - -Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. - Is it the case that users home directory is not defined? + + Verify that the interactive user account passwords last change time is not in the future +The following command should return no output +$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); +for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; +then echo "Expiry date in future"; +fi; done + Is it the case that any interactive user password that has last change time in the future? - - The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra -0. + + To check the minimum password length, run the command: +$ grep PASS_MIN_LEN /etc/login.defs +The profile requirement is +. + Is it the case that it is not set to the required value? + + + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. - Is it the case that the correct value is not returned? - - - - Verify the nodev option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nodev . . . +Check the value for "dcredit" with the following command: - Is it the case that the "/tmp" file system does not have the "nodev" option set? - - - - The rsh package can be removed with the following command: $ sudo yum erase rsh - Is it the case that ? - - - - Verify the nosuid option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nosuid . . . +$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? +/etc/security/pwquality.conf:dcredit = + Is it the case that the value of "dcredit" is a positive number or is commented out? - - For each private key stored on the system, use the following command: -$ sudo ssh-keygen -y -f /path/to/file -If the contents of the key are displayed, this is a finding. - Is it the case that no ssh private key is accessible without a passcode? - - - - Ensure that Oracle Linux 9 does not disable SELinux. + + Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: -Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: +$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf -$ sudo getenforce -Enforcing --OR- -Permissive - Is it the case that SELinux is disabled? - - - - Run the following command to determine if the cronie package is installed: -$ rpm -q cronie - Is it the case that the package is installed? +/etc/security/pwquality.conf:dictcheck=1 + Is it the case that "dictcheck" does not have a value other than "0", or is commented out? @@ -253894,83 +277594,15 @@ difok = Is it the case that the value of "difok" is set to less than "<sub idref="var_password_pam_difok" />", or is commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECCOMP /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure that remote access requires credentials, run the following command: -$ gsettings get org.gnome.Vino authentication-methods -If properly configured, the output should be false. -To ensure that users cannot disable credentials for remote access, run the following: -$ grep authentication-methods /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/authentication-methods - Is it the case that wireless network notification is enabled and not disabled? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - Verify the system-wide shared library directories are owned by "root" with the following command: + + Verify that Oracle Linux 9 enforces password complexity rules for the root account. -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; - Is it the case that any system-wide shared library directory is not owned by root? - - - - Verify the system-wide shared library files are group-owned by "root" with the following command: +Check if root user is required to use complex passwords with the following command: -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; - Is it the case that any system wide shared library file is returned and is not group-owned by a required system account? - - - - To verify ExecShield is enabled on 64-bit Oracle Linux 9 systems, -run the following command: -$ dmesg | grep '[NX|DX]*protection' -The output should not contain 'disabled by kernel command line option'. -Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes noexec=off, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*noexec=off.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*noexec=off.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'noexec=off' -The command should not return any output. - Is it the case that ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration.? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd with the following command: +$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf -$ sudo auditctl -l | grep -E '(/etc/shadow)' - --w /etc/shadow -p wa -k identity - Is it the case that command does not return a line, or the line is commented out? - - - - To verify all files and directories in a local interactive user's -home directory have a valid owner, run the following command: -$ sudo ls -lLR /home/USER - Is it the case that the user ownership is incorrect? +/etc/security/pwquality.conf:enforce_for_root + Is it the case that "enforce_for_root" is commented or missing? @@ -253984,299 +277616,22 @@ $ sudo grep lcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/ Is it the case that the value of "lcredit" is a positive number or is commented out? - - + + Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: -Run the following command to determine the current status of the -chronyd service: -$ sudo systemctl is-active chronyd -If the service is running, it should return the following: active - Is it the case that the chronyd process is not running? - - - - Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld - Is it the case that the package is not installed? - - - - To check the permissions of /etc/sudoers.d, -run the command: -$ ls -l /etc/sudoers.d -If properly configured, the output should indicate the following permissions: -0750 - Is it the case that /etc/sudoers.d does not have unix mode 0750? - - - - To check the current idle time-out value, run the following command: -$ gsettings get org.gnome.desktop.session idle-delay -If properly configured, the output should be 'uint32 '. -To ensure that users cannot change the screensaver inactivity timeout setting, run the following: -$ grep idle-delay /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? - - - - To determine if the system is configured to audit account changes, -run the following command: -auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' -If the system is configured to watch for account changes, lines should be returned for -each file specified (and with perm=wa for each). - Is it the case that the system is not configured to audit account changes? - - - - To check the permissions of /etc/ssh/sshd_config, -run the command: -$ ls -l /etc/ssh/sshd_config -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? - - - - root password is not set - Is it the case that Perform the following to determine if a password is set for the -root user: -<pre># grep -Eq '^root:\$[0-9]' /etc/shadow || echo "root is locked"</pre> -No results should be returned. -Otherwise, run the following command and follow the prompts to set a -password for the root user: -<pre># passwd root</pre>? - - - - To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, -run the following command: -$ sudo grep allow /etc/usbguard/rules.conf -The output lines should include -allow with-interface match-all { 03:*:* 09:00:* } - Is it the case that USB devices of class 3 and 9:00 are not authorized? - - - - Verify that a separate file system/partition has been created for /tmp with the following command: +$ grep maxclassrepeat /etc/security/pwquality.conf -$ mountpoint /tmp +maxclassrepeat = + Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? + + + + Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: - Is it the case that "/tmp is not a mountpoint" is returned? - - - - +$ grep maxrepeat /etc/security/pwquality.conf -Run the following command to determine the current status of the -sshd service: -$ sudo systemctl is-active sshd -If the service is running, it should return the following: active - Is it the case that sshd service is disabled? - - - - To check the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following -permissions: -rw------- - Is it the case that it does not? - - - - To determine how the SSH daemon's Banner option is set, run the following command: - -$ sudo grep -i Banner /etc/ssh/sshd_config - -If a line indicating /etc/issue.net is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.icmp_ignore_bogus_error_responses -1. - - Is it the case that the correct value is not returned? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules -The output has to be exactly as follows: -## Successful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change - Is it the case that the file does not exist or the content differs? - - - - -If the system is configured to prevent the loading of the bluetooth kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Run the following command to determine if the libselinux package is installed: $ rpm -q libselinux - Is it the case that the package is not installed? - - - - To check the ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow does not have an owner of root? - - - - Run the following command to determine if the net-snmp package is installed: -$ rpm -q net-snmp - Is it the case that the package is installed? - - - - The ftp package can be removed with the following command: $ sudo yum erase ftp - Is it the case that ? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: - -$ sudo auditctl -l | grep poweroff - --a always,exit -F path=/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow- does not have a group owner of root? - - - - To check the ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log/messages does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -umount2 system call, run the following command: -$ sudo grep "umount2" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - The following command will locate the mount points related to local devices: -$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) - -The following command will show files which do not belong to a valid group: -$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null - -Replace MOUNTPOINT by the mount points listed by the fist command. - -No files without a valid group should be located. - Is it the case that there is output? - - - - Verify the nosuid option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nosuid . . . - - Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? - - - - -To properly set the permissions of /etc/audit/, run the command: -$ sudo chmod 0640 /etc/audit/ - -To properly set the permissions of /etc/audit/rules.d/, run the command: -$ sudo chmod 0640 /etc/audit/rules.d/ - Is it the case that ? - - - - To check the permissions of /etc/audit/rules.d/*.rules, -run the command: -$ ls -l /etc/audit/rules.d/*.rules -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-------? - - - - To check the group ownership of /usr/bin/sudo, -run the command: -$ ls -lL /usr/bin/sudo -If properly configured, the output should indicate the following group-owner: - - Is it the case that /usr/bin/sudo does not have a group owner of <sub idref="var_sudo_dedicated_group" />? - - - - Verify that a separate file system/partition has been created for /srv with the following command: - -$ mountpoint /srv - - Is it the case that "/srv is not a mountpoint" is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_BASE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure the failed password attempt policy is configured correctly, run the following command: - -$ grep fail_interval /etc/security/faillock.conf -The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. - Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" -or less (but not "0"), the line is commented out, or the line is missing? +maxrepeat = + Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? @@ -254288,1321 +277643,44 @@ minclass = Is it the case that the value of "minclass" is set to less than "<sub idref="var_password_pam_minclass" />" or is commented out? - - To determine if the system is configured to audit changes to its network configuration, -run the following command: -auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' + + Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: -If the system is configured to watch for network configuration changes, a line should be returned for -each file specified (and perm=wa should be indicated for each). - Is it the case that the system is not configured to audit changes of the network configuration? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/screensaver/lock-delay - Is it the case that GNOME3 session settings are not locked or configured properly? - - - - -Run the following command to determine if the authlogin_nsswitch_use_ldap SELinux boolean is disabled: -$ getsebool authlogin_nsswitch_use_ldap -If properly configured, the output should show the following: -authlogin_nsswitch_use_ldap --> off - Is it the case that authlogin_nsswitch_use_ldap is not disabled? - - - - In order to be sure that the databases are up-to-date, run the -dconf update -command as the administrator. - Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? - - - - To determine if the system is configured to audit calls to the -fchmod system call, run the following command: -$ sudo grep "fchmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check that no password hashes are stored in -/etc/passwd, run the following command: -awk '!/\S:x|\*/ {print}' /etc/passwd -If it produces any output, then a password hash is -stored in /etc/passwd. - Is it the case that any stored hashes are found in /etc/passwd? - - - - To check which SSH protocol version is allowed, check version of openssh-server with following command: - -$ rpm -qi openssh-server | grep Version - -Versions equal to or higher than 7.4 only allow Protocol 2. -If version is lower than 7.4, run the following command to check configuration: -$ sudo grep Protocol /etc/ssh/sshd_config -If configured properly, output should be Protocol 2 - Is it the case that it is commented out or is not set correctly to Protocol 2? - - - - Verify that there are no wireless interfaces configured on the system -with the following command: - -Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. - -$ nmcli device status -DEVICE TYPE STATE CONNECTION -virbr0 bridge connected virbr0 -wlp7s0 wifi connected wifiSSID -enp6s0 ethernet disconnected -- -p2p-dev-wlp7s0 wifi-p2p disconnected -- -lo loopback unmanaged -- -virbr0-nic tun unmanaged -- - Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules -The output has to be exactly as follows: -## Successful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create --a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create - Is it the case that the file does not exist or the content differs? - - - - Run the following command to determine if the cryptsetup package is installed: $ rpm -q cryptsetup - Is it the case that the package is not installed? - - - - To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check -that the ctrl-alt-del.target is masked and not active with the following -command: -sudo systemctl status ctrl-alt-del.target -The output should indicate that the target is masked and not active. It -might resemble following output: -ctrl-alt-del.target -Loaded: masked (/dev/null; bad) -Active: inactive (dead) - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? - - - - Run the following command to determine if the opensc package is installed: $ rpm -q opensc - Is it the case that the package is not installed? - - - - To verify that there are no unauthorized local user accounts, run the following command: -$ less /etc/passwd -Inspect the results, and if unauthorized local user accounts exist, remove them by running -the following command: -$ sudo userdel unauthorized_user - Is it the case that there are unauthorized local user accounts on the system? - - - - To ensure root may not directly login to the system over physical consoles, -run the following command: -cat /etc/securetty -If any output is returned, this is a finding. - Is it the case that the /etc/securetty file is not empty? - - - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: - -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - -To properly set the owner of /etc/audit/, run the command: -$ sudo chown root /etc/audit/ - -To properly set the owner of /etc/audit/rules.d/, run the command: -$ sudo chown root /etc/audit/rules.d/ - Is it the case that ? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 set the days of warning before a password expires to - or more for users with a -password: - -$ sudo awk -F: '$6 || $6 == "" {print $1}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - To determine if the system is configured to audit calls to the -chown system call, run the following command: -$ sudo grep "chown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Run the following command to determine if the nfs-utils package is installed: -$ rpm -q nfs-utils - Is it the case that the package is installed? - - - - System commands are stored in the following directories: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -For each of these directories, run the following command to find directories not -owned by root: -$ sudo find -L $DIR ! -user root -type d - Is it the case that any of these directories are not owned by root? - - - - To check the ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group does not have an owner of root? - - - - Run the following command to determine if the cyrus-imapd package is installed: -$ rpm -q cyrus-imapd - Is it the case that the package is installed? - - - - Check the system partitions to determine if they are encrypted with the following command: -blkid - -Output will be similar to: -/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 -" TYPE="crypto_LUKS" -/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 -" TYPE="crypto_LUKS" - -The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, -are not required to use disk encryption and are not a finding. - Is it the case that partitions do not have a type of crypto_LUKS? - - - - To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify the usrquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . usrquota . . . - - Is it the case that the "/home" file system does not have the "usrquota" option set? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: - -$ sudo auditctl -l | grep usermod - --a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod - Is it the case that the command does not return a line, or the line is commented out? - - - - -Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: -$ getsebool selinuxuser_execstack -If properly configured, the output should show the following: -selinuxuser_execstack --> off - Is it the case that selinuxuser_execstack is not disabled? - - - - Inspect /etc/default/grub for any instances of selinux=0 -in the kernel boot arguments. Presence of selinux=0 indicates -that SELinux is disabled at boot time. - Is it the case that SELinux is disabled at boot time? - - - - To determine if the system is configured to audit accesses to -/var/log/audit directory, run the following command: -$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. - -This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. - -This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. - -For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. - -For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. - -If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: - -Verify the operating system disables the ability to load the uvcvideo kernel module. - -$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" - -install uvcvideo /bin/true - Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? - - - - Verify that temporary accounts have been provisioned with an expiration date -of 72 hours. For every temporary account, run the following command to -obtain its account aging and expiration information: -$ sudo chage -l temporary_account_name -Verify each of these accounts has an expiration date set within 72 hours or -as documented. - Is it the case that any temporary accounts have no expiration date set or do not expire within 72 hours? - - - - Verify Oracle Linux 9 audits the execution of privileged functions. - -Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: - -$ sudo grep execve /etc/audit/audit.rules - -The output should be the following: - - --a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid --a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid --a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid - Is it the case that the command does not return all lines, or the lines are commented out? - - - - If IPv6 is disabled, this is not applicable. - -Inspect the file /etc/sysconfig/ip6tables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/ip6tables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: - -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: - -$ sudo auditctl -l | grep setsebool - --a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; - Is it the case that any system-wide shared library file is found to be group-writable or world-writable? - - - - To check for virtual console entries which permit root login, run the -following command: -$ sudo grep ^vc/[0-9] /etc/securetty -If any output is returned, then root logins over virtual console devices is permitted. - Is it the case that root login over virtual console devices is permitted? - - - - The runtime status of the kernel.randomize_va_space kernel parameter can be queried -by running the following command: -$ sysctl kernel.randomize_va_space -2. - - Is it the case that the correct value is not returned? - - - - Check whether the maximum time period for existing passwords is restricted to days with the following commands: - -$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow - -$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - Verify the nosuid option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . nosuid . . . - - Is it the case that the "/tmp" file system does not have the "nosuid" option set? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check if UsePrivilegeSeparation is enabled or set correctly, run the -following command: -$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config -If configured properly, output should be . - Is it the case that it is commented out or is not enabled? - - - - The file /etc/at.deny should not exist. -This can be checked by running the following - -stat /etc/at.deny - -and the output should be - -stat: cannot stat `/etc/at.deny': No such file or directory - - Is it the case that the file /etc/at.deny exists? - - - - Run the following command to determine if the sudo package is installed: $ rpm -q sudo - Is it the case that the package is not installed? - - - - The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried -by running the following command: -$ sysctl kernel.yama.ptrace_scope -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.rp_filter -1. - - Is it the case that the correct value is not returned? - - - - Run the following command to see what the max sessions number is: -$ sudo grep MaxSessions /etc/ssh/sshd_config -If properly configured, the output should be: -MaxSessions - Is it the case that MaxSessions is not configured or not configured correctly? - - - - To check the group ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/crontab does not have a group owner of root? - - - - To check the group ownership of /etc/shells, -run the command: -$ ls -lL /etc/shells -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shells does not have a group owner of root? - - - - To check the ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.weekly does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was built with the required value? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is installed? - - - - -If the system is configured to prevent the loading of the firewire-core kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - -To check that the rlogin service is disabled in system boot configuration with xinetd, run the following command: -$ chkconfig rlogin --list -Output should indicate the rlogin service has either not been installed, or has been disabled, as shown in the example below: -$ chkconfig rlogin --list - -Note: This output shows SysV services only and does not include native -systemd services. SysV configuration data might be overridden by native -systemd configuration. - -If you want to list systemd services use 'systemctl list-unit-files'. -To see services enabled on particular target use -'systemctl list-dependencies [target]'. - -rlogin off - -To check that the rlogin socket is disabled in system boot configuration with systemd, run the following command: -$ systemctl is-enabled rlogin -Output should indicate the rlogin socket has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled rlogindisabled - -Run the following command to verify rlogin is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active rlogin - -If the socket is not running the command will return the following output: -inactive - -The socket will also be masked, to check that the rlogin is masked, run the following command: -$ sudo systemctl show rlogin | grep "LoadState\|UnitFileState" - -If the socket is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that service and/or socket are running? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PROC_KCORE /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd does not have a group owner of root? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules -The output has to be exactly as follows: -## Successful file modifications (open for write or truncate) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification --a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification - Is it the case that the file does not exist or the content differs? - - - - To verify that the Dracut FIPS module is enabled, run the following command: -grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf -The output should look like this: -add_dracutmodules+=" fips " - Is it the case that the Dracut FIPS module is not enabled? - - - - To check the ownership of /etc/sudoers, -run the command: -$ ls -lL /etc/sudoers -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sudoers does not have an owner of root? - - - - Verify the umask setting is configured correctly in the /etc/profile file -or scripts within /etc/profile.d directory with the following command: -$ grep "umask" /etc/profile* -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", -or the "umask" parameter is missing or is commented out? - - - - To determine how the SSH daemon's X11Forwarding option is set, run the following command: - -$ sudo grep -i X11Forwarding /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, -run the following command: -$ sudo postconf -n smtpd_client_restrictions - Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? - - - - Run the following command to determine if the audit package is installed: $ rpm -q audit - Is it the case that the audit package is not installed? - - - - Inspect /etc/login.defs and ensure that if either -SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS -are set, they must have the minimum value of . - Is it the case that it does not? - - - - Inspect the network interfaces assigned to the firewalld trusted zone and verify the -lo interface is listed by running the following command: - -$ sudo firewall-cmd --list-interfaces --zone=trusted - Is it the case that loopback traffic is not trusted? - - - - To check the ownership of /etc/cron.monthly, -run the command: -$ ls -lL /etc/cron.monthly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.monthly does not have an owner of root? - - - - The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.router_solicitations -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.log_martians -1. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: - -$ sudo auditctl -l | grep semanage - --a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if logfile has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that logfile is not enabled in sudo? - - - - Verify that core dumps are disabled for all users, run the following command: -$ grep core /etc/security/limits.conf -* hard core 0 - Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? - - - - The runtime status of the kernel.core_uses_pid kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_uses_pid -0. - Is it the case that the returned line does not have a value of 0? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/passwd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/passwd)' - --w /etc/passwd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: -$ grep -i macs /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -MACs - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - -Run the following command to determine if the kerberos_enabled SELinux boolean is enabled: -$ getsebool kerberos_enabled -If properly configured, the output should show the following: -kerberos_enabled --> on - Is it the case that kerberos_enabled is not enabled? - - - - To check the permissions of /etc/passwd-, -run the command: -$ ls -l /etc/passwd- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? - - - - To ensure the X Windows package group is removed, run the following command: - -$ rpm -qi xorg-x11-server-Xorg xorg-x11-server-common xorg-x11-server-utils xorg-x11-server-Xwayland - -For each package mentioned above you should receive following line: -package <package> is not installed - Is it the case that xorg related packages are not removed and run level is not correctly configured? - - - - To verify that execution of the command is being audited, run the following command: -$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* -The output should return something similar to: --a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged - Is it the case that ? - - - - Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: - sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' -or if cvtsudoers not supported: - sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; -If no results are returned, this is a finding. -If conflicting results are returned, this is a finding. -If "Defaults !targetpw" is not defined, this is a finding. -If "Defaults !rootpw" is not defined, this is a finding. -If "Defaults !runaspw" is not defined, this is a finding. - Is it the case that invoke user passwd when using sudo? - - - - Verify the nodev option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . nodev . . . - - Is it the case that the "/dev/shm" file system does not have the "nodev" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_LIST /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/chrony.keys, -run the command: -$ ls -lL /etc/chrony.keys -If properly configured, the output should indicate the following group-owner: -chrony - Is it the case that /etc/chrony.keys does not have a group owner of chrony? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_ON_OOPS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the kernel.modules_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.modules_disabled -1. - - Is it the case that the correct value is not returned? - - - - Verify that a separate file system/partition has been created for /var/log with the following command: - -$ mountpoint /var/log - - Is it the case that "/var/log is not a mountpoint" is returned? - - - - To check the group ownership of /etc/group, -run the command: -$ ls -lL /etc/group -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group does not have a group owner of root? - - - - Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: -$ grep -w cmdport /etc/chrony.conf -cmdport 0 - Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? - - - - Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils - Is it the case that the package is not installed? - - - - To check that the debug-shell service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled debug-shell -Output should indicate the debug-shell service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled debug-shell disabled - -Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active debug-shell - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the debug-shell is masked, run the following command: -$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "debug-shell" is loaded and not masked? - - - - To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: -$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oMACS= - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_IPV6 /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. -To determine if the system is configured to audit calls to the -"umount" system call, run the following command: -$ sudo grep "umount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line like the following. --a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - - -Run the following command to determine the current status of the -syslog-ng service: -$ sudo systemctl is-active syslog-ng -If the service is running, it should return the following: active - Is it the case that the "syslog-ng" service is disabled, masked, or not started.? - - - - -Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: -$ getsebool selinuxuser_execheap -If properly configured, the output should show the following: -selinuxuser_execheap --> off - Is it the case that selinuxuser_execheap is not disabled? - - - - Verify that the IPSec service uses the system crypto policy. - -If the ipsec service is not installed is not applicable. +$ grep minlen /etc/security/pwquality.conf -Check to see if the "IPsec" service is active with the following command: - -$ systemctl status ipsec - -ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec -Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) -Active: inactive (dead) - -If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: - -$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf - -/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config - Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? - - - - -Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: -$ getsebool selinuxuser_execmod -If properly configured, the output should show the following: -selinuxuser_execmod --> on - Is it the case that selinuxuser_execmod is not enabled? - - - - To check the ownership of /etc/gshadow-, -run the command: -$ ls -lL /etc/gshadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/gshadow- does not have an owner of root? - - - - -If the system is configured to prevent the loading of the cramfs kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: - -$ sudo auditctl -l | grep chsh - --a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/iptables, -run the command: -$ ls -lL /etc/iptables -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/iptables does not have a group owner of root? - - - - Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite - Is it the case that the package is not installed? - - - - To check for incorrectly labeled device files, run following commands: -$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" -$ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" -It should produce no output in a well-configured system. - Is it the case that there is output? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -finit_module system call, run the following command: -$ sudo grep "finit_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? +minlen = + Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? - - Verify users are provided with feedback on when account accesses last occurred with the following command: - -$ sudo grep pam_lastlog /etc/pam.d/postlogin + + Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: -session required pam_lastlog.so showfailed - Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file? - - - - Verify that DNS servers have been configured properly, perform the following: -$ sudo grep nameserver /etc/resolv.conf - Is it the case that less than two lines are returned that are not commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes mds=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mds=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*mds=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'mds=' -The command should not return any output. - Is it the case that MDS mitigations are not configured appropriately? - - - - Run the following command to determine if the aide package is installed: $ rpm -q aide - Is it the case that the package is not installed? - - - - Run the following command to determine if the rear package is installed: $ rpm -q rear - Is it the case that the package is not installed? - - - - Verify the noexec option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . noexec . . . +$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - Is it the case that the "/home" file system does not have the "noexec" option set? - - - - To check the group ownership of /var/log/messages, -run the command: -$ ls -lL /var/log/messages -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log/messages does not have a group owner of root? - - - - Inspect the file /etc/firewalld/firewalld.conf to determine -the default zone for the firewalld. It should be set to DefaultZone=drop: -$ sudo grep DefaultZone /etc/firewalld/firewalld.conf - Is it the case that the default zone is not set to DROP? - - - - Verify that only the "root" account has a UID "0" assignment with the -following command: -$ awk -F: '$3 == 0 {print $1}' /etc/passwd -root - Is it the case that any accounts other than "root" have a UID of "0"? +ocredit = + Is it the case that value of "ocredit" is a positive number or is commented out? - - Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: + + Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file +and is configured to prohibit password reuse for a minimum of +generations. -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; - Is it the case that any system commands are found to be group-writable or world-writable? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: +Verify the "/etc/pam.d/password-auth" file with the following command: -$ sudo auditctl -l | grep userhelper +$ grep pam_pwhistory.so /etc/pam.d/password-auth +password pam_pwhistory.so use_authtok remember= --a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: - -$ sudo auditctl -l | grep gpasswd - --a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -renameat system call, run the following command: -$ sudo grep "renameat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - To check the ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/user.cfg does not have an owner of root? - - - - Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: - -Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. - -The runtime status of the user.max_user_namespaces kernel parameter can be queried -by running the following command: -$ sysctl user.max_user_namespaces -0. - - Is it the case that the correct value is not returned? - - - - To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep apply_updates /etc/dnf/automatic.conf -The output should return the following: -apply_updates = yes - Is it the case that apply_updates is not set to yes? - - - - Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: - -$ sudo grep action_mail_acct /etc/audit/auditd.conf - -action_mail_acct = - Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the retuned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? - - - - To verify that McAfee Endpoint Security for Linux is -running, run the following command: -$ sudo ps -ef | grep -i mfetpd - Is it the case that virus scanning software is not running? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_PTYS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -rename system call, run the following command: -$ sudo grep "rename" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? - - - - To determine if the system is configured to audit calls to the -mount system call, run the following command: -$ sudo grep "mount" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.hourly does not have an owner of root? - - - - To check the permissions of /boot/grub2/user.cfg, -run the command: -$ ls -l /boot/grub2/user.cfg -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: - -$ sudo auditctl -l | grep passwd - --a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.shared_media -0. - - Is it the case that the correct value is not returned? - - - - Ensure that Oracle Linux 9 verifies correct operation of security functions. -Check if "SELinux" is active and in "" mode with the following command: +Verify the "/etc/security/pwhistory.conf" file using the following command: -$ sudo getenforce +$ grep remember /etc/security/pwhistory.conf +remember = - Is it the case that SELINUX is not set to enforcing? +The pam_pwhistory.so "remember" option must be configured only in one file. + Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in +/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set +with a value less than "<sub idref="var_password_pam_remember" />"? @@ -255627,699 +277705,37 @@ The pam_pwhistory.so "remember" option must be configured only in one file. with a value less than "<sub idref="var_password_pam_remember" />"? - - To verify that Linux Audit logging is enabled for the USBGuard daemon, -run the following command: -$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf -The output should be -AuditBackend=LinuxAudit - Is it the case that AuditBackend is not set to LinuxAudit? + + To check if pam_pwquality.so is enabled in password-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/password-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in password-auth? - - To check the permissions of /etc/cron.monthly, -run the command: -$ ls -l /etc/cron.monthly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.monthly does not have unix mode -rwx------? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_VDSO /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: + + Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . -Verify "firewalld" has "nftables" set as the default backend: - -$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf - -# FirewallBackend -FirewallBackend=nftables - Is it the case that the "nftables" is not set as the "firewallbackend"? +Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: +$ grep retry /etc/security/pwquality.conf + Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? - - To check the group ownership of /etc/issue.net, -run the command: -$ ls -lL /etc/issue.net -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/issue.net does not have a group owner of root? + + To check if pam_pwquality.so is enabled in system-auth, run the following command: +$ grep pam_pwquality /etc/pam.d/system-auth +The output should be similar to the following: +password requisite pam_pwquality.so + Is it the case that pam_pwquality.so is not enabled in system-auth? - - -Run the following command to determine the current status of the -tmp mount: -$ sudo systemctl is-active tmp.mount -If the mount unit is running, it should return the following: active - Is it the case that the tmp.mount unit is masked or disabled? - - - - Verify the nosuid option is configured for the /boot/efi mount point, - run the following command: - $ sudo mount | grep '\s/boot/efi\s' - . . . /boot/efi . . . nosuid . . . - - Is it the case that the "/boot/efi" file system does not have the "nosuid" option set? - - - - To determine if the system is configured to audit calls to the -setxattr system call, run the following command: -$ sudo grep "setxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the group ownership of /etc/selinux, -run the command: -$ ls -lL /etc/selinux -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/selinux does not have a group owner of root? - - - - Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: - -$ sestatus | grep policy - -Loaded policy name: - Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check that the nftables service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled nftables -Output should indicate the nftables service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled nftables disabled - -Run the following command to verify nftables is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active nftables - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the nftables is masked, run the following command: -$ sudo systemctl show nftables | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "nftables" is loaded and not masked? - - - - To check the ownership of /etc/passwd, -run the command: -$ ls -lL /etc/passwd -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd does not have an owner of root? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -$ sudo cat /etc/audit/rules.d/11-loginuid.rules -The output has to be exactly as follows: -## Make the loginuid immutable. This prevents tampering with the auid. ---loginuid-immutable - Is it the case that the file does not exist or the content differs? - - - - To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, -run the following command: -$ sudo pwck -qr -There should be no output. - Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? - - - - To determine the status and frequency of logrotate, run the following command: -$ sudo grep logrotate /var/log/cron* -If logrotate is configured properly, output should include references to -/etc/cron.daily. - Is it the case that logrotate is not configured to run daily? - - - - Run the following command to determine if the setroubleshoot-server package is installed: -$ rpm -q setroubleshoot-server - Is it the case that the package is installed? - - - - Verify the nodev option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nodev . . . - - Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? - - - - To verify the INACTIVE setting, run the following command: -$ grep "INACTIVE" /etc/default/useradd -The output should indicate the INACTIVE configuration option is set -to an appropriate integer as shown in the example below: -$ grep "INACTIVE" /etc/default/useradd -INACTIVE= - Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: - -$ sudo auditctl -l | grep ssh-keysign - --a always,exit -F path=/usr/libexec/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. - -Check the octal permission of each audit tool by running the following command: - -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - Is it the case that any of these files have more permissive permissions than 0755? - - - - To check the group ownership of /etc/ipsec.conf, -run the command: -$ ls -lL /etc/ipsec.conf -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.conf does not have a group owner of root? - - - - Verify the operating system audits activities performed during nonlocal -maintenance and diagnostic sessions. Run the following command: -$ sudo auditctl -l | grep sudo.log --w /var/log/sudo.log -p wa -k maintenance - - Is it the case that Audit rule is not present? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to check if the line is present: -grep pam_wheel /etc/pam.d/su -The output should contain the following line: -auth required pam_wheel.so use_uid - Is it the case that the line is not in the file or it is commented? - - - - To check that the kdump service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled kdump -Output should indicate the kdump service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled kdump disabled - -Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active kdump - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the kdump is masked, run the following command: -$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "kdump" is loaded and not masked? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling autorun-never -If properly configured, the output for autorun-nevershould be true. -To ensure that users cannot enable autorun in GNOME3, run the following: -$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* -If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never - Is it the case that GNOME autorun is not disabled? - - - - To ensure logs are sent to a remote host, examine the file -/etc/rsyslog.conf. -If using UDP, a line similar to the following should be present: - *.* @ -If using TCP, a line similar to the following should be present: - *.* @@ -If using RELP, a line similar to the following should be present: - *.* :omrelp: - Is it the case that no evidence that the audit logs are being off-loaded to another system or media? - - - - To find SUID files, run the following command: -$ sudo find / -xdev -type f -perm -4000 - Is it the case that only authorized files appear in the output of the find command? - - - - To check the ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following owner: -syslog - Is it the case that /var/log/syslog does not have an owner of syslog? - - - - To check the group ownership of /etc/gshadow, -run the command: -$ ls -lL /etc/gshadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/gshadow does not have a group owner of root? - - - - To verify that null passwords cannot be used, run the following command: - -$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth - -If this produces any output, it may be possible to log into accounts -with empty passwords. Remove any instances of the nullok option to -prevent logins with empty passwords. - Is it the case that NULL passwords can be used? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: - -$ sudo auditctl -l | grep reboot - --a always,exit -F path=/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /var/log/syslog, -run the command: -$ ls -lL /var/log/syslog -If properly configured, the output should indicate the following group-owner: -adm - Is it the case that /var/log/syslog does not have a group owner of adm? - - - - To verify that all user initialization files have a mode of 0740 or -less permissive, run the following command: -$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) -There should be no output. - Is it the case that they are not 0740 or more permissive? - - - - To determine if the system is configured to audit calls to the -clock_settime system call, run the following command: -$ sudo grep "clock_settime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slab_nomerge=yes, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' -The command should not return any output. - Is it the case that merging of slabs with similar size is enabled? - - - - To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: -$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config -and verify that the line matches: -Ciphers - Is it the case that Crypto Policy for OpenSSH client is not configured correctly? - - - - First, check whether the password is defined in either /boot/grub2/user.cfg or -/boot/grub2/grub.cfg. -Run the following commands: -$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg -$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg + + Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . -Second, check that a superuser is defined in /boot/grub2/grub.cfg. -$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg - Is it the case that it does not produce any output? - - - - To check the permissions of /var/log/syslog, -run the command: -$ ls -l /var/log/syslog -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /var/log/syslog does not have unix mode -rw-r-----? - - - - To check the group ownership of /etc/cron.allow, -run the command: -$ ls -lL /etc/cron.allow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.allow does not have a group owner of root? - - - - To verify that only security updates will be automatically installed by dnf-automatic, run the following command: -$ sudo grep upgrade_type /etc/dnf/automatic.conf -The output should return the following: -upgrade_type = security - Is it the case that the upgrade_type is not set to security? - - - - The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried -by running the following command: -$ sysctl net.core.bpf_jit_harden -2. - - Is it the case that the correct value is not returned? - - - - Run the following command to see what the timeout interval is: -$ sudo grep ClientAliveInterval /etc/ssh/sshd_config -If properly configured, the output should be: -ClientAliveInterval - Is it the case that it is commented out or not configured properly? - - - - To check the ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/passwd- does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -removexattr system call, run the following command: -$ sudo grep "removexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - The file permissions for all log files written by rsyslog should -be set to 640, or more restrictive. These log files are determined by the -second part of each Rule line in /etc/rsyslog.conf and typically -all appear in /var/log. To see the permissions of a given log -file, run the following command: -$ ls -l LOGFILE -The permissions should be 640, or more restrictive. - Is it the case that the permissions are not correct? - - - - Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: - -$ grep umask /etc/csh.cshrc - -umask 077 -umask 077 - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BINFMT_MISC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to ensure that /tmp is configured as a -polyinstantiated directory: -$ sudo grep /tmp /etc/security/namespace.conf -The output should return the following: -/tmp /tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - To check the group ownership of /etc/ipsec.secrets, -run the command: -$ ls -lL /etc/ipsec.secrets -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.secrets does not have a group owner of root? - - - - To verify that the system will shutdown when auditd fails, -run the following command: -$ sudo grep "\-f " /etc/audit/audit.rules -The output should contain: --f - Is it the case that the system is not configured to shutdown on auditd failures? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STRICT_KERNEL_WRX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_RETPOLINE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect the password section of /etc/pam.d/password-auth -and ensure that the pam_unix.so module is configured to use the argument -: - -$ grep /etc/pam.d/password-auth - Is it the case that it does not? - - - - Verify the system-wide shared library files are owned by "root" with the following command: - -$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; - Is it the case that any system wide shared library file is not owned by root? - - - - To verify that smart cards are enabled in SSSD, run the following command: -$ sudo grep pam_cert_auth /etc/sssd/sssd.conf -If configured properly, output should be -pam_cert_auth = True - - -To verify that smart cards are enabled in PAM files, run the following command: -$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth -If configured properly, output should be - -/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name -/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth - - Is it the case that smart cards are not enabled in SSSD? - - - - - -Run the following command to determine the current status of the -ufw service: -$ sudo systemctl is-active ufw -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - Run the following command to check the mode of the system audit logs: -$ sudo grep -iw log_file /etc/audit/auditd.conf -log_file=/var/log/audit/audit.log -$ sudo stat -c "%n %a" /var/log/audit/* -$ sudo ls -l /var/log/audit -Audit logs must be mode 0640 or less permissive. - Is it the case that any permissions are more permissive? - - - - Verify that a separate file system/partition has been created for /var/tmp with the following command: - -$ mountpoint /var/tmp - - Is it the case that "/var/tmp is not a mountpoint" is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: - -$ sudo auditctl -l | grep pam_timestamp_check - --a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -unlinkat system call, run the following command: -$ sudo grep "unlinkat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - - - -To determine if firewalld is configured to allow access - -on port 22/tcp, run the following command(s): - firewall-cmd --list-ports - - -to ssh - firewall-cmd --list-services - -If firewalld is configured to allow access through the firewall, something similar to the following will be output: - -If it is a service: -ssh - - -If it is a port: -22/tcp - - Is it the case that sshd service is not enabled in the proper firewalld zone? - - - - To find world-writable files, run the following command: -$ sudo find / -xdev -type f -perm -002 - Is it the case that there is output? - - - - The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_ignore -. - - Is it the case that the correct value is not returned? - - - - To verify that Audit Daemon is configured to resolve all uid, gid, syscall, -architecture, and socket address information before writing the event to disk, -run the following command: -$ sudo grep log_format /etc/audit/auditd.conf -The output should return the following: -log_format = ENRICHED - Is it the case that log_format isn't set to ENRICHED? - - - - To check that the screen locks immediately when activated, run the following command: -$ gsettings get org.gnome.desktop.screensaver lock-delay -If properly configured, the output should be 'uint32 '. - Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? - - - - The runtime status of the kernel.dmesg_restrict kernel parameter can be queried -by running the following command: -$ sysctl kernel.dmesg_restrict -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra -0. - - Is it the case that the correct value is not returned? +Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: +$ grep retry /etc/security/pwquality.conf + Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? @@ -256333,68 +277749,29 @@ ucredit = -1 Is it the case that the value of "ucredit" is a positive number or is commented out? - - Verify that a separate file system/partition has been created for /var/log/audit with the following command: + + To verify the password reuse setting is compliant, run the following command: +$ grep remember /etc/pam.d/system-auth +The output should show the following at the end of the line: +remember= -$ mountpoint /var/log/audit - Is it the case that "/var/log/audit is not a mountpoint" is returned? +In newer systems, the pam_pwhistory PAM module options can also be set in +"/etc/security/pwhistory.conf" file. Use the following command to verify: +$ grep remember /etc/security/pwhistory.conf +remember = + +The pam_pwhistory remember option must be configured only in one file. + Is it the case that the value of remember is not equal to or greater than the expected value? - - The runtime status of the fs.protected_hardlinks kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_hardlinks -1. + + To verify the number of rounds for the password hashing algorithm is configured, run the following command: +$ sudo grep rounds /etc/pam.d/password-auth +The output should show the following match: - Is it the case that the correct value is not returned? - - - - Verify that yum verifies the signature of local packages prior to install with the following command: - -$ grep localpkg_gpgcheck /etc/yum.conf - -localpkg_gpgcheck=1 - -If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. - Is it the case that there is no process to validate certificates for local packages that is approved by the organization? - - - - - -Run the following command to determine the current status of the -usbguard service: -$ sudo systemctl is-active usbguard -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/usr/share/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - -Check if SSSD allows cached authentications with the following command: - -$ sudo grep cache_credentials /etc/sssd/sssd.conf -cache_credentials = true - -If "cache_credentials" is set to "false" or is missing no further checks are required. - -To verify that SSSD expires offline credentials, run the following command: -$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf -If configured properly, output should be -offline_credentials_expiration = 1 - Is it the case that it does not exist or is not configured properly? +password sufficient pam_unix.so sha512 rounds= + Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? @@ -256405,392 +277782,364 @@ password sufficient pam_unix.so sha512 rounds= Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The following command will list which files on the system have ownership different from what -is expected by the RPM database: -$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' - Is it the case that there is output? - - - - To check that the snmpd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled snmpd -Output should indicate the snmpd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled snmpd disabled + + Check whether the maximum time period for existing passwords is restricted to days with the following commands: -Run the following command to verify snmpd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active snmpd +$ sudo awk -F: '$5 > 60 {print $1 " " $5}' /etc/shadow -If the service is not running the command will return the following output: -inactive +$ sudo awk -F: '$5 <= 0 {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Check whether the maximum time period for root account password is restricted to days with the following commands: -The service will also be masked, to check that the snmpd is masked, run the following command: -$ sudo systemctl show snmpd | grep "LoadState\|UnitFileState" +$ sudo awk -F: '$1 == "root" {print $1 " " $5}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: -If the service is masked the command will return the following outputs: +$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + Verify that Oracle Linux 9 set the days of warning before a password expires to + or more for users with a +password: -LoadState=masked +$ sudo awk -F: '$6 || $6 == "" {print $1}' /etc/shadow + Is it the case that any results are returned that are not associated with a system account? + + + + To check the password warning age, run the command: +$ grep PASS_WARN_AGE /etc/login.defs +The profile requirement is . + Is it the case that it is not set to the required value? + + + + Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: -UnitFileState=masked - Is it the case that the "snmpd" is loaded and not masked? - - - - The following command will list which files on the system have file hashes different from what -is expected by the RPM database. -$ rpm -Va --noconfig | awk '$1 ~ /..5/' - Is it the case that there is output? - - - - To check the group ownership of /etc/ssh/sshd_config, -run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/sshd_config does not have a group owner of root? - - - - Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies - Is it the case that the package is not installed? - - - - Make sure that the kernel is not disabling SMEP with the following -commands. -grep -q nosmep /boot/config-`uname -r` -If the command returns a line, it means that SMEP is being disabled. - Is it the case that the kernel is configured to disable SMEP? - - - - Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins - Is it the case that the package is not installed? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes slub_debug=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' -The command should not return any output. - Is it the case that SLUB/SLAB poisoning is not enabled? - - - - To check the group ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow- does not have a group owner of root? - - - - Verify the operating system encrypts audit records off-loaded onto a different system -or media from the system being audited with the following commands: +$ sudo grep audit /etc/security/faillock.conf -$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf +audit + Is it the case that the "audit" option is not set, is missing or commented out? + + + + Verify Oracle Linux 9 is configured to lock an account after +unsuccessful logon attempts with the command: -The output should be: +$ grep 'deny =' /etc/security/faillock.conf +deny = . + Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" +or less (but not "0"), is missing or commented out? + + + + Verify Oracle Linux 9 is configured to lock the root account after +unsuccessful logon attempts with the command: -/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 - Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? +$ grep even_deny_root /etc/security/faillock.conf +even_deny_root + Is it the case that the "even_deny_root" option is not set, is missing or commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_VMAP_STACK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? + + To ensure the tally directory is configured correctly, run the following command: +$ sudo grep 'dir =' /etc/security/faillock.conf +The output should show that dir is set to something other than "/var/run/faillock" + Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - To check the group ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /var/log does not have a group owner of root? - - - - To verify if the OpenSSH Client uses defined Crypto Policy, run: -$ cat /etc/ssh/ssh_config.d/02-ospp.conf -and verify that the line matches -Match final all -RekeyLimit 512M 1h -GSSAPIAuthentication no -Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc -PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 -MACs hmac-sha2-512,hmac-sha2-256 -KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 - Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? - - - - To check the permissions of /etc/gshadow-, -run the command: -$ ls -l /etc/gshadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow- does not have unix mode ----------? - - - - To verify all squashing has been disabled, run the following command: -$ grep all_squash /etc/exports - Is it the case that there is output? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/system-auth" file: + + To ensure the failed password attempt policy is configured correctly, run the following command: -$ sudo grep pam_faillock.so /etc/pam.d/system-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/system-auth" file with the "preauth" line listed before pam_unix.so? +$ grep fail_interval /etc/security/faillock.conf +The output should show fail_interval = <interval-in-seconds> where interval-in-seconds is or greater. + Is it the case that the "fail_interval" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_fail_interval" />" +or less (but not "0"), the line is commented out, or the line is missing? - - To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + + Verify Oracle Linux 9 is configured to lock an account until released by an administrator +after unsuccessful logon +attempts with the command: -$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? +$ grep 'unlock_time =' /etc/security/faillock.conf +unlock_time = + Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", +the line is missing, or commented out? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SYN_COOKIES /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/group- does not have an owner of root? - - - - To verify that Audit Daemon is configured to record the computer node -name in the audit events, run the following command: -$ sudo grep name_format /etc/audit/auditd.conf + + Run the following command to ensure that /tmp is configured as a +polyinstantiated directory: +$ sudo grep /tmp /etc/security/namespace.conf The output should return the following: -name_format = - Is it the case that name_format isn't set to <sub idref="var_auditd_name_format" />? +/tmp /tmp/tmp-inst/ level root,adm + Is it the case that is not configured? - - -To check that the telnet service is disabled in system boot configuration with xinetd, run the following command: -$ chkconfig telnet --list -Output should indicate the telnet service has either not been installed, or has been disabled, as shown in the example below: -$ chkconfig telnet --list - -Note: This output shows SysV services only and does not include native -systemd services. SysV configuration data might be overridden by native -systemd configuration. - -If you want to list systemd services use 'systemctl list-unit-files'. -To see services enabled on particular target use -'systemctl list-dependencies [target]'. - -telnet off - -To check that the telnet socket is disabled in system boot configuration with systemd, run the following command: -$ systemctl is-enabled telnet -Output should indicate the telnet socket has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled telnetdisabled - -Run the following command to verify telnet is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active telnet - -If the socket is not running the command will return the following output: -inactive - -The socket will also be masked, to check that the telnet is masked, run the following command: -$ sudo systemctl show telnet | grep "LoadState\|UnitFileState" - -If the socket is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that service and/or socket are running? + + Run the following command to ensure that /var/tmp is configured as a +polyinstantiated directory: +$ sudo grep /var/tmp /etc/security/namespace.conf +The output should return the following: +/var/tmp /var/tmp/tmp-inst/ level root,adm + Is it the case that is not configured? - - To check the permissions of /etc/selinux, -run the command: -$ ls -l /etc/selinux -If properly configured, the output should indicate the following permissions: -0755 - Is it the case that /etc/selinux does not have unix mode 0755? + + To verify that root's primary group is zero run the following command: + + grep '^root:' /etc/passwd | cut -d : -f 4 + +The command should return: + +0 + + Is it the case that root has a primary gid not equal to zero? - - The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_event_paranoid -2. - - Is it the case that the correct value is not returned? + + To ensure write permissions are disabled for group and other + for each element in root's path, run the following command: +# ls -ld DIR + Is it the case that group or other write permissions exist? - - To determine if the system is configured to audit calls to the -lremovexattr system call, run the following command: -$ sudo grep "lremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. + + Verify that Oracle Linux 9 's INACTIVE conforms to site policy (no more than 30 days) with the following command: - Is it the case that no line is returned? +$ sudo awk -F: '$7 > 30 {print $1 " " $7}' /etc/shadow + Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - To determine how the SSH daemon's Banner option is set, run the following command: + + Run the following command to ensure the TMOUT value is configured for all users +on the system: -$ sudo grep -i Banner /etc/ssh/sshd_config +$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh -If a line indicating /etc/issue is returned, then the required value is set. - - Is it the case that the required value is not set? +The output should return the following: +TMOUT= + Is it the case that the TMOUT value is not configured, is set to 0, or is not less than or equal to the expected setting? - - Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. + + Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: -Check the owner of each audit tool by running the following command: +$ sudo grep "umask" /etc/bashrc -$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not owned by root? +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - To determine if the system is configured to audit calls to the -unlink system call, run the following command: -$ sudo grep "unlink" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. + + Verify the "umask" setting is configured correctly in the "/etc/csh.cshrc" file with the following command: - Is it the case that no line is returned? +$ grep umask /etc/csh.cshrc + +umask 077 +umask 077 + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - Display the contents of the file /etc/systemd/logind.conf: -cat /etc/systemd/logind.conf -Ensure that there is a section [login] which contains the -configuration StopIdleSessionSec=. - Is it the case that the option is not configured? + + Verify Oracle Linux 9 defines default permissions for all authenticated users in such a way that the user can only read and modify their own files with the following command: + +# grep -i umask /etc/login.defs + +UMASK + Is it the case that the value for the "UMASK" parameter is not "<sub idref="var_accounts_user_umask" />", or the "UMASK" parameter is missing or is commented out? - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. - -Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: - -$ sudo grep disk_error_action /etc/audit/auditd.conf - -disk_error_action = - -If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. - Is it the case that there is no evidence of appropriate action? + + Verify the umask setting is configured correctly in the /etc/profile file +or scripts within /etc/profile.d directory with the following command: +$ grep "umask" /etc/profile* +umask + Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", +or the "umask" parameter is missing or is commented out? - - To ensure screen locking on smartcard removal is enabled, run the following command: -$ grep removal-action /etc/dconf/db/local.d/* -The output should be 'lock-screen'. -To ensure that users cannot disable screen locking on smartcard removal, run the following: -$ grep removal-action /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action - Is it the case that removal-action has not been configured? - - - - To determine if the system is configured to audit changes to its SELinux -configuration files, run the following command: -$ sudo auditctl -l | grep "dir=/etc/selinux" -If the system is configured to watch for changes to its SELinux -configuration, a line should be returned (including -perm=wa indicating permissions that are watched). - Is it the case that the system is not configured to audit attempts to change the MAC policy? - - - - To check the permissions of /etc/ipsec.secrets, -run the command: -$ ls -l /etc/ipsec.secrets -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/ipsec.secrets does not have unix mode 0644? - - - - The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_redirects -0. + + Verify that the default umask for all local interactive users is "077". - Is it the case that the correct value is not returned? +Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. + +Check all local interactive user initialization files for interactive users with the following command: + +Note: The example is for a system that is configured to create users home directories in the "/home" directory. + +$ sudo find /home -maxdepth 2 -type f -name ".[^.]*" -exec grep -iH -d skip --exclude=.bash_history umask {} \; + +/home/wadea/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile +/home/wadea/.bash_history:grep -i umask /etc/login.defs + Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? + + To verify the local initialization files of all local interactive users are group- +owned by the appropriate user, inspect the primary group of the respective +users in /etc/passwd and verify all initialization files under the +respective users home directory. Check the group owner of all local interactive users +initialization files. + Is it the case that they are not? - - To check the group ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*.pub does not have a group owner of root? + + Verify that local initialization files do not execute world-writable programs with the following command: + +Note: The example will be for a system that is configured to create user home directories in the "/home" directory. + +$ sudo find /home -perm -002 -type f -name ".[^.]*" -exec ls -ld {} \; + Is it the case that any local initialization files are found to reference world-writable files? + + + + To verify all local initialization files for interactive users are owned by the +primary user, run the following command: +$ sudo ls -al /home/USER/.* +The user initialization files should be owned by USER. + Is it the case that they are not? + + + + Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: + +$ sudo grep -i path= /home/*/.* + +/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin + Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? + + + + Verify that interactive users on the system have a home directory assigned with the following command: + +$ sudo awk -F: '($3>=1000)&&($7 !~ /nologin/){print $1, $3, $6}' /etc/passwd + +Inspect the output and verify that all interactive users (normally users with a UID greater than 1000) have a home directory defined. + Is it the case that users home directory is not defined? + + + + Verify the assigned home directories of all interactive users on the system exist with the following command: + +$ sudo pwck -r + +user 'mailnull': directory 'var/spool/mqueue' does not exist + +The output should not return any interactive users. + Is it the case that users home directory does not exist? + + + + To verify all files and directories in interactive user home directory are +group-owned by a group the user is a member of, run the +following command: +$ sudo ls -lLR /home/USER + Is it the case that the group ownership is incorrect? + + + + To verify all files and directories in a local interactive user's +home directory have a valid owner, run the following command: +$ sudo ls -lLR /home/USER + Is it the case that the user ownership is incorrect? + + + + To verify all files and directories contained in interactive user home +directory, excluding local initialization files, have a mode of 0750, +run the following command: +$ sudo ls -lLR /home/USER + Is it the case that home directory files or folders have incorrect permissions? + + + + To verify that McAfee Endpoint Security for Linux is +running, run the following command: +$ sudo ps -ef | grep -i mfetpd + Is it the case that virus scanning software is not running? + + + + To find the location of the AIDE database file, run the following command: +$ sudo ls -l DBDIR/database_file_name + Is it the case that there is no database file? + + + + Check that AIDE is properly configured to protect the integrity of the +audit tools by running the following command: + +# sudo cat /etc/aide.conf | grep /usr/sbin/au + +/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 + +/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 +/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 + + +If AIDE is configured properly to protect the integrity of the audit tools, +all lines listed above will be returned from the command. + +If one or more lines are missing, this is a finding. + Is it the case that integrity checks of the audit tools are missing or incomplete? + + + + Verify the operating system routinely checks the baseline configuration for unauthorized changes. + +To determine that periodic AIDE execution has been scheduled, run the following command: +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check + +NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. + Is it the case that AIDE is not configured to scan periodically? + + + + To determine that periodic AIDE execution has been scheduled, run the following command: + +$ grep aide /etc/crontab +The output should return something similar to the following: +05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost +The email address that the notifications are sent to can be changed by overriding +. + Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? + + + + To determine that AIDE is configured for FIPS 140-2 file hashing, run the following command: +$ grep sha512 /etc/aide.conf +Verify that the sha512 option is added to the correct ruleset. + Is it the case that the sha512 option is missing or not added to the correct ruleset? + + + + To determine that AIDE is verifying ACLs, run the following command: +$ grep acl /etc/aide.conf +Verify that the acl option is added to the correct ruleset. + Is it the case that the acl option is missing or not added to the correct ruleset? + + + + To determine that AIDE is verifying extended file attributes, run the following command: +$ grep xattrs /etc/aide.conf +Verify that the xattrs option is added to the correct ruleset. + Is it the case that the xattrs option is missing or not added to the correct ruleset? @@ -256805,384 +278154,68 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - Verify the noexec option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . noexec . . . - - Is it the case that the "/var" file system does not have the "noexec" option set? - - - - The telnet package can be removed with the following command: $ sudo yum erase telnet - Is it the case that ? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating VERBOSE is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.router_solicitations -0. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STRICT_MODULE_RWX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Check whether the maximum time period for root account password is restricted to days with the following commands: - -$ sudo awk -F: '$1 == "root" {print $1 " " $5}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_defrtr -0. - - Is it the case that the correct value is not returned? - - - - To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: - -$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - Is it the case that The AllowTcpForwarding option exists and is disabled? - - - - To check the ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*_key does not have an owner of root? - - - - Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a -certification path (which includes status information) to an accepted trust anchor. - -Check that the system has a valid DoD root CA installed with the following command: - -$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem - -Certificate: -Data: -Version: 3 (0x2) -Serial Number: 1 (0x1) -Signature Algorithm: sha256WithRSAEncryption -Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Validity -Not Before: Mar 20 18:46:41 2012 GMT -Not After : Dec 30 18:46:41 2029 GMT -Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 -Subject Public Key Info: -Public Key Algorithm: rsaEncryption - Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? - - - - Verify the value of the "maxrepeat" option in "/etc/security/pwquality.conf" with the following command: - -$ grep maxrepeat /etc/security/pwquality.conf - -maxrepeat = - Is it the case that the value of "maxrepeat" is set to more than "<sub idref="var_password_pam_maxrepeat" />" or is commented out? - - - - To determine if use_pty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that use_pty is not enabled in sudo? - - - - -Run the following command to get the current configured value for secure_mode_insmod -SELinux boolean: -$ getsebool secure_mode_insmod -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that secure_mode_insmod is not set as expected? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/43-module-load.rules +cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules The output has to be exactly as follows: -## These rules watch for kernel module insertion. By monitoring -## the syscall, we do not need any watches on programs. --a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load --a always,exit -F arch=b32 -S delete_module -F key=module-unload --a always,exit -F arch=b64 -S delete_module -F key=module-unload +## Successful file access (any other opens) This has to go last. +## These next two are likely to result in a whole lot of events +-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access +-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access Is it the case that the file does not exist or the content differs? - - To check the permissions of /etc/ssh/*_key, -run the command: -$ ls -l /etc/ssh/*_key -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/ssh/*_key does not have unix mode -rw-------? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the root user: -$ sudo postmap -q root hash:/etc/aliases -The output should return an alias. - Is it the case that the alias is not set? - - - - To check the group ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.d does not have a group owner of root? - - - - Verify that the system is integrated with a centralized authentication mechanism -such as as Active Directory, Kerberos, Directory Server, etc. that has -automated account mechanisms in place. - Is it the case that the system is not using a centralized authentication mechanism, or it is not automated? - - - - To check the permissions of /etc/cron.allow, -run the command: -$ ls -l /etc/cron.allow -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? - - - - To determine if the users are allowed to run commands as root, run the following commands: -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ -and -$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ -Both commands should return no output. - Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/10-base-config.rules +The output has to be exactly as follows: +## First rule - delete all +-D -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: +## Increase the buffers to survive stress events. +## Make this bigger for busy systems +-b 8192 -$ sudo grep disk_full_action /etc/audit/auditd.conf +## This determine how long to wait in burst of events +--backlog_wait_time 60000 -disk_full_action = - -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? +## Set failure mode to syslog +-f 1 + Is it the case that the file does not exist or the content differs? - - The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_source_route -0. - - Is it the case that the correct value is not returned? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules +The output has to be exactly as follows: +## Unsuccessful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create + Is it the case that the file does not exist or the content differs? - - Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: - -$ sudo auditctl -l | grep mount - --a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils - Is it the case that the policycoreutils package is not installed? - - - - To check if the installed Operating System is 64-bit, run the following command: -$ uname -m -The output should be one of the following: x86_64, aarch64, ppc64le or s390x. -If the output is i686 or i386 the operating system is 32-bit. -Check if the installed CPU supports 64-bit operating systems by running the following command: -$ lscpu | grep "CPU op-mode" -If the output contains 64bit, the CPU supports 64-bit operating systems. - Is it the case that the installed operating sytem is 32-bit but the CPU supports operation in 64-bit? - - - - To determine that periodic AIDE execution has been scheduled, run the following command: - -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost -The email address that the notifications are sent to can be changed by overriding -. - Is it the case that AIDE has not been configured or has not been configured to notify personnel of scan details? - - - - To check if the system login banner is compliant, run the following command: -$ cat /etc/issue.net - Is it the case that it does not display the required banner? - - - - Find the list of alias maps used by the Postfix mail server: -$ sudo postconf alias_maps -Query the Postfix alias maps for an alias for the postmaster user: -$ sudo postmap -q postmaster hash:/etc/aliases -The output should return root. - Is it the case that the alias is not set or is not root? - - - - Run the following command to determine if the chrony package is installed: $ rpm -q chrony - Is it the case that the package is not installed? - - - - The runtime status of the kernel.pid_max kernel parameter can be queried -by running the following command: -$ sysctl kernel.pid_max -65536. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /var/log, -run the command: -$ ls -l /var/log -If properly configured, the output should indicate the following permissions: -drwxr-xr-x - Is it the case that /var/log does not have unix mode drwxr-xr-x? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that FIPS mode is enabled properly, run the following command: -cat /proc/sys/crypto/fips_enabled -The output be must: -1 - Is it the case that FIPS mode is not enabled? - - - - To verify that null passwords cannot be used, run the following command: -$ sudo awk -F: '!$2 {print $1}' /etc/shadow -If this produces any output, it may be possible to log into accounts -with empty passwords. - Is it the case that Blank or NULL passwords can be used? - - - - The following command will locate the mount points related to local devices: -$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) - -The following command will show files which do not belong to a valid user: -$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null - -Replace MOUNTPOINT by the mount points listed by the fist command. - -No files without a valid user should be located. - Is it the case that files exist that are not owned by a valid user? - - - - Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard - Is it the case that the package is not installed? - - - - To determine if NOEXEC has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that noexec is not enabled in sudo? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: - -$ sudo auditctl -l | grep postqueue - --a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide - Is it the case that the package is not installed? - - - - The runtime status of the kernel.core_pattern kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_pattern | cat -A -kernel.core_pattern = $ - - Is it the case that the returned line does not have an empty string? - - - - The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried -by running the following command: -$ sysctl kernel.perf_cpu_time_max_percent -1. - - Is it the case that the correct value is not returned? - - - - To verify the boot loader superuser account has been set, run the following -command: -sudo grep -A1 "superusers" /boot/grub2/grub.cfg -The output should show the following: -set superusers="superusers-account" -export superusers -where superusers-account is the actual account name different from common names like root, -admin, or administrator and different from any other existing user name. - Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-1-create-success.rules +The output has to be exactly as follows: +## Successful file creation (open with O_CREAT) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create +-a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create + Is it the case that the file does not exist or the content differs? @@ -257197,652 +278230,23 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - To check if pam_pwquality.so is enabled in password-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/password-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in password-auth? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules +The output has to be exactly as follows: +## Successful file delete +-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete +-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete + Is it the case that the file does not exist or the content differs? - - To determine if arguments that commands can be executed with are restricted, run the following command: -$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? - - - - To check that the avahi-daemon service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled avahi-daemon -Output should indicate the avahi-daemon service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled avahi-daemon disabled - -Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active avahi-daemon - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the avahi-daemon is masked, run the following command: -$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "avahi-daemon" is loaded and not masked? - - - - Run the following command to check if the group exists: -grep /etc/group -The output should contain the following line: -:x: - Is it the case that group exists and has no user members? - - - - The runtime status of the kernel.core_pattern kernel parameter can be queried -by running the following command: -$ sysctl kernel.core_pattern -|/bin/false. - - Is it the case that the returned line does not have a value of "|/bin/false", or a line is not -returned and the need for core dumps is not documented with the Information -System Security Officer (ISSO) as an operational requirement? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/gshadow" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/gshadow)' - --w /etc/gshadow -p wa -k identity - -If the command does not return a line, or the line is commented out, this is a finding. - Is it the case that the system is not configured to audit account changes? - - - - To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: - -$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - Is it the case that the display proxy is listening on wildcard address? - - - - Verify the noexec option is configured for the /dev/shm mount point, - run the following command: - $ sudo mount | grep '\s/dev/shm\s' - . . . /dev/shm . . . noexec . . . - - Is it the case that the "/dev/shm" file system does not have the "noexec" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PANIC_TIMEOUT /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.max_addresses -1. - - Is it the case that the correct value is not returned? - - - - To check the ownership of /etc/chrony.keys, -run the command: -$ ls -lL /etc/chrony.keys -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/chrony.keys does not have an owner of root? - - - - To determine if the system is configured to audit calls to the -fremovexattr system call, run the following command: -$ sudo grep "fremovexattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/group" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/group)' - --w /etc/group -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv4.ip_forward kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.ip_forward -0. -The ability to forward packets is only appropriate for routers. - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -pcscd service: -$ sudo systemctl is-active pcscd -If the service is running, it should return the following: active - Is it the case that the pcscd service is not enabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the permissions of /etc/passwd, -run the command: -$ ls -l /etc/passwd -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/passwd does not have unix mode -rw-r--r--? - - - - Inspect the password section of /etc/pam.d/system-auth -and ensure that the pam_unix.so module is configured to use the argument -: - -$ sudo grep "^password.*pam_unix\.so.*" /etc/pam.d/system-auth - -password sufficient pam_unix.so - Is it the case that "<sub idref="var_password_hashing_algorithm_pam" />" is missing, or is commented out? - - - - Verify that the system backups user data. - Is it the case that it is not? - - - - To determine if NOPASSWD has been configured for the vdsm user for sudo, -run the following command: -$ sudo grep -ri nopasswd /etc/sudoers.d/ -The command should return output only for the vdsm user. - Is it the case that nopasswd is set for any users beyond vdsm? - - - - Run the following command to determine if the rsyslog-gnutls package is installed: -$ rpm -q rsyslog-gnutls - Is it the case that the package is installed? - - - - To verify the audispd's syslog plugin is active, run the following command: -$ sudo grep active /etc/audit/plugins.d/syslog.conf -If the plugin is active, the output will show yes. - Is it the case that it is not activated? - - - - To check the permissions of /etc/group-, -run the command: -$ ls -l /etc/group- -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group- does not have unix mode -rw-r--r--? - - - - To check the ownership of /boot/System.map*, -run the command: -$ ls -lL /boot/System.map* -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/System.map* does not have an owner of root? - - - - Verify the noexec option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . noexec . . . - - Is it the case that the "/var/tmp" file system does not have the "noexec" option set? - - - - To check that the squid service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled squid -Output should indicate the squid service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled squid disabled - -Run the following command to verify squid is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active squid - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the squid is masked, run the following command: -$ sudo systemctl show squid | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "squid" is loaded and not masked? - - - - To check the permissions of /etc/crontab, -run the command: -$ ls -l /etc/crontab -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /etc/crontab does not have unix mode -rw-------? - - - - To determine if !authenticate has not been configured for sudo, run the following command: -$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that !authenticate is specified in the sudo config files? - - - - Check group owners of the system audit logs. - -First, determine where the audit log file is located. - -$ sudo grep -iw ^log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log - -The log_file option specifies the audit log file path. -If the log_file option isn't defined, check all files within /var/log/audit directory. - - -Then, determine the audit log group by running the following command: -$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf - - -Then, check that the audit log file is owned by the correct group. -Run the following command to display the owner of the audit log file: - -$ sudo stat -c "%n %G" log_file - - -The audit log file must be owned by the log_group or by root if the log_group is not specified. - Is it the case that audit log files are owned by incorrect group? - - - - Determine if "sudoers" file restricts sudo access run the following commands: -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* -$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* - Is it the case that either of the commands returned a line? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: - -$ sudo auditctl -l | grep init - --a always,exit -F path=/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/group-, -run the command: -$ ls -lL /etc/group- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/group- does not have a group owner of root? - - - - To verify that BIND uses the system crypto policy, check out that the BIND config file -/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; -directive: -$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf -Verify that the directive is at the bottom of the options section of the config file. - Is it the case that BIND is installed and the BIND config file doesn't contain the -<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? - - - - The runtime status of the kernel.unprivileged_bpf_disabled -kernel parameter can be queried by running the following command: -$ sysctl kernel.unprivileged_bpf_disabled -The output of the command should indicate either: -kernel.unprivileged_bpf_disabled = 1 -or: -kernel.unprivileged_bpf_disabled = 2 -The output of the command should not indicate: -kernel.unprivileged_bpf_disabled = 0 - -The preferable way how to assure the runtime compliance is to have -correct persistent configuration, and rebooting the system. - -The persistent kernel parameter configuration is performed by specifying the appropriate -assignment in any file located in the /etc/sysctl.d directory. -Verify that there is not any existing incorrect configuration by executing the following command: -$ grep -r '^\s*\s*=' /etc/sysctl.conf /etc/sysctl.d -The command should not find any assignments other than: -kernel.unprivileged_bpf_disabled = 1 -or: -kernel.unprivileged_bpf_disabled = 2 - -Duplicate assignments are not allowed. Empty output is allowed, because the system default is 2. - Is it the case that the kernel.unprivileged_bpf_disabled is not set to 1 or 2 or is configured to be 0? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: - -$ sudo auditctl -l | grep newgrp - --a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the fs.protected_regular kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_regular -2. - - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -auditd service: -$ sudo systemctl is-active auditd -If the service is running, it should return the following: active - Is it the case that the auditd service is not running? - - - - To check that the rsyncd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled rsyncd -Output should indicate the rsyncd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled rsyncd disabled - -Run the following command to verify rsyncd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active rsyncd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the rsyncd is masked, run the following command: -$ sudo systemctl show rsyncd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "rsyncd" is loaded and not masked? - - - - To check the ownership of /etc/ipsec.d, -run the command: -$ ls -lL /etc/ipsec.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.d does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_KEXEC /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine if the system is configured to audit calls to the -rmdir system call, run the following command: -$ sudo grep "rmdir" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -adjtimex system call, run the following command: -$ sudo grep "adjtimex" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: - -$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the ownership of /var/log, -run the command: -$ ls -lL /var/log -If properly configured, the output should indicate the following owner: -root - Is it the case that /var/log does not have an owner of root? - - - - # grep "^OPTIONS.*-u" /etc/sysconfig/chronyd | grep -v -e '-u\s*chrony\b' -returns no output - Is it the case that chronyd is not running under chrony user account? - - - - To determine how the SSH daemon's UsePAM option is set, run the following command: - -$ sudo grep -i UsePAM /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Run the following command to ensure postfix accepts mail messages from only the local system: -$ grep inet_interfaces /etc/postfix/main.cf -If properly configured, the output should show only . - Is it the case that it does not? - - - - To check the ownership of /etc/sestatus.conf, -run the command: -$ ls -lL /etc/sestatus.conf -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sestatus.conf does not have an owner of root? - - - - Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. - -Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: - -$ sudo grep disk_error_action /etc/audit/auditd.conf - -disk_error_action = HALT - -If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. - Is it the case that there is no evidence of appropriate action? - - - - Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: -$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf /etc/chrony.d/ -server [ntp.server.name] iburst maxpoll . - Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? - - - - Verify the noexec option is configured for the /tmp mount point, - run the following command: - $ sudo mount | grep '\s/tmp\s' - . . . /tmp . . . noexec . . . - - Is it the case that the "/tmp" file system does not have the "noexec" option set? - - - - -Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: -$ getsebool ssh_sysadm_login -If properly configured, the output should show the following: -ssh_sysadm_login --> off - Is it the case that ssh_sysadm_login is not disabled? - - - - To verify that auditing of privileged command use is configured, run the following command -to search privileged commands in relevant partitions and check if they are covered by auditd -rules: - -FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) -PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') -for PARTITION in $PARTITIONS; do - for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do - grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && - printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" - done -done - -The output should not contain any WARNING. - Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? - - - - To check the group ownership of /boot/System.map*, -run the command: -$ ls -lL /boot/System.map* -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/System.map* does not have a group owner of root? - - - - To verify the noexec option is configured for all NFS mounts, run the following command: -$ mount | grep nfs -All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is -not implemented. - Is it the case that the setting does not show? - - - - To check if MaxStartups is configured, run the following command: -$ sudo grep -r ^[\s]*MaxStartups /etc/ssh/sshd_config* -If configured, this command should output the configuration. - Is it the case that maxstartups is not configured? - - - - Run the following command and verify remote servers are configured properly: -# grep -E "^(server|pool)" /etc/chrony.conf - Is it the case that a remote time server is not configured? - - - - To check the group ownership of /etc/nftables, -run the command: -$ ls -lL /etc/nftables -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/nftables does not have a group owner of root? - - - - To check the group ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.daily does not have a group owner of root? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: - -$ sudo auditctl -l | grep unix_update - --a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w space_left /etc/audit/auditd.conf - -space_left = % - Is it the case that the value of the "space_left" keyword is not set to <sub idref="var_auditd_space_left_percentage" />% of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. If the "space_left" value is not configured to the correct value? - - - - -If the system is configured to prevent the loading of the usb-storage kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify the number of rounds for the password hashing algorithm is configured, run the following command: -$ sudo grep rounds /etc/pam.d/password-auth -The output should show the following match: - -password sufficient pam_unix.so sha512 rounds= - Is it the case that rounds is not set to <sub idref="var_password_pam_unix_rounds" /> or is commented out? + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +$ sudo cat /etc/audit/rules.d/11-loginuid.rules +The output has to be exactly as follows: +## Make the loginuid immutable. This prevents tampering with the auid. +--loginuid-immutable + Is it the case that the file does not exist or the content differs? @@ -257865,500 +278269,31 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - Verify the noexec option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . noexec . . . - - Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine how the SSH daemon's PermitRootLogin option is set, run the following command: - -$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config - -If a line indicating prohibit-password is returned, then the required value is set. - Is it the case that it is commented out or not configured properly? - - - - Verify that the default umask for all local interactive users is "077". - -Identify the locations of all local interactive user home directories by looking at the "/etc/passwd" file. - -Check all local interactive user initialization files for interactive users with the following command: - -Note: The example is for a system that is configured to create users home directories in the "/home" directory. - -$ sudo find /home -maxdepth 2 -type f -name ".[^.]*" -exec grep -iH -d skip --exclude=.bash_history umask {} \; - -/home/wadea/.bash_history:grep -i umask /etc/bashrc /etc/csh.cshrc /etc/profile -/home/wadea/.bash_history:grep -i umask /etc/login.defs - Is it the case that any local interactive user initialization files are found to have a umask statement that sets a value less restrictive than "077"? - - - - Verify the noexec option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . noexec . . . - - Is it the case that the "/boot" file system does not have the "noexec" option set? - - - - Run the following command to determine if the sssd package is installed: $ rpm -q sssd - Is it the case that the package is not installed? - - - - Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active - Is it the case that the dnf-automatic.timer is not enabled? - - - - To check the permissions of /etc/crypttab, -run the command: -$ ls -l /etc/crypttab -If properly configured, the output should indicate the following permissions: -0600 - Is it the case that /etc/crypttab does not have unix mode 0600? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules +cat /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules The output has to be exactly as follows: -## Unsuccessful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +## Successful file modifications (open for write or truncate) +-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification +-a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification Is it the case that the file does not exist or the content differs? - - Verify the assigned home directories of all interactive users on the system exist with the following command: - -$ sudo pwck -r - -user 'mailnull': directory 'var/spool/mqueue' does not exist - -The output should not return any interactive users. - Is it the case that users home directory does not exist? - - - - Verify the USBGuard has a policy configured with the following command: - -$ usbguard list-rules - -allow id 1d6b:0001 serial - -If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. - Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if compression is enabled or set correctly, run the -following command: -$ sudo grep Compression /etc/ssh/sshd_config -If configured properly, output should be no or delayed. - Is it the case that it is commented out, or is not set to no or delayed? - - - - Ensure there are no unconfined daemons running on the system, -the following command should produce no output: -$ sudo ps -eZ | grep "unconfined_service_t" - Is it the case that There are unconfined daemons running on the system? - - - - The following command will discover and print world-writable directories that -are not owned by root. Run it once for each local partition PART: -$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print - Is it the case that there are world-writable directories not owned by root? - - - - If the system is not configured to audit time changes, this is a finding. -If the system is 64-bit only, this is not applicable -ocil: | -To determine if the system is configured to audit calls to the -stime system call, run the following command: -$ sudo grep "stime" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: - -$ sudo auditctl -l | grep chcon - --a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that acquiring, saving, and processing core dumps is disabled, run the -following command: -$ systemctl status systemd-coredump.socket -The output should be similar to: -● systemd-coredump.socket - Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) - Active: inactive (dead) ... - - Is it the case that unit systemd-coredump.socket is not masked or running? - - - - Verify the nosuid option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nosuid . . . - - Is it the case that the "/home" file system does not have the "nosuid" option set? - - - - The group-owner of all log files written by rsyslog should be -root. -These log files are determined by the second part of each Rule line in -/etc/rsyslog.conf and typically all appear in /var/log. -To see the group-owner of a given log file, run the following command: -$ ls -l LOGFILE - Is it the case that the group-owner is not correct? - - - - To check the permissions of /etc/iptables, -run the command: -$ ls -l /etc/iptables -If properly configured, the output should indicate the following permissions: -0700 - Is it the case that /etc/iptables does not have unix mode 0700? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine if the system is configured to synchronize audit event data -with the log files on the disk: -$ sudo grep flush /etc/audit/auditd.conf -flush = DATA -Acceptable values are DATA, and SYNC. The setting is -case-insensitive. - Is it the case that auditd is not configured to synchronously write audit event data to disk? - - - - Verify the nosuid option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nosuid . . . - - Is it the case that the "/var" file system does not have the "nosuid" option set? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_SG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_WX /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: - -$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-3-access-success.rules +cat /etc/audit/rules.d/43-module-load.rules The output has to be exactly as follows: -## Successful file access (any other opens) This has to go last. -## These next two are likely to result in a whole lot of events --a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access --a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access +## These rules watch for kernel module insertion. By monitoring +## the syscall, we do not need any watches on programs. +-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load +-a always,exit -F arch=b32 -S delete_module -F key=module-unload +-a always,exit -F arch=b64 -S delete_module -F key=module-unload Is it the case that the file does not exist or the content differs? - - - - Run the following command to check for duplicate group names: -Check that the operating system contains no duplicate Group ID (GID) for interactive users by running the following command: - - cut -d : -f 3 /etc/group | uniq -d - -If output is produced, this is a finding. -Configure the operating system to contain no duplicate GIDs. -Edit the file "/etc/group" and provide each group that has a duplicate GID with a unique GID. - Is it the case that the system has duplicate group ids? - - - - Run the following command to determine if the s-nail package is installed: $ rpm -q s-nail - Is it the case that the package is not installed? - - - - To check the ownership of /etc/issue.net, -run the command: -$ ls -lL /etc/issue.net -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/issue.net does not have an owner of root? - - - - Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: - -$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should be -$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name - Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? - - - - To check the ownership of /etc/ipsec.secrets, -run the command: -$ ls -lL /etc/ipsec.secrets -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.secrets does not have an owner of root? - - - - The runtime status of the fs.protected_fifos kernel parameter can be queried -by running the following command: -$ sysctl fs.protected_fifos -2. - - Is it the case that the correct value is not returned? - - - - Verify that a separate file system/partition has been created for /var with the following command: - -$ mountpoint /var - - Is it the case that "/var is not a mountpoint" is returned? - - - - To check the ownership of /etc/ipsec.conf, -run the command: -$ ls -lL /etc/ipsec.conf -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ipsec.conf does not have an owner of root? - - - - Verify the nosuid option is configured for the /var/log/audit mount point, - run the following command: - $ sudo mount | grep '\s/var/log/audit\s' - . . . /var/log/audit . . . nosuid . . . - - Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? - - - - To determine if NOPASSWD has been configured for sudo, run the following command: -$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd is specified in the sudo config files? - - - - Verify the nodev option is configured for the /var/tmp mount point, - run the following command: - $ sudo mount | grep '\s/var/tmp\s' - . . . /var/tmp . . . nodev . . . - - Is it the case that the "/var/tmp" file system does not have the "nodev" option set? - - - - Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. - - -Check the hashing algorithm that is being used to hash passwords with the following command: - -$ sudo grep -i ENCRYPT_METHOD /etc/login.defs - -ENCRYPT_METHOD - Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? - - - - To check that the autofs service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled autofs -Output should indicate the autofs service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled autofs disabled - -Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active autofs - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the autofs is masked, run the following command: -$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "autofs" is loaded and not masked? - - - - To check the permissions of /etc/issue.net, -run the command: -$ ls -l /etc/issue.net -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/issue.net does not have unix mode -rw-r--r--? - - - - Verify that Oracle Linux 9 is configured to boot to the command line: -$ systemctl get-default -multi-user.target - Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? - - - - To ensure the system is configured to ignore the Ctrl-Alt-Del setting, -enter the following command: -$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf -The output should return: -CtrlAltDelBurstAction=none - Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? - - - - To ensure the X Windows package group is removed, run the following command: -$ rpm -qi xorg-x11-server-common -The output should be: -package xorg-x11-server-common is not installed - Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? - - - - Verify the noexec option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . noexec . . . - - Is it the case that the "/var/log" file system does not have the "noexec" option set? - - - - To determine if the system is configured to audit calls to the -chmod system call, run the following command: -$ sudo grep "chmod" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if the system is configured to audit calls to the -lsetxattr system call, run the following command: -$ sudo grep "lsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r openat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep openat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/sudoers, -run the command: -$ ls -l /etc/sudoers -If properly configured, the output should indicate the following permissions: -0440 - Is it the case that /etc/sudoers does not have unix mode 0440? - - - - To check the group ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? - - - - Verify Oracle Linux 9 security patches and updates are installed and up to date. -Updates are required to be applied with a frequency determined by organizational policy. - - - -Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. - Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? @@ -258378,6 +278313,9 @@ The output has to be exactly as follows: ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules +## +## original copies may be found in /usr/share/audit/sample-rules/ + ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and @@ -258481,46 +278419,855 @@ The output has to be exactly as follows: Is it the case that the file does not exist or the content differs? - - + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules +The output has to be exactly as follows: +## Unsuccessful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules +The output has to be exactly as follows: +## Successful ownership change +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change +-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules +The output has to be exactly as follows: +## Unsuccessful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change + Is it the case that the file does not exist or the content differs? + + + + To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: +cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules +The output has to be exactly as follows: +## Successful permission change +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change + Is it the case that the file does not exist or the content differs? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "init" command with the following command: -Run the following command to determine the current status of the -crond service: -$ sudo systemctl is-active crond -If the service is running, it should return the following: active +$ sudo auditctl -l | grep init + +-a always,exit -F path={{{ path }}}/init -F perm=x -F auid>=1000 -F auid!=unset -k privileged-init + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "poweroff" command with the following command: + +$ sudo auditctl -l | grep poweroff + +-a always,exit -F path={{{ path }}}/poweroff -F perm=x -F auid>=1000 -F auid!=unset -k privileged-poweroff + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "reboot" command with the following command: + +$ sudo auditctl -l | grep reboot + +-a always,exit -F path={{{ path }}}/reboot -F perm=x -F auid>=1000 -F auid!=unset -k privileged-reboot + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: + +$ sudo auditctl -l | grep shutdown + +-a always,exit -F path={{{ path }}}/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +chmod system call, run the following command: +$ sudo grep "chmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +chown system call, run the following command: +$ sudo grep "chown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchmod system call, run the following command: +$ sudo grep "fchmod" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchmodat system call, run the following command: +$ sudo grep "fchmodat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchown system call, run the following command: +$ sudo grep "fchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fchownat system call, run the following command: +$ sudo grep "fchownat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fremovexattr system call, run the following command: +$ sudo grep "fremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +fsetxattr system call, run the following command: +$ sudo grep "fsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lchown system call, run the following command: +$ sudo grep "lchown" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lremovexattr system call, run the following command: +$ sudo grep "lremovexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +lsetxattr system call, run the following command: +$ sudo grep "lsetxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +removexattr system call, run the following command: +$ sudo grep "removexattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +setxattr system call, run the following command: +$ sudo grep "setxattr" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify that Oracle Linux 9 generates an audit record for all uses of the "umount" and system call. +To determine if the system is configured to audit calls to the +"umount" system call, run the following command: +$ sudo grep "umount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line like the following. +-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit calls to the +umount2 system call, run the following command: +$ sudo grep "umount2" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/cron.d/" with the following command: + +$ sudo auditctl -l | grep /etc/cron.d/ + +-w /etc/cron.d/ -p wa -k cronjobs + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: + +$ sudo auditctl -l | grep chacl + +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chcon" command with the following command: + +$ sudo auditctl -l | grep chcon + +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: + +$ sudo auditctl -l | grep restorecon + +-a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "semanage" command with the following command: + +$ sudo auditctl -l | grep semanage + +-a always,exit -F path=/usr/sbin/semanage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: + +$ sudo auditctl -l | grep setfacl + +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: + +$ sudo auditctl -l | grep setfiles + +-a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "setsebool" command with the following command: + +$ sudo auditctl -l | grep setsebool + +-a always,exit -F path=/usr/sbin/setsebool -F perm=x -F auid>=1000 -F auid!=unset -k privileged + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that execution of the command is being audited, run the following command: +$ sudo grep "path=/usr/sbin/seunshare" /etc/audit/audit.rules /etc/audit/rules.d/* +The output should return something similar to: +-a always,exit -F path=/usr/sbin/seunshare -F auid>=1000 -F auid!=unset -F key=privileged Is it the case that ? - - The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.secure_redirects -0. + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +renameat2 system call, run the following command: +$ sudo grep "renameat2" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +rename system call, run the following command: +$ sudo grep "rename" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. - Is it the case that the correct value is not returned? + Is it the case that no line is returned? - - To check the permissions of /etc/cron.d, -run the command: -$ ls -l /etc/cron.d -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.d does not have unix mode -rwx------? - - - - Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog - Is it the case that the package is not installed? - - - - Verify the nodev option is configured for the /var mount point, - run the following command: - $ sudo mount | grep '\s/var\s' - . . . /var . . . nodev . . . + + To determine if the system is configured to audit calls to the +renameat system call, run the following command: +$ sudo grep "renameat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. - Is it the case that the "/var" file system does not have the "nodev" option set? + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +rmdir system call, run the following command: +$ sudo grep "rmdir" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +unlink system call, run the following command: +$ sudo grep "unlink" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +unlinkat system call, run the following command: +$ sudo grep "unlinkat" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + Verify the audit system prevents unauthorized changes with the following command: + +$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 +-e 2 + + Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? + + + + To determine if the system is configured to make login UIDs immutable, run +one of the following commands. +If the auditd daemon is configured to use the +augenrules program to read audit rules during daemon startup (the +default), run the following: +sudo grep immutable /etc/audit/rules.d/*.rules +If the auditd daemon is configured to use the auditctl +utility to read audit rules during daemon startup, run the following command: +sudo grep immutable /etc/audit/audit.rules +The following line should be returned: +--loginuid-immutable + Is it the case that the system is not configured to make login UIDs immutable? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. +To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +delete_module system call, run the following command: +$ sudo grep "delete_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +finit_module system call, run the following command: +$ sudo grep "finit_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +init_module system call, run the following command: +$ sudo grep "init_module" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "" with the following command: + +$ sudo auditctl -l | grep + +-w -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/lastlog" with the following command: + +$ sudo auditctl -l | grep /var/log/lastlog + +-w /var/log/lastlog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/tallylog" with the following command: + +$ sudo auditctl -l | grep /var/log/tallylog + +-w /var/log/tallylog -p wa -k logins + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/etc/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/selinux/" with the following command: + +$ sudo auditctl -l | grep /etc/selinux/ + +-w /etc/selinux/ -p wa -k MAC-policy + Is it the case that the system is not configured to audit attempts to change files within the /etc/selinux directory? + + + + To determine if the system is configured to audit changes to its SELinux +configuration files, run the following command: +$ sudo auditctl -l | grep "dir=/usr/share/selinux" +If the system is configured to watch for changes to its SELinux +configuration, a line should be returned (including +perm=wa indicating permissions that are watched). + Is it the case that the system is not configured to audit attempts to change the MAC policy? + + + + To determine if the system is configured to audit calls to the +mount system call, run the following command: +$ sudo grep "mount" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit changes to its network configuration, +run the following command: +auditctl -l | grep -E '(/etc/issue|/etc/issue.net|/etc/hosts|/etc/sysconfig/network)' + +If the system is configured to watch for network configuration changes, a line should be returned for +each file specified (and perm=wa should be indicated for each). + Is it the case that the system is not configured to audit changes of the network configuration? + + + + To verify that auditing of privileged command use is configured, run the following command +to search privileged commands in relevant partitions and check if they are covered by auditd +rules: + +FILTER_NODEV=$(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) +PARTITIONS=$(findmnt -n -l -k -it $FILTER_NODEV | grep -Pv "noexec|nosuid" | awk '{ print $1 }') +for PARTITION in $PARTITIONS; do + for PRIV_CMD in $(find "${PARTITION}" -xdev -perm /6000 -type f 2>/dev/null); do + grep -qr "${PRIV_CMD}" /etc/audit/rules.d /etc/audit/audit.rules && + printf "OK: ${PRIV_CMD}\n" || printf "WARNING - rule not found for: ${PRIV_CMD}\n" + done +done + +The output should not contain any WARNING. + Is it the case that any setuid or setgid programs doesn't have a line in the audit rules? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: + +$ sudo auditctl -l | grep chage + +-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "chsh" command with the following command: + +$ sudo auditctl -l | grep chsh + +-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chsh + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: + +$ sudo auditctl -l | grep crontab + +-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "gpasswd" command with the following command: + +$ sudo auditctl -l | grep gpasswd + +-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-gpasswd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: + +$ sudo auditctl -l | grep kmod + +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "mount" command with the following command: + +$ sudo auditctl -l | grep mount + +-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-mount + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "newgrp" command with the following command: + +$ sudo auditctl -l | grep newgrp + +-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -k privileged-newgrp + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "pam_timestamp_check" command with the following command: + +$ sudo auditctl -l | grep pam_timestamp_check + +-a always,exit -F path=/usr/sbin/pam_timestamp_check -F perm=x -F auid>=1000 -F auid!=unset -k privileged-pam_timestamp_check + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "passwd" command with the following command: + +$ sudo auditctl -l | grep passwd + +-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-passwd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: + +$ sudo auditctl -l | grep postdrop + +-a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "postqueue" command with the following command: + +$ sudo auditctl -l | grep postqueue + +-a always,exit -F path=/usr/bin/postqueue -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postqueue + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: + +$ sudo auditctl -l | grep ssh-agent + +-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-keysign" command with the following command: + +$ sudo auditctl -l | grep ssh-keysign + +-a always,exit -F path=/usr/libexec/openssh/ssh-keysignssh-keysign -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-keysign + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: + +$ sudo auditctl -l | grep su + +-a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: + +$ sudo auditctl -l | grep sudo + +-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: + +$ sudo auditctl -l | grep sudoedit + +-a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: + +$ sudo auditctl -l | grep umount + +-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_chkpwd" command with the following command: + +$ sudo auditctl -l | grep unix_chkpwd + +-a always,exit -F path=/usr/bin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_chkpwd + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "unix_update" command with the following command: + +$ sudo auditctl -l | grep unix_update + +-a always,exit -F path=/usr/bin/unix_update -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix_update + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "userhelper" command with the following command: + +$ sudo auditctl -l | grep userhelper + +-a always,exit -F path=/usr/bin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -k privileged-userhelper + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify that Oracle Linux 9 is configured to audit the execution of the "usermod" command with the following command: + +$ sudo auditctl -l | grep usermod + +-a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-usermod + Is it the case that the command does not return a line, or the line is commented out? + + + + To verify that auditing of privileged command use is configured, run the +following command: +$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* +It should return a relevant line in the audit rules. + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/btmp" with the following command: + +$ sudo auditctl -l | grep /var/log/btmp + +-w /var/log/btmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/run/utmp" with the following command: + +$ sudo auditctl -l | grep /var/run/utmp + +-w /var/run/utmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/wtmp" with the following command: + +$ sudo auditctl -l | grep /var/log/wtmp + +-w /var/log/wtmp -p wa -k session + Is it the case that Audit rule is not present? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers + +-w /etc/sudoers -p wa -k actions + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers.d/" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers.d/ + +-w /etc/sudoers.d/ -p wa -k actions + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 audits the execution of privileged functions. + +Check if Oracle Linux 9 is configured to audit the execution of the "execve" system call using the following command: + +$ sudo grep execve /etc/audit/audit.rules + +The output should be the following: + + +-a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid +-a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid +-a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid + Is it the case that the command does not return all lines, or the lines are commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers + +-w /etc/sudoers -p wa -k actions + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/sudoers.d/" with the following command: + +$ sudo auditctl -l | grep /etc/sudoers.d/ + +-w /etc/sudoers.d/ -p wa -k actions + Is it the case that there is not output? + + + + To verify that the system will shutdown when auditd fails, +run the following command: +$ sudo grep "\-f " /etc/audit/audit.rules +The output should contain: +-f + Is it the case that the system is not configured to shutdown on auditd failures? + + + + To determine if the system is configured to audit calls to the +adjtimex system call, run the following command: +$ sudo grep "adjtimex" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? + + + + To determine if the system is configured to audit calls to the +clock_settime system call, run the following command: +$ sudo grep "clock_settime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + + Is it the case that no line is returned? @@ -258530,6 +279277,3639 @@ $ sudo grep "settimeofday" /etc/audit/audit.* If the system is configured to audit this activity, it will return a line. Is it the case that no line is returned? + + + + If the system is not configured to audit time changes, this is a finding. +If the system is 64-bit only, this is not applicable +ocil: | +To determine if the system is configured to audit calls to the +stime system call, run the following command: +$ sudo grep "stime" /etc/audit/audit.* +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/localtime" with the following command: + +$ sudo auditctl -l | grep /etc/localtime + +-w /etc/localtime -p wa -k audit_time_rules + Is it the case that the system is not configured to audit time changes? + + + + To verify that the audit system collects unauthorized file accesses, run the following commands: +$ sudo grep EACCES /etc/audit/audit.rules +$ sudo grep EPERM /etc/audit/audit.rules + Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r creat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep creat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r ftruncate /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep ftruncate /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r open_by_handle_at /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep open_by_handle_at /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the openat system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r openat /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep openat /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. + +If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: + +$ sudo grep -r truncate /etc/audit/rules.d + +If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: + +$ sudo grep truncate /etc/audit/audit.rules + +The output should be the following: + +-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access +-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access + Is it the case that the command does not return a line, or the line is commented out? + + + + To determine if the system is configured to audit account changes, +run the following command: +auditctl -l | grep -E '(/etc/passwd|/etc/shadow|/etc/group|/etc/gshadow|/etc/security/opasswd)' +If the system is configured to watch for account changes, lines should be returned for +each file specified (and with perm=wa for each). + Is it the case that the system is not configured to audit account changes? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/group" with the following command: + +$ sudo auditctl -l | grep /etc/group + +-w /etc/group -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/gshadow" with the following command: + +$ sudo auditctl -l | grep /etc/gshadow + +-w /etc/gshadow -p wa -k audit_rules_usergroup_modification + Is it the case that the system is not configured to audit account changes? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/security/opasswd" with the following command: + +$ sudo auditctl -l | grep /etc/security/opasswd + +-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/passwd" with the following command: + +$ sudo auditctl -l | grep /etc/passwd + +-w /etc/passwd -p wa -k audit_rules_usergroup_modification + Is it the case that the command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/etc/shadow" with the following command: + +$ sudo auditctl -l | grep /etc/shadow + +-w /etc/shadow -p wa -k audit_rules_usergroup_modification + Is it the case that command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/spool/cron" with the following command: + +$ sudo auditctl -l | grep /var/spool/cron + +-w /var/spool/cron -p wa -k cronjobs + Is it the case that command does not return a line, or the line is commented out? + + + + +Verify Oracle Linux 9 generates audit records for all events that affect "/var/log/sudo.log" with the following command: + +$ sudo auditctl -l | grep /var/log/sudo.log + +-w /var/log/sudo.log -p wa -k maintenance + Is it the case that Audit rule is not present? + + + + To verify whether audispd plugin off-loads audit records onto a different +system or media from the system being audited, run the following command: + +$ sudo grep -i remote_server /etc/audit/audisp-remote.conf + +The output should return something similar to where REMOTE_SYSTEM +is an IP address or hostname: +remote_server = REMOTE_SYSTEM + +Determine which partition the audit records are being written to with the +following command: + +$ sudo grep log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log + +Check the size of the partition that audit records are written to with the +following command and verify whether it is sufficiently large: + +$ sudo df -h /var/log/audit/ +/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit + Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? + + + + To verify the audispd's syslog plugin is active, run the following command: +$ sudo grep active /etc/audit/plugins.d/syslog.conf +If the plugin is active, the output will show yes. + Is it the case that it is not activated? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. + +Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: + +$ sudo grep disk_error_action /etc/audit/auditd.conf + +disk_error_action = + +If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when an audit processing failure occurs. + +Check that Oracle Linux 9 takes the appropriate action when an audit processing failure occurs with the following command: + +$ sudo grep disk_error_action /etc/audit/auditd.conf + +disk_error_action = HALT + +If the value of the "disk_error_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit process failure occurs. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. + +Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: + +$ sudo grep disk_full_action /etc/audit/auditd.conf + +disk_full_action = + +If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. + Is it the case that there is no evidence of appropriate action? + + + + Verify that Oracle Linux 9 is configured to notify the SA and/or ISSO (at a minimum) in the event of an audit processing failure with the following command: + +$ sudo grep action_mail_acct /etc/audit/auditd.conf + +action_mail_acct = + Is it the case that the value of the "action_mail_acct" keyword is not set to "<sub idref="var_auditd_action_mail_acct" />" and/or other accounts for security personnel, the "action_mail_acct" keyword is missing, or the returned line is commented out, ask the system administrator to indicate how they and the ISSO are notified of an audit process failure. If there is no evidence of the proper personnel being notified of an audit processing failure? + + + + Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep admin_space_left_action /etc/audit/auditd.conf + +admin_space_left_action = single + +If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w admin_space_left /etc/audit/auditd.conf + +admin_space_left = % + +If the value of the "admin_space_left" keyword is not set to % of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is taking action if the allocated storage is about to reach capacity. + Is it the case that the "admin_space_left" value is not configured to the correct value? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured to synchronize audit event data +with the log files on the disk: +$ sudo grep flush /etc/audit/auditd.conf +flush = DATA +Acceptable values are DATA, and SYNC. The setting is +case-insensitive. + Is it the case that auditd is not configured to synchronously write audit event data to disk? + + + + Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. + +Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? + + + + Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. + +Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: + +$ sudo grep max_log_file_action /etc/audit/auditd.conf + +max_log_file_action = + Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? + + + + Inspect /etc/audit/auditd.conf and locate the following line to +determine if the system is configured correctly: +space_left SIZE_in_MB + Is it the case that the system is not configured a specific size in MB to notify administrators of an issue? + + + + Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w space_left_action /etc/audit/auditd.conf + +space_left_action = + +If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. + Is it the case that there is no evidence that real-time alerts are configured on the system? + + + + Verify Oracle Linux 9 takes action when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: + +$ sudo grep -w space_left /etc/audit/auditd.conf + +space_left = % + Is it the case that the value of the "space_left" keyword is not set to <sub idref="var_auditd_space_left_percentage" />% of the storage volume allocated to audit logs, or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. If the "space_left" value is not configured to the correct value? + + + + To verify that Audit Daemon is configured to flush to disk after +every records, run the following command: +$ sudo grep freq /etc/audit/auditd.conf +The output should return the following: +freq = + Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? + + + + To verify that Audit Daemon is configured to include local events, run the +following command: +$ sudo grep local_events /etc/audit/auditd.conf +The output should return the following: +local_events = yes + Is it the case that local_events isn't set to yes? + + + + To verify that Audit Daemon is configured to resolve all uid, gid, syscall, +architecture, and socket address information before writing the event to disk, +run the following command: +$ sudo grep log_format /etc/audit/auditd.conf +The output should return the following: +log_format = ENRICHED + Is it the case that log_format isn't set to ENRICHED? + + + + To verify that Audit Daemon is configured to record the computer node +name in the audit events, run the following command: +$ sudo grep name_format /etc/audit/auditd.conf +The output should return the following: +name_format = + Is it the case that name_format isn't set to <sub idref="var_auditd_name_format" />? + + + + Verify the audit system is configured to take an appropriate action when the internal event queue is full: +$ sudo grep -i overflow_action /etc/audit/auditd.conf + +The output should contain overflow_action = syslog + +If the value of the "overflow_action" option is not set to syslog, +single, halt or the line is commented out, ask the System Administrator +to indicate how the audit logs are off-loaded to a different system or media. + Is it the case that auditd overflow action is not set correctly? + + + + To verify that Audit Daemon is configured to write logs to the disk, run the +following command: +$ sudo grep write_logs /etc/audit/auditd.conf +The output should return the following: +write_logs = yes + Is it the case that write_logs isn't set to yes? + + + + To check if the system login banner is compliant, +run the following command: + +$ cat /etc/issue + Is it the case that it does not display the required banner? + + + + To check if the system login banner is compliant, run the following command: +$ cat /etc/issue.net + Is it the case that it does not display the required banner? + + + + To check if the system motd banner is compliant, +run the following command: +$ cat /etc/motd + Is it the case that it does not display the required banner? + + + + Verify the NX (no-execution) bit flag is set on the system. + +Check that the no-execution bit flag is set with the following commands: + +$ sudo dmesg | grep NX + +[ 0.000000] NX (Execute Disable) protection: active + +If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: + +$ sudo grep flags /proc/cpuinfo +flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts + +The output should contain the "nx" flag. + Is it the case that NX is disabled? + + + + Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: +$ grep -w port /etc/chrony.conf +port 0 + Is it the case that the "port" option is not set to "0", is commented out, or is missing? + + + + Run the following command and verify remote servers are configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + Verify Oracle Linux 9 disables network management of the chrony daemon with the following command: +$ grep -w cmdport /etc/chrony.conf +cmdport 0 + Is it the case that the "cmdport" option is not set to "0", is commented out, or is missing? + + + + Verify Oracle Linux 9 is securely comparing internal information system clocks at a regular interval with an NTP server with the following command: +$ sudo grep maxpoll /etc/ntp.conf /etc/chrony.conf /etc/chrony.d/ +server [ntp.server.name] iburst maxpoll . + Is it the case that "maxpoll" has not been set to the value of "<sub idref="var_time_service_set_maxpoll" />", is commented out, or is missing? + + + + # grep "^OPTIONS.*-u" /etc/sysconfig/chronyd | grep -v -e '-u\s*chrony\b' +returns no output + Is it the case that chronyd is not running under chrony user account? + + + + Run the following command and verify that time sources are only configured with server directive: +# grep -E "^(server|pool)" /etc/chrony.conf +A line with the appropriate server should be returned, any line returned starting with pool is a finding. + Is it the case that an authoritative remote time server is not configured or configured with pool directive? + + + + Run the following command and verify remote server is configured properly: +# grep -E "^(server|pool)" /etc/chrony.conf + Is it the case that a remote time server is not configured? + + + + Verify Oracle Linux 9 removes all software components after updated versions have been installed. + + +$ grep clean_requirements_on_remove /etc/yum.conf +clean_requirements_on_remove=1 + Is it the case that '"clean_requirements_on_remove" is not set to "1"'? + + + + To verify that BIND uses the system crypto policy, check out that the BIND config file +/etc/named.conf contains the include "/etc/crypto-policies/back-ends/bind.config"; +directive: +$ sudo grep 'include "/etc/crypto-policies/back-ends/bind.config";' /etc/named.conf +Verify that the directive is at the bottom of the options section of the config file. + Is it the case that BIND is installed and the BIND config file doesn't contain the +<pre>include "/etc/crypto-policies/back-ends/bind.config";</pre> directive? + + + + To verify that cryptography policy has been configured correctly, run the +following command: +$ update-crypto-policies --show +The output should return . +Run the command to check if the policy is correctly applied: +$ update-crypto-policies --is-applied +The output should be The configured policy is applied. +Moreover, check if settings for selected crypto policy are as expected. +List all libraries for which it holds that their crypto policies do not have symbolic link in /etc/crypto-policies/back-ends. +$ ls -l /etc/crypto-policies/back-ends/ | grep '^[^l]' | tail -n +2 | awk -F' ' '{print $NF}' | awk -F'.' '{print $1}' | sort +Subsequently, check if matching libraries have drop in files in the /etc/crypto-policies/local.d directory. +$ ls /etc/crypto-policies/local.d/ | awk -F'-' '{print $1}' | uniq | sort +Outputs of two previous commands should match. + Is it the case that cryptographic policy is not configured or is configured incorrectly? + + + + Inspect the list of enabled firewall ports and verify they are configured correctly by running +the following command: + +$ sudo firewall-cmd --list-all + +Ask the System Administrator for the site or program Ports, Protocols, and Services Management Component Local Service Assessment (PPSM CLSA). Verify the services allowed by the firewall match the PPSM CLSA. + Is it the case that there are additional ports, protocols, or services that are not in the PPSM CLSA, or there are ports, protocols, or services that are prohibited by the PPSM Category Assurance List (CAL), or there are no firewall rules configured? + + + + Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: +file /etc/krb5.conf.d/crypto-policies +If command output shows the following line, Kerberos is configured to use the system-wide crypto policy. +/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config + Is it the case that the symlink does not exist or points to a different target? + + + + Verify that the IPSec service uses the system crypto policy. + +If the ipsec service is not installed is not applicable. + +Check to see if the "IPsec" service is active with the following command: + +$ systemctl status ipsec + +ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec +Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) +Active: inactive (dead) + +If the "IPsec" service is active, check to see if it is using the system crypto policy with the following command: + +$ sudo grep include /etc/ipsec.conf /etc/ipsec.d/*.conf + +/etc/ipsec.conf:include /etc/crypto-policies/back-ends/libreswan.config + Is it the case that the "IPsec" service is active and the ipsec configuration file does not contain does not contain <tt>include /etc/crypto-policies/back-ends/libreswan.config</tt>? + + + + Verify that Oracle Linux 9 loads the driver with the following command: + +$ grep card_drivers /etc/opensc.conf + +card_drivers = ; + Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? + + + + To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file +/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the +.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: + +$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. + Is it the case that the OpenSSL config file doesn't contain the whole section, +or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? + + + + Verify that sshd isn't configured to ignore the system wide cryptographic policy. + +Check that the CRYPTO_POLICY variable is not set or is commented out in the +/etc/sysconfig/sshd. + +Run the following command: + +$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd + Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? + + + + To verify that Linux Audit logging is enabled for the USBGuard daemon, +run the following command: +$ sudo grep AuditBackend /etc/usbguard/usbguard-daemon.conf +The output should be +AuditBackend=LinuxAudit + Is it the case that AuditBackend is not set to LinuxAudit? + + + + Verify that the system backups user data. + Is it the case that it is not? + + + + Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: + +$ sudo firewall-cmd --state + +running + +$ sudo firewall-cmd --get-active-zones + +[custom] +interfaces: ens33 + +$ sudo firewall-cmd --info-zone=[custom] | grep target + +target: DROP + Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? + + + + Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: + +$ grep -i process /etc/systemd/coredump.conf /etc/systemd/coredump.conf.d/*.conf + +ProcessSizeMax=0 + Is it the case that the "ProcessSizeMax" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + + + + Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: + +$ grep -i storage /etc/systemd/coredump.conf /etc/systemd/coredump.conf.d/*.conf + +Storage=none + Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + + + + In order to be sure that the databases are up-to-date, run the +dconf update +command as the administrator. + Is it the case that The system-wide dconf databases are up-to-date with regards to respective keyfiles? + + + + To ensure a login warning banner is enabled, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/* +If properly configured, the output should be true. +To ensure a login warning banner is locked and cannot be changed by a user, run the following: +$ grep banner-message-enable /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. + Is it the case that it is not? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount +If properly configured, the output for automount should be false. +To ensure that users cannot enable automount in GNOME3, run the following: +$ grep 'automount' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount should be /org/gnome/desktop/media-handling/automount + Is it the case that GNOME automounting is not disabled? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling automount-open +If properly configured, the output for automount-openshould be false. +To ensure that users cannot enable automount opening in GNOME3, run the following: +$ grep 'automount-open' /etc/dconf/db/local.d/locks/* +If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open + Is it the case that GNOME automounting is not disabled? + + + + These settings can be verified by running the following: +$ gsettings get org.gnome.desktop.media-handling autorun-never +If properly configured, the output for autorun-nevershould be true. +To ensure that users cannot enable autorun in GNOME3, run the following: +$ grep 'autorun-never' /etc/dconf/db/local.d/locks/* +If properly configured, the output for autorun-never should be /org/gnome/desktop/media-handling/autorun-never + Is it the case that GNOME autorun is not disabled? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, +run the following command: +$ gsettings get org.gnome.settings-daemon.plugins.media-keys logout +$ grep logout /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/settings-daemon/plugins/media-keys/logout + Is it the case that GNOME3 is configured to reboot when Ctrl-Alt-Del is pressed? + + + + To ensure disable and restart on the login screen are disabled, run the following command: +$ grep disable-restart-buttons /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable disable and restart on the login screen, run the following: +$ grep disable-restart-buttons /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons + Is it the case that disable-restart-buttons has not been configured or is not disabled? + + + + To ensure the user list is disabled, run the following command: +$ grep disable-user-list /etc/dconf/db/local.d/* +The output should be true. +To ensure that users cannot enable displaying the user list, run the following: +$ grep disable-user-list /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/disable-user-list + Is it the case that disable-user-list has not been configured or is not disabled? + + + + To ensure screen locking on smartcard removal is enabled, run the following command: +$ grep removal-action /etc/dconf/db/local.d/* +The output should be 'lock-screen'. +To ensure that users cannot disable screen locking on smartcard removal, run the following: +$ grep removal-action /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/settings-daemon/peripherals/smartcard/removal-action + Is it the case that removal-action has not been configured? + + + + +To ensure the login warning banner text is properly set, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/* +If properly configured, the proper banner text will appear. +To ensure the login warning banner text is locked and cannot be changed by a user, run the following: +$ grep banner-message-text /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/login-screen/banner-message-text. + Is it the case that it does not? + + + + To ensure that remote access requires credentials, run the following command: +$ gsettings get org.gnome.Vino authentication-methods +If properly configured, the output should be false. +To ensure that users cannot disable credentials for remote access, run the following: +$ grep authentication-methods /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/authentication-methods + Is it the case that wireless network notification is enabled and not disabled? + + + + To ensure that remote access connections are encrypted, run the following command: +$ gsettings get org.gnome.Vino require-encrpytion +If properly configured, the output should be true. +To ensure that users cannot disable encrypted remote connections, run the following: +$ grep require-encryption /etc/dconf/db/local.d/locks/* +If properly configured, the output should be +/org/gnome/Vino/require-encryption + Is it the case that remote access connections are not encrypted? + + + + To check the screensaver mandatory use status, run the following command: +$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled +If properly configured, the output should be true. +To ensure that users cannot disable the screensaver idle inactivity setting, run the following: +$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled + Is it the case that idle-activation-enabled is not enabled or configured? + + + + To check the current idle time-out value, run the following command: +$ gsettings get org.gnome.desktop.session idle-delay +If properly configured, the output should be 'uint32 '. +To ensure that users cannot change the screensaver inactivity timeout setting, run the following: +$ grep idle-delay /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is set to 0 or a value greater than <sub idref="inactivity_timeout_value" />? + + + + To check that the screen locks immediately when activated, run the following command: +$ gsettings get org.gnome.desktop.screensaver lock-delay +If properly configured, the output should be 'uint32 '. + Is it the case that the screensaver lock delay is missing, or is set to a value greater than <sub idref="var_screensaver_lock_delay" />? + + + + To check the status of the idle screen lock activation, run the following command: + +$ gsettings get org.gnome.desktop.screensaver lock-enabled +If properly configured, the output should be true. +To ensure that users cannot change how long until the screensaver locks, run the following: +$ grep lock-enabled /etc/dconf/db/local.d/locks/* +If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled + Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? + + + + To ensure the screensaver is configured to be blank, run the following command: +$ gsettings get org.gnome.desktop.screensaver picture-uri +If properly configured, the output should be ''. + +To ensure that users cannot set the screensaver background, run the following: +$ grep picture-uri /etc/dconf/db/local.d/locks/* +If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri + Is it the case that it is not set or configured properly? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'lock-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/screensaver/lock-delay + Is it the case that GNOME3 session settings are not locked or configured properly? + + + + To ensure that users cannot change session idle and lock settings, run the following: +$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* +If properly configured, the output should return: +/org/gnome/desktop/session/idle-delay + Is it the case that idle-delay is not locked? + + + + Verify the system-wide shared library directories are group-owned by "root" with the following command: + +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; + +If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. + Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/local/bin +/usr/local/sbin +/usr/sbin +For each of these directories, run the following command to find files +not owned by root: +$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; + Is it the case that any system executables directories are found to not be owned by root? + + + + Verify the system-wide shared library directories are owned by "root" with the following command: + +$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -user root -type d -exec stat -c "%n %U" '{}' \; + Is it the case that any system-wide shared library directory is not owned by root? + + + + System executables are stored in the following directories by default: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +To find system executables directories that are group-writable or +world-writable, run the following command for each directory DIR +which contains system executables: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + Shared libraries are stored in the following directories: +/lib +/lib64 +/usr/lib +/usr/lib64 + +To find shared libraries that are group-writable or world-writable, +run the following command for each directory DIR which contains shared libraries: +$ sudo find -L DIR -perm /022 -type d + Is it the case that any of these files are group-writable or world-writable? + + + + The following command will discover and print world-writable directories that +are not owned by root. Run it once for each local partition PART: +$ sudo find PART -xdev -type d -perm -0002 -uid +0 -print + Is it the case that there are world-writable directories not owned by root? + + + + To find world-writable directories that lack the sticky bit, run the following command: +$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null +fixtext: |- +Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. + +Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: + +$ chmod a+t [World-Writable Directory] +srg_requirement: +A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. + Is it the case that any world-writable directories are missing the sticky bit? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -group root -type d -exec chgrp root {} \; + Is it the case that any of these directories are not group owned by root? + + + + System commands are stored in the following directories: +/bin +/sbin +/usr/bin +/usr/sbin +/usr/local/bin +/usr/local/sbin +For each of these directories, run the following command to find directories not +owned by root: +$ sudo find -L $DIR ! -user root -type d + Is it the case that any of these directories are not owned by root? + + + + To determine if the system is configured to audit accesses to +/var/log/audit directory, run the following command: +$ sudo grep "dir=/var/log/audit" /etc/audit/audit.rules +If the system is configured to audit this activity, it will return a line. + Is it the case that no line is returned? + + + + +Determine the audit log group by running the following command: + +$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf + +Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. +Run the following command: + +$ sudo find /var/log/audit -type d -printf "%p %g\n" + +All listed directories must be owned by the log_group or by root if the log_group is not specified. + Is it the case that there is a directory owned by different group? + + + + To check the group ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/iptables does not have a group owner of +root +? + + + + To check the group ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/nftables does not have a group owner of +root +? + + + + To check the group ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/selinux does not have a group owner of +root +? + + + + To check the group ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sudoers.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sysctl.d does not have a group owner of +root +? + + + + To check the ownership of /etc/ipsec.d, +run the command: +$ ls -lL /etc/ipsec.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.d does not have an owner of root? + + + + To check the ownership of /etc/iptables, +run the command: +$ ls -lL /etc/iptables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/iptables does not have an owner of root? + + + + To check the ownership of /etc/nftables, +run the command: +$ ls -lL /etc/nftables +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/nftables does not have an owner of root? + + + + To check the ownership of /etc/selinux, +run the command: +$ ls -lL /etc/selinux +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/selinux does not have an owner of root? + + + + To check the ownership of /etc/sudoers.d, +run the command: +$ ls -lL /etc/sudoers.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers.d does not have an owner of root? + + + + To check the ownership of /etc/sysctl.d, +run the command: +$ ls -lL /etc/sysctl.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sysctl.d does not have an owner of root? + + + + Determine where the audit logs are stored with the following command: + +$ sudo grep -iw log_file /etc/audit/auditd.conf + +log_file = /var/log/audit/audit.log + +Determine the owner of the audit log directory by using the output of the above command +(default: "/var/log/audit/"). Run the following command with the correct audit log directory +path: + +$ sudo ls -ld /var/log/audit + +drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit + +The audit log directory must be owned by "root" + Is it the case that the directory is not owned by root? + + + + To check the permissions of /etc/ipsec.d, +run the command: +$ ls -l /etc/ipsec.d +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/ipsec.d does not have unix mode 0700? + + + + To check the permissions of /etc/iptables, +run the command: +$ ls -l /etc/iptables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/iptables does not have unix mode 0700? + + + + To check the permissions of /etc/nftables, +run the command: +$ ls -l /etc/nftables +If properly configured, the output should indicate the following permissions: +0700 + Is it the case that /etc/nftables does not have unix mode 0700? + + + + To check the permissions of /etc/selinux, +run the command: +$ ls -l /etc/selinux +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/selinux does not have unix mode 0755? + + + + To check the permissions of /etc/sudoers.d, +run the command: +$ ls -l /etc/sudoers.d +If properly configured, the output should indicate the following permissions: +0750 + Is it the case that /etc/sudoers.d does not have unix mode 0750? + + + + To check the permissions of /etc/sysctl.d, +run the command: +$ ls -l /etc/sysctl.d +If properly configured, the output should indicate the following permissions: +0755 + Is it the case that /etc/sysctl.d does not have unix mode 0755? + + + + Verify the audit log directories have a correct mode or less permissive mode. + +Find the location of the audit logs: + +$ sudo grep "^log_file" /etc/audit/auditd.conf + + +Find the group that owns audit logs: + +$ sudo grep "^log_group" /etc/audit/auditd.conf + + +Run the following command to check the mode of the system audit logs: + +$ sudo stat -c "%a %n" [audit_log_directory] + +Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". + + +If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. + Is it the case that audit logs have a more permissive mode? + + + + To ensure the system is configured to ignore the Ctrl-Alt-Del setting, +enter the following command: +$ sudo grep -i ctrlaltdelburstaction /etc/systemd/system.conf +The output should return: +CtrlAltDelBurstAction=none + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed more than 7 times in 2 seconds.? + + + + To ensure the system is configured to mask the Ctrl-Alt-Del sequence, Check +that the ctrl-alt-del.target is masked and not active with the following +command: +sudo systemctl status ctrl-alt-del.target +The output should indicate that the target is masked and not active. It +might resemble following output: +ctrl-alt-del.target +Loaded: masked (/dev/null; bad) +Active: inactive (dead) + Is it the case that the system is configured to reboot when Ctrl-Alt-Del is pressed? + + + + To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: + +$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + Verify that core dumps are disabled for all users, run the following command: +$ grep core /etc/security/limits.conf +* hard core 0 + Is it the case that the "core" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core"? + + + + Verify the operating system is not configured to bypass password requirements for privilege +escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: +$ sudo grep pam_succeed_if /etc/pam.d/sudo + Is it the case that system is configured to bypass password requirements for privilege escalation? + + + + Verify users are provided with feedback on when account accesses last occurred with the following command: + +$ sudo grep pam_lastlog /etc/pam.d/postlogin + +session required pam_lastlog.so showfailed + Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file? + + + + To verify that packages comprising the available updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep apply_updates /etc/dnf/automatic.conf +The output should return the following: +apply_updates = yes + Is it the case that apply_updates is not set to yes? + + + + To verify that only security updates will be automatically installed by dnf-automatic, run the following command: +$ sudo grep upgrade_type /etc/dnf/automatic.conf +The output should return the following: +upgrade_type = security + Is it the case that the upgrade_type is not set to security? + + + + Verify that authselect is enabled by running +authselect current +If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. + Is it the case that authselect is not used to manage user authentication setup on the system? + + + + To verify that the DConf User profile is configured correctly, run the following +command: + +$ cat /etc/dconf/profile/user +The output should show the following: +user-db:user +system-db:local +system-db:site +system-db:distro + Is it the case that DConf User profile does not exist or is not configured correctly? + + + + To verify that the Dracut FIPS module is enabled, run the following command: +grep "add_dracutmodules" /etc/dracut.conf.d/40-fips.conf +The output should look like this: +add_dracutmodules+=" fips " + Is it the case that the Dracut FIPS module is not enabled? + + + + To verify that FIPS mode is enabled properly, run the following command: +cat /proc/sys/crypto/fips_enabled +The output be must: +1 + Is it the case that FIPS mode is not enabled? + + + + Check the system partitions to determine if they are encrypted with the following command: +blkid + +Output will be similar to: +/dev/sda1: UUID=" ab12c3de-4f56-789a-8f33-3850cc8ce3a2 +" TYPE="crypto_LUKS" +/dev/sda2: UUID=" bc98d7ef-6g54-321h-1d24-9870de2ge1a2 +" TYPE="crypto_LUKS" + +The boot partition and pseudo-file systems, such as /proc, /sys, and tmpfs, +are not required to use disk encryption and are not a finding. + Is it the case that partitions do not have a type of crypto_LUKS? + + + + To verify that EPEL repository is not enabled, run the following commands: +$ grep -r "^\[.*epel.*\]" /etc/yum.repos.d/ +For each EPEL repository found, check if it is enabled: +$ grep -A 5 "^\[.*epel.*\]" /etc/yum.repos.d/*.repo | grep "enabled" +The output should show enabled=0 for all EPEL repositories, or no EPEL repositories +should be present. + Is it the case that EPEL repository is enabled? + + + + Verify that yum verifies the signature of packages from a repository prior to install with the following command: + +$ grep gpgcheck /etc/yum.conf + +gpgcheck=1 + +If "gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates that is approved by the organization? + + + + Verify that yum verifies the signature of local packages prior to install with the following command: + +$ grep localpkg_gpgcheck /etc/yum.conf + +localpkg_gpgcheck=1 + +If "localpkg_gpgcheck" is not set to "1", or if the option is missing or commented out, ask the System Administrator how the certificates for patches and other operating system components are verified. + Is it the case that there is no process to validate certificates for local packages that is approved by the organization? + + + + To determine whether yum has been configured to disable +gpgcheck for any repos, inspect all files in +/etc/yum.repos.d and ensure the following does not appear in any +sections: +gpgcheck=0 +A value of 0 indicates that gpgcheck has been disabled for that repo. + Is it the case that GPG checking is disabled? + + + + To determine the status and frequency of logrotate, run the following command: +$ sudo grep logrotate /var/log/cron* +If logrotate is configured properly, output should include references to +/etc/cron.daily. + Is it the case that logrotate is not configured to run daily? + + + + To ensure that the GPG key is installed, run: +$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey +The command should return the string below: +gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> + Is it the case that the Oracle GPG Key is not installed? + + + + Run the following command to check if the group exists: +grep /etc/group +The output should contain the following line: +:x: + Is it the case that group exists and has no user members? + + + + root password is not set + Is it the case that Perform the following to determine if a password is set for the +root user: +<pre># grep -Eq '^root:\$[0-9]' /etc/shadow || echo "root is locked"</pre> +No results should be returned. +Otherwise, run the following command and follow the prompts to set a +password for the root user: +<pre># passwd root</pre>? + + + + To verify /etc/system-fips exists, run the following command: +ls -l /etc/system-fips +The output should be similar to the following: +-rw-r--r--. 1 root root 36 Nov 26 11:31 /etc/system-fips + Is it the case that /etc/system-fips does not exist? + + + + Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. + +Check that "fapolicyd" is in enforcement mode with the following command: + +$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf + +permissive = 0 + +Check that fapolicyd employs a deny-all policy on system mounts with the following commands: +$ sudo tail /etc/fapolicyd/compiled.rules + +allow exe=/usr/bin/python3.7 : ftype=text/x-python +deny_audit perm=any pattern=ld_so : all +deny perm=any all : all + Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? + + + + The file /etc/at.deny should not exist. +This can be checked by running the following + +stat /etc/at.deny + +and the output should be + +stat: cannot stat `/etc/at.deny': No such file or directory + + Is it the case that the file /etc/at.deny exists? + + + + Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the group-owner of each audit tool by running the following command: + +$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not group-owned by root? + + + + Verify the audit tools are owned by "root" to prevent any unauthorized access, deletion, or modification. + +Check the owner of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + +root /sbin/auditctl +root /sbin/aureport +root /sbin/ausearch +root /sbin/autrace +root /sbin/auditd +root /sbin/rsyslogd +root /sbin/augenrules + Is it the case that any audit tools are not owned by root? + + + + Verify the audit tools are protected from unauthorized access, deletion, or modification by checking the permissive mode. + +Check the octal permission of each audit tool by running the following command: + +$ sudo stat -c "%U %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules + Is it the case that any of these files have more permissive permissions than 0755? + + + + The file /etc/cron.deny should not exist. +This can be checked by running the following + +stat /etc/cron.deny + +and the output should be + +stat: cannot stat `/etc/cron.deny': No such file or directory + + Is it the case that the file /etc/cron.deny exists? + + + + Check group owners of the system audit logs. + +First, determine where the audit log file is located. + +$ sudo grep -iw ^log_file /etc/audit/auditd.conf +log_file = /var/log/audit/audit.log + +The log_file option specifies the audit log file path. +If the log_file option isn't defined, check all files within /var/log/audit directory. + + +Then, determine the audit log group by running the following command: +$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf + + +Then, check that the audit log file is owned by the correct group. +Run the following command to display the owner of the audit log file: + +$ sudo stat -c "%n %G" log_file + + +The audit log file must be owned by the log_group or by root if the log_group is not specified. + Is it the case that audit log files are owned by incorrect group? + + + + To check the group ownership of /etc/at.allow, +run the command: +$ ls -lL /etc/at.allow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/at.allow does not have a group owner of +root +? + + + + To check the group ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/group- does not have a group owner of +root +? + + + + To check the group ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/gshadow- does not have a group owner of +root +? + + + + To check the group ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/passwd- does not have a group owner of +root +? + + + + To check the group ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shadow- does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.allow does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.d does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.daily does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.deny does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.hourly does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.monthly, +run the command: +$ ls -lL /etc/cron.monthly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.monthly does not have a group owner of +root +? + + + + To check the group ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/cron.weekly does not have a group owner of +root +? + + + + To check the group ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/crontab does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/user.cfg does not have a group owner of +root +? + + + + To check the group ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following group-owner: + + chrony + + Is it the case that /etc/chrony.keys does not have a group owner of +chrony +? + + + + To check the group ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/crypttab does not have a group owner of +root +? + + + + To check the group ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/group does not have a group owner of +root +? + + + + To check the group ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/gshadow does not have a group owner of +root +? + + + + To check the group ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.conf does not have a group owner of +root +? + + + + To check the group ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ipsec.secrets does not have a group owner of +root +? + + + + To check the group ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/issue.net does not have a group owner of +root +? + + + + To check the group ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/passwd does not have a group owner of +root +? + + + + To check the group ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sestatus.conf does not have a group owner of +root +? + + + + To check the group ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shadow does not have a group owner of +root +? + + + + To check the group ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/shells does not have a group owner of +root +? + + + + To check the group ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/sudoers does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/grub.cfg does not have a group owner of +root +? + + + + To check the group ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/sshd_config does not have a group owner of +root +? + + + + To check the group ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/System.map* does not have a group owner of +root +? + + + + To check the group ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /boot/grub2/user.cfg does not have a group owner of +root +? + + + + To check the group ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /var/log does not have a group owner of +root +? + + + + To check the group ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /var/log/messages does not have a group owner of +root +? + + + + To check the group ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following group-owner: + + adm + + Is it the case that /var/log/syslog does not have a group owner of +adm +? + + + + +To properly set the group owner of /etc/audit/, run the command: + + $ sudo chgrp root /etc/audit/ + + + +To properly set the group owner of /etc/audit/rules.d/, run the command: + + $ sudo chgrp root /etc/audit/rules.d/ + + Is it the case that ? + + + + To verify the assigned home directory of all interactive users is group- +owned by that users primary GID, run the following command: +# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) + Is it the case that the group ownership is incorrect? + + + + To check the group ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/*_key does not have a group owner of +root +? + + + + To check the group ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following group-owner: + + root + + Is it the case that /etc/ssh/*.pub does not have a group owner of +root +? + + + + Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; + Is it the case that any system commands are returned and is not group-owned by a required system account? + + + + To check the ownership of /etc/group-, +run the command: +$ ls -lL /etc/group- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group- does not have an owner of root? + + + + To check the ownership of /etc/gshadow-, +run the command: +$ ls -lL /etc/gshadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow- does not have an owner of root? + + + + To check the ownership of /etc/passwd-, +run the command: +$ ls -lL /etc/passwd- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd- does not have an owner of root? + + + + To check the ownership of /etc/shadow-, +run the command: +$ ls -lL /etc/shadow- +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow- does not have an owner of root? + + + + To check the ownership of /etc/cron.allow, +run the command: +$ ls -lL /etc/cron.allow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.allow does not have an owner of root? + + + + To check the ownership of /etc/cron.d, +run the command: +$ ls -lL /etc/cron.d +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.d does not have an owner of root? + + + + To check the ownership of /etc/cron.daily, +run the command: +$ ls -lL /etc/cron.daily +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.daily does not have an owner of root? + + + + To check the ownership of /etc/cron.deny, +run the command: +$ ls -lL /etc/cron.deny +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.deny does not have an owner of root? + + + + To check the ownership of /etc/cron.hourly, +run the command: +$ ls -lL /etc/cron.hourly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.hourly does not have an owner of root? + + + + To check the ownership of /etc/cron.monthly, +run the command: +$ ls -lL /etc/cron.monthly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.monthly does not have an owner of root? + + + + To check the ownership of /etc/cron.weekly, +run the command: +$ ls -lL /etc/cron.weekly +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/cron.weekly does not have an owner of root? + + + + To check the ownership of /etc/crontab, +run the command: +$ ls -lL /etc/crontab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crontab does not have an owner of root? + + + + To check the ownership of /etc/chrony.keys, +run the command: +$ ls -lL /etc/chrony.keys +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/chrony.keys does not have an owner of root? + + + + To check the ownership of /etc/crypttab, +run the command: +$ ls -lL /etc/crypttab +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/crypttab does not have an owner of root? + + + + To check the ownership of /etc/group, +run the command: +$ ls -lL /etc/group +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/group does not have an owner of root? + + + + To check the ownership of /etc/gshadow, +run the command: +$ ls -lL /etc/gshadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/gshadow does not have an owner of root? + + + + To check the ownership of /etc/ipsec.conf, +run the command: +$ ls -lL /etc/ipsec.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.conf does not have an owner of root? + + + + To check the ownership of /etc/ipsec.secrets, +run the command: +$ ls -lL /etc/ipsec.secrets +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ipsec.secrets does not have an owner of root? + + + + To check the ownership of /etc/issue.net, +run the command: +$ ls -lL /etc/issue.net +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/issue.net does not have an owner of root? + + + + To check the ownership of /etc/passwd, +run the command: +$ ls -lL /etc/passwd +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/passwd does not have an owner of root? + + + + To check the ownership of /etc/sestatus.conf, +run the command: +$ ls -lL /etc/sestatus.conf +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sestatus.conf does not have an owner of root? + + + + To check the ownership of /etc/shadow, +run the command: +$ ls -lL /etc/shadow +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shadow does not have an owner of root? + + + + To check the ownership of /etc/shells, +run the command: +$ ls -lL /etc/shells +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/shells does not have an owner of root? + + + + To check the ownership of /etc/sudoers, +run the command: +$ ls -lL /etc/sudoers +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/sudoers does not have an owner of root? + + + + To check the ownership of /boot/grub2/grub.cfg, +run the command: +$ ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/grub.cfg does not have an owner of root? + + + + To check the ownership of /etc/ssh/sshd_config, +run the command: +$ ls -lL /etc/ssh/sshd_config +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/sshd_config does not have an owner of root? + + + + To check the ownership of /boot/System.map*, +run the command: +$ ls -lL /boot/System.map* +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/System.map* does not have an owner of root? + + + + To check the ownership of /boot/grub2/user.cfg, +run the command: +$ ls -lL /boot/grub2/user.cfg +If properly configured, the output should indicate the following owner: +root + Is it the case that /boot/grub2/user.cfg does not have an owner of root? + + + + To check the ownership of /var/log, +run the command: +$ ls -lL /var/log +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log does not have an owner of root? + + + + To check the ownership of /var/log/messages, +run the command: +$ ls -lL /var/log/messages +If properly configured, the output should indicate the following owner: +root + Is it the case that /var/log/messages does not have an owner of root? + + + + To check the ownership of /var/log/syslog, +run the command: +$ ls -lL /var/log/syslog +If properly configured, the output should indicate the following owner: +syslog + Is it the case that /var/log/syslog does not have an owner of syslog? + + + + +To properly set the owner of /etc/audit/, run the command: + + $ sudo chown root /etc/audit/ + + + +To properly set the owner of /etc/audit/rules.d/, run the command: + + $ sudo chown root /etc/audit/rules.d/ + + Is it the case that ? + + + + Verify the system commands contained in the following directories are owned by "root" with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; + Is it the case that any system commands are found to not be owned by root? + + + + Verify the system-wide shared library files are owned by "root" with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -user root -exec ls -l {} \; + Is it the case that any system wide shared library file is not owned by root? + + + + To check the ownership of /etc/ssh/*_key, +run the command: +$ ls -lL /etc/ssh/*_key +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*_key does not have an owner of root? + + + + To check the ownership of /etc/ssh/*.pub, +run the command: +$ ls -lL /etc/ssh/*.pub +If properly configured, the output should indicate the following owner: +root + Is it the case that /etc/ssh/*.pub does not have an owner of root? + + + + +To properly set the owner of /var/log/audit, run the command: + + $ sudo chown root /var/log/audit + + + +To properly set the owner of /var/log/audit/*, run the command: + + $ sudo chown root /var/log/audit/* + + Is it the case that ? + + + + To verify that all user initialization files have a mode of 0740 or +less permissive, run the following command: +$ sudo find /home -type f -name '\.*' \( -perm -0002 -o -perm -0020 \) +There should be no output. + Is it the case that they are not 0740 or more permissive? + + + + To check the permissions of /etc/at.allow, +run the command: +$ ls -l /etc/at.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/at.allow does not have unix mode -rw-r-----? + + + + +To properly set the permissions of /etc/audit/, run the command: +$ sudo chmod 0640 /etc/audit/ + +To properly set the permissions of /etc/audit/rules.d/, run the command: +$ sudo chmod 0640 /etc/audit/rules.d/ + Is it the case that ? + + + + To check the permissions of /etc/group-, +run the command: +$ ls -l /etc/group- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group- does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/gshadow-, +run the command: +$ ls -l /etc/gshadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow- does not have unix mode ----------? + + + + To check the permissions of /etc/passwd-, +run the command: +$ ls -l /etc/passwd- +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd- does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/shadow-, +run the command: +$ ls -l /etc/shadow- +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow- does not have unix mode ----------? + + + + Verify the system commands contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin -perm /022 -exec ls -l {} \; + Is it the case that any system commands are found to be group-writable or world-writable? + + + + To check the permissions of /etc/cron.allow, +run the command: +$ ls -l /etc/cron.allow +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/cron.allow does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/cron.d, +run the command: +$ ls -l /etc/cron.d +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.d does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.daily, +run the command: +$ ls -l /etc/cron.daily +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.daily does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.hourly, +run the command: +$ ls -l /etc/cron.hourly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.hourly does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.monthly, +run the command: +$ ls -l /etc/cron.monthly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.monthly does not have unix mode -rwx------? + + + + To check the permissions of /etc/cron.weekly, +run the command: +$ ls -l /etc/cron.weekly +If properly configured, the output should indicate the following permissions: +-rwx------ + Is it the case that /etc/cron.weekly does not have unix mode -rwx------? + + + + To check the permissions of /etc/crontab, +run the command: +$ ls -l /etc/crontab +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/crontab does not have unix mode -rw-------? + + + + To check the permissions of /etc/audit/auditd.conf, +run the command: +$ ls -l /etc/audit/auditd.conf +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/audit/rules.d/*.rules, +run the command: +$ ls -l /etc/audit/rules.d/*.rules +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/audit/rules.d/*.rules does not have unix mode -rw-------? + + + + To check the permissions of /etc/chrony.keys, +run the command: +$ ls -l /etc/chrony.keys +If properly configured, the output should indicate the following permissions: +0640 + Is it the case that /etc/chrony.keys does not have unix mode 0640? + + + + To check the permissions of /etc/crypttab, +run the command: +$ ls -l /etc/crypttab +If properly configured, the output should indicate the following permissions: +0600 + Is it the case that /etc/crypttab does not have unix mode 0600? + + + + To check the permissions of /etc/group, +run the command: +$ ls -l /etc/group +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/group does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/gshadow, +run the command: +$ ls -l /etc/gshadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/gshadow does not have unix mode ----------? + + + + To check the permissions of /etc/ipsec.conf, +run the command: +$ ls -l /etc/ipsec.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.conf does not have unix mode 0644? + + + + To check the permissions of /etc/ipsec.secrets, +run the command: +$ ls -l /etc/ipsec.secrets +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/ipsec.secrets does not have unix mode 0644? + + + + To check the permissions of /etc/issue.net, +run the command: +$ ls -l /etc/issue.net +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/issue.net does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/passwd, +run the command: +$ ls -l /etc/passwd +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/passwd does not have unix mode -rw-r--r--? + + + + To check the permissions of /etc/sestatus.conf, +run the command: +$ ls -l /etc/sestatus.conf +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/sestatus.conf does not have unix mode 0644? + + + + To check the permissions of /etc/shadow, +run the command: +$ ls -l /etc/shadow +If properly configured, the output should indicate the following permissions: +---------- + Is it the case that /etc/shadow does not have unix mode ----------? + + + + To check the permissions of /etc/shells, +run the command: +$ ls -l /etc/shells +If properly configured, the output should indicate the following permissions: +0644 + Is it the case that /etc/shells does not have unix mode 0644? + + + + To check the permissions of /etc/sudoers, +run the command: +$ ls -l /etc/sudoers +If properly configured, the output should indicate the following permissions: +0440 + Is it the case that /etc/sudoers does not have unix mode 0440? + + + + To check the permissions of /boot/grub2/grub.cfg, run the command: +$ sudo ls -lL /boot/grub2/grub.cfg +If properly configured, the output should indicate the following +permissions: -rw------- + Is it the case that it does not? + + + + To verify the assigned home directory of all interactive user home directories +have a mode of 0750 or less permissive, run the following command: +$ sudo ls -l /home +Inspect the output for any directories with incorrect permissions. + Is it the case that they are more permissive? + + + + To ensure the user home directory is not group-writable or world-readable, run the following: +# ls -ld /home/USER + Is it the case that the user home directory is group-writable or world-readable? + + + + Verify the system-wide shared library files contained in the following directories have mode "755" or less permissive with the following command: + +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 -perm /022 -type f -exec ls -l {} \; + Is it the case that any system-wide shared library file is found to be group-writable or world-writable? + + + + To check the permissions of /etc/ssh/sshd_config, +run the command: +$ ls -l /etc/ssh/sshd_config +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /etc/ssh/sshd_config does not have unix mode -rw-------? + + + + To check the permissions of /etc/ssh/*_key, +run the command: +$ ls -l /etc/ssh/*_key +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /etc/ssh/*_key does not have unix mode -rw-r-----? + + + + To check the permissions of /etc/ssh/*.pub, +run the command: +$ ls -l /etc/ssh/*.pub +If properly configured, the output should indicate the following permissions: +-rw-r--r-- + Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? + + + + To check the permissions of /boot/System.map*, +run the command: +$ ls -l /boot/System.map* +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/System.map* does not have unix mode -rw-------? + + + + To find SGID files, run the following command: +$ sudo find / -xdev -type f -perm -2000 + Is it the case that there is output? + + + + To find SUID files, run the following command: +$ sudo find / -xdev -type f -perm -4000 + Is it the case that only authorized files appear in the output of the find command? + + + + To find world-writable files, run the following command: +$ sudo find / -xdev -type f -perm -002 + Is it the case that there is output? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid group: +$ sudo find MOUNTPOINT -xdev -nogroup 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid group should be located. + Is it the case that there is output? + + + + To check the permissions of /boot/grub2/user.cfg, +run the command: +$ ls -l /boot/grub2/user.cfg +If properly configured, the output should indicate the following permissions: +-rw------- + Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? + + + + To check the permissions of /var/log, +run the command: +$ ls -l /var/log +If properly configured, the output should indicate the following permissions: +drwxr-xr-x + Is it the case that /var/log does not have unix mode drwxr-xr-x? + + + + Run the following command to check the mode of the system audit logs: +$ sudo grep -iw log_file /etc/audit/auditd.conf +log_file=/var/log/audit/audit.log +$ sudo stat -c "%n %a" /var/log/audit/* +$ sudo ls -l /var/log/audit +Audit logs must be mode 0640 or less permissive. + Is it the case that any permissions are more permissive? + + + + To check the permissions of /var/log/messages, +run the command: +$ ls -l /var/log/messages +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /var/log/messages does not have unix mode -rw-r-----? + + + + To check the permissions of /var/log/syslog, +run the command: +$ ls -l /var/log/syslog +If properly configured, the output should indicate the following permissions: +-rw-r----- + Is it the case that /var/log/syslog does not have unix mode -rw-r-----? + + + + Validate all files are symlinks to pointing to /usr/share/crypto-policies/FIPS/ except for +nss.config: + +$ stat -c%N /etc/crypto-policies/back-ends/* +'/etc/crypto-policies/back-ends/bind.config' -> '/usr/share/crypto-policies/FIPS/bind.txt' +'/etc/crypto-policies/back-ends/gnutls.config' -> '/usr/share/crypto-policies/FIPS/gnutls.txt' +'/etc/crypto-policies/back-ends/java.config' -> '/usr/share/crypto-policies/FIPS/java.txt' +'/etc/crypto-policies/back-ends/javasystem.config' -> '/usr/share/crypto-policies/FIPS/javasystem.txt' +'/etc/crypto-policies/back-ends/krb5.config' -> '/usr/share/crypto-policies/FIPS/krb5.txt' +'/etc/crypto-policies/back-ends/libreswan.config' -> '/usr/share/crypto-policies/FIPS/libreswan.txt' +'/etc/crypto-policies/back-ends/libssh.config' -> '/usr/share/crypto-policies/FIPS/libssh.txt' +'/etc/crypto-policies/back-ends/nss.config' +'/etc/crypto-policies/back-ends/openssh.config' -> '/usr/share/crypto-policies/FIPS/openssh.txt' +'/etc/crypto-policies/back-ends/opensshserver.config' -> '/usr/share/crypto-policies/FIPS/opensshserver.txt' +'/etc/crypto-policies/back-ends/opensslcnf.config' -> '/usr/share/crypto-policies/FIPS/opensslcnf.txt' +'/etc/crypto-policies/back-ends/openssl.config' -> '/usr/share/crypto-policies/FIPS/openssl.txt' +'/etc/crypto-policies/back-ends/openssl_fips.config' -> '/usr/share/crypto-policies/FIPS/openssl_fips.txt' + + Is it the case that Any file shows a different output? + + + + Verify "nftables" is configured to allow rate limits on any connection to the system with the following command: + +Verify "firewalld" has "nftables" set as the default backend: + +$ sudo grep -i firewallbackend /etc/firewalld/firewalld.conf + +# FirewallBackend +FirewallBackend=nftables + Is it the case that the "nftables" is not set as the "firewallbackend"? + + + + Inspect the firewalld trusted and default zones and verify the loopback traffic is restricted +to the lo interface by running the following command: + +$ sudo firewall-cmd --list-rich-rules --zone=trusted + +The following rich-rules should be listed: + +rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop +rule family="ipv6" source address="::1" destination not address="127.0.0.1" drop + + Is it the case that loopback traffic is not restricted? + + + + Inspect the network interfaces assigned to the firewalld trusted zone and verify the +lo interface is listed by running the following command: + +$ sudo firewall-cmd --list-interfaces --zone=trusted + Is it the case that loopback traffic is not trusted? + + + + + + +To determine if firewalld is configured to allow access + +on port 22/tcp, run the following command(s): + firewall-cmd --list-ports + + +to ssh + firewall-cmd --list-services + +If firewalld is configured to allow access through the firewall, something similar to the following will be output: + +If it is a service: +ssh + + +If it is a port: +22/tcp + + Is it the case that sshd service is not enabled in the proper firewalld zone? + + + + To ensure all GIDs referenced in /etc/passwd are defined in /etc/group, +run the following command: +$ sudo pwck -qr +There should be no output. + Is it the case that GIDs referenced in /etc/passwd are returned as not defined in /etc/group? + + + + To verify that automatic logins are disabled, run the following command: +$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf +The output should show the following: +[daemon] +AutomaticLoginEnable=false + Is it the case that GDM allows users to automatically login? + + + + To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: +grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf +The output should return the following: + +[xdmcp] +Enable=false + + Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? + + + + Run the following command to check for duplicate group names: +Check that the operating system contains no duplicate Group ID (GID) for interactive users by running the following command: + + cut -d : -f 3 /etc/group | uniq -d + +If output is produced, this is a finding. +Configure the operating system to contain no duplicate GIDs. +Edit the file "/etc/group" and provide each group that has a duplicate GID with a unique GID. + Is it the case that the system has duplicate group ids? + + + + To verify the boot loader superuser account has been set, run the following +command: +sudo grep -A1 "superusers" /boot/grub2/grub.cfg +The output should show the following: +set superusers="superusers-account" +export superusers +where superusers-account is the actual account name different from common names like root, +admin, or administrator and different from any other existing user name. + Is it the case that superuser account is not set or is set to root, admin, administrator or any other existing user name? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' +The command should not return any output. + Is it the case that auditing is not enabled at boot time? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes audit_backlog_limit=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=' +The command should not return any output. + Is it the case that audit backlog limit is not configured? + + + + Inspect /etc/default/grub for any instances of +systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. +Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates +that interactive boot is enabled at boot time and verify that +GRUB_DISABLE_RECOVERY=true to disable recovery boot. + Is it the case that Interactive boot is enabled at boot time? + + + + Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. +Run the following command: + +$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub + Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes iommu=force, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' +The command should not return any output. + Is it the case that I/OMMU is not activated? + + + + Inspect /etc/default/grub for any instances of selinux=0 +in the kernel boot arguments. Presence of selinux=0 indicates +that SELinux is disabled at boot time. + Is it the case that SELinux is disabled at boot time? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes init_on_alloc=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' +The command should not return any output. + Is it the case that the kernel is not configured to zero out memory before allocation? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes l1tf=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*l1tf=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*l1tf=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'l1tf=' +The command should not return any output. + Is it the case that l1tf mitigations are not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mce=0, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' +The command should not return any output. + Is it the case that MCE tolerance is not set to zero? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes mds=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mds=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*mds=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'mds=' +The command should not return any output. + Is it the case that MDS mitigations are not configured appropriately? + + + + Make sure that the kernel is not disabling SMAP with the following +commands. +grep -q nosmap /boot/config-`uname -r` +If the command returns a line, it means that SMAP is being disabled. + Is it the case that the kernel is configured to disable SMAP? + + + + Make sure that the kernel is not disabling SMEP with the following +commands. +grep -q nosmep /boot/config-`uname -r` +If the command returns a line, it means that SMEP is being disabled. + Is it the case that the kernel is configured to disable SMEP? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes page_alloc.shuffle=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_alloc.shuffle=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*page_alloc.shuffle=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'page_alloc.shuffle=1' +The command should not return any output. + Is it the case that randomization of the page allocator is not enabled in the kernel? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes page_poison=1, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' +The command should not return any output. + Is it the case that page allocator poisoning is not enabled? + + + + First, check whether the password is defined in either /boot/grub2/user.cfg or +/boot/grub2/grub.cfg. +Run the following commands: +$ sudo grep '^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$' /boot/grub2/user.cfg +$ sudo grep '^[\s]*password_pbkdf2[\s]+.*[\s]+grub\.pbkdf2\.sha512.*$' /boot/grub2/grub.cfg + + +Second, check that a superuser is defined in /boot/grub2/grub.cfg. +$ sudo grep '^[\s]*set[\s]+superusers=("?)[a-zA-Z_]+\1$' /boot/grub2/grub.cfg + Is it the case that it does not produce any output? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes pti=on, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' +The command should not return any output. + Is it the case that Kernel page-table isolation is not enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes rng_core.default_quality=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*rng_core.default_quality=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*rng_core.default_quality=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'rng_core.default_quality=' +The command should not return any output. + Is it the case that trust on hardware random number generator is not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slab_nomerge=yes, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slab_nomerge=yes.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slab_nomerge=yes.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slab_nomerge=yes' +The command should not return any output. + Is it the case that merging of slabs with similar size is enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes slub_debug=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*slub_debug=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*slub_debug=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'slub_debug=' +The command should not return any output. + Is it the case that SLUB/SLAB poisoning is not enabled? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes spec_store_bypass_disable=, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' +The command should not return any output. + Is it the case that SSB is not configured appropriately? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes spectre_v2=on, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spectre_v2=on.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*spectre_v2=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'spectre_v2=on' +The command should not return any output. + Is it the case that spectre_v2 mitigation is not enforced? + + + + Ensure that debug-shell service is not enabled with the following command: +grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub +If the command returns a line, it means that debug-shell service is being enabled. + Is it the case that the command returns a line? + + + + Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes vsyscall=none, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*vsyscall=none.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*vsyscall=none.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'vsyscall=none' +The command should not return any output. + Is it the case that vsyscalls are enabled? + + + + To verify if the OpenSSH Client uses defined Crypto Policy, run: +$ cat /etc/ssh/ssh_config.d/02-ospp.conf +and verify that the line matches +Match final all +RekeyLimit 512M 1h +GSSAPIAuthentication no +Ciphers aes256-ctr,aes256-cbc,aes128-ctr,aes128-cbc +PubkeyAcceptedKeyTypes ssh-rsa,ecdsa-sha2-nistp384,ecdsa-sha2-nistp256 +MACs hmac-sha2-512,hmac-sha2-256 +KexAlgorithms ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group14-sha1 + Is it the case that Crypto Policy for OpenSSH Client is not configured according to CC requirements? + + + + To verify if the OpenSSH client uses defined Cipher suite in the Crypto Policy, run: +$ grep -i ciphers /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +Ciphers + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: +$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oCiphers= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + To verify if the OpenSSH client uses defined MACs in the Crypto Policy, run: +$ grep -i macs /etc/crypto-policies/back-ends/openssh.config +and verify that the line matches: +MACs + Is it the case that Crypto Policy for OpenSSH client is not configured correctly? + + + + To verify if the OpenSSH server uses defined MACs in the Crypto Policy, run: +$ grep -Po '(-oMACs=\S+)' /etc/crypto-policies/back-ends/opensshserver.config +and verify that the line matches: +-oMACS= + Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? + + + + Check that Oracle Linux 9 has the packages for smart card support installed. + +Run the following command to determine if the openssl-pkcs11 package is installed: +$ rpm -q openssl-pkcs11 + Is it the case that smartcard software is not installed? + + + + To verify that the installed operating system is supported, run +the following command: + +$ grep -i "oracle" /etc/oracle-release + +Oracle Linux 9 + Is it the case that the installed operating system is not supported? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ACPI_CUSTOM_METHOD /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BINFMT_MISC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_BRK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_COMPAT_VDSO /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_CREDENTIALS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_FS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_LIST /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_NOTIFIERS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_SG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEBUG_WX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: +$ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* +For each kernel installed, a line with value should be returned. +If the system architecture is x86_64, the value should be 65536. +If the system architecture is aarch64, the value should be 32768. + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_DEVKMEM /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_FORTIFY_SOURCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_LATENT_ENTROPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_RANDSTRUCT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STACKLEAK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HARDENED_USERCOPY_FALLBACK /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_HIBERNATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_IA32_EMULATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_IPV6 /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_KEXEC /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_PTYS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_NONE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_LEGACY_VSYSCALL_XONLY /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODIFY_LDT_SYSCALL /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_ALL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? @@ -258541,13 +282921,1405 @@ If the system is configured to audit this activity, it will return a line. Is it the case that the kernel was not built with the required value? - - The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_local -0. + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_KEY /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_MODULE_SIG_SHA512 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_ON_OOPS /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PANIC_TIMEOUT /boot/config.* + + For each kernel installed, a line with value "" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_PROC_KCORE /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_BASE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RANDOMIZE_MEMORY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_REFCOUNT_FULL /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_RETPOLINE /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SCHED_STACK_END_CHECK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECCOMP_FILTER /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_DMESG_RESTRICT /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_WRITABLE_HOOKS /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SECURITY_YAMA /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_HARDENED /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_FREELIST_RANDOM /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLAB_MERGE_DEFAULT /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SLUB_DEBUG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STACKPROTECTOR_STRONG /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_KERNEL_WRX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_STRICT_MODULE_RWX /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_SYN_COOKIES /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_VMAP_STACK /boot/config.* + + For each kernel installed, a line with value "y" should be returned. + + Is it the case that the kernel was not built with the required value? + + + + To determine the config value the kernel was built with, run the following command: + $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* + + Configs with value 'n' are not explicitly set in the file, so either commented lines or no + lines should be returned. + + Is it the case that the kernel was not built with the required value? + + + + +If the system is configured to prevent the loading of the atm kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - Is it the case that the correct value is not returned? +These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r atm /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the bluetooth kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the bluetooth kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r bluetooth /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the can kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r can /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the cramfs kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the cramfs kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r cramfs /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the dccp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the dccp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r dccp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the firewire-core kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the firewire-core kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r firewire-core /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to disable the +ipv6 kernel module, it will contain a line +of the form: +options ipv6 disable=1 +Such lines may be inside any file in /etc/modprobe.d or the +deprecated/etc/modprobe.conf. This permits insertion of the IPv6 +kernel module (which other parts of the system expect to be present), but +otherwise keeps it inactive. Run the following command to search for such +lines in all files in /etc/modprobe.d and the deprecated +/etc/modprobe.conf: +$ grep -r ipv6 /etc/modprobe.conf /etc/modprobe.d + Is it the case that the ipv6 kernel module is not disabled? + + + + +If the system is configured to prevent the loading of the rds kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the rds kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r rds /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the sctp kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the tipc kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the tipc kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r tipc /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + +If the system is configured to prevent the loading of the usb-storage kernel module, +it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. +These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + +These lines can also instruct the module loading system to ignore the usb-storage kernel module via blacklist keyword. + +Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: +$ grep -r usb-storage /etc/modprobe.conf /etc/modprobe.d + Is it the case that no line is returned? + + + + If the device or Oracle Linux 9 does not have a camera installed, this requirement is not applicable. + +This requirement is not applicable to mobile devices (smartphones and tablets), where the use of the camera is a local AO decision. + +This requirement is not applicable to dedicated VTC suites located in approved VTC locations that are centrally managed. + +For an external camera, if there is not a method for the operator to manually disconnect the camera at the end of collaborative computing sessions, this is a finding. + +For a built-in camera, the camera must be protected by a camera cover (e.g., laptop camera cover slide) when not in use. If the built-in camera is not protected with a camera cover, or is not physically disabled, this is a finding. + +If the camera is not disconnected, covered, or physically disabled, determine if it is being disabled via software with the following commands: + +Verify the operating system disables the ability to load the uvcvideo kernel module. + +$ sudo grep -r uvcvideo /etc/modprobe.d/* | grep "/bin/true" + +install uvcvideo /bin/true + Is it the case that the command does not return any output, or the line is commented out, and the collaborative computing device has not been authorized for use? + + + + Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. + + +# yum list installed libreswan +libreswan.x86-64 3.20-5.el7_4 + + +If "libreswan" is installed, check to see if the "IPsec" service is active with the following command: + +# systemctl status ipsec +ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec +Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) +Active: inactive (dead) + + +If the "IPsec" service is active, check for configured IPsec connections (conn), perform the following: +grep -rni conn /etc/ipsec.conf /etc/ipsec.d/ +Verify any returned results for organizational approval. + Is it the case that the IPSec tunnels are not approved? + + + + Display the contents of the file /etc/systemd/logind.conf: +cat /etc/systemd/logind.conf +Ensure that there is a section [login] which contains the +configuration StopIdleSessionSec=. + Is it the case that the option is not configured? + + + + Verify the nosuid option is configured for the /boot/efi mount point, + run the following command: + $ sudo mount | grep '\s/boot/efi\s' + . . . /boot/efi . . . nosuid . . . + + Is it the case that the "/boot/efi" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nodev . . . + + Is it the case that the "/boot" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . noexec . . . + + Is it the case that the "/boot" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /boot mount point, + run the following command: + $ sudo mount | grep '\s/boot\s' + . . . /boot . . . nosuid . . . + + Is it the case that the "/boot" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nodev . . . + + Is it the case that the "/dev/shm" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . noexec . . . + + Is it the case that the "/dev/shm" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /dev/shm mount point, + run the following command: + $ sudo mount | grep '\s/dev/shm\s' + . . . /dev/shm . . . nosuid . . . + + Is it the case that the "/dev/shm" file system does not have the "nosuid" option set? + + + + Verify the grpquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . grpquota . . . + + Is it the case that the "/home" file system does not have the "grpquota" option set? + + + + Verify the nodev option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nodev . . . + + Is it the case that the "/home" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . noexec . . . + + Is it the case that the "/home" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . nosuid . . . + + Is it the case that the "/home" file system does not have the "nosuid" option set? + + + + Verify the usrquota option is configured for the /home mount point, + run the following command: + $ sudo mount | grep '\s/home\s' + . . . /home . . . usrquota . . . + + Is it the case that the "/home" file system does not have the "usrquota" option set? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ mount | grep "sec=" +All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + To verify the nodev option is configured for non-root local partitions, run the following command: +$ sudo mount | grep '^/dev\S* on /\S' | grep --invert-match 'nodev' +The output shows local non-root partitions mounted without the nodev option, and there should be no output at all. + + Is it the case that some mounts appear among output lines? + + + + To verify the nodev option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nodev setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? + + + + To verify the noexec option is configured for all NFS mounts, run the following command: +$ mount | grep nfs +All NFS mounts should show the noexec setting in parentheses. This is not applicable if NFS is +not implemented. + Is it the case that the setting does not show? + + + + To verify that binaries cannot be directly executed from removable media, run the following command: +$ grep -v noexec /etc/fstab +The resulting output will show partitions which do not have the noexec flag. Verify all partitions +in the output are not removable media. + Is it the case that removable media partitions are present? + + + + To verify the nosuid option is configured for all NFS mounts, run +the following command: +$ mount | grep nfs +All NFS mounts should show the nosuid setting in parentheses. This +is not applicable if NFS is not implemented. + Is it the case that the setting does not show? + + + + Verify file systems that are used for removable media are mounted with the "nosuid" option with the following command: + +$ sudo more /etc/fstab + +UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 + Is it the case that file system found in "/etc/fstab" refers to removable media and it does not have the "nosuid" option set? + + + + Verify the nosuid option is configured for the /opt mount point, + run the following command: + $ sudo mount | grep '\s/opt\s' + . . . /opt . . . nosuid . . . + + Is it the case that the "/opt" file system does not have the "nosuid" option set? + + + + Verify the nosuid option is configured for the /srv mount point, + run the following command: + $ sudo mount | grep '\s/srv\s' + . . . /srv . . . nosuid . . . + + Is it the case that the "/srv" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nodev . . . + + Is it the case that the "/tmp" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . noexec . . . + + Is it the case that the "/tmp" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /tmp mount point, + run the following command: + $ sudo mount | grep '\s/tmp\s' + . . . /tmp . . . nosuid . . . + + Is it the case that the "/tmp" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nodev . . . + + Is it the case that the "/var/log/audit" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . noexec . . . + + Is it the case that the "/var/log/audit" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/log/audit mount point, + run the following command: + $ sudo mount | grep '\s/var/log/audit\s' + . . . /var/log/audit . . . nosuid . . . + + Is it the case that the "/var/log/audit" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nodev . . . + + Is it the case that the "/var/log" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . noexec . . . + + Is it the case that the "/var/log" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/log mount point, + run the following command: + $ sudo mount | grep '\s/var/log\s' + . . . /var/log . . . nosuid . . . + + Is it the case that the "/var/log" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nodev . . . + + Is it the case that the "/var" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . noexec . . . + + Is it the case that the "/var" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var mount point, + run the following command: + $ sudo mount | grep '\s/var\s' + . . . /var . . . nosuid . . . + + Is it the case that the "/var" file system does not have the "nosuid" option set? + + + + Verify the nodev option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nodev . . . + + Is it the case that the "/var/tmp" file system does not have the "nodev" option set? + + + + Verify the noexec option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . noexec . . . + + Is it the case that the "/var/tmp" file system does not have the "noexec" option set? + + + + Verify the nosuid option is configured for the /var/tmp mount point, + run the following command: + $ sudo mount | grep '\s/var/tmp\s' + . . . /var/tmp . . . nosuid . . . + + Is it the case that the "/var/tmp" file system does not have the "nosuid" option set? + + + + Verify that DNS servers have been configured properly, perform the following: +$ sudo grep nameserver /etc/resolv.conf + Is it the case that less than two lines are returned that are not commented out? + + + + Using a non-privileged account, verify that users cannot modify or change +network settings with the nmcli command with the following command: +$ nmcli general permissions +The output should contain the following: +PERMISSION VALUE +org.freedesktop.NetworkManager.enable-disable-network auth +org.freedesktop.NetworkManager.enable-disable-wifi auth +org.freedesktop.NetworkManager.enable-disable-wwan auth +org.freedesktop.NetworkManager.enable-disable-wimax auth +org.freedesktop.NetworkManager.sleep-wake auth +org.freedesktop.NetworkManager.network-control auth +org.freedesktop.NetworkManager.wifi.share.protected auth +org.freedesktop.NetworkManager.wifi.share.open auth +org.freedesktop.NetworkManager.settings.modify.system auth +org.freedesktop.NetworkManager.settings.modify.own auth +org.freedesktop.NetworkManager.settings.modify.hostname auth +org.freedesktop.NetworkManager.settings.modify.global-dns auth +org.freedesktop.NetworkManager.reload auth +org.freedesktop.NetworkManager.checkpoint-rollback auth +org.freedesktop.NetworkManager.enable-disable-statistics auth +org.freedesktop.NetworkManager.enable-disable-connectivity-check auth +org.freedesktop.NetworkManager.wifi.scan auth + + Is it the case that non-privileged users can modify or change network settings? + + + + Verify that Promiscuous mode of an interface is disabled, run the following command: +$ ip link | grep PROMISC + Is it the case that any network device is in promiscuous mode? + + + + Verify that Oracle Linux 9 has a DNS mode configured in Network Manager. + +$ NetworkManager --print-config +[main] +dns= + Is it the case that the dns key under main does not exist or is not set to "none" or "default"? + + + + To verify all squashing has been disabled, run the following command: +$ grep all_squash /etc/exports + Is it the case that there is output? + + + + To ensure root may not directly login to the system over physical consoles, +run the following command: +cat /etc/securetty +If any output is returned, this is a finding. + Is it the case that the /etc/securetty file is not empty? + + + + To verify that null passwords cannot be used, run the following command: + +$ grep nullok /etc/pam.d/system-auth /etc/pam.d/password-auth + +If this produces any output, it may be possible to log into accounts +with empty passwords. Remove any instances of the nullok option to +prevent logins with empty passwords. + Is it the case that NULL passwords can be used? + + + + To verify that null passwords cannot be used, run the following command: +$ sudo awk -F: '!$2 {print $1}' /etc/shadow +If this produces any output, it may be possible to log into accounts +with empty passwords. + Is it the case that Blank or NULL passwords can be used? + + + + The following command will locate the mount points related to local devices: +$ findmnt -n -l -k -it $(awk '/nodev/ { print $2 }' /proc/filesystems | paste -sd,) + +The following command will show files which do not belong to a valid user: +$ sudo find MOUNTPOINT -xdev -nouser 2>/dev/null + +Replace MOUNTPOINT by the mount points listed by the fist command. + +No files without a valid user should be located. + Is it the case that files exist that are not owned by a valid user? + + + + Verify that there are no shosts.equiv files on the system, run the following command: +$ find / -name shosts.equiv + Is it the case that shosts.equiv files exist? + + + + To check the system for the existence of any .netrc files, +run the following command: +$ sudo find /home -xdev -name .netrc + Is it the case that any .netrc files exist? + + + + To obtain a list of all users and the content of their shadow password field, run the command: +$ sudo readarray -t systemaccounts +Verify if all accounts are locked. + Is it the case that system accounts are not locked? + + + + The existence of the file /etc/hosts.equiv or a file named +.rhosts inside a user home directory indicates the presence +of an Rsh trust relationship. + Is it the case that these files exist? + + + + To obtain a listing of all users, their UIDs, and their shells, run the command: +$ awk -F: '{print $1 ":" $3 ":" $7}' /etc/passwd +Identify the system accounts from this listing. These will primarily be the accounts with UID +numbers less than 1000, other than root. + Is it the case that any system account other than root has a login shell? + + + + To verify that there are no .shosts files +on the system, run the following command: +$ sudo find / -name '.shosts' + Is it the case that .shosts files exist? + + + + Run the following command to determine if the aide package is installed: $ rpm -q aide + Is it the case that the package is not installed? + + + + Run the following command to determine if the audispd-plugins package is installed: $ rpm -q audispd-plugins + Is it the case that the package is not installed? + + + + Run the following command to determine if the audit package is installed: $ rpm -q audit + Is it the case that the audit package is not installed? + + + + Run the following command to determine if the bind package is installed: +$ rpm -q bind + Is it the case that the package is installed? + + + + Run the following command to determine if the chrony package is installed: $ rpm -q chrony + Is it the case that the package is not installed? + + + + Run the following command to determine if the cronie package is installed: +$ rpm -q cronie + Is it the case that the package is installed? + + + + Run the following command to determine if the crypto-policies package is installed: $ rpm -q crypto-policies + Is it the case that the package is not installed? + + + + Run the following command to determine if the cryptsetup package is installed: $ rpm -q cryptsetup + Is it the case that the package is not installed? + + + + Run the following command to determine if the cyrus-imapd package is installed: +$ rpm -q cyrus-imapd + Is it the case that the package is installed? + + + + Run the following command to determine if the dhcp-server package is installed: +$ rpm -q dhcp-server + Is it the case that the package is installed? + + + + Run the following command to determine if the dnf-automatic package is installed: $ rpm -q dnf-automatic + Is it the case that the package is not installed? + + + + Run the following command to determine if the dovecot package is installed: +$ rpm -q dovecot + Is it the case that the package is installed? + + + + Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd + Is it the case that the fapolicyd package is not installed? + + + + Run the following command to determine if the firewalld package is installed: $ rpm -q firewalld + Is it the case that the package is not installed? + + + + The ftp package can be removed with the following command: $ sudo yum erase ftp + Is it the case that ? + + + + Run the following command to determine if the gnutls-utils package is installed: $ rpm -q gnutls-utils + Is it the case that the package is not installed? + + + + Run the following command to determine if the gssproxy package is installed: +$ rpm -q gssproxy + Is it the case that the package is installed? + + + + Run the following command to determine if the iprutils package is installed: +$ rpm -q iprutils + Is it the case that the package is installed? + + + + Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan + Is it the case that the package is not installed? + + + + Run the following command to determine if the libselinux package is installed: $ rpm -q libselinux + Is it the case that the package is not installed? + + + + Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate + Is it the case that the package is not installed? + + + + Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP + Is it the case that the package is not installed? + + + + Run the following command to determine if the net-snmp package is installed: +$ rpm -q net-snmp + Is it the case that the package is installed? + + + + Run the following command to determine if the nfs-utils package is installed: +$ rpm -q nfs-utils + Is it the case that the package is installed? + + + + Run the following command to determine if the nftables package is installed: $ rpm -q nftables + Is it the case that the package is not installed? + + + + Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools + Is it the case that the package is not installed? + + + + Run the following command to determine if the opensc package is installed: $ rpm -q opensc + Is it the case that the package is not installed? + + + + Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is not installed? + + + + Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server + Is it the case that the package is installed? + + + + Run the following command to determine if the pcsc-lite package is installed: $ rpm -q pcsc-lite + Is it the case that the package is not installed? + + + + Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils + Is it the case that the package is not installed? + + + + Run the following command to determine if the policycoreutils package is installed: $ rpm -q policycoreutils + Is it the case that the policycoreutils package is not installed? + + + + Run the following command to determine if the postfix package is installed: $ rpm -q postfix + Is it the case that the package is not installed? + + + + Run the following command to determine if the quagga package is installed: +$ rpm -q quagga + Is it the case that the package is installed? + + + + Run the following command to determine if the rear package is installed: $ rpm -q rear + Is it the case that the package is not installed? + + + + Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools + Is it the case that the package is not installed? + + + + Run the following command to determine if the rsyslog-gnutls package is installed: +$ rpm -q rsyslog-gnutls + Is it the case that the package is installed? + + + + Run the following command to determine if the rsyslog package is installed: $ rpm -q rsyslog + Is it the case that the package is not installed? + + + + Run the following command to determine if the s-nail package is installed: $ rpm -q s-nail + Is it the case that the package is not installed? + + + + Run the following command to determine if the scap-security-guide package is installed: $ rpm -q scap-security-guide + Is it the case that the package is not installed? + + + + Run the following command to determine if the sendmail package is installed: +$ rpm -q sendmail + Is it the case that the package is installed? + + + + Run the following command to determine if the setroubleshoot-plugins package is installed: +$ rpm -q setroubleshoot-plugins + Is it the case that the package is installed? + + + + Run the following command to determine if the setroubleshoot-server package is installed: +$ rpm -q setroubleshoot-server + Is it the case that the package is installed? + + + + Run the following command to determine if the squid package is installed: +$ rpm -q squid + Is it the case that the package is installed? + + + + Run the following command to determine if the sssd package is installed: $ rpm -q sssd + Is it the case that the package is not installed? + + + + Run the following command to determine if the sudo package is installed: $ rpm -q sudo + Is it the case that the package is not installed? + + + + Run the following command to determine if the syslog-ng-core package is installed: $ rpm -q syslog-ng-core + Is it the case that the package is not installed? + + + + Run the following command to determine if the telnet-server package is installed: +$ rpm -q telnet-server + Is it the case that the package is installed? + + + + The telnet package can be removed with the following command: $ sudo yum erase telnet + Is it the case that ? + + + + Run the following command to determine if the tftp-server package is installed: +$ rpm -q tftp-server + Is it the case that the package is installed? + + + + The tftp package can be removed with the following command: $ sudo yum erase tftp + Is it the case that ? + + + + Run the following command to determine if the tuned package is installed: +$ rpm -q tuned + Is it the case that the package is installed? + + + + Run the following command to determine if the usbguard package is installed: $ rpm -q usbguard + Is it the case that the package is not installed? + + + + Run the following command to determine if the vsftpd package is installed: +$ rpm -q vsftpd + Is it the case that the package is installed? + + + + To ensure the X Windows package group is removed, run the following command: +$ rpm -qi xorg-x11-server-common +The output should be: +package xorg-x11-server-common is not installed + Is it the case that the X Windows package group or xorg-x11-server-common has not be removed? + + + + Verify that a separate file system/partition has been created for /dev/shm with the following command: + +$ mountpoint /dev/shm + + Is it the case that "/dev/shm is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /home with the following command: + +$ mountpoint /home + + Is it the case that "/home is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /srv with the following command: + +$ mountpoint /srv + + Is it the case that "/srv is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /tmp with the following command: + +$ mountpoint /tmp + + Is it the case that "/tmp is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var with the following command: + +$ mountpoint /var + + Is it the case that "/var is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/log with the following command: + +$ mountpoint /var/log + + Is it the case that "/var/log is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/log/audit with the following command: + +$ mountpoint /var/log/audit + + Is it the case that "/var/log/audit is not a mountpoint" is returned? + + + + Verify that a separate file system/partition has been created for /var/tmp with the following command: + +$ mountpoint /var/tmp + + Is it the case that "/var/tmp is not a mountpoint" is returned? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the root user: +$ sudo postmap -q root hash:/etc/aliases +The output should return an alias. + Is it the case that the alias is not set? + + + + Find the list of alias maps used by the Postfix mail server: +$ sudo postconf alias_maps +Query the Postfix alias maps for an alias for the postmaster user: +$ sudo postmap -q postmaster hash:/etc/aliases +The output should return root. + Is it the case that the alias is not set or is not root? + + + + Run the following command to ensure postfix routes mail to this system: +$ grep relayhost /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it is not? + + + + Run the following command to ensure postfix accepts mail messages from only the local system: +$ grep inet_interfaces /etc/postfix/main.cf +If properly configured, the output should show only . + Is it the case that it does not? + + + + Verify that Oracle Linux 9 is configured to prevent unrestricted mail relaying, +run the following command: +$ sudo postconf -n smtpd_client_restrictions + Is it the case that the "smtpd_client_restrictions" parameter contains any entries other than "permit_mynetworks" and "reject"? + + + + To check if the installed Operating System is 64-bit, run the following command: +$ uname -m +The output should be one of the following: x86_64, aarch64, ppc64le or s390x. +If the output is i686 or i386 the operating system is 32-bit. +Check if the installed CPU supports 64-bit operating systems by running the following command: +$ lscpu | grep "CPU op-mode" +If the output contains 64bit, the CPU supports 64-bit operating systems. + Is it the case that the installed operating system is 32-bit but the CPU supports operation in 64-bit? + + + + To check if authentication is required for emergency mode, run the following command: +$ grep sulogin /usr/lib/systemd/system/emergency.service +The output should be similar to the following, and the line must begin with +ExecStart and /usr/lib/systemd/systemd-sulogin-shell. + ExecStart=-/usr/lib/systemd/systemd-sulogin-shell emergency + +Then, check if the emergency target requires the emergency service: +Run the following command: +$ sudo grep Requires /usr/lib/systemd/system/emergency.target +The output should be the following: +Requires=emergency.service + +Then, check if there is no custom emergency target configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.target /etc/systemd/system/ +The output should be empty. + +Then, check if there is no custom emergency service configured in systemd configuration. +Run the following command: +$ sudo grep -r emergency.service /etc/systemd/system/ +The output should be empty. + Is it the case that the output is different? @@ -258583,64 +284355,78 @@ There should be no output. Is it the case that the output is different? - - To ensure a login warning banner is enabled, run the following: -$ grep banner-message-enable /etc/dconf/db/local.d/* -If properly configured, the output should be true. -To ensure a login warning banner is locked and cannot be changed by a user, run the following: -$ grep banner-message-enable /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-enable. - Is it the case that it is not? + + To check for serial port entries which permit root login, +run the following command: +$ sudo grep ^ttyS/[0-9] /etc/securetty +If any output is returned, then root login over serial ports is permitted. + Is it the case that root login over serial ports is permitted? - - Verify the value of the "maxclassrepeat" option in "/etc/security/pwquality.conf" with the following command: + + Verify the system-wide shared library files are group-owned by root with the following command: -$ grep maxclassrepeat /etc/security/pwquality.conf +$ sudo find -L /lib /lib64 /usr/lib /usr/lib64 ! -group root -exec ls -l {} \; + Is it the case that any system wide shared library file is returned and is not group-owned by root? + + + + Verify that Oracle Linux 9 crypto-policies package has not been modified with the following command: +$ rpm -V crypto-policies +If the command has any output, this is a finding. + Is it the case that there is output? + + + + The following command will list which files on the system have file hashes different from what +is expected by the RPM database. +$ rpm -Va --noconfig | awk '$1 ~ /..5/' + Is it the case that there is output? + + + + The following command will list which files on the system have ownership different from what +is expected by the RPM database: +$ rpm -Va | rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }' + Is it the case that there is output? + + + + The following command will list which files on the system have permissions different from what +is expected by the RPM database: +$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' + Is it the case that there is output? + + + + Verify that cron is logging to rsyslog, +run the following command: +grep -rni "cron\.\*" /etc/rsyslog.* +cron.* /var/log/cron +or +cron.* action(type="omfile" file="/var/log/cron") + Is it the case that cron is not logging to rsyslog? + + + + Verify the operating system authenticates the remote logging server for off-loading audit logs with the following command: -maxclassrepeat = - Is it the case that the value of "maxclassrepeat" is set to "0", more than "<sub idref="var_password_pam_maxclassrepeat" />" or is commented out? +$ sudo grep -i '$ActionSendStreamDriverAuthMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should be +$/etc/rsyslog.conf:$ActionSendStreamDriverAuthMode x509/name + Is it the case that $ActionSendStreamDriverAuthMode in /etc/rsyslog.conf is not set to x509/name? - - To verify the boot loader superuser password has been set, run the following command: -$ sudo grep "^[\s]*GRUB2_PASSWORD=grub\.pbkdf2\.sha512.*$" /boot/grub2/user.cfg -The output should be similar to: -GRUB2_PASSWORD=grub.pbkdf2.sha512.10000.C4E08AC72FBFF7E837FD267BFAD7AEB3D42DDC -2C99F2A94DD5E2E75C2DC331B719FE55D9411745F82D1B6CFD9E927D61925F9BBDD1CFAA0080E0 -916F7AB46E0D.1302284FCCC52CD73BA3671C6C12C26FF50BA873293B24EE2A96EE3B57963E6D7 -0C83964B473EC8F93B07FE749AA6710269E904A9B08A6BBACB00A2D242AD828 - Is it the case that no password is set? - - - - To verify that rsyslog's Forwarding Output Module is configured -to use TLS for logging to remote server, run the following command: -$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" - StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") + + Verify the operating system encrypts audit records off-loaded onto a different system +or media from the system being audited with the following commands: -where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. - Is it the case that omfwd is not configured with gtls and AuthMode? - - - - The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.accept_source_route -0. +$ sudo grep -i '$ActionSendStreamDriverMode' /etc/rsyslog.conf /etc/rsyslog.d/*.conf - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/cron.weekly, -run the command: -$ ls -l /etc/cron.weekly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.weekly does not have unix mode -rwx------? +The output should be: + +/etc/rsyslog.conf:$ActionSendStreamDriverMode 1 + Is it the case that rsyslogd ActionSendStreamDriverMode is not set to 1? @@ -258655,457 +284441,14 @@ The output should be: Is it the case that rsyslogd DefaultNetstreamDriver not set to gtls? - - - -Run the following command to determine the current status of the -fapolicyd service: -$ sudo systemctl is-active fapolicyd -If the service is running, it should return the following: active - Is it the case that the service is not enabled? - - - - Run the following command to determine if the rsh-server package is installed: -$ rpm -q rsh-server - Is it the case that the package is installed? - - - - To determine if the system is configured to audit calls to the -fsetxattr system call, run the following command: -$ sudo grep "fsetxattr" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_COMPAT_BRK /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_FREELIST_RANDOM /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to determine if the sendmail package is installed: -$ rpm -q sendmail - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit storage volume is full. - -Check that Oracle Linux 9 takes the appropriate action when the audit storage volume is full with the following command: - -$ sudo grep disk_full_action /etc/audit/auditd.conf - -disk_full_action = - -If the value of the "disk_full_action" option is not "SYSLOG", "SINGLE", or "HALT", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. - Is it the case that there is no evidence of appropriate action? - - - - Verify the operating system requires re-authentication -when using the "sudo" command to elevate privileges, run the following command: -sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d -The output should be: -/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. -If conflicting results are returned, this is a finding. - Is it the case that timestamp_timeout is not set with the appropriate value for sudo? - - - - To ensure that remote access connections are encrypted, run the following command: -$ gsettings get org.gnome.Vino require-encrpytion -If properly configured, the output should be true. -To ensure that users cannot disable encrypted remote connections, run the following: -$ grep require-encryption /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/Vino/require-encryption - Is it the case that remote access connections are not encrypted? - - - - To check the group ownership of /etc/at.allow, -run the command: -$ ls -lL /etc/at.allow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/at.allow does not have a group owner of root? - - - - To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: - -$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To determine if NOPASSWD or !authenticate have been configured for -sudo, run the following command: -$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that nopasswd and/or !authenticate is enabled in sudo? - - - - To check the permissions of /etc/gshadow, -run the command: -$ ls -l /etc/gshadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/gshadow does not have unix mode ----------? - - - - To verify Certmap is enabled in SSSD, run the following command: -$ sudo cat /etc/sssd/sssd.conf -If configured properly, output should contain section like the following - -[certmap/testing.test/rule_name] -matchrule =<SAN>.*EDIPI@mil -maprule = (userCertificate;binary={cert!bin}) -domains = testing.test - - Is it the case that Certmap is not configured in SSSD? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HIBERNATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure disable and restart on the login screen are disabled, run the following command: -$ grep disable-restart-buttons /etc/dconf/db/local.d/* -The output should be true. -To ensure that users cannot enable disable and restart on the login screen, run the following: -$ grep disable-restart-buttons /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-restart-buttons - Is it the case that disable-restart-buttons has not been configured or is not disabled? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes l1tf=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*l1tf=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*l1tf=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'l1tf=' -The command should not return any output. - Is it the case that l1tf mitigations are not configured appropriately? - - - - The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.default.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "crontab" command with the following command: - -$ sudo auditctl -l | grep crontab - --a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -k privileged-crontab - Is it the case that the command does not return a line, or the line is commented out? - - - - To ensure sshd limits the users who can log in, run the following: -pre>$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* -If properly configured, the output should be a list of usernames and/or -groups allowed to log in to this system. - Is it the case that sshd does not limit the users who can log in? - - - - To find SGID files, run the following command: -$ sudo find / -xdev -type f -perm -2000 - Is it the case that there is output? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes page_alloc.shuffle=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_alloc.shuffle=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*page_alloc.shuffle=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'page_alloc.shuffle=1' -The command should not return any output. - Is it the case that randomization of the page allocator is not enabled in the kernel? - - - - To verify that the DConf User profile is configured correctly, run the following -command: - -$ cat /etc/dconf/profile/user -The output should show the following: -user-db:user -system-db:local -system-db:site -system-db:distro - Is it the case that DConf User profile does not exist or is not configured correctly? - - - - To check the screensaver mandatory use status, run the following command: -$ gsettings get org.gnome.desktop.screensaver idle-activation-enabled -If properly configured, the output should be true. -To ensure that users cannot disable the screensaver idle inactivity setting, run the following: -$ grep idle-activation-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/idle-activation-enabled - Is it the case that idle-activation-enabled is not enabled or configured? - - - - Verify that authselect is enabled by running -authselect current -If authselect is enabled on the system, the output should show the ID of the profile which is currently in use. - Is it the case that authselect is not used to manage user authentication setup on the system? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_X86_VSYSCALL_EMULATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Promiscuous mode of an interface is disabled, run the following command: -$ ip link | grep PROMISC - Is it the case that any network device is in promiscuous mode? - - - - The file /etc/cron.deny should not exist. -This can be checked by runnig the following - -stat /etc/cron.deny - -and the output should be - -stat: cannot stat `/etc/cron.deny': No such file or directory - - Is it the case that the file /etc/cron.deny exists? - - - - Run the following command to determine if the nftables package is installed: $ rpm -q nftables - Is it the case that the package is not installed? - - - - To check the group ownership of /etc/cron.hourly, -run the command: -$ ls -lL /etc/cron.hourly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.hourly does not have a group owner of root? - - - - To check that the oddjobd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled oddjobd -Output should indicate the oddjobd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled oddjobd disabled - -Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active oddjobd - -If the service is not running the command will return the following output: -inactive - -The service will also be masked, to check that the oddjobd is masked, run the following command: -$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" - -If the service is masked the command will return the following outputs: - -LoadState=masked - -UnitFileState=masked - Is it the case that the "oddjobd" is loaded and not masked? - - - - Verify that the interactive user account passwords last change time is not in the future -The following command should return no output -$ sudo expiration=$(cat /etc/shadow|awk -F ':' '{print $3}'); -for edate in ${expiration[@]}; do if [[ $edate > $(( $(date +%s)/86400 )) ]]; -then echo "Expiry date in future"; -fi; done - Is it the case that any interactive user password that has last change time in the future? - - - - Run the following command to determine if the tftp-server package is installed: -$ rpm -q tftp-server - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size. - -Check that Oracle Linux 9 takes the appropriate action when the audit files have reached maximum size with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf - -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is not "ROTATE", "SINGLE", or the line is commented out, ask the system administrator to indicate how the system takes appropriate action when an audit storage volume is full. If there is no evidence of appropriate action? - - - - Verify the system-wide shared library directories are group-owned by "root" with the following command: - -$ sudo find /lib /lib64 /usr/lib /usr/lib64 ! -group root -type d -exec stat -c "%n %G" '{}' \; - -If any system-wide shared library directory is returned and is not group-owned by a required system account, this is a finding. - Is it the case that any system-wide shared library directory is returned and is not group-owned by a required system account? - - - - Check that AIDE is properly configured to protect the integrity of the -audit tools by running the following command: - -# sudo cat /etc/aide.conf | grep /usr/sbin/au - -/usr/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512 - -/usr/sbin/rsyslogd p+i+n+u+g+s+b+acl+xattrs+sha512 -/usr/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512 - - -If AIDE is configured properly to protect the integrity of the audit tools, -all lines listed above will be returned from the command. - -If one or more lines are missing, this is a finding. - Is it the case that integrity checks of the audit tools are missing or incomplete? - - - - To determine if the system is configured to audit calls to the -init_module system call, run the following command: -$ sudo grep "init_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -finit_module system call, run the following command: -$ sudo grep "finit_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. -To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - Is it the case that no line is returned? - - - - Verify "firewalld" is configured to employ a deny-all, allow-by-exception policy for allowing connections to other systems with the following commands: - -$ sudo firewall-cmd --state - -running - -$ sudo firewall-cmd --get-active-zones - -[custom] -interfaces: ens33 - -$ sudo firewall-cmd --info-zone=[custom] | grep target - -target: DROP - Is it the case that no zones are active on the interfaces or if the target is set to a different option other than "DROP"? - - - - Verify the audit tools are group-owned by "root" to prevent any unauthorized access, deletion, or modification. - -Check the group-owner of each audit tool by running the following command: - -$ sudo stat -c "%G %n" /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/rsyslogd /sbin/augenrules - -root /sbin/auditctl -root /sbin/aureport -root /sbin/ausearch -root /sbin/autrace -root /sbin/auditd -root /sbin/rsyslogd -root /sbin/augenrules - Is it the case that any audit tools are not group-owned by root? - - - - To check the permissions of /etc/shells, -run the command: -$ ls -l /etc/shells -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/shells does not have unix mode 0644? - - - - To check the permissions of /etc/ssh/*.pub, -run the command: -$ ls -l /etc/ssh/*.pub -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/ssh/*.pub does not have unix mode -rw-r--r--? - - - - To ensure LoginGraceTime is set correctly, run the following command: -$ sudo grep LoginGraceTime /etc/ssh/sshd_config -If properly configured, the output should be: -LoginGraceTime -If the option is set to a number greater than 0, then the unauthenticated session will be disconnected -after the configured number seconds. - Is it the case that it is commented out or not configured properly? + + The group-owner of all log files written by rsyslog should be +root. +These log files are determined by the second part of each Rule line in +/etc/rsyslog.conf and typically all appear in /var/log. +To see the group-owner of a given log file, run the following command: +$ ls -l LOGFILE + Is it the case that the group-owner is not correct? @@ -259120,1134 +284463,15 @@ $ ls -l LOGFILE Is it the case that the owner is not correct? - - - -Run the following command to determine the current status of the -postfix service: -$ sudo systemctl is-active postfix -If the service is running, it should return the following: active - Is it the case that the system is not a cross domain solution and the service is not enabled? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep - --w -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - To verify that the installed operating system is supported, run -the following command: - -$ grep -i "oracle" /etc/oracle-release - -Oracle Linux 9 - Is it the case that the installed operating system is not supported? - - - - To ensure the user home directory is not group-writable or world-readable, run the following: -# ls -ld /home/USER - Is it the case that the user home directory is group-writable or world-readable? - - - - To check the permissions of /etc/sysctl.d, -run the command: -$ ls -l /etc/sysctl.d -If properly configured, the output should indicate the following permissions: -0755 - Is it the case that /etc/sysctl.d does not have unix mode 0755? - - - - To check the ownership of /etc/ssh/sshd_config, -run the command: -$ ls -lL /etc/ssh/sshd_config -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/sshd_config does not have an owner of root? - - - - To check the permissions of /boot/grub2/grub.cfg, run the command: -$ sudo ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following -permissions: -rwx------ - Is it the case that it does not? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "shutdown" command with the following command: - -$ sudo auditctl -l | grep shutdown - --a always,exit -F path=/shutdown -F perm=x -F auid>=1000 -F auid!=unset -k privileged-shutdown - Is it the case that the command does not return a line, or the line is commented out? - - - - - -Run the following command to determine the current status of the -firewalld service: -$ sudo systemctl is-active firewalld -If the service is running, it should return the following: active - Is it the case that the "firewalld" service is disabled, masked, or not started.? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chacl" command with the following command: - -$ sudo auditctl -l | grep chacl - --a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the quagga package is installed: -$ rpm -q quagga - Is it the case that the package is installed? - - - - Verify Oracle Linux 9 disables the chrony daemon from acting as a server with the following command: -$ grep -w port /etc/chrony.conf -port 0 - Is it the case that the "port" option is not set to "0", is commented out, or is missing? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "ssh-agent" command with the following command: - -$ sudo auditctl -l | grep ssh-agent - --a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent - Is it the case that the command does not return a line, or the line is commented out? - - - - Check to see if Online Certificate Status Protocol (OCSP) -is enabled and using the proper digest value on the system with the following command: -$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" -If configured properly, output should look like - - certificate_verification = ocsp_dgst= - - Is it the case that certificate_verification in sssd is not configured? - - - - To check the group ownership of /etc/sestatus.conf, -run the command: -$ ls -lL /etc/sestatus.conf -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sestatus.conf does not have a group owner of root? - - - - Run the following command to determine if the talk package is installed: -$ rpm -q talk - Is it the case that the package is installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_FORTIFY_SOURCE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_MERGE_DEFAULT /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if RekeyLimit is set correctly, run the -following command: - -$ sudo grep RekeyLimit /etc/ssh/sshd_config - -If configured properly, output should be -RekeyLimit - Is it the case that it is commented out or is not set? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open_by_handle_at system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open_by_handle_at /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open_by_handle_at /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/cron.hourly, -run the command: -$ ls -l /etc/cron.hourly -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.hourly does not have unix mode -rwx------? - - - - Verify the pam_faillock.so module is present in the "/etc/pam.d/password-auth" file: - -$ sudo grep pam_faillock.so /etc/pam.d/password-auth - -auth required pam_faillock.so preauth -auth required pam_faillock.so authfail -account required pam_faillock.so - Is it the case that the pam_faillock.so module is not present in the "/etc/pam.d/password-auth" file with the "preauth" line listed before pam_unix.so? - - - - To verify that Audit Daemon is configured to flush to disk after -every records, run the following command: -$ sudo grep freq /etc/audit/auditd.conf -The output should return the following: -freq = - Is it the case that freq isn't set to <sub idref="var_auditd_freq" />? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_ALL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_pinfo -0. - - Is it the case that the correct value is not returned? - - - - Run the following command to determine if the openssh-clients package is installed: $ rpm -q openssh-clients - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_UNMAP_KERNEL_AT_EL0 /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify the LDAP client backend demands a valid certificate from the server in -remote LDAP access sessions, run the following command: -$ sudo grep ldap_tls_reqcert /etc/sssd/sssd.conf -The output should return the following: -ldap_tls_reqcert = demand - Is it the case that the TLS reqcert is not set to demand? - - - - Verify Oracle Linux 9 prevents the use of dictionary words for passwords with the following command: - -$ sudo grep dictcheck /etc/security/pwquality.conf /etc/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dictcheck=1 - Is it the case that "dictcheck" does not have a value other than "0", or is commented out? - - - - To check the ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/user.cfg does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SCHED_STACK_END_CHECK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command to determine if the logrotate package is installed: $ rpm -q logrotate - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_NO_SANITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To ensure that users cannot change session idle and lock settings, run the following: -$ grep 'idle-delay' /etc/dconf/db/local.d/locks/* -If properly configured, the output should return: -/org/gnome/desktop/session/idle-delay - Is it the case that idle-delay is not locked? - - - - To check the permissions of /etc/shadow-, -run the command: -$ ls -l /etc/shadow- -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow- does not have unix mode ----------? - - - - Inspect the firewalld trusted and default zones and verify the loopback traffic is restricted -to the lo interface by running the following command: - -$ sudo firewall-cmd --list-rich-rules --zone=trusted - -The following rich-rules should be listed: - -rule family="ipv4" source address="127.0.0.1" destination not address="127.0.0.1" drop -rule family="ipv6" source address="::1" destination not address="127.0.0.1" drop - - Is it the case that loopback traffic is not restricted? - - - - -Run the following command to get the current configured value for polyinstantiation_enabled -SELinux boolean: -$ getsebool polyinstantiation_enabled -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that polyinstantiation_enabled is not set as expected? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_KEY /boot/config.* - - For each kernel installed, a line with value "" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To find the location of the AIDE database file, run the following command: -$ sudo ls -l DBDIR/database_file_name - Is it the case that there is no database file? - - - - To check the group ownership of /etc/sudoers.d, -run the command: -$ ls -lL /etc/sudoers.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/sudoers.d does not have a group owner of root? - - - - Run the following command to determine if the vsftpd package is installed: -$ rpm -q vsftpd - Is it the case that the package is installed? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/system-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify the inactive setting, run the following command: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -The output should indicate the inactive configuration option is set -to an appropriate integer between 1 and -; and should appear -before the pam_unix.so module as shown in the example below: -$ grep 'inactive\|pam_unix' /etc/pam.d/password-auth | grep -w auth -auth required pam_lastlog.so inactive= -auth sufficient pam_unix.so - Is it the case that the value of inactive is incorrect or is not set before pam_unix.so? - - - - To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: -sysctl crypto.fips_enabled -The output should contain the following: -crypto.fips_enabled = 1 - Is it the case that crypto.fips_enabled is not 1? - - - - To check the ownership of /etc/crontab, -run the command: -$ ls -lL /etc/crontab -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/crontab does not have an owner of root? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -To find system executables directories that are group-writable or -world-writable, run the following command for each directory DIR -which contains system executables: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - Verify that Oracle Linux 9 enforces a minimum -character password length with the following command: - -$ grep minlen /etc/security/pwquality.conf - -minlen = - Is it the case that the command does not return a "minlen" value of "<sub idref="var_password_pam_minlen" />" or greater, does not return a line, or the line is commented out? - - - - To check the group ownership of /etc/ipsec.d, -run the command: -$ ls -lL /etc/ipsec.d -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ipsec.d does not have a group owner of root? - - - - To check the ownership of /etc/cron.allow, -run the command: -$ ls -lL /etc/cron.allow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.allow does not have an owner of root? - - - - Verify Oracle Linux 9 is configured to lock the root account after -unsuccessful logon attempts with the command: - -$ grep even_deny_root /etc/security/faillock.conf -even_deny_root - Is it the case that the "even_deny_root" option is not set, is missing or commented out? - - - - The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.accept_ra_defrtr -0. - - Is it the case that the correct value is not returned? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the creat system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r creat /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep creat /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_HARDENED_USERCOPY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling automount-open -If properly configured, the output for automount-openshould be false. -To ensure that users cannot enable automount opening in GNOME3, run the following: -$ grep 'automount-open' /etc/dconf/db/local.d/locks/* -If properly configured, the output for automount-open should be /org/gnome/desktop/media-handling/automount-open - Is it the case that GNOME automounting is not disabled? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify that Oracle Linux 9 is configured to take action in the event of allocated audit record storage volume reaches 95 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep admin_space_left_action /etc/audit/auditd.conf - -admin_space_left_action = single - -If the value of the "admin_space_left_action" is not set to "single", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - Run the following command to check if the line is present: -grep pam_wheel /etc/pam.d/su -The output should contain the following line: -auth required pam_wheel.so use_uid group= - Is it the case that the line is not in the file or it is commented? - - - - Verify the "/etc/security/faillock.conf" file is configured use a non-default faillock directory to ensure contents persist after reboot: - -$ sudo grep 'dir =' /etc/security/faillock.conf - -dir = /var/log/faillock - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - To ensure the tally directory is configured correctly, run the following command: -$ sudo grep 'dir =' /etc/security/faillock.conf -The output should show that dir is set to something other than "/var/run/faillock" - Is it the case that the "dir" option is not set to a non-default documented tally log directory, is missing or commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes init_on_alloc=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*init_on_alloc=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*init_on_alloc=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'init_on_alloc=1' -The command should not return any output. - Is it the case that the kernel is not configured to zero out memory before allocation? - - - - Only strong MACs should be used. To verify that only strong -MACs are in use, run the following command: -$ sudo grep -i macs /etc/ssh/sshd_config -The output should contain only those MACs which are strong, namely, - hash functions. - Is it the case that MACs option is commented out or not using strong hash algorithms? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "umount" command with the following command: - -$ sudo auditctl -l | grep umount - --a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -k privileged-umount - Is it the case that the command does not return a line, or the line is commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit_backlog_limit=8192, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit_backlog_limit=8192.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit_backlog_limit=8192.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit_backlog_limit=8192' -The command should not return any output. - Is it the case that audit backlog limit is not configured? - - - - Run the following command to determine if the postfix package is installed: $ rpm -q postfix - Is it the case that the package is not installed? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BUG_ON_DATA_CORRUPTION /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/cron.deny, -run the command: -$ ls -lL /etc/cron.deny -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.deny does not have a group owner of root? - - - - The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.unprivileged_bpf_disabled -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the kernel.sysrq kernel parameter can be queried -by running the following command: -$ sysctl kernel.sysrq -0. - - Is it the case that the correct value is not returned? - - - - - -Run the following command to determine the current status of the -systemd-journald service: -$ sudo systemctl is-active systemd-journald -If the service is running, it should return the following: active - Is it the case that the systemd-journald service is not running? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one special character with the following command: - -$ sudo grep ocredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -ocredit = - Is it the case that value of "ocredit" is a positive number or is commented out? - - - - Verify that all local interactive user initialization file executable search path statements do not contain statements that will reference a working directory other than user home directories with the following commands: - -$ sudo grep -i path= /home/*/.* - -/home/[localinteractiveuser]/.bash_profile:PATH=$PATH:$HOME/.local/bin:$HOME/bin - Is it the case that any local interactive user initialization files have executable search path statements that include directories outside of their home directory and is not documented with the ISSO as an operational requirement? - - - - Verify the audit log directories have a correct mode or less permissive mode. - -Find the location of the audit logs: - -$ sudo grep "^log_file" /etc/audit/auditd.conf - - -Find the group that owns audit logs: - -$ sudo grep "^log_group" /etc/audit/auditd.conf - - -Run the following command to check the mode of the system audit logs: - -$ sudo stat -c "%a %n" [audit_log_directory] - -Replace "[audit_log_directory]" to the correct audit log directory path, by default this location is "/var/log/audit". - - -If the log_group is "root" or is not set, the correct permissions are 0700, otherwise they are 0750. - Is it the case that audit logs have a more permissive mode? - - - - To determine the config value the kernel was built with, run the following command: -$ grep CONFIG_DEFAULT_MMAP_MIN_ADDR /boot/config.* -For each kernel installed, a line with value should be returned. -If the system architecture is x86_64, the value should be 65536. -If the system architecture is aarch64, the value should be 32768. - Is it the case that the kernel was not built with the required value? - - - - These settings can be verified by running the following: -$ gsettings get org.gnome.desktop.media-handling automount -If properly configured, the output for automount should be false. -To ensure that users cannot enable automount in GNOME3, run the following: -$ grep 'automount' /etc/dconf/db/local.d/locks/* -If properly configured, the output for automount should be /org/gnome/desktop/media-handling/automount - Is it the case that GNOME automounting is not disabled? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the open system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r open /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep open /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine how the SSH daemon's HostbasedAuthentication option is set, run the following command: - -$ sudo grep -i HostbasedAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - -To properly set the owner of /var/log/audit, run the command: -$ sudo chown root /var/log/audit - -To properly set the owner of /var/log/audit/*, run the command: -$ sudo chown root /var/log/audit/* - Is it the case that ? - - - - Verify the nosuid option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nosuid . . . - - Is it the case that the "/boot" file system does not have the "nosuid" option set? - - - - To verify that Audit Daemon is configured to write logs to the disk, run the -following command: -$ sudo grep write_logs /etc/audit/auditd.conf -The output should return the following: -write_logs = yes - Is it the case that write_logs isn't set to yes? - - - - Verify Oracle Linux 9 notifies the SA and ISSO (at a minimum) when allocated audit record storage volume reaches 75 percent of the repository maximum audit record storage capacity with the following command: - -$ sudo grep -w space_left_action /etc/audit/auditd.conf - -space_left_action = - -If the value of the "space_left_action" is not set to "", or if the line is commented out, ask the System Administrator to indicate how the system is providing real-time alerts to the SA and ISSO. - Is it the case that there is no evidence that real-time alerts are configured on the system? - - - - The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.max_addresses -1. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.arp_filter -. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODULE_SIG_FORCE /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify the system commands contained in the following directories are owned by "root" with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/libexec /usr/local/bin /usr/local/sbin ! -user root -exec ls -l {} \; - Is it the case that any system commands are found to not be owned by root? - - - - To verify the password reuse setting is compliant, run the following command: -$ grep remember /etc/pam.d/system-auth -The output should show the following at the end of the line: -remember= - - -In newer systems, the pam_pwhistory PAM module options can also be set in -"/etc/security/pwhistory.conf" file. Use the following command to verify: -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory remember option must be configured only in one file. - Is it the case that the value of remember is not equal to or greater than the expected value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_LEGACY_VSYSCALL_EMULATE /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules -The output has to be exactly as follows: -## Unsuccessful file creation (open with O_CREAT) --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create --a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create - Is it the case that the file does not exist or the content differs? - - - - To check the group ownership of /boot/grub2/user.cfg, -run the command: -$ ls -lL /boot/grub2/user.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/user.cfg does not have a group owner of root? - - - - To ensure that the GPG key is installed, run: -$ rpm -q --queryformat "%{SUMMARY}\n" gpg-pubkey -The command should return the string below: -gpg(Oracle OSS group (Open Source Software group) <build@oss.oracle.com> - Is it the case that the Oracle GPG Key is not installed? - - - - To verify that Audit Daemon is configured to include local events, run the -following command: -$ sudo grep local_events /etc/audit/auditd.conf -The output should return the following: -local_events = yes - Is it the case that local_events isn't set to yes? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STACKPROTECTOR /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify the grpquota option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . grpquota . . . - - Is it the case that the "/home" file system does not have the "grpquota" option set? - - - - Verify Oracle Linux 9 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file -and is configured to prohibit password reuse for a minimum of -generations. - -Verify the "/etc/pam.d/password-auth" file with the following command: - -$ grep pam_pwhistory.so /etc/pam.d/password-auth -password pam_pwhistory.so use_authtok remember= - - -Verify the "/etc/security/pwhistory.conf" file using the following command: - -$ grep remember /etc/security/pwhistory.conf -remember = - -The pam_pwhistory.so "remember" option must be configured only in one file. - Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in -/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set -with a value less than "<sub idref="var_password_pam_remember" />"? - - - - Run the following command to determine if the openssh-server package is installed: $ rpm -q openssh-server - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "postdrop" command with the following command: - -$ sudo auditctl -l | grep postdrop - --a always,exit -F path=/usr/bin/postdrop -F perm=x -F auid>=1000 -F auid!=unset -k privileged-postdrop - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers.d/" with the following command: - -$ sudo auditctl -l | grep/etc/sudoers.d - --w /etc/sudoers.d/ -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.forwarding -0. -The ability to forward packets is only appropriate for routers. - Is it the case that IP forwarding value is "1" and the system is not router? - - - - To determine if the system is configured to audit attempts to -alter time via the /etc/localtime file, run the following -command: -$ sudo auditctl -l | grep "watch=/etc/localtime" -If the system is configured to audit this activity, it will return a line. - Is it the case that the system is not configured to audit time changes? - - - - The runtime status of the net.ipv4.conf.all.forwarding kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.forwarding -0. -The ability to forward packets is only appropriate for routers. - Is it the case that IP forwarding value is "1" and the system is not router? - - - - Run the following command to determine if the fapolicyd package is installed: $ rpm -q fapolicyd - Is it the case that the fapolicyd package is not installed? - - - - -To ensure the login warning banner text is properly set, run the following: -$ grep banner-message-text /etc/dconf/db/local.d/* -If properly configured, the proper banner text will appear. -To ensure the login warning banner text is locked and cannot be changed by a user, run the following: -$ grep banner-message-text /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/banner-message-text. - Is it the case that it does not? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes spectre_v2=on, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spectre_v2=on.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*spectre_v2=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'spectre_v2=on' -The command should not return any output. - Is it the case that spectre_v2 mitigation is not enforced? - - - - The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_source_route -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.default.autoconf -0. - - Is it the case that the correct value is not returned? - - - - The runtime status of the vm.mmap_min_addr kernel parameter can be queried -by running the following command: -$ sysctl vm.mmap_min_addr -65536. - - Is it the case that the correct value is not returned? - - - - To check the permissions of /etc/ipsec.conf, -run the command: -$ ls -l /etc/ipsec.conf -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/ipsec.conf does not have unix mode 0644? - - - - The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_syncookies -1. - - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_GCC_PLUGIN_STRUCTLEAK /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_ARM64_SW_TTBR0_PAN /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to prevent the usage of the ipv6 on -network interfaces, it will contain a line of the form: -net.ipv6.conf.default.disable_ipv6 = 1 -Such lines may be inside any file in the /etc/sysctl.d directory. -This permits insertion of the IPv6 kernel module (which other parts of the -system expect to be present), but otherwise keeps network interfaces -from using IPv6. Run the following command to search for such lines in all -files in /etc/sysctl.d: -$ grep -r ipv6 /etc/sysctl.d - Is it the case that the ipv6 support is disabled by default on network interfaces? - - - - Verify the nosuid option is configured for the /srv mount point, - run the following command: - $ sudo mount | grep '\s/srv\s' - . . . /srv . . . nosuid . . . - - Is it the case that the "/srv" file system does not have the "nosuid" option set? - - - - To ensure the user list is disabled, run the following command: -$ grep disable-user-list /etc/dconf/db/local.d/* -The output should be true. -To ensure that users cannot enable displaying the user list, run the following: -$ grep disable-user-list /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/login-screen/disable-user-list - Is it the case that disable-user-list has not been configured or is not disabled? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_IA32_EMULATION /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that GRUB_DISABLE_RECOVERY is set to true in /etc/default/grub to disable recovery boot. -Run the following command: - -$ sudo grep GRUB_DISABLE_RECOVERY /etc/default/grub - Is it the case that GRUB_DISABLE_RECOVERY is not set to true or is missing? + + The file permissions for all log files written by rsyslog should +be set to 640, or more restrictive. These log files are determined by the +second part of each Rule line in /etc/rsyslog.conf and typically +all appear in /var/log. To see the permissions of a given log +file, run the following command: +$ ls -l LOGFILE +The permissions should be 640, or more restrictive. + Is it the case that the permissions are not correct? @@ -260276,318 +284500,244 @@ input(type="imudp" port="514") Is it the case that rsyslog accepts remote messages and is not documented as a log aggregation system? - - To verify all accounts have unique names, run the following command: -$ sudo getent passwd | awk -F: '{ print $1}' | uniq -d -No output should be returned. - Is it the case that a line is returned? - - - - To check the group ownership of /etc/cron.weekly, -run the command: -$ ls -lL /etc/cron.weekly -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/cron.weekly does not have a group owner of root? - - - - Check that Oracle Linux 9 has the packages for smart card support installed. - -Run the following command to determine if the openssl-pkcs11 package is installed: -$ rpm -q openssl-pkcs11 - Is it the case that smartcard software is not installed? - - - - To verify if the OpenSSH server uses defined ciphers in the Crypto Policy, run: -$ grep -Po '(-oCiphers=\S+)' /etc/crypto-policies/back-ends/opensshserver.config -and verify that the line matches: --oCiphers= - Is it the case that Crypto Policy for OpenSSH Server is not configured correctly? - - - - To check the group ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /boot/grub2/grub.cfg does not have a group owner of root? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes pti=on, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*pti=on.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*pti=on.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'pti=on' -The command should not return any output. - Is it the case that Kernel page-table isolation is not enabled? - - - - To check the system for the existence of any .netrc files, + + To verify that remote access methods are logging to rsyslog, run the following command: -$ sudo find /home -xdev -name .netrc - Is it the case that any .netrc files exist? + +grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* + +The output should contain auth.*, authpriv.*, and daemon.* +pointing to a log file. + Is it the case that remote access methods are not logging to rsyslog? - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/tallylog" with the following command: - -$ sudo auditctl -l | grep /var/log/tallylog - --w /var/log/tallylog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? + + To ensure logs are sent to a remote host, examine the file +/etc/rsyslog.conf. +If using UDP, a line similar to the following should be present: + *.* @ +or +*.* action(type="omfwd" ... target="" protocol="udp") +If using TCP, a line similar to the following should be present: + *.* @@ +or +*.* action(type="omfwd" ... target="" protocol="tcp") +If using RELP, a line similar to the following should be present: + *.* :omrelp: +or +*.* action(type="omfwd" ... target="" protocol="relp") + Is it the case that no evidence that the audit logs are being off-loaded to another system or media? - + + To verify that rsyslog's Forwarding Output Module is configured +to use TLS for logging to remote server, run the following command: +$ grep omfwd /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514" + StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on") + +where the <remote system> present in the configuration line above must be a valid IP address or a host name of the remote logging server. + Is it the case that omfwd is not configured with gtls and AuthMode? + + + + To verify that rsyslog's Forwarding Output Module has CA certificate +configured for its TLS connections to remote server, run the following command: +$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf +The output should include record similar to +global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") +where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. + Is it the case that CA certificate for rsyslog remote logging via TLS is not set? + + + -Determine the audit log group by running the following command: - -$ sudo grep -P '^[ ]*log_group[ ]+=.*$' /etc/audit/auditd.conf - -Then, check that all directories within the /var/log/audit directory are owned by the group specified as log_group or by root if the log_group is not specified. -Run the following command: - -$ sudo find /var/log/audit -type d -printf "%p %g\n" - -All listed directories must be owned by the log_group or by root if the log_group is not specified. - Is it the case that there is a directory owned by different group? +Run the following command to determine if the auditadm_exec_content SELinux boolean is enabled: +$ getsebool auditadm_exec_content +If properly configured, the output should show the following: +auditadm_exec_content --> on + Is it the case that auditadm_exec_content is not enabled? - - To verify the assigned home directory of all interactive user home directories -have a mode of 0750 or less permissive, run the following command: -$ sudo ls -l /home -Inspect the output for any directories with incorrect permissions. - Is it the case that they are more permissive? + + +Run the following command to determine if the authlogin_nsswitch_use_ldap SELinux boolean is disabled: +$ getsebool authlogin_nsswitch_use_ldap +If properly configured, the output should show the following: +authlogin_nsswitch_use_ldap --> off + Is it the case that authlogin_nsswitch_use_ldap is not disabled? - - Run the following command to determine if the nss-tools package is installed: $ rpm -q nss-tools - Is it the case that the package is not installed? + + +Run the following command to determine if the authlogin_radius SELinux boolean is disabled: +$ getsebool authlogin_radius +If properly configured, the output should show the following: +authlogin_radius --> off + Is it the case that authlogin_radius is not disabled? - - To verify that auditing of privileged command use is configured, run the + + +Run the following command to get the current configured value for deny_execmem +SELinux boolean: +$ getsebool deny_execmem +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that deny_execmem is not set as expected? + + + + +Run the following command to determine if the kerberos_enabled SELinux boolean is enabled: +$ getsebool kerberos_enabled +If properly configured, the output should show the following: +kerberos_enabled --> on + Is it the case that kerberos_enabled is not enabled? + + + + +Run the following command to get the current configured value for polyinstantiation_enabled +SELinux boolean: +$ getsebool polyinstantiation_enabled +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that polyinstantiation_enabled is not set as expected? + + + + +Run the following command to get the current configured value for secure_mode_insmod +SELinux boolean: +$ getsebool secure_mode_insmod +The expected cofiguration is . +"on" means true, and "off" means false + Is it the case that secure_mode_insmod is not set as expected? + + + + +Run the following command to determine if the selinuxuser_execheap SELinux boolean is disabled: +$ getsebool selinuxuser_execheap +If properly configured, the output should show the following: +selinuxuser_execheap --> off + Is it the case that selinuxuser_execheap is not disabled? + + + + +Run the following command to determine if the selinuxuser_execmod SELinux boolean is enabled: +$ getsebool selinuxuser_execmod +If properly configured, the output should show the following: +selinuxuser_execmod --> on + Is it the case that selinuxuser_execmod is not enabled? + + + + +Run the following command to determine if the selinuxuser_execstack SELinux boolean is disabled: +$ getsebool selinuxuser_execstack +If properly configured, the output should show the following: +selinuxuser_execstack --> off + Is it the case that selinuxuser_execstack is not disabled? + + + + +Run the following command to determine if the ssh_sysadm_login SELinux boolean is disabled: +$ getsebool ssh_sysadm_login +If properly configured, the output should show the following: +ssh_sysadm_login --> off + Is it the case that ssh_sysadm_login is not disabled? + + + + Check that Secure Boot is enabled with the mokutil command. + +When Secure Boot is enabled: + +mokutil --sb-state +SecureBoot enabled + + +When Secure Boot is disabled: + +mokutil --sb-state +Failed to read SecureBoot + + +or: + +mokutil --sb-state +SecureBoot disabled + + Is it the case that Secure Boot is not enabled? + + + + To check for virtual console entries which permit root login, run the following command: -$ sudo grep '\bat\b' /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? +$ sudo grep ^vc/[0-9] /etc/securetty +If any output is returned, then root logins over virtual console devices is permitted. + Is it the case that root login over virtual console devices is permitted? - - To check the group ownership of /etc/ssh/*_key, -run the command: -$ ls -lL /etc/ssh/*_key -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/ssh/*_key does not have a group owner of root? - - - - To check that the sshd service is disabled in system boot configuration, -run the following command: -$ sudo systemctl is-enabled sshd -Output should indicate the sshd service has either not been installed, -or has been disabled at all runlevels, as shown in the example below: -$ sudo systemctl is-enabled sshd disabled + + Verify Oracle Linux 9 security patches and updates are installed and up to date. +Updates are required to be applied with a frequency determined by organizational policy. -Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: -$ sudo systemctl is-active sshd -If the service is not running the command will return the following output: -inactive -The service will also be masked, to check that the sshd is masked, run the following command: -$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" +Typical update frequency may be overridden by Information Assurance Vulnerability Alert (IAVA) notifications from CYBERCOM. + Is it the case that Oracle Linux 9 is in non-compliance with the organizational patching policy? + + + + To check for incorrectly labeled device files, run following commands: +$ sudo find /dev -context *:device_t:* \( -type c -o -type b \) -printf "%p %Z\n" +$ sudo find /dev -context *:unlabeled_t:* \( -type c -o -type b \) -printf "%p %Z\n" +It should produce no output in a well-configured system. + Is it the case that there is output? + + + + Ensure there are no unconfined daemons running on the system, +the following command should produce no output: +$ sudo ps -eZ | grep "unconfined_service_t" + Is it the case that There are unconfined daemons running on the system? + + + + Ensure that Oracle Linux 9 does not disable SELinux. -If the service is masked the command will return the following outputs: +Check if "SELinux" is active and in "enforcing" or "permissive" mode with the following command: -LoadState=masked +$ sudo getenforce +Enforcing +-OR- +Permissive + Is it the case that SELinux is disabled? + + + + Verify the SELINUX on Oracle Linux 9 is using the policy with the following command: -UnitFileState=masked - Is it the case that the "sshd" is loaded and not masked? - - - - Run the following command to ensure that /var/tmp is configured as a -polyinstantiated directory: -$ sudo grep /var/tmp /etc/security/namespace.conf -The output should return the following: -/var/tmp /var/tmp/tmp-inst/ level root,adm - Is it the case that is not configured? - - - - To check the ownership of /etc/cron.daily, -run the command: -$ ls -lL /etc/cron.daily -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.daily does not have an owner of root? - - - - Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active - Is it the case that logrotate timer is not enabled? - - - - To verify the assigned home directory of all interactive users is group- -owned by that users primary GID, run the following command: -# ls -ld $(awk -F: '($3>=1000)&&($7 !~ /nologin/){print $6}' /etc/passwd) - Is it the case that the group ownership is incorrect? - - - - Inspect the file /etc/sysconfig/iptables to determine -the default policy for the INPUT chain. It should be set to DROP: -$ sudo grep ":INPUT" /etc/sysconfig/iptables - Is it the case that the default policy for the INPUT chain is not set to DROP? - - - - The existence of the file /etc/hosts.equiv or a file named -.rhosts inside a user home directory indicates the presence -of an Rsh trust relationship. - Is it the case that these files exist? - - - - To find world-writable directories that lack the sticky bit, run the following command: -$ sudo find / -type d \( -perm -0002 -a ! -perm -1000 \) -print 2>/dev/null -fixtext: |- -Configure all world-writable directories to have the sticky bit set to prevent unauthorized and unintended information transferred via shared system resources. +$ sestatus | grep policy -Set the sticky bit on all world-writable directories using the command, replace "[World-Writable Directory]" with any directory path missing the sticky bit: +Loaded policy name: + Is it the case that the loaded policy name is not "<sub idref="var_selinux_policy_name" />"? + + + + Ensure that Oracle Linux 9 verifies correct operation of security functions. -$ chmod a+t [World-Writable Directory] -srg_requirement: -A sticky bit must be set on all Oracle Linux 9 public directories to prevent unauthorized and unintended information transferred via shared system resources. - Is it the case that any world-writable directories are missing the sticky bit? - - - - The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.autoconf -0. +Check if "SELinux" is active and in "" mode with the following command: - Is it the case that the correct value is not returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_TABLE_ISOLATION /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "kmod" command with the following command: +$ sudo getenforce -$ sudo auditctl -l | grep kmod - --a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>=1000 -F auid!=unset -k privileged-kmod - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the telnet-server package is installed: -$ rpm -q telnet-server - Is it the case that the package is installed? - - - - To check the ownership of /etc/selinux, -run the command: -$ ls -lL /etc/selinux -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/selinux does not have an owner of root? - - - - Run the following command to determine if the openscap-scanner package is installed: $ rpm -q openscap-scanner - Is it the case that the package is not installed? - - - - Verify Oracle Linux 9 enforces a delay of at least seconds between console logon prompts following a failed logon attempt with the following command: - -$ sudo grep -i "FAIL_DELAY" /etc/login.defs -FAIL_DELAY - Is it the case that the value of "FAIL_DELAY" is not set to "<sub idref="var_accounts_fail_delay" />" or greater, or the line is commented out? - - - - To determine if the system is configured to audit calls to the -delete_module system call, run the following command: -$ sudo grep "delete_module" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow does not have an owner of root? - - - - To check the ownership of /etc/crypttab, -run the command: -$ ls -lL /etc/crypttab -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/crypttab does not have an owner of root? - - - - To check the permissions of /etc/chrony.keys, -run the command: -$ ls -l /etc/chrony.keys -If properly configured, the output should indicate the following permissions: -0640 - Is it the case that /etc/chrony.keys does not have unix mode 0640? - - - - Shared libraries are stored in the following directories: -/lib -/lib64 -/usr/lib -/usr/lib64 - -To find shared libraries that are group-writable or world-writable, -run the following command for each directory DIR which contains shared libraries: -$ sudo find -L DIR -perm /022 -type d - Is it the case that any of these files are group-writable or world-writable? - - - - To determine if the system is configured to audit calls to the -fchown system call, run the following command: -$ sudo grep "fchown" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? + Is it the case that SELINUX is not set to enforcing? @@ -260615,58 +284765,129 @@ UnitFileState=masked Is it the case that the "atd" is loaded and not masked? - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/sudoers" with the following command: + + -$ sudo auditctl -l | grep /etc/sudoers +Run the following command to determine the current status of the +auditd service: +$ sudo systemctl is-active auditd +If the service is running, it should return the following: active + Is it the case that the auditd service is not running? + + + + To check that the autofs service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled autofs +Output should indicate the autofs service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled autofs disabled --w /etc/sudoers -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_STACKPROTECTOR_STRONG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect the list of enabled firewall ports and verify they are configured correctly by running -the following command: +Run the following command to verify autofs is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active autofs -$ sudo firewall-cmd --list-all +If the service is not running the command will return the following output: +inactive -Ask the System Administrator for the site or program Ports, Protocols, and Services Management Component Local Service Assessment (PPSM CLSA). Verify the services allowed by the firewall match the PPSM CLSA. - Is it the case that there are additional ports, protocols, or services that are not in the PPSM CLSA, or there are ports, protocols, or services that are prohibited by the PPSM Category Assurance List (CAL), or there are no firewall rules configured? +The service will also be masked, to check that the autofs is masked, run the following command: +$ sudo systemctl show autofs | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "autofs" is loaded and not masked? - - Run the following command to determine if the policycoreutils-python-utils package is installed: $ rpm -q policycoreutils-python-utils - Is it the case that the package is not installed? + + To check that the avahi-daemon service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled avahi-daemon +Output should indicate the avahi-daemon service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled avahi-daemon disabled + +Run the following command to verify avahi-daemon is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active avahi-daemon + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the avahi-daemon is masked, run the following command: +$ sudo systemctl show avahi-daemon | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "avahi-daemon" is loaded and not masked? - - To determine that AIDE is configured for FIPS 140-2 file hashing, run the following command: -$ grep sha512 /etc/aide.conf -Verify that the sha512 option is added to the correct ruleset. - Is it the case that the sha512 option is missing or not added to the correct ruleset? + + + +Run the following command to determine the current status of the +chronyd service: +$ sudo systemctl is-active chronyd +If the service is running, it should return the following: active + Is it the case that the chronyd process is not running? - - Verify that there are no shosts.equiv files on the system, run the following command: -$ find / -name shosts.equiv - Is it the case that shosts.equiv files exist? + + + +Run the following command to determine the current status of the +crond service: +$ sudo systemctl is-active crond +If the service is running, it should return the following: active + Is it the case that ? - - Make sure that the kernel is not disabling SMAP with the following -commands. -grep -q nosmap /boot/config-`uname -r` -If the command returns a line, it means that SMAP is being disabled. - Is it the case that the kernel is configured to disable SMAP? + + To check that the debug-shell service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled debug-shell +Output should indicate the debug-shell service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled debug-shell disabled + +Run the following command to verify debug-shell is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active debug-shell + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the debug-shell is masked, run the following command: +$ sudo systemctl show debug-shell | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "debug-shell" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +fapolicyd service: +$ sudo systemctl is-active fapolicyd +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + + +Run the following command to determine the current status of the +firewalld service: +$ sudo systemctl is-active firewalld +If the service is running, it should return the following: active + Is it the case that the "firewalld" service is disabled, masked, or not started.? @@ -260679,283 +284900,99 @@ If the service is running, it should return the following: active Is it the case that ? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - -If the system is configured to prevent the loading of the can kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. + + To check that the kdump service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled kdump +Output should indicate the kdump service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled kdump disabled -These lines can also instruct the module loading system to ignore the can kernel module via blacklist keyword. +Run the following command to verify kdump is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active kdump -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r can /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the kdump is masked, run the following command: +$ sudo systemctl show kdump | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "kdump" is loaded and not masked? - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_REFCOUNT_FULL /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? + + To check that the nftables service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled nftables +Output should indicate the nftables service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled nftables disabled + +Run the following command to verify nftables is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active nftables + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the nftables is masked, run the following command: +$ sudo systemctl show nftables | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "nftables" is loaded and not masked? - + + To check that the oddjobd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled oddjobd +Output should indicate the oddjobd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled oddjobd disabled + +Run the following command to verify oddjobd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active oddjobd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the oddjobd is masked, run the following command: +$ sudo systemctl show oddjobd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "oddjobd" is loaded and not masked? + + + Run the following command to determine the current status of the -rsyslog service: -$ sudo systemctl is-active rsyslog +pcscd service: +$ sudo systemctl is-active pcscd If the service is running, it should return the following: active - Is it the case that the "rsyslog" service is disabled, masked, or not started.? + Is it the case that the pcscd service is not enabled? - - To check for serial port entries which permit root login, -run the following command: -$ sudo grep ^ttyS/[0-9] /etc/securetty -If any output is returned, then root login over serial ports is permitted. - Is it the case that root login over serial ports is permitted? - - - - Verify the audit system is configured to take an appropriate action when the internal event queue is full: -$ sudo grep -i overflow_action /etc/audit/auditd.conf + + -The output should contain overflow_action = syslog - -If the value of the "overflow_action" option is not set to syslog, -single, halt or the line is commented out, ask the System Administrator -to indicate how the audit logs are off-loaded to a different system or media. - Is it the case that auditd overflow action is not set correctly? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "su" command with the following command: - -$ sudo auditctl -l | grep su - --a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset -k privileged-su - Is it the case that the command does not return a line, or the line is commented out? - - - - To ensure only SNMPv3 or newer is used, run the following command: -$ sudo grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#" -There should be no output. - Is it the case that there is output? - - - - The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_redirects -0. - - Is it the case that the correct value is not returned? - - - - To check the ownership of /etc/sudoers.d, -run the command: -$ ls -lL /etc/sudoers.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sudoers.d does not have an owner of root? - - - - To obtain a list of all users and the content of their shadow password field, run the command: -$ sudo readarray -t systemaccounts -Verify if all accounts are locked. - Is it the case that system accounts are not locked? - - - - To determine how the SSH daemon's PrintLastLog option is set, run the following command: - -$ sudo grep -i PrintLastLog /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To verify the nosuid option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nosuid setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - System executables are stored in the following directories by default: -/bin -/sbin -/usr/bin -/usr/local/bin -/usr/local/sbin -/usr/sbin -For each of these directories, run the following command to find files -not owned by root: -$ sudo find -L DIR/ ! -user root -type d -exec chown root {} \; - Is it the case that any system executables directories are found to not be owned by root? - - - - The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried -by running the following command: -$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref -0. - - Is it the case that the correct value is not returned? - - - - To check if RekeyLimit is set correctly, run the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf -If configured properly, output should be -/etc/ssh/ssh_config.d/02-rekey-limit.conf: -RekeyLimit -Check also the main configuration file with the following command: -$ sudo grep RekeyLimit /etc/ssh/ssh_config -The command should not return any output. - Is it the case that it is commented out or is not set? - - - - Verify that sshd isn't configured to ignore the system wide cryptographic policy. - -Check that the CRYPTO_POLICY variable is not set or is commented out in the -/etc/sysconfig/sshd. - -Run the following command: - -$ sudo grep CRYPTO_POLICY /etc/sysconfig/sshd - Is it the case that the CRYPTO_POLICY variable is set or is not commented out in the /etc/sysconfig/sshd? - - - - Verify the audit system prevents unauthorized changes with the following command: - -$ sudo grep "^\s*[^#]" /etc/audit/audit.rules | tail -1 --e 2 - - Is it the case that the audit system is not set to be immutable by adding the "-e 2" option to the end of "/etc/audit/audit.rules"? - - - - To verify that SSSD is configured for PAM services, run the following command: -$ sudo grep services /etc/sssd/sssd.conf -If configured properly, output should be similar to -services = pam - Is it the case that it does not exist or 'pam' is not added to the 'services' option under the 'sssd' section? - - - - To check the minimum password length, run the command: -$ grep PASS_MIN_LEN /etc/login.defs -The DoD requirement is 15. - Is it the case that it is not set to the required value? - - - - To check the permissions of /etc/at.allow, -run the command: -$ ls -l /etc/at.allow -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/at.allow does not have unix mode -rw-r-----? - - - - To check the group ownership of /etc/crypttab, -run the command: -$ ls -lL /etc/crypttab -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/crypttab does not have a group owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLAB_FREELIST_HARDENED /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - The runtime status of the kernel.panic_on_oops kernel parameter can be queried -by running the following command: -$ sysctl kernel.panic_on_oops -1. - - Is it the case that the correct value is not returned? - - - - Run the following command to ensure the default FORWARD policy is DROP: -grep ":FORWARD" /etc/sysconfig/iptables -The output should be similar to the following: -$ sudo grep ":FORWARD" /etc/sysconfig/iptables -:FORWARD DROP [0:0 - Is it the case that the default policy for the FORWARD chain is not set to DROP? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_BUG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the group ownership of /etc/shadow, -run the command: -$ ls -lL /etc/shadow -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/shadow does not have a group owner of root? - - - - To ensure that XDMCP is disabled in /etc/gdm/custom.conf, run the following command: -grep -Pzo "\[xdmcp\]\nEnable=false" /etc/gdm/custom.conf -The output should return the following: - -[xdmcp] -Enable=false - - Is it the case that the Enable is not set to false or is missing in the xdmcp section of the /etc/gdm/custom.conf gdm configuration file? - - - - To ensure ClientAliveInterval is set correctly, run the following command: - -$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config - -If properly configured, the output should be: -ClientAliveCountMax 0 - -In this case, the SSH timeout occurs precisely when -the ClientAliveInterval is set. - Is it the case that it is commented out or not configured properly? +Run the following command to determine the current status of the +postfix service: +$ sudo systemctl is-active postfix +If the service is running, it should return the following: active + Is it the case that the system is not a cross domain solution and the service is not enabled? @@ -260983,569 +285020,44 @@ UnitFileState=masked Is it the case that the "rdisc" is loaded and not masked? - - Verify that Oracle Linux 9 enforces password complexity rules for the root account. - -Check if root user is required to use complex passwords with the following command: - -$ grep enforce_for_root /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:enforce_for_root - Is it the case that "enforce_for_root" is commented or missing? - - - - Run the following command to determine if the tuned package is installed: -$ rpm -q tuned - Is it the case that the package is installed? - - - - To check if the system motd banner is compliant, -run the following command: -$ cat /etc/motd - Is it the case that it does not display the required banner? - - - - To check the permissions of /etc/audit/auditd.conf, -run the command: -$ ls -l /etc/audit/auditd.conf -If properly configured, the output should indicate the following permissions: --rw-r----- - Is it the case that /etc/audit/auditd.conf does not have unix mode -rw-r-----? - - - - Verify the NX (no-execution) bit flag is set on the system. - -Check that the no-execution bit flag is set with the following commands: - -$ sudo dmesg | grep NX - -[ 0.000000] NX (Execute Disable) protection: active - -If "dmesg" does not show "NX (Execute Disable) protection" active, check the cpuinfo settings with the following command: - -$ sudo grep flags /proc/cpuinfo -flags : fpu vme de pse tsc ms nx rdtscp lm constant_ts - -The output should contain the "nx" flag. - Is it the case that NX is disabled? - - - - Verify the operating system routinely checks the baseline configuration for unauthorized changes. - -To determine that periodic AIDE execution has been scheduled, run the following command: -$ grep aide /etc/crontab -The output should return something similar to the following: -05 4 * * * root /usr/sbin/aide --check - -NOTE: The usage of special cron times, such as @daily or @weekly, is acceptable. - Is it the case that AIDE is not configured to scan periodically? - - - - Verify that Oracle Linux 9 contains no duplicate User IDs (UIDs) for interactive users. - -Check that the operating system contains no duplicate UIDs for interactive users with the following command: - -$ sudo awk -F ":" 'list[$3]++{print $1, $3}' /etc/passwd - Is it the case that output is produced and the accounts listed are interactive user accounts? - - - - Run the following command to determine if the bind package is installed: -$ rpm -q bind - Is it the case that the package is installed? - - - - Verify that a separate file system/partition has been created for /dev/shm with the following command: - -$ mountpoint /dev/shm - - Is it the case that "/dev/shm is not a mountpoint" is returned? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_MODIFY_LDT_SYSCALL /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfiles" command with the following command: - -$ sudo auditctl -l | grep setfiles - --a always,exit -F path=/usr/sbin/setfiles -F perm=x -F auid>=1000 -F auid!=unset -k privileged-unix-update - Is it the case that the command does not return a line, or the line is commented out? - - - + -Run the following command to determine if the auditadm_exec_content SELinux boolean is enabled: -$ getsebool auditadm_exec_content -If properly configured, the output should show the following: -auditadm_exec_content --> on - Is it the case that auditadm_exec_content is not enabled? - - - - Run the following command to determine if the McAfeeTP package is installed: $ rpm -q McAfeeTP - Is it the case that the package is not installed? - - - - Verify that Oracle Linux 9 does not have unauthorized IP tunnels configured. +To check that the rlogin service is disabled in system boot configuration with xinetd, run the following command: +$ chkconfig rlogin --list +Output should indicate the rlogin service has either not been installed, or has been disabled, as shown in the example below: +$ chkconfig rlogin --list +Note: This output shows SysV services only and does not include native +systemd services. SysV configuration data might be overridden by native +systemd configuration. -# yum list installed libreswan -libreswan.x86-64 3.20-5.el7_4 +If you want to list systemd services use 'systemctl list-unit-files'. +To see services enabled on particular target use +'systemctl list-dependencies [target]'. +rlogin off -If "libreswan" is installed, check to see if the "IPsec" service is active with the following command: +To check that the rlogin socket is disabled in system boot configuration with systemd, run the following command: +$ systemctl is-enabled rlogin +Output should indicate the rlogin socket has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rlogindisabled -# systemctl status ipsec -ipsec.service - Internet Key Exchange (IKE) Protocol Daemon for IPsec -Loaded: loaded (/usr/lib/systemd/system/ipsec.service; disabled) -Active: inactive (dead) +Run the following command to verify rlogin is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rlogin +If the socket is not running the command will return the following output: +inactive -If the "IPsec" service is active, check for configured IPsec connections (conn), perform the following: -grep -rni conn /etc/ipsec.conf /etc/ipsec.d/ -Verify any returned results for organizational approval. - Is it the case that the IPSec tunnels are not approved? - - - - To ensure the screensaver is configured to be blank, run the following command: -$ gsettings get org.gnome.desktop.screensaver picture-uri -If properly configured, the output should be ''. +The socket will also be masked, to check that the rlogin is masked, run the following command: +$ sudo systemctl show rlogin | grep "LoadState\|UnitFileState" -To ensure that users cannot set the screensaver background, run the following: -$ grep picture-uri /etc/dconf/db/local.d/locks/* -If properly configured, the output should be /org/gnome/desktop/screensaver/picture-uri - Is it the case that it is not set or configured properly? - - - - Run the following command to determine if the gssproxy package is installed: -$ rpm -q gssproxy - Is it the case that the package is installed? - - - - Verify that Oracle Linux 9 has a DNS mode configured in Network Manager. +If the socket is masked the command will return the following outputs: -$ NetworkManager --print-config -[main] -dns= - Is it the case that the dns key under main does not exist or is not set to "none" or "default"? - - - - Verify the nosuid option is configured for the /opt mount point, - run the following command: - $ sudo mount | grep '\s/opt\s' - . . . /opt . . . nosuid . . . +LoadState=masked - Is it the case that the "/opt" file system does not have the "nosuid" option set? - - - - To ensure write permissions are disabled for group and other - for each element in root's path, run the following command: -# ls -ld DIR - Is it the case that group or other write permissions exist? - - - - Verify Oracle Linux 9 is configured to lock an account until released by an administrator -after unsuccessful logon -attempts with the command: - -$ grep 'unlock_time =' /etc/security/faillock.conf -unlock_time = - Is it the case that the "unlock_time" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_unlock_time" />", -the line is missing, or commented out? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SECURITY_YAMA /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To verify that OpenSSL uses the system crypto policy, check out that the OpenSSL config file -/etc/pki/tls/openssl.cnf contains the [ crypto_policy ] section with the -.include = /etc/crypto-policies/back-ends/opensslcnf.config directive: - -$ sudo grep '\.include\s* /etc/crypto-policies/back-ends/opensslcnf.config$' /etc/pki/tls/openssl.cnf. - Is it the case that the OpenSSL config file doesn't contain the whole section, -or the section doesn't contain the <pre>.include = /etc/crypto-policies/back-ends/opensslcnf.config</pre> directive? - - - - Determine where the audit logs are stored with the following command: - -$ sudo grep -iw log_file /etc/audit/auditd.conf - -log_file = /var/log/audit/audit.log - -Determine the owner of the audit log directory by using the output of the above command -(default: "/var/log/audit/"). Run the following command with the correct audit log directory -path: - -$ sudo ls -ld /var/log/audit - -drwx------ 2 root root 23 Jun 11 11:56 /var/log/audit - -The audit log directory must be owned by "root" - Is it the case that the directory is not owned by root? - - - - To verify all local initialization files for interactive users are owned by the -primary user, run the following command: -$ sudo ls -al /home/USER/.* -The user initialization files should be owned by USER. - Is it the case that they are not? - - - - Check that the symlink exists and target the correct Kerberos crypto policy, with the following command: -file /etc/krb5.conf.d/crypto-policies -If command ouput shows the following line, Kerberos is configured to use the system-wide crypto policy. -/etc/krb5.conf.d/crypto-policies: symbolic link to /etc/crypto-policies/back-ends/krb5.config - Is it the case that the symlink does not exist or points to a different target? - - - - The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.drop_gratuitous_arp -1. - - Is it the case that the correct value is not returned? - - - - To determine that AIDE is verifying ACLs, run the following command: -$ grep acl /etc/aide.conf -Verify that the acl option is added to the correct ruleset. - Is it the case that the acl option is missing or not added to the correct ruleset? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes audit=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*audit=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*audit=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'audit=1' -The command should not return any output. - Is it the case that auditing is not enabled at boot time? - - - - To check if the system login banner is compliant, -run the following command: - -$ cat /etc/issue - Is it the case that it does not display the required banner? - - - - -If the system is configured to prevent the loading of the atm kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the atm kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r atm /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify that rsyslog's Forwarding Output Module has CA certificate -configured for its TLS connections to remote server, run the following command: -$ grep DefaultNetstreamDriverCAFile /etc/rsyslog.conf /etc/rsyslog.d/*.conf -The output should include record similar to -global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem") -where the path to the CA file (/etc/pki/tls/cert.pem in case above) must point to the correct CA certificate. - Is it the case that CA certificate for rsyslog remote logging via TLS is not set? - - - - To verify that the audit system collects unauthorized file accesses, run the following commands: -$ sudo grep EACCES /etc/audit/audit.rules -$ sudo grep EPERM /etc/audit/audit.rules - Is it the case that 32-bit and 64-bit system calls to creat, open, openat, open_by_handle_at, truncate, and ftruncate are not audited during EACCES and EPERM? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules -The output has to be exactly as follows: -## Unsuccessful permission change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change --a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change - Is it the case that the file does not exist or the content differs? - - - - The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried -by running the following command: -$ sysctl kernel.kexec_load_disabled -1. - - Is it the case that the correct value is not returned? - - - - Verify the umask setting is configured correctly in the /etc/bashrc file with the following command: - -$ sudo grep "umask" /etc/bashrc - -umask - Is it the case that the value for the "umask" parameter is not "<sub idref="var_accounts_user_umask" />", or the "umask" parameter is missing or is commented out? - - - - To verify that root's primary group is zero run the following command: - - grep '^root:' /etc/passwd | cut -d : -f 4 - -The command should return: - -0 - - Is it the case that root has a primary gid not equal to zero? - - - - Inspect /etc/audit/auditd.conf and locate the following line to -determine if the system is configured correctly: -space_left SIZE_in_MB - Is it the case that the system is not configured a specfic size in MB to notify administrators of an issue? - - - - The tftp package can be removed with the following command: $ sudo yum erase tftp - Is it the case that ? - - - - To check which SSH protocol version is allowed, check version of -openssh-server with following command: -$ rpm -qi openssh-server | grep Version -Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. -If version is lower than 7.4, run the following command to check configuration: -To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: - -$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the permissions of /etc/cron.daily, -run the command: -$ ls -l /etc/cron.daily -If properly configured, the output should indicate the following permissions: --rwx------ - Is it the case that /etc/cron.daily does not have unix mode -rwx------? - - - - The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.send_redirects -0. - - Is it the case that the correct value is not returned? - - - - To verify whether audispd plugin off-loads audit records onto a different -system or media from the system being audited, run the following command: - -$ sudo grep -i remote_server /etc/audit/audisp-remote.conf - -The output should return something similar to where REMOTE_SYSTEM -is an IP address or hostname: -remote_server = REMOTE_SYSTEM - -Determine which partition the audit records are being written to with the -following command: - -$ sudo grep log_file /etc/audit/auditd.conf -log_file = /var/log/audit/audit.log - -Check the size of the partition that audit records are written to with the -following command and verify whether it is sufficiently large: - -$ sudo df -h /var/log/audit/ -/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit - Is it the case that audispd is not sending logs to a remote system and the local partition has inadequate space? - - - - Verify the system commands contained in the following directories are group-owned by "root", or a required system account, with the following command: - -$ sudo find -L /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin ! -group root -exec ls -l {} \; - Is it the case that any system commands are returned and is not group-owned by a required system account? - - - - Run the following command to determine if the dovecot package is installed: -$ rpm -q dovecot - Is it the case that the package is installed? - - - - To check the permissions of /etc/group, -run the command: -$ ls -l /etc/group -If properly configured, the output should indicate the following permissions: --rw-r--r-- - Is it the case that /etc/group does not have unix mode -rw-r--r--? - - - - To verify that remote access methods are logging to rsyslog, -run the following command: -grep -rE '(auth.\*|authpriv.\*|daemon.\*)' /etc/rsyslog.* -The output should contain auth.*, authpriv.*, and daemon.* -pointing to a log file. - Is it the case that remote access methods are not logging to rsyslog? - - - - System commands are stored in the following directories: -/bin -/sbin -/usr/bin -/usr/sbin -/usr/local/bin -/usr/local/sbin -For each of these directories, run the following command to find directories not -owned by root: -$ sudo find -L $DIR ! -group root -type d -exec chgrp root {} \; - Is it the case that any of these directories are not group owned by root? - - - - To check the ownership of /etc/iptables, -run the command: -$ ls -lL /etc/iptables -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/iptables does not have an owner of root? - - - - The runtime status of the fs.suid_dumpable kernel parameter can be queried -by running the following command: -$ sysctl fs.suid_dumpable -0. - - Is it the case that the correct value is not returned? - - - - -To properly set the group owner of /etc/audit/, run the command: -$ sudo chgrp root /etc/audit/ - -To properly set the group owner of /etc/audit/rules.d/, run the command: -$ sudo chgrp root /etc/audit/rules.d/ - Is it the case that ? - - - - To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: - -$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config - -If a line indicating no is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Verify Oracle Linux 9 disables storing core dumps for all users by issuing the following command: - -$ grep -i storage /etc/systemd/coredump.conf - -Storage=none - Is it the case that Storage is not set to none or is commented out and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? - - - - The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.route_localnet -0. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "chage" command with the following command: - -$ sudo auditctl -l | grep chage - --a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset -k privileged-chage - Is it the case that the command does not return a line, or the line is commented out? - - - - If the system uses IPv6, this is not applicable. - -If the system is configured to disable the -ipv6 kernel module, it will contain a line -of the form: -options ipv6 disable=1 -Such lines may be inside any file in /etc/modprobe.d or the -deprecated/etc/modprobe.conf. This permits insertion of the IPv6 -kernel module (which other parts of the system expect to be present), but -otherwise keeps it inactive. Run the following command to search for such -lines in all files in /etc/modprobe.d and the deprecated -/etc/modprobe.conf: -$ grep -r ipv6 /etc/modprobe.conf /etc/modprobe.d - Is it the case that the ipv6 kernel module is not disabled? - - - - The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.ip_local_port_range -32768 65535. - - Is it the case that the correct value is not returned? +UnitFileState=masked + Is it the case that service and/or socket are running? @@ -261556,6 +285068,126 @@ rngd service: $ sudo systemctl is-active rngd If the service is running, it should return the following: active Is it the case that the "rngd" service is disabled, masked, or not started.? + + + + To check that the rsyncd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled rsyncd +Output should indicate the rsyncd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled rsyncd disabled + +Run the following command to verify rsyncd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active rsyncd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the rsyncd is masked, run the following command: +$ sudo systemctl show rsyncd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "rsyncd" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +rsyslog service: +$ sudo systemctl is-active rsyslog +If the service is running, it should return the following: active + Is it the case that the "rsyslog" service is disabled, masked, or not started.? + + + + To check that the snmpd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled snmpd +Output should indicate the snmpd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled snmpd disabled + +Run the following command to verify snmpd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active snmpd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the snmpd is masked, run the following command: +$ sudo systemctl show snmpd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "snmpd" is loaded and not masked? + + + + To check that the squid service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled squid +Output should indicate the squid service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled squid disabled + +Run the following command to verify squid is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active squid + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the squid is masked, run the following command: +$ sudo systemctl show squid | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "squid" is loaded and not masked? + + + + To check that the sshd service is disabled in system boot configuration, +run the following command: +$ sudo systemctl is-enabled sshd +Output should indicate the sshd service has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled sshd disabled + +Run the following command to verify sshd is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active sshd + +If the service is not running the command will return the following output: +inactive + +The service will also be masked, to check that the sshd is masked, run the following command: +$ sudo systemctl show sshd | grep "LoadState\|UnitFileState" + +If the service is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that the "sshd" is loaded and not masked? + + + + + +Run the following command to determine the current status of the +sshd service: +$ sudo systemctl is-active sshd +If the service is running, it should return the following: active + Is it the case that sshd service is disabled? @@ -261568,85 +285200,927 @@ If the service is running, it should return the following: active Is it the case that the service is not enabled? - + -If the system is configured to prevent the loading of the tipc kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. -These lines can also instruct the module loading system to ignore the tipc kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r tipc /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? +Run the following command to determine the current status of the +syslog-ng service: +$ sudo systemctl is-active syslog-ng +If the service is running, it should return the following: active + Is it the case that the "syslog-ng" service is disabled, masked, or not started.? - - Verify the "/etc/security/faillock.conf" file is configured to log user name information when unsuccessful logon attempts occur: + + To verify that acquiring, saving, and processing core dumps is disabled, run the +following command: +$ systemctl status systemd-coredump.socket +The output should be similar to: +● systemd-coredump.socket + Loaded: masked (Reason: Unit systemd-coredump.socket is masked.) + Active: inactive (dead) ... -$ sudo grep audit /etc/security/faillock.conf - -audit - Is it the case that the "audit" option is not set, is missing or commented out? + Is it the case that unit systemd-coredump.socket is not masked or running? - - Verify Oracle Linux 9 is configured to lock an account after -unsuccessful logon attempts with the command: + + -$ grep 'deny =' /etc/security/faillock.conf -deny = . - Is it the case that the "deny" option is not set to "<sub idref="var_accounts_passwords_pam_faillock_deny" />" -or less (but not "0"), is missing or commented out? +Run the following command to determine the current status of the +systemd-journald service: +$ sudo systemctl is-active systemd-journald +If the service is running, it should return the following: active + Is it the case that the systemd-journald service is not running? - - To verify that there are no .shosts files -on the system, run the following command: -$ sudo find / -name '.shosts' - Is it the case that .shosts files exist? + + +To check that the telnet service is disabled in system boot configuration with xinetd, run the following command: +$ chkconfig telnet --list +Output should indicate the telnet service has either not been installed, or has been disabled, as shown in the example below: +$ chkconfig telnet --list + +Note: This output shows SysV services only and does not include native +systemd services. SysV configuration data might be overridden by native +systemd configuration. + +If you want to list systemd services use 'systemctl list-unit-files'. +To see services enabled on particular target use +'systemctl list-dependencies [target]'. + +telnet off + +To check that the telnet socket is disabled in system boot configuration with systemd, run the following command: +$ systemctl is-enabled telnet +Output should indicate the telnet socket has either not been installed, +or has been disabled at all runlevels, as shown in the example below: +$ sudo systemctl is-enabled telnetdisabled + +Run the following command to verify telnet is not active (i.e. not running) through current runtime configuration: +$ sudo systemctl is-active telnet + +If the socket is not running the command will return the following output: +inactive + +The socket will also be masked, to check that the telnet is masked, run the following command: +$ sudo systemctl show telnet | grep "LoadState\|UnitFileState" + +If the socket is masked the command will return the following outputs: + +LoadState=masked + +UnitFileState=masked + Is it the case that service and/or socket are running? - - Verify that Oracle Linux 9 is configured to audit the execution of the "setfacl" command with the following command: + + -$ sudo auditctl -l | grep setfacl - --a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_mod - Is it the case that the command does not return a line, or the line is commented out? +Run the following command to determine the current status of the +ufw service: +$ sudo systemctl is-active ufw +If the service is running, it should return the following: active + Is it the case that the service is not enabled? - - The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried + + + +Run the following command to determine the current status of the +usbguard service: +$ sudo systemctl is-active usbguard +If the service is running, it should return the following: active + Is it the case that the service is not enabled? + + + + Inspect the file /etc/firewalld/firewalld.conf to determine +the default zone for the firewalld. It should be set to DefaultZone=drop: +$ sudo grep DefaultZone /etc/firewalld/firewalld.conf + Is it the case that the default zone is not set to DROP? + + + + If IPv6 is disabled, this is not applicable. + +Inspect the file /etc/sysconfig/ip6tables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/ip6tables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + Inspect the file /etc/sysconfig/iptables to determine +the default policy for the INPUT chain. It should be set to DROP: +$ sudo grep ":INPUT" /etc/sysconfig/iptables + Is it the case that the default policy for the INPUT chain is not set to DROP? + + + + Run the following command to ensure the default FORWARD policy is DROP: +grep ":FORWARD" /etc/sysconfig/iptables +The output should be similar to the following: +$ sudo grep ":FORWARD" /etc/sysconfig/iptables +:FORWARD DROP [0:0 + Is it the case that the default policy for the FORWARD chain is not set to DROP? + + + + Verify that the libuser is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i crypt_style /etc/libuser.conf + +crypt_style = + Is it the case that crypt_style is not set to sha512? + + + + Verify that the shadow password suite configuration is set to encrypt password with a FIPS 140-3 approved cryptographic hashing algorithm. + + +Check the hashing algorithm that is being used to hash passwords with the following command: + +$ sudo grep -i ENCRYPT_METHOD /etc/login.defs + +ENCRYPT_METHOD + Is it the case that ENCRYPT_METHOD is not set to <sub idref="var_password_hashing_algorithm" />? + + + + Inspect the password section of /etc/pam.d/password-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ grep /etc/pam.d/password-auth + Is it the case that it does not? + + + + Inspect the password section of /etc/pam.d/system-auth +and ensure that the pam_unix.so module is configured to use the argument +: + +$ sudo grep "^password.*pam_unix\.so.*" /etc/pam.d/system-auth + +password sufficient pam_unix.so + Is it the case that "<sub idref="var_password_hashing_algorithm_pam" />" is missing, or is commented out? + + + + Inspect /etc/login.defs and ensure that if either +SHA_CRYPT_MIN_ROUNDS or SHA_CRYPT_MAX_ROUNDS +are set, they must have the minimum value of . + Is it the case that it does not? + + + + To ensure only SNMPv3 or newer is used, run the following command: +$ sudo grep 'rocommunity\|rwcommunity\|com2sec' /etc/snmp/snmpd.conf | grep -v "^#" +There should be no output. + Is it the case that there is output? + + + + To check if RekeyLimit is set correctly, run the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config.d/*.conf +If configured properly, output should be +/etc/ssh/ssh_config.d/02-rekey-limit.conf: +RekeyLimit +Check also the main configuration file with the following command: +$ sudo grep RekeyLimit /etc/ssh/ssh_config +The command should not return any output. + Is it the case that it is commented out or is not set? + + + + For each private key stored on the system, use the following command: +$ sudo ssh-keygen -y -f /path/to/file +If the contents of the key are displayed, this is a finding. + Is it the case that no ssh private key is accessible without a passcode? + + + + To check which SSH protocol version is allowed, check version of openssh-server with following command: + +$ rpm -qi openssh-server | grep Version + +Versions equal to or higher than 7.4 only allow Protocol 2. +If version is lower than 7.4, run the following command to check configuration: +$ sudo grep Protocol /etc/ssh/sshd_config +If configured properly, output should be Protocol 2 + Is it the case that it is commented out or is not set correctly to Protocol 2? + + + + To check if compression is enabled or set correctly, run the +following command: +$ sudo grep Compression /etc/ssh/sshd_config +If configured properly, output should be no or delayed. + Is it the case that it is commented out, or is not set to no or delayed? + + + + To determine how the SSH daemon's PermitEmptyPasswords option is set, run the following command: + +$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PermitEmptyPasswords /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's KerberosAuthentication option is set, run the following command: + +$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i KerberosAuthentication /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: + +$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check which SSH protocol version is allowed, check version of +openssh-server with following command: +$ rpm -qi openssh-server | grep Version +Versions equal to or higher than 7.4 have deprecated the RhostsRSAAuthentication option. +If version is lower than 7.4, run the following command to check configuration: +To determine how the SSH daemon's RhostsRSAAuthentication option is set, run the following command: + +$ sudo grep -i RhostsRSAAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitRootLogin option is set, run the following command: + +$ sudo grep -i PermitRootLogin /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating prohibit-password is returned, then the required value is set. + Is it the case that it is commented out or not configured properly? + + + + To determine how the SSH daemon's AllowTcpForwarding option is set, run the following command: + +$ sudo grep -i AllowTcpForwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating no is returned, then the required value is set. + Is it the case that The AllowTcpForwarding option exists and is disabled? + + + + To determine how the SSH daemon's IgnoreUserKnownHosts option is set, run the following command: + +$ sudo grep -i IgnoreUserKnownHosts /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PermitUserEnvironment option is set, run the following command: + +$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PermitUserEnvironment /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating no is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's GSSAPIAuthentication option is set, run the following command: + +$ sudo grep -i GSSAPIAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's UsePAM option is set, run the following command: + +$ sudo grep -i UsePAM /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: + +$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's StrictModes option is set, run the following command: + +$ sudo grep -i StrictModes /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i StrictModes /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's Banner option is set, run the following command: + +$ sudo grep -i Banner /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating /etc/issue is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's Banner option is set, run the following command: + +$ sudo grep -i Banner /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating /etc/issue.net is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's X11Forwarding option is set, run the following command: + +$ sudo grep -i X11Forwarding /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To ensure sshd limits the users who can log in, run the following: +$ sudo grep -rPi '^\h*(allow|deny)(users|groups)\h+\H+(\h+.*)?$' /etc/ssh/sshd_config* +If properly configured, the output should be a list of usernames and/or +groups allowed to log in to this system. + Is it the case that sshd does not limit the users who can log in? + + + + To determine how the SSH daemon's PrintLastLog option is set, run the following command: + +$ sudo grep -i PrintLastLog /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i PrintLastLog /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To check if RekeyLimit is set correctly, run the +following command: + +$ sudo grep RekeyLimit /etc/ssh/sshd_config /etc/ssh/sshd_config.d/* + +If configured properly, output should be +RekeyLimit + Is it the case that it is commented out or is not set? + + + + Run the following command to see what the timeout interval is: +$ sudo grep ClientAliveInterval /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveInterval + Is it the case that it is commented out or not configured properly? + + + + To ensure ClientAliveInterval is set correctly, run the following command: +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config +If properly configured, the output should be: +ClientAliveCountMax +For SSH earlier than v8.2, a ClientAliveCountMax value of 0 causes a timeout precisely when +the ClientAliveInterval is set. Starting with v8.2, a value of 0 disables the timeout +functionality completely. +If the option is set to a number greater than 0, then the session will be disconnected after +ClientAliveInterval * ClientAliveCountMax seconds without receiving a keep alive message. + Is it the case that it is commented out or not configured properly? + + + + To ensure ClientAliveInterval is set correctly, run the following command: + +$ sudo grep ClientAliveCountMax /etc/ssh/sshd_config /etc/ssh/sshd_config.d/*.conf + +If properly configured, the output should be: +ClientAliveCountMax 0 + +In this case, the SSH timeout occurs precisely when +the ClientAliveInterval is set. + Is it the case that it is commented out or not configured properly? + + + + To ensure LoginGraceTime is set correctly, run the following command: +$ sudo grep LoginGraceTime /etc/ssh/sshd_config +If properly configured, the output should be: +LoginGraceTime +If the option is set to a number greater than 0, then the unauthenticated session will be disconnected +after the configured number seconds. + Is it the case that it is commented out or not configured properly? + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: + +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating INFO is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To determine how the SSH daemon's LogLevel option is set, run the following command: + +$ sudo grep -i LogLevel /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf + + +If a line indicating VERBOSE is returned, then the required value is set. + + Is it the case that the required value is not set? + + + + To ensure the MaxAuthTries parameter is set, run the following command: +$ sudo grep MaxAuthTries /etc/ssh/sshd_config +If properly configured, output should be: +MaxAuthTries + Is it the case that it is commented out or not configured properly? + + + + Run the following command to see what the max sessions number is: +$ sudo grep MaxSessions /etc/ssh/sshd_config +If properly configured, the output should be: +MaxSessions + Is it the case that MaxSessions is not configured or not configured correctly? + + + + To check if MaxStartups is configured, run the following command: +$ sudo grep -r ^[\s]*MaxStartups /etc/ssh/sshd_config* +If configured, this command should output the configuration. + Is it the case that maxstartups is not configured? + + + + To determine whether the SSH server includes configuration files from the right directory, run the following command: +$ sudo grep -i '^Include' /etc/ssh/sshd_config +If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. + Is it the case that you don't include other configuration files from the main configuration file? + + + + To check if UsePrivilegeSeparation is enabled or set correctly, run the +following command: +$ sudo grep UsePrivilegeSeparation /etc/ssh/sshd_config +If configured properly, output should be . + Is it the case that it is commented out or is not enabled? + + + + To determine how the SSH daemon's X11UseLocalhost option is set, run the following command: + +$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf +$ sudo grep -i X11UseLocalhost /etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.conf + +If a line indicating yes is returned, then the required value is set. + Is it the case that the display proxy is listening on wildcard address? + + + + Check to see if Online Certificate Status Protocol (OCSP) +is enabled and using the proper digest value on the system with the following command: +$ sudo grep certificate_verification /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf | grep -v "^#" +If configured properly, output should look like + + certificate_verification = ocsp_dgst= + + Is it the case that certificate_verification in sssd is not configured? + + + + To verify Certmap is enabled in SSSD, run the following command: +$ sudo cat /etc/sssd/sssd.conf +If configured properly, output should contain section like the following + +[certmap/testing.test/rule_name] +matchrule =<SAN>.*EDIPI@mil +maprule = (userCertificate;binary={cert!bin}) +domains = testing.test + + Is it the case that Certmap is not configured in SSSD? + + + + To verify that SSSD is configured for PAM services, run the following command: +$ sudo grep services /etc/sssd/sssd.conf +If configured properly, output should be similar to +services = pam + Is it the case that it does not exist or 'pam' is not added to the 'services' option under the 'sssd' section? + + + + To verify that smart cards are enabled in SSSD, run the following command: +$ sudo grep pam_cert_auth /etc/sssd/sssd.conf +If configured properly, output should be +pam_cert_auth = True + + +To verify that smart cards are enabled in PAM files, run the following command: +$ sudo grep -e "auth.*pam_sss\.so.*\(allow_missing_name\|try_cert_auth\)" /etc/pam.d/smartcard-auth /etc/pam.d/system-auth +If configured properly, output should be + +/etc/pam.d/smartcard-auth:auth sufficient pam_sss.so allow_missing_name +/etc/pam.d/system-auth:auth [success=done authinfo_unavail=ignore ignore=ignore default=die] pam_sss.so try_cert_auth + + Is it the case that smart cards are not enabled in SSSD? + + + + Verify Oracle Linux 9 for PKI-based authentication has valid certificates by constructing a +certification path (which includes status information) to an accepted trust anchor. + +Check that the system has a valid DoD root CA installed with the following command: + +$ sudo openssl x509 -text -in /etc/sssd/pki/sssd_auth_ca_db.pem + +Certificate: +Data: +Version: 3 (0x2) +Serial Number: 1 (0x1) +Signature Algorithm: sha256WithRSAEncryption +Issuer: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Validity +Not Before: Mar 20 18:46:41 2012 GMT +Not After : Dec 30 18:46:41 2029 GMT +Subject: C = US, O = U.S. Government, OU = DoD, OU = PKI, CN = DoD Root CA 3 +Subject Public Key Info: +Public Key Algorithm: rsaEncryption + Is it the case that root CA file is not a DoD-issued certificate with a valid date and installed in the /etc/sssd/pki/sssd_auth_ca_db.pem location? + + + + To verify the LDAP client backend demands a valid certificate from the server in +remote LDAP access sessions, run the following command: +$ sudo grep ldap_tls_reqcert /etc/sssd/sssd.conf +The output should return the following: +ldap_tls_reqcert = demand + Is it the case that the TLS reqcert is not set to demand? + + + + If the system is not using TLS, set the ldap_id_use_start_tls option +in /etc/sssd/sssd.conf to true. + Is it the case that the 'ldap_id_use_start_tls' option is not set to 'true'? + + + + +Check if SSSD allows cached authentications with the following command: + +$ sudo grep cache_credentials /etc/sssd/sssd.conf +cache_credentials = true + +If "cache_credentials" is set to "false" or is missing no further checks are required. + +To verify that SSSD expires offline credentials, run the following command: +$ sudo grep offline_credentials_expiration /etc/sssd/sssd.conf /etc/sssd/conf.d/*.conf +If configured properly, output should be +offline_credentials_expiration = 1 + Is it the case that it does not exist or is not configured properly? + + + + To determine if NOEXEC has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\bnoexec\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that noexec is not enabled in sudo? + + + + To determine if requiretty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that requiretty is not enabled in sudo? + + + + To determine if use_pty has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults.*\buse_pty\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that use_pty is not enabled in sudo? + + + + To determine if logfile has been configured for sudo, run the following command: +$ sudo grep -ri "^[\s]*Defaults\s*\blogfile\b.*" /etc/sudoers /etc/sudoers.d/ +The command should return a matching output. + Is it the case that logfile is not enabled in sudo? + + + + To check the group ownership of /usr/bin/sudo, +run the command: +$ ls -lL /usr/bin/sudo +If properly configured, the output should indicate the following group-owner: + + + + Is it the case that /usr/bin/sudo does not have a group owner of +<sub idref="var_sudo_dedicated_group" /> +? + + + + To determine if !authenticate has not been configured for sudo, run the following command: +$ sudo grep -r \!authenticate /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that !authenticate is specified in the sudo config files? + + + + To determine if NOPASSWD has been configured for sudo, run the following command: +$ sudo grep -ri nopasswd /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd is specified in the sudo config files? + + + + To determine if NOPASSWD or !authenticate have been configured for +sudo, run the following command: +$ sudo grep -ri "nopasswd\|\!authenticate" /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that nopasswd and/or !authenticate is enabled in sudo? + + + + Verify the operating system requires re-authentication +when using the "sudo" command to elevate privileges, run the following command: +sudo grep -ri '^Defaults.*timestamp_timeout' /etc/sudoers /etc/sudoers.d +The output should be: +/etc/sudoers:Defaults timestamp_timeout=0 or "timestamp_timeout" is set to a positive number. +If conflicting results are returned, this is a finding. + Is it the case that timestamp_timeout is not set with the appropriate value for sudo? + + + + Determine if "sudoers" file restricts sudo access run the following commands: +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* +$ sudo grep -PR '^\s*ALL\s+ALL\=\(ALL\:ALL\)\s+ALL\s*$' /etc/sudoers /etc/sudoers.d/* + Is it the case that either of the commands returned a line? + + + + To determine if NOPASSWD has been configured for the vdsm user for sudo, +run the following command: +$ sudo grep -ri nopasswd /etc/sudoers.d/ +The command should return output only for the vdsm user. + Is it the case that nopasswd is set for any users beyond vdsm? + + + + To determine if arguments that commands can be executed with are restricted, run the following command: +$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+(?:[ \t]+[^,\s]+)+[ \t]*,)*(\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,\s]+[ \t]*(?:,|$))' /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that /etc/sudoers file contains user specifications that allow execution of commands with any arguments? + + + + To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: +$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).*' /etc/sudoers /etc/sudoers.d/ +The command should return no output. + Is it the case that /etc/sudoers file contains rules that define the set of allowed commands using negation? + + + + To determine if the users are allowed to run commands as root, run the following commands: +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*[^\(\s]' /etc/sudoers /etc/sudoers.d/ +and +$ sudo grep -PR '^\s*((?!root\b)[\w]+)\s*(\w+)\s*=\s*(.*,)?\s*\([\w\s]*\b(root|ALL)\b[\w\s]*\)' /etc/sudoers /etc/sudoers.d/ +Both commands should return no output. + Is it the case that /etc/sudoers file contains rules that allow non-root users to run commands as root? + + + + Run the following command to Verify that the sudoers security policy is configured to use the invoking user's password for privilege escalation: + sudo cvtsudoers -f sudoers /etc/sudoers | grep -E '^Defaults !?(rootpw|targetpw|runaspw)' +or if cvtsudoers not supported: + sudo find /etc/sudoers /etc/sudoers.d \( \! -name '*~' -a \! -name '*.*' \) -exec grep -E --with-filename '^[[:blank:]]*Defaults[[:blank:]](.*[[:blank:]])?!?\b(rootpw|targetpw|runaspw)' -- {} \; +If no results are returned, this is a finding. +If conflicting results are returned, this is a finding. +If "Defaults !targetpw" is not defined, this is a finding. +If "Defaults !rootpw" is not defined, this is a finding. +If "Defaults !runaspw" is not defined, this is a finding. + Is it the case that invoke user passwd when using sudo? + + + + To verify that kernel parameter 'crypto.fips_enabled' is set properly, run the following command: +sysctl crypto.fips_enabled +The output should contain the following: +crypto.fips_enabled = 1 + Is it the case that crypto.fips_enabled is not 1? + + + + The runtime status of the fs.protected_fifos kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.icmp_echo_ignore_broadcasts +$ sysctl fs.protected_fifos +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the fs.protected_hardlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_hardlinks 1. Is it the case that the correct value is not returned? - - Verify Oracle Linux 9 disables core dump backtraces by issuing the following command: + + The runtime status of the fs.protected_regular kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_regular +2. -$ grep -i process /etc/systemd/coredump.conf - -ProcessSizeMax=0 - Is it the case that the "ProcessSizeMax" item is missing, commented out, or the value is anything other than "0" and the need for core dumps is not documented with the Information System Security Officer (ISSO) as an operational requirement for all domains that have the "core" item assigned? + Is it the case that the correct value is not returned? - - To determine if the system is configured to make login UIDs immutable, run -one of the following commands. -If the auditd daemon is configured to use the -augenrules program to read audit rules during daemon startup (the -default), run the following: -sudo grep immutable /etc/audit/rules.d/*.rules -If the auditd daemon is configured to use the auditctl -utility to read audit rules during daemon startup, run the following command: -sudo grep immutable /etc/audit/audit.rules -The following line should be returned: ---loginuid-immutable - Is it the case that the system is not configured to make login UIDs immutable? + + The runtime status of the fs.protected_symlinks kernel parameter can be queried +by running the following command: +$ sysctl fs.protected_symlinks +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the fs.suid_dumpable kernel parameter can be queried +by running the following command: +$ sysctl fs.suid_dumpable +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern +|/bin/false. + + Is it the case that the returned line does not have a value of "|/bin/false", or a line is not +returned and the need for core dumps is not documented with the Information +System Security Officer (ISSO) as an operational requirement? + + + + The runtime status of the kernel.core_pattern kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_pattern | cat -A +kernel.core_pattern = $ + + Is it the case that the returned line does not have an empty string? + + + + The runtime status of the kernel.core_uses_pid kernel parameter can be queried +by running the following command: +$ sysctl kernel.core_uses_pid +0. + Is it the case that the returned line does not have a value of 0? + + + + The runtime status of the kernel.dmesg_restrict kernel parameter can be queried +by running the following command: +$ sysctl kernel.dmesg_restrict +1. + + Is it the case that the correct value is not returned? + + + + To verify ExecShield is enabled on 64-bit Oracle Linux 9 systems, +run the following command: +$ dmesg | grep '[NX|DX]*protection' +The output should not contain 'disabled by kernel command line option'. +Inspect the form of default GRUB 2 command line for the Linux operating system +in /etc/default/grub. If it includes noexec=off, +then the parameter will be configured for newly installed kernels. +First check if the GRUB recovery is enabled: +$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub +If this option is set to true, then check that a line is output by the following command: +$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*noexec=off.*' /etc/default/grub +If the recovery is disabled, check the line with +$ sudo grep 'GRUB_CMDLINE_LINUX.*noexec=off.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. +Run the following command: +$ sudo grubby --info=ALL | grep args | grep -v 'noexec=off' +The command should not return any output. + Is it the case that ExecShield is not supported by the hardware, is not enabled, or has been disabled by the kernel configuration.? + + + + The runtime status of the kernel.kexec_load_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.kexec_load_disabled +1. + + Is it the case that the correct value is not returned? @@ -261676,168 +286150,211 @@ Conflicting assignments are not allowed. Is it the case that the kernel.kptr_restrict is not set to 1 or 2 or is configured to be 0? - - To determine how the SSH daemon's StrictModes option is set, run the following command: - -$ sudo grep -i StrictModes /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To check the ownership of /etc/cron.deny, -run the command: -$ ls -lL /etc/cron.deny -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.deny does not have an owner of root? - - - - The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried + + The runtime status of the kernel.modules_disabled kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.conf.all.shared_media -0. - - Is it the case that the correct value is not returned? - - - - To check the password warning age, run the command: -$ grep PASS_WARN_AGE /etc/login.defs -The DoD requirement is 7. - Is it the case that it is not set to the required value? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ grep "sec=" /etc/exports -All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - To check the group ownership of /etc/passwd-, -run the command: -$ ls -lL /etc/passwd- -If properly configured, the output should indicate the following group-owner: -root - Is it the case that /etc/passwd- does not have a group owner of root? - - - - The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.tcp_rfc1337 +$ sysctl kernel.modules_disabled 1. Is it the case that the correct value is not returned? - - To verify the nodev option is configured for all NFS mounts, run -the following command: -$ mount | grep nfs -All NFS mounts should show the nodev setting in parentheses. This -is not applicable if NFS is not implemented. - Is it the case that the setting does not show? - - - - To determine whether yum has been configured to disable -gpgcheck for any repos, inspect all files in -/etc/yum.repos.d and ensure the following does not appear in any -sections: -gpgcheck=0 -A value of 0 indicates that gpgcheck has been disabled for that repo. - Is it the case that GPG checking is disabled? - - - - To determine if requiretty has been configured for sudo, run the following command: -$ sudo grep -ri "^[\s]*Defaults.*\brequiretty\b.*" /etc/sudoers /etc/sudoers.d/ -The command should return a matching output. - Is it the case that requiretty is not enabled in sudo? - - - - -Run the following command to get the current configured value for deny_execmem -SELinux boolean: -$ getsebool deny_execmem -The expected cofiguration is . -"on" means true, and "off" means false - Is it the case that deny_execmem is not set as expected? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the truncate system call. + + The runtime status of the kernel.panic_on_oops kernel parameter can be queried +by running the following command: +$ sysctl kernel.panic_on_oops +1. -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r truncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep truncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? + Is it the case that the correct value is not returned? - - To ensure the system is configured to ignore the Ctrl-Alt-Del sequence, -run the following command: -$ gsettings get org.gnome.settings-daemon.plugins.media-keys logout -$ grep logout /etc/dconf/db/local.d/locks/* -If properly configured, the output should be -/org/gnome/settings-daemon/plugins/media-keys/logout - Is it the case that GNOME3 is configured to reboot when Ctrl-Alt-Del is pressed? - - - - The following command will list which files on the system have permissions different from what -is expected by the RPM database: -$ rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }' - Is it the case that there is output? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudo" command with the following command: + + The runtime status of the kernel.perf_cpu_time_max_percent kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_cpu_time_max_percent +1. -$ sudo auditctl -l | grep sudo + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_max_sample_rate +1. --a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudo - Is it the case that the command does not return a line, or the line is commented out? + Is it the case that the correct value is not returned? - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes mce=0, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*mce=0.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*mce=0.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'mce=0' -The command should not return any output. - Is it the case that MCE tolerance is not set to zero? + + The runtime status of the kernel.perf_event_paranoid kernel parameter can be queried +by running the following command: +$ sysctl kernel.perf_event_paranoid +2. + + Is it the case that the correct value is not returned? - - Run the following command to determine if the rng-tools package is installed: $ rpm -q rng-tools - Is it the case that the package is not installed? + + The runtime status of the kernel.pid_max kernel parameter can be queried +by running the following command: +$ sysctl kernel.pid_max +65536. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.randomize_va_space kernel parameter can be queried +by running the following command: +$ sysctl kernel.randomize_va_space +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.sysrq kernel parameter can be queried +by running the following command: +$ sysctl kernel.sysrq +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.unprivileged_bpf_disabled kernel parameter can be queried +by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the kernel.unprivileged_bpf_disabled +kernel parameter can be queried by running the following command: +$ sysctl kernel.unprivileged_bpf_disabled +The output of the command should indicate either: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 +The output of the command should not indicate: +kernel.unprivileged_bpf_disabled = 0 + +The preferable way how to assure the runtime compliance is to have +correct persistent configuration, and rebooting the system. + +The persistent kernel parameter configuration is performed by specifying the appropriate +assignment in any file located in the /etc/sysctl.d directory. +Verify that there is not any existing incorrect configuration by executing the following command: +$ grep -r '^\s*\s*=' /etc/sysctl.conf /etc/sysctl.d +The command should not find any assignments other than: +kernel.unprivileged_bpf_disabled = 1 +or: +kernel.unprivileged_bpf_disabled = 2 + +Duplicate assignments are not allowed. Empty output is allowed, because the system default is 2. + Is it the case that the kernel.unprivileged_bpf_disabled is not set to 1 or 2 or is configured to be 0? + + + + The runtime status of the kernel.yama.ptrace_scope kernel parameter can be queried +by running the following command: +$ sysctl kernel.yama.ptrace_scope +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.core.bpf_jit_harden kernel parameter can be queried +by running the following command: +$ sysctl net.core.bpf_jit_harden +2. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_local kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_local +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.arp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_filter +. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.arp_ignore kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.arp_ignore +. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.drop_gratuitous_arp kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.drop_gratuitous_arp +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + The runtime status of the net.ipv4.conf.all.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.log_martians +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.all.route_localnet kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.route_localnet +0. + + Is it the case that the correct value is not returned? @@ -261846,8 +286363,7 @@ by running the following command: $ sysctl net.ipv4.conf.all.rp_filter The output of the command should indicate either: net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 + The output of the command should not indicate: net.ipv4.conf.all.rp_filter = 0 @@ -261860,756 +286376,37 @@ Verify that there is not any existing incorrect configuration by executing the f $ grep -r '^\s*net.ipv4.conf.all.rp_filter\s*=' /etc/sysctl.conf /etc/sysctl.d The command should not find any assignments other than: net.ipv4.conf.all.rp_filter = 1 -or: -net.ipv4.conf.all.rp_filter = 2 + Conflicting assignments are not allowed. - Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or 2 or is configured to be 0? + Is it the case that the net.ipv4.conf.all.rp_filter is not set to 1 or is configured to be 0 or 2? - - To determine how the SSH daemon's IgnoreRhosts option is set, run the following command: - -$ sudo grep -i IgnoreRhosts /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - Run the following command to ensure the TMOUT value is configured for all users -on the system: - -$ sudo grep TMOUT /etc/profile /etc/profile.d/*.sh - -The output should return the following: -TMOUT= - Is it the case that value of TMOUT is not less than or equal to expected setting? - - - - To determine how the SSH daemon's LogLevel option is set, run the following command: - -$ sudo grep -i LogLevel /etc/ssh/sshd_config - -If a line indicating INFO is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules -The output has to be exactly as follows: -## Successful ownership change --a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change --a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change - Is it the case that the file does not exist or the content differs? - - - - To determine whether the SSH server includes configuration files from the right directory, run the following command: -$ sudo grep -i '^Include' /etc/ssh/sshd_config -If a line Include /etc/ssh/sshd_config.d/*.conf is returned, then the configuration file inclusion is set correctly. - Is it the case that you don't include other configuration files from the main configuration file? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/etc/security/opasswd" with the following command: - -$ sudo auditctl -l | grep -E '(/etc/security/opasswd)' - --w /etc/security/opasswd -p wa -k identity - Is it the case that the command does not return a line, or the line is commented out? - - - - To check the permissions of /etc/sestatus.conf, -run the command: -$ ls -l /etc/sestatus.conf -If properly configured, the output should indicate the following permissions: -0644 - Is it the case that /etc/sestatus.conf does not have unix mode 0644? - - - - To determine that AIDE is verifying extended file attributes, run the following command: -$ grep xattrs /etc/aide.conf -Verify that the xattrs option is added to the correct ruleset. - Is it the case that the xattrs option is missing or not added to the correct ruleset? - - - - Verify that Oracle Linux 9 has configured the minimum time period between password changes for each user account is one day or greater with the following command: - -$ sudo awk -F: '$4 < 1 {print $1 " " $4}' /etc/shadow - Is it the case that any results are returned that are not associated with a system account? - - - - Verify that the SA and ISSO (at a minimum) are notified when the audit storage volume is full. - -Check which action Oracle Linux 9 takes when the audit storage volume is full with the following command: - -$ sudo grep max_log_file_action /etc/audit/auditd.conf -max_log_file_action = - Is it the case that the value of the "max_log_file_action" option is set to "ignore", "rotate", or "suspend", or the line is commented out? - - - - To verify that cryptography policy has been configured correctly, run the -following command: -$ update-crypto-policies --show -The output should return . -Run the command to check if the policy is correctly applied: -$ update-crypto-policies --is-applied -The output should be The configured policy is applied. -Moreover, check if settings for selected crypto policy are as expected. -List all libraries for which it holds that their crypto policies do not have symbolic link in /etc/crypto-policies/back-ends. -$ ls -l /etc/crypto-policies/back-ends/ | grep '^[^l]' | tail -n +2 | awk -F' ' '{print $NF}' | awk -F'.' '{print $1}' | sort -Subsequently, check if matching libraries have drop in files in the /etc/crypto-policies/local.d directory. -$ ls /etc/crypto-policies/local.d/ | awk -F'-' '{print $1}' | uniq | sort -Outputs of two previous commands should match. - Is it the case that cryptographic policy is not configured or is configured incorrectly? - - - - Verify Oracle Linux 9 generates audit records for all account creations, modifications, disabling, and termination events that affect "/var/log/lastlog" with the following command: - -$ sudo auditctl -l | grep /var/log/lastlog - --w /var/log/lastlog -p wa -k logins - Is it the case that the command does not return a line, or the line is commented out? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes iommu=force, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*iommu=force.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*iommu=force.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'iommu=force' -The command should not return any output. - Is it the case that I/OMMU is not activated? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEVKMEM /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Run the following command and verify that time sources are only configured with server directive: -# grep -E "^(server|pool)" /etc/chrony.conf -A line with the appropriate server should be returned, any line returned starting with pool is a finding. - Is it the case that an authoritative remote time server is not configured or configured with pool directive? - - - - To check the permissions of /var/log/messages, -run the command: -$ ls -l /var/log/messages -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /var/log/messages does not have unix mode -rw-------? - - - - Verify Oracle Linux 9 enforces 24 hours/one day as the minimum password lifetime for new user accounts. - -Check for the value of "PASS_MIN_DAYS" in "/etc/login.defs" with the following command: - -$ grep -i pass_min_days /etc/login.defs - -PASS_MIN_DAYS - Is it the case that the "PASS_MIN_DAYS" parameter value is not "<sub idref="var_accounts_minimum_age_login_defs" />" or greater, or is commented out? - - - - Run the following command to determine if the libreswan package is installed: $ rpm -q libreswan - Is it the case that the package is not installed? - - - - Ensure that debug-shell service is not enabled with the following command: -grep systemd\.debug-shell=1 /boot/grub2/grubenv /etc/default/grub -If the command returns a line, it means that debug-shell service is being enabled. - Is it the case that the comand returns a line? - - - - Using a non-privileged account, verify that users cannot modify or change -network settings with the nmcli command with the following command: -$ nmcli general permissions -The output should contain the following: -PERMISSION VALUE -org.freedesktop.NetworkManager.enable-disable-network auth -org.freedesktop.NetworkManager.enable-disable-wifi auth -org.freedesktop.NetworkManager.enable-disable-wwan auth -org.freedesktop.NetworkManager.enable-disable-wimax auth -org.freedesktop.NetworkManager.sleep-wake auth -org.freedesktop.NetworkManager.network-control auth -org.freedesktop.NetworkManager.wifi.share.protected auth -org.freedesktop.NetworkManager.wifi.share.open auth -org.freedesktop.NetworkManager.settings.modify.system auth -org.freedesktop.NetworkManager.settings.modify.own auth -org.freedesktop.NetworkManager.settings.modify.hostname auth -org.freedesktop.NetworkManager.settings.modify.global-dns auth -org.freedesktop.NetworkManager.reload auth -org.freedesktop.NetworkManager.checkpoint-rollback auth -org.freedesktop.NetworkManager.enable-disable-statistics auth -org.freedesktop.NetworkManager.enable-disable-connectivity-check auth -org.freedesktop.NetworkManager.wifi.scan auth - - Is it the case that non-privileged users can modify or change network settings? - - - - Verify the nodev option is configured for the /boot mount point, - run the following command: - $ sudo mount | grep '\s/boot\s' - . . . /boot . . . nodev . . . - - Is it the case that the "/boot" file system does not have the "nodev" option set? - - - - Verify that Oracle Linux 9 enforces password complexity by requiring that at least one numeric character be used. - -Check the value for "dcredit" with the following command: - -$ sudo grep dcredit /etc/security/pwquality.conf /etc/security/pwquality.conf.d/*.conf - -/etc/security/pwquality.conf:dcredit = - Is it the case that the value of "dcredit" is a positive number or is commented out? - - - - To determine how the SSH daemon's PubkeyAuthentication option is set, run the following command: - -$ sudo grep -i PubkeyAuthentication /etc/ssh/sshd_config - -If a line indicating yes is returned, then the required value is set. - - Is it the case that the required value is not set? - - - - The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried + + The runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter can be queried by running the following command: -$ sysctl net.ipv4.conf.default.secure_redirects +$ sysctl net.ipv4.conf.all.secure_redirects 0. Is it the case that the correct value is not returned? - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/10-base-config.rules -The output has to be exactly as follows: -## First rule - delete all --D - -## Increase the buffers to survive stress events. -## Make this bigger for busy systems --b 8192 - -## This determine how long to wait in burst of events ---backlog_wait_time 60000 - -## Set failure mode to syslog --f 1 - Is it the case that the file does not exist or the content differs? - - - - Verify the nodev option is configured for the /home mount point, - run the following command: - $ sudo mount | grep '\s/home\s' - . . . /home . . . nodev . . . - - Is it the case that the "/home" file system does not have the "nodev" option set? - - - - To check the status of the idle screen lock activation, run the following command: - -$ gsettings get org.gnome.desktop.screensaver lock-enabled -If properly configured, the output should be true. -To ensure that users cannot change how long until the screensaver locks, run the following: -$ grep lock-enabled /etc/dconf/db/local.d/locks/* -If properly configured, the output for lock-enabled should be /org/gnome/desktop/screensaver/lock-enabled - Is it the case that screensaver locking is not enabled and/or has not been set or configured correctly? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes page_poison=1, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*page_poison=1.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*page_poison=1.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'page_poison=1' -The command should not return any output. - Is it the case that page allocator poisoning is not enabled? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "sudoedit" command with the following command: - -$ sudo auditctl -l | grep sudoedit - --a always,exit -F path=/usr/bin/sudoedit -F perm=x -F auid>=1000 -F auid!=unset -k privileged-sudoedit - Is it the case that the command does not return a line, or the line is commented out? - - - - -If the system is configured to prevent the loading of the sctp kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the sctp kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r sctp /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - To verify that auditing is configured for system administrator actions, run the following command: -$ sudo auditctl -l | grep "watch=/etc/sudoers\|watch=/etc/sudoers.d\|-w /etc/sudoers\|-w /etc/sudoers.d" - Is it the case that there is not output? - - - - To determine if the system is configured to audit calls to the -fchownat system call, run the following command: -$ sudo grep "fchownat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To check the ownership of /etc/cron.d, -run the command: -$ ls -lL /etc/cron.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/cron.d does not have an owner of root? - - - - Run the following command and verify remote server is configured properly: -# grep -E "^(server|pool)" /etc/chrony.conf - Is it the case that a remote time server is not configured? - - - - To verify all files and directories in interactive user home directory are -group-owned by a group the user is a member of, run the -following command: -$ sudo ls -lLR /home/USER - Is it the case that the group ownership is incorrect? - - - - If the system does not have SELinux enabled and enforcing a targeted policy, or if the -pam_faillock.so module is not configured for use, this requirement is not applicable. - -Verify the location of the non-default tally directory for the pam_faillock.so module with -the following command: - -$ sudo grep -w dir /etc/security/faillock.conf - -dir = /var/log/faillock - -Check the security context type of the non-default tally directory with the following command: - -$ sudo ls -Zd /var/log/faillock - -unconfined_u:object_r:faillog_t:s0 /var/log/faillock - Is it the case that the security context type of the non-default tally directory is not "faillog_t"? - - - - To check the ownership of /etc/shells, -run the command: -$ ls -lL /etc/shells -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shells does not have an owner of root? - - - - Verify that the interactive user account passwords are using a strong -password hash with the following command: - -$ sudo cut -d: -f2 /etc/shadow - -$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/ - -Password hashes ! or * indicate inactive accounts not -available for logon and are not evaluated. - Is it the case that any interactive user password hash does not begin with "$6"? - - - - To verify that automatic logins are disabled, run the following command: -$ grep -Pzoi "^\[daemon]\\nautomaticlogin.*" /etc/gdm/custom.conf -The output should show the following: -[daemon] -AutomaticLoginEnable=false - Is it the case that GDM allows users to automatically login? - - - - Verify that Oracle Linux 9 enforces a -day maximum password lifetime for new user accounts by running the following command: - -$ grep -i pass_max_days /etc/login.defs - -PASS_MAX_DAYS - Is it the case that the "PASS_MAX_DAYS" parameter value is greater than "<sub idref="var_accounts_maximum_age_login_defs" />", or commented out? - - - - To determine if the system is configured to audit calls to the -fchmodat system call, run the following command: -$ sudo grep "fchmodat" /etc/audit/audit.* -If the system is configured to audit this activity, it will return a line. - - Is it the case that no line is returned? - - - - To determine if negation is used to define commands users are allowed to execute using sudo, run the following command: -$ sudo grep -PR '^(?:\s*[^#=]+)=(?:\s*(?:\([^\)]+\))?\s*(?!\s*\()[^,!\n][^,\n]+,)*\s*(?:\([^\)]+\))?\s*(?!\s*\()(!\S+).*' /etc/sudoers /etc/sudoers.d/ -The command should return no output. - Is it the case that /etc/sudoers file contains rules that define the set of allowed commands using negation? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_SLUB_DEBUG /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - Inspect /etc/default/grub for any instances of -systemd.confirm_spawn=(1|yes|true|on) in the kernel boot arguments. -Presence of a systemd.confirm_spawn=(1|yes|true|on) indicates -that interactive boot is enabled at boot time and verify that -GRUB_DISABLE_RECOVERY=true to disable recovery boot. - Is it the case that Interactive boot is enabled at boot time? - - - - To check the permissions of /boot/grub2/user.cfg, -run the command: -$ ls -l /boot/grub2/user.cfg -If properly configured, the output should indicate the following permissions: --rw------- - Is it the case that /boot/grub2/user.cfg does not have unix mode -rw-------? - - - - To check the permissions of /etc/shadow, -run the command: -$ ls -l /etc/shadow -If properly configured, the output should indicate the following permissions: ----------- - Is it the case that /etc/shadow does not have unix mode ----------? - - - - To verify that the Audit is correctly configured according to recommended rules, check the content of the file with the following command: -cat /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules -The output has to be exactly as follows: -## Successful file delete --a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete --a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete - Is it the case that the file does not exist or the content differs? - - - - Run the following command to determine if the iprutils package is installed: -$ rpm -q iprutils - Is it the case that the package is installed? - - - - The runtime status of the kernel.perf_event_max_sample_rate kernel parameter can be queried + + The runtime status of the net.ipv4.conf.all.send_redirects kernel parameter can be queried by running the following command: -$ sysctl kernel.perf_event_max_sample_rate -1. - - Is it the case that the correct value is not returned? - - - - Verify that Oracle Linux 9 loads the driver with the following command: - -$ grep card_drivers /etc/opensc.conf - -card_drivers = ; - Is it the case that "<sub idref="var_smartcard_drivers" />" is not listed as a card driver, or there is no line returned for "card_drivers"? - - - - The runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter can be queried -by running the following command: -$ sysctl net.ipv4.conf.all.accept_source_route +$ sysctl net.ipv4.conf.all.send_redirects 0. Is it the case that the correct value is not returned? - - Verify that Oracle Linux 9 's INACTIVE conforms to site policy (no more than 30 days) with the following command: + + The runtime status of the net.ipv4.conf.all.shared_media kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.all.shared_media +0. -$ sudo awk -F: '$7 > 30 {print $1 " " $7}' /etc/shadow - Is it the case that the value of INACTIVE is greater than the expected value or is -1? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_DEBUG_FS /boot/config.* - - Configs with value 'n' are not explicitly set in the file, so either commented lines or no - lines should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check the ownership of /boot/grub2/grub.cfg, -run the command: -$ ls -lL /boot/grub2/grub.cfg -If properly configured, the output should indicate the following owner: -root - Is it the case that /boot/grub2/grub.cfg does not have an owner of root? - - - - Verify that Oracle Linux 9 is configured to audit the execution of the "restorecon" command with the following command: - -$ sudo auditctl -l | grep restorecon - --a always,exit -F path=/usr/sbin/restorecon -F perm=x -F auid>=1000 -F auid!=unset -k privileged-restorecon - Is it the case that the command does not return a line, or the line is commented out? - - - - Verify Oracle Linux 9 generates an audit record for unsuccessful attempts to use the ftruncate system call. - -If the auditd daemon is configured to use the "augenrules" program to to read audit rules during daemon startup (the default), run the following command: - -$ sudo grep -r ftruncate /etc/audit/rules.d - -If the auditd daemon is configured to use the "auditctl" utility to read audit rules during daemon startup, run the following command: - -$ sudo grep ftruncate /etc/audit/audit.rules - -The output should be the following: - --a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access --a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access - Is it the case that the command does not return a line, or the line is commented out? - - - - Run the following command to determine if the setroubleshoot-plugins package is installed: -$ rpm -q setroubleshoot-plugins - Is it the case that the package is installed? - - - - -If the system is configured to prevent the loading of the dccp kernel module, -it will contain lines inside any file in /etc/modprobe.d or the deprecated /etc/modprobe.conf. -These lines instruct the module loading system to run another program (such as /bin/false) upon a module install event. - -These lines can also instruct the module loading system to ignore the dccp kernel module via blacklist keyword. - -Run the following command to search for such lines in all files in /etc/modprobe.d and the deprecated /etc/modprobe.conf: -$ grep -r dccp /etc/modprobe.conf /etc/modprobe.d - Is it the case that no line is returned? - - - - Verify all local interactive users on Oracle Linux 9 are assigned a home -directory upon creation with the following command: -$ grep -i create_home /etc/login.defs -CREATE_HOME yes - Is it the case that the value for "CREATE_HOME" parameter is not set to "yes", the line is missing, or the line is commented out? - - - - To ensure the MaxAuthTries parameter is set, run the following command: -$ sudo grep MaxAuthTries /etc/ssh/sshd_config -If properly configured, output should be: -MaxAuthTries - Is it the case that it is commented out or not configured properly? - - - - Verify file systems that are used for removable media are mounted with the "nodev" option with the following command: - -$ sudo more /etc/fstab - -UUID=2bc871e4-e2a3-4f29-9ece-3be60c835222 /mnt/usbflash vfat noauto,owner,ro,nosuid,nodev,noexec 0 0 - Is it the case that a file system found in "/etc/fstab" refers to removable media and it does not have the "nodev" option set? - - - - To verify the local initialization files of all local interactive users are group- -owned by the appropriate user, inspect the primary group of the respective -users in /etc/passwd and verify all initialization files under the -respective users home directory. Check the group owner of all local interactive users -initialization files. - Is it the case that they are not? - - - - To check the ownership of /etc/nftables, -run the command: -$ ls -lL /etc/nftables -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/nftables does not have an owner of root? - - - - To check the ownership of /etc/shadow-, -run the command: -$ ls -lL /etc/shadow- -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/shadow- does not have an owner of root? - - - - To determine the config value the kernel was built with, run the following command: - $ grep CONFIG_PAGE_POISONING_ZERO /boot/config.* - - For each kernel installed, a line with value "y" should be returned. - - Is it the case that the kernel was not built with the required value? - - - - To check if pam_pwquality.so is enabled in system-auth, run the following command: -$ grep pam_pwquality /etc/pam.d/system-auth -The output should be similar to the following: -password requisite pam_pwquality.so - Is it the case that pam_pwquality.so is not enabled in system-auth? - - - - Verify Oracle Linux 9 is configured to limit the "pwquality" retry option to . - - -Check for the use of the "pwquality" retry option in the pwquality.conf file with the following command: -$ grep retry /etc/security/pwquality.conf - Is it the case that the value of "retry" is set to "0" or greater than "<sub idref="var_password_pam_retry" />", or is missing? - - - - -Run the following command to determine if the authlogin_radius SELinux boolean is disabled: -$ getsebool authlogin_radius -If properly configured, the output should show the following: -authlogin_radius --> off - Is it the case that authlogin_radius is not disabled? - - - - To check the ownership of /etc/sysctl.d, -run the command: -$ ls -lL /etc/sysctl.d -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/sysctl.d does not have an owner of root? - - - - Verify the Oracle Linux 9 "fapolicyd" employs a deny-all, permit-by-exception policy. - -Check that "fapolicyd" is in enforcement mode with the following command: - -$ sudo grep permissive /etc/fapolicyd/fapolicyd.conf - -permissive = 0 - -Check that fapolicyd employs a deny-all policy on system mounts with the following commands: -$ sudo tail /etc/fapolicyd/compiled.rules - -allow exe=/usr/bin/python3.7 : ftype=text/x-python -deny_audit perm=any pattern=ld_so : all -deny perm=any all : all - Is it the case that fapolicyd is not running in enforcement mode with a deny-all, permit-by-exception policy? - - - - Verify the nosuid option is configured for the /var/log mount point, - run the following command: - $ sudo mount | grep '\s/var/log\s' - . . . /var/log . . . nosuid . . . - - Is it the case that the "/var/log" file system does not have the "nosuid" option set? - - - - Verify that a separate file system/partition has been created for /home with the following command: - -$ mountpoint /home - - Is it the case that "/home is not a mountpoint" is returned? - - - - To verify the sec option is configured for all NFS mounts, run the following command: -$ mount | grep "sec=" -All NFS mounts should show the sec=krb5:krb5i:krb5p setting in parentheses. -This is not applicable if NFS is not implemented. - Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? - - - - Inspect the form of default GRUB 2 command line for the Linux operating system -in /etc/default/grub. If it includes spec_store_bypass_disable=, -then the parameter will be configured for newly installed kernels. -First check if the GRUB recovery is enabled: -$ sudo grep 'GRUB_DISABLE_RECOVERY' /etc/default/grub -If this option is set to true, then check that a line is output by the following command: -$ sudo grep 'GRUB_CMDLINE_LINUX_DEFAULT.*spec_store_bypass_disable=.*' /etc/default/grub -If the recovery is disabled, check the line with -$ sudo grep 'GRUB_CMDLINE_LINUX.*spec_store_bypass_disable=.*' /etc/default/grub.Moreover, command line parameters for currently installed kernels should be checked as well. -Run the following command: -$ sudo grubby --info=ALL | grep args | grep -v 'spec_store_bypass_disable=' -The command should not return any output. - Is it the case that SSB is not configured appropriately? + Is it the case that the correct value is not returned? @@ -262621,40 +286418,456 @@ $ sysctl net.ipv4.conf.default.accept_redirects Is it the case that the correct value is not returned? - - To verify that auditing of privileged command use is configured, run the -following command: -$ sudo grep usernetctl /etc/audit/audit.rules /etc/audit/rules.d/* -It should return a relevant line in the audit rules. - Is it the case that the command does not return a line, or the line is commented out? + + The runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? - - Verify the operating system is not configured to bypass password requirements for privilege -escalation. Check the configuration of the "/etc/pam.d/sudo" file with the following command: -$ sudo grep pam_succeed_if /etc/pam.d/sudo - Is it the case that system is configured to bypass password requirements for privilege escalation? + + The runtime status of the net.ipv4.conf.default.log_martians kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.log_martians +1. + + Is it the case that the correct value is not returned? - - To check the ownership of /etc/ssh/*.pub, -run the command: -$ ls -lL /etc/ssh/*.pub -If properly configured, the output should indicate the following owner: -root - Is it the case that /etc/ssh/*.pub does not have an owner of root? + + The runtime status of the net.ipv4.conf.default.rp_filter kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.rp_filter +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.secure_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.send_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.send_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.conf.default.shared_media kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.conf.default.shared_media +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.icmp_echo_ignore_broadcasts +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.icmp_ignore_bogus_error_responses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.ip_forward kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.ip_forward +0. +The ability to forward packets is only appropriate for routers. + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.ip_local_port_range kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.ip_local_port_range +32768 65535. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.tcp_rfc1337 kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.tcp_rfc1337 +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv4.tcp_syncookies kernel parameter can be queried +by running the following command: +$ sysctl net.ipv4.tcp_syncookies +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_defrtr +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.autoconf +0. + + Is it the case that the correct value is not returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.all.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps all network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled on all network interfaces? + + + + The runtime status of the net.ipv6.conf.all.forwarding kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.forwarding +0. +The ability to forward packets is only appropriate for routers. + Is it the case that IP forwarding value is "1" and the system is not router? + + + + The runtime status of the net.ipv6.conf.all.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.all.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.all.router_solicitations +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_defrtr kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_defrtr +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_pinfo kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_pinfo +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_ra_rtr_pref kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_ra_rtr_pref +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_redirects +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.accept_source_route +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.autoconf kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.autoconf +0. + + Is it the case that the correct value is not returned? + + + + If the system uses IPv6, this is not applicable. + +If the system is configured to prevent the usage of the ipv6 on +network interfaces, it will contain a line of the form: +net.ipv6.conf.default.disable_ipv6 = 1 +Such lines may be inside any file in the /etc/sysctl.d directory. +This permits insertion of the IPv6 kernel module (which other parts of the +system expect to be present), but otherwise keeps network interfaces +from using IPv6. Run the following command to search for such lines in all +files in /etc/sysctl.d: +$ grep -r ipv6 /etc/sysctl.d + Is it the case that the ipv6 support is disabled by default on network interfaces? + + + + The runtime status of the net.ipv6.conf.default.max_addresses kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.max_addresses +1. + + Is it the case that the correct value is not returned? + + + + The runtime status of the net.ipv6.conf.default.router_solicitations kernel parameter can be queried +by running the following command: +$ sysctl net.ipv6.conf.default.router_solicitations +0. + + Is it the case that the correct value is not returned? + + + + Verify that Oracle Linux 9 disables the use of user namespaces with the following commands: + +Note: User namespaces are used primarily for Linux containers. If containers are in use, this requirement is not applicable. + +The runtime status of the user.max_user_namespaces kernel parameter can be queried +by running the following command: +$ sysctl user.max_user_namespaces +0. + + Is it the case that the correct value is not returned? + + + + The runtime status of the vm.mmap_min_addr kernel parameter can be queried +by running the following command: +$ sysctl vm.mmap_min_addr +65536. + + Is it the case that the correct value is not returned? + + + + +Run the following command to determine the current status of the +tmp mount: +$ sudo systemctl is-active tmp.mount +If the mount unit is running, it should return the following: active + Is it the case that the tmp.mount unit is masked or disabled? + + + + Use sudo systemctl show tftp to verify that tftp service is using secure mode. +$ sudo systemctl show tftp | grep ExecStart= +ExecStart={ path=/usr/sbin/in.tftpd ; argv[]=/usr/sbin/in.tftpd -s /var/lib/tftpboot ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }e + + +and ensure the ExecStart line on that file includes the -s option with a subdirectory: +ExecStart=/usr/sbin/in.tftpd -s + Is it the case that the ExecStart property of tftp does not contain correctly set -s flag? + + + + Run the following command to determine the current status of the dnf-automatic timer: $ sudo systemctl is-active dnf-automatic.timer If the timer is running, it should return the following: active + Is it the case that the dnf-automatic.timer is not enabled? + + + + Run the following command to determine the current status of the logrotate timer: $ sudo systemctl is-active logrotate.timer If the timer is running, it should return the following: active + Is it the case that logrotate timer is not enabled? + + + + To verify that USB Human Interface Devices and hubs will be authorized by the USBGuard daemon, +run the following command: +$ sudo grep allow /etc/usbguard/rules.conf +The output lines should include +allow with-interface match-all { 03:*:* 09:00:* } + Is it the case that USB devices of class 3 and 9:00 are not authorized? + + + + Verify the USBGuard has a policy configured with the following command: + +$ usbguard list-rules + +allow id 1d6b:0001 serial + +If the command does not return results or an error is returned, ask the SA to indicate how unauthorized peripherals are being blocked. + Is it the case that there is no evidence that unauthorized peripherals are being blocked before establishing a connection? + + + + To verify the sec option is configured for all NFS mounts, run the following command: +$ grep "sec=" /etc/exports +All configured NFS exports should show the sec=krb5:krb5i:krb5p setting in parentheses. +This is not applicable if NFS is not implemented. + Is it the case that the setting is not configured, has the 'sys' option added, or does not have all Kerberos options added? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid + Is it the case that the line is not in the file or it is commented? + + + + Run the following command to check if the line is present: +grep pam_wheel /etc/pam.d/su +The output should contain the following line: +auth required pam_wheel.so use_uid group= + Is it the case that the line is not in the file or it is commented? + + + + Verify that there are no wireless interfaces configured on the system +with the following command: + +Note: This requirement is Not Applicable for systems that do not have physical wireless network radios. + +$ nmcli device status +DEVICE TYPE STATE CONNECTION +virbr0 bridge connected virbr0 +wlp7s0 wifi connected wifiSSID +enp6s0 ethernet disconnected -- +p2p-dev-wlp7s0 wifi-p2p disconnected -- +lo loopback unmanaged -- +virbr0-nic tun unmanaged -- + Is it the case that a wireless interface is configured and has not been documented and approved by the Information System Security Officer (ISSO)? + + + + To ensure the X Windows package group is removed, run the following command: +$ rpm -qi xorg-x11-server-Xorg +$ rpm -qi xorg-x11-server-common +$ rpm -qi xorg-x11-server-utils +$ rpm -qi xorg-x11-server-Xwayland +For each package mentioned above you should receive following line: +package <package> is not installed + Is it the case that xorg related packages are not removed and run level is not correctly configured? + + + + Verify that Oracle Linux 9 is configured to boot to the command line: +$ systemctl get-default +multi-user.target + Is it the case that the system default target is not set to "multi-user.target" and the Information System Security Officer (ISSO) lacks a documented requirement for a graphical user interface? - + build_cpe.py from SCAP Security Guide - ssg: [0, 1, 76], python: 3.9.21 + ssg: [0, 1, 79], python: 3.9.23 5.11 - 2025-05-06T00:00:00 + 2025-12-16T00:00:00 @@ -262669,6 +286882,10 @@ root + + + + @@ -262766,18 +286983,6 @@ root - - - Test that the architecture is ppc64le - - Oracle Linux 9 - - Check that architecture of kernel in /proc/sys/kernel is ppc64le - - - - - Test that the architecture is s390x @@ -262842,32 +287047,6 @@ root - - - Non-UEFI system boot mode check - - Oracle Linux 9 - - - Check if System boot mode is non-UEFI. - - - - - - - - UEFI system boot mode check - - Oracle Linux 9 - - - Check if system boot mode is UEFI. - - - - - @@ -262936,6 +287115,23 @@ root + + + Mountpoint /boot/efi is active (mounted) or configured in /etc/fstab + + Oracle Linux 9 + + + + + + + + + + + + Mountpoint /home is active (mounted) or configured in /etc/fstab @@ -263271,6 +287467,18 @@ root + + + Package libpwquality is installed + + Oracle Linux 9 + + The RPM package libpwquality should be installed. + + + + + Package libreswan is installed @@ -263557,9 +287765,12 @@ root - - - + + + + + + @@ -263573,9 +287784,12 @@ root - - - + + + + + + @@ -263589,9 +287803,12 @@ root - - - + + + + + + @@ -263609,6 +287826,13 @@ root + + + + + + + @@ -263630,9 +287854,6 @@ root - - - @@ -263653,10 +287874,7 @@ root - - - - + @@ -263685,6 +287903,12 @@ root + + + + + + @@ -263816,6 +288040,9 @@ root + + + @@ -263893,6 +288120,10 @@ root + + + + @@ -263904,6 +288135,10 @@ root + + + + @@ -263915,6 +288150,10 @@ root + + + + @@ -263932,6 +288171,12 @@ root openshift-kubelet + + /run/ostree-booted + + + /ostree + grub2-common @@ -263953,22 +288198,17 @@ root 1 - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.aarch64$|^aarch64$ 1 - - /proc/sys/kernel/(osrelease|arch) - ^.*\.ppc64le$|^ppc64le$ - 1 - - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.s390x$|^s390x$ 1 - /proc/sys/kernel/(osrelease|arch) + ^/proc/sys/kernel/(osrelease|arch) ^.*\.x86_64$|^x86_64$ 1 @@ -263989,12 +288229,8 @@ root ^[\s]*\[domain\/[^]]*]([^\n\[\]]*\n+)+?[\s]*id_provider[ \t]*=[ \t]*((?i)ldap)[ \t]*$ 1 - - /sys/firmware/efi - - - kernel + kernel-core kernel-uek @@ -264013,6 +288249,14 @@ root ^\s*GRUB_CMDLINE_LINUX=".*ipv6\.disable=(\d).*$ 1 + + /boot/efi + + + /etc/fstab + ^[\s]*[\S]+[\s]+/boot/efi[\s]+[\S]+[\s]+([\S]+) + 1 + /home @@ -264174,6 +288418,9 @@ root iptables + + libpwquality + libreswan @@ -264278,6 +288525,10 @@ root + + /ostree + symbolic link + 1 @@ -264347,19 +288598,6817 @@ root masked + + not-found + inactive|failed masked + + not-found + inactive|failed masked + + not-found + + + #!/bin/bash +if [[ $(systemctl is-enabled dnf-automatic.timer) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled debug-shell.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled pcscd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rsyslog.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled systemd-journald.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled logrotate.timer) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled syslog-ng.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled firewalld.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled iptables.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash + +# Pass rule if IPv6 is disabled on kernel +if [ ! -e /proc/sys/net/ipv6/conf/all/disable_ipv6 ] || [ "$(cat /proc/sys/net/ipv6/conf/all/disable_ipv6)" -eq 1 ]; then + exit "$XCCDF_RESULT_PASS" +fi + +output="$(ip6tables -L | grep Chain)" +if [ -z "${output}" ]; then + exit "$XCCDF_RESULT_FAIL" +fi + +while read -r line; do + chain=$(echo "$line" | cut -f1-2 -d' ') + policy=$(echo "$line" | cut -f4 -d' ' | tr -d ')') + if [ "$chain" = "Chain INPUT" ] || [ "$chain" = "Chain FORWARD" ] || + [ "$chain" = "Chain OUTPUT" ]; then + if [ "$policy" != "DROP" ] && [ "$policy" != "REJECT" ]; then + exit "$XCCDF_RESULT_FAIL" + fi + fi +done <<< "$output" + +exit "$XCCDF_RESULT_PASS" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="1" +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="1" +check_sysctl_configuration "net.ipv6.conf.default.disable_ipv6" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_defrtr_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_defrtr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_pinfo_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_pinfo" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_ra_rtr_pref_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_ra_rtr_pref" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_redirects_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_accept_source_route_value" +check_sysctl_configuration "net.ipv6.conf.all.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_autoconf_value" +check_sysctl_configuration "net.ipv6.conf.all.autoconf" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_forwarding_value" +check_sysctl_configuration "net.ipv6.conf.all.forwarding" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_max_addresses_value" +check_sysctl_configuration "net.ipv6.conf.all.max_addresses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_all_router_solicitations_value" +check_sysctl_configuration "net.ipv6.conf.all.router_solicitations" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_defrtr_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_defrtr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_pinfo_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_pinfo" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_ra_rtr_pref_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_ra_rtr_pref" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_redirects_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_accept_source_route_value" +check_sysctl_configuration "net.ipv6.conf.default.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_autoconf_value" +check_sysctl_configuration "net.ipv6.conf.default.autoconf" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_max_addresses_value" +check_sysctl_configuration "net.ipv6.conf.default.max_addresses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + +# pass if IPv6 is disabled +check_sysctl_configuration "net.ipv6.conf.all.disable_ipv6" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv6_conf_default_router_solicitations_value" +check_sysctl_configuration "net.ipv6.conf.default.router_solicitations" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.accept_local" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_accept_redirects_value" +check_sysctl_configuration "net.ipv4.conf.all.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_accept_source_route_value" +check_sysctl_configuration "net.ipv4.conf.all.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_arp_filter_value" +check_sysctl_configuration "net.ipv4.conf.all.arp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_arp_ignore_value" +check_sysctl_configuration "net.ipv4.conf.all.arp_ignore" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "net.ipv4.conf.all.drop_gratuitous_arp" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_forwarding_value" +check_sysctl_configuration "net.ipv4.conf.all.forwarding" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_log_martians_value" +check_sysctl_configuration "net.ipv4.conf.all.log_martians" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.route_localnet" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_rp_filter_value" +check_sysctl_configuration "net.ipv4.conf.all.rp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_secure_redirects_value" +check_sysctl_configuration "net.ipv4.conf.all.secure_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_all_shared_media_value" +check_sysctl_configuration "net.ipv4.conf.all.shared_media" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_accept_redirects_value" +check_sysctl_configuration "net.ipv4.conf.default.accept_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_accept_source_route_value" +check_sysctl_configuration "net.ipv4.conf.default.accept_source_route" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_log_martians_value" +check_sysctl_configuration "net.ipv4.conf.default.log_martians" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_rp_filter_value" +check_sysctl_configuration "net.ipv4.conf.default.rp_filter" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_secure_redirects_value" +check_sysctl_configuration "net.ipv4.conf.default.secure_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_conf_default_shared_media_value" +check_sysctl_configuration "net.ipv4.conf.default.shared_media" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value" +check_sysctl_configuration "net.ipv4.icmp_echo_ignore_broadcasts" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value" +check_sysctl_configuration "net.ipv4.icmp_ignore_bogus_error_responses" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="32768 65535" +check_sysctl_configuration "net.ipv4.ip_local_port_range" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_tcp_rfc1337_value" +check_sysctl_configuration "net.ipv4.tcp_rfc1337" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="$XCCDF_VALUE_sysctl_net_ipv4_tcp_syncookies_value" +check_sysctl_configuration "net.ipv4.tcp_syncookies" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.all.send_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.conf.default.send_redirects" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "net.ipv4.ip_forward" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled nftables.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled ufw.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "fs.protected_fifos" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "fs.protected_hardlinks" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "fs.protected_regular" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "fs.protected_symlinks" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled autofs.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="|/bin/false" +check_sysctl_configuration "kernel.core_pattern" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "kernel.core_uses_pid" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.dmesg_restrict" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.kexec_load_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.modules_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.panic_on_oops" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.perf_cpu_time_max_percent" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.perf_event_max_sample_rate" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "kernel.perf_event_paranoid" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="65536" +check_sysctl_configuration "kernel.pid_max" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "kernel.sysrq" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + + +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +check_sysctl_configuration "kernel.unprivileged_bpf_disabled" "2" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="1" +check_sysctl_configuration "kernel.yama.ptrace_scope" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "net.core.bpf_jit_harden" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "user.max_user_namespaces" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="65536" +check_sysctl_configuration "vm.mmap_min_addr" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/bin/bash +if [[ $(systemctl is-enabled systemd-coredump.socket) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="0" +check_sysctl_configuration "fs.suid_dumpable" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + + +check_sysctl_configuration "kernel.kptr_restrict" "1" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +check_sysctl_configuration "kernel.kptr_restrict" "2" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +FILES_NOT_MANAGED_BY_PACKAGES=("/etc/sysctl.conf" "/etc/sysctl.d/*.conf" "/usr/local/lib/sysctl.d/*.conf" "/run/sysctl.d/*.conf") + +FILES_MANAGED_BY_PACKAGES=("/usr/lib/sysctl.d/*.conf") + + +function pass_if_set_correctly() +{ + local filelist="$1" + local regex="$2" + local expected_value="$3" + local found=0 + for files in $filelist ; do + [[ -e "$files" ]] || continue + found_value=$(grep -P "$regex" $files | sed -E "s/$regex/\1/") + if [[ -n "$found_value" ]] ; then + if [[ "$found_value" == "$expected_value" ]] ; then + found=1 + else + return 1 + fi + fi + done + if [[ $found == 1 ]] ; then + return 0 + fi + return 1 +} + +function pass_if_missing() +{ + local filelist="$1" + local regex="$2" + for files in $filelist ; do + [[ -e "$files" ]] || continue + if grep -P "$regex" $files ; then + return 1 + fi + done + return 0 +} + +function check_sysctl_configuration() +{ + local sysctlvar="$1" + local expected_value="$2" + + regex="^\s*$sysctlvar\s*=\s*(.*)\s*" + + # kernel static parameter $sysctlvar set to $sysctlvar in sysctl files not managed by packages + pass_if_set_correctly "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_not_managed="$?" + + # kernel static parameter $sysctlvar missing in sysctl files not managed by packages + pass_if_missing "${FILES_NOT_MANAGED_BY_PACKAGES[*]}" "$regex" + missing_in_not_managed="$?" + + # kernel static parameter $sysctlvar set to $sysctlval in sysctl files managed by packages + pass_if_set_correctly "${FILES_MANAGED_BY_PACKAGES[*]}" "$regex" "$expected_value" + set_correctly_in_managed="$?" + + if [[ "$set_correctly_in_not_managed" == 0 || ( "$missing_in_not_managed" == 0 && "$set_correctly_in_managed" == 0 ) ]] ; then + return 0 + fi + return 1 +} + + + + +expected_value="2" +check_sysctl_configuration "kernel.randomize_va_space" "$expected_value" +if [[ $? == 0 ]] ; then + exit $XCCDF_RESULT_PASS +fi + +exit $XCCDF_RESULT_FAIL + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_auditadm_exec_content" + +check_sebool_value auditadm_exec_content "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_authlogin_nsswitch_use_ldap" + +check_sebool_value authlogin_nsswitch_use_ldap "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_authlogin_radius" + +check_sebool_value authlogin_radius "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_deny_execmem" + +check_sebool_value deny_execmem "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_kerberos_enabled" + +check_sebool_value kerberos_enabled "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_polyinstantiation_enabled" + +check_sebool_value polyinstantiation_enabled "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_secure_mode_insmod" + +check_sebool_value secure_mode_insmod "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execheap" + +check_sebool_value selinuxuser_execheap "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execmod" + +check_sebool_value selinuxuser_execmod "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_selinuxuser_execstack" + +check_sebool_value selinuxuser_execstack "$expected_value" +exit $? + + + + #!/usr/bin/env bash + + + +function check_sebool_value() +{ + local seboolid="$1" + local exp_value="$2" + + # Check if seinfo is available + if command -v seinfo &> /dev/null; then + if seinfo -xb "$seboolid" | grep -q "$seboolid[[:space:]]\+$exp_value;"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + else + # getsebool returns either on or off and we have to translate the value first + if [[ "$2" == "true" ]]; then + exp_value="on" + elif [[ "$2" == "false" ]]; then + exp_value="off" + fi + + if getsebool "$seboolid" | grep -q "$seboolid[[:space:]]-->[[:space:]]$exp_value"; then + return $XCCDF_RESULT_PASS + else + return $XCCDF_RESULT_FAIL + fi + fi +} + +expected_value="$XCCDF_VALUE_var_ssh_sysadm_login" + +check_sebool_value ssh_sysadm_login "$expected_value" +exit $? + + + + #!/bin/bash +if [[ $(systemctl is-enabled avahi-daemon.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled kdump.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled oddjobd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rdisc.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled crond.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled atd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled fapolicyd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled postfix.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled chronyd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rsyncd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rlogin.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled telnet.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled squid.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled rngd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled snmpd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sshd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sshd.service) == "masked" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/usr/bin/env bash + +user_list=$(awk -F: -n '{ if ($7 !~ /\/s?bin\/false/ && $7 !~ /\/s?bin\/nologin/) { print $0; } }' /etc/passwd) +user_dirs=$(cut -d: -f6 <<<"${user_list}" | sort | uniq) +for dir in ${user_dirs} +do + pubkeys=$(find "${dir}/.ssh/" -type f -name '*.pub') + for pubkey in ${pubkeys} + do + ssh-keygen -y -P "" -f "${pubkey%.pub}" >/dev/null + if [ $? -ne 255 ]; then + echo "Key '${pubkey}' is not passphrase-protected" + exit "${XCCDF_RESULT_FAIL}" + fi + done +done + +exit "${XCCDF_RESULT_PASS}" + + + + #!/bin/bash +if [[ $(systemctl is-enabled sssd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled usbguard.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + + + + #!/bin/bash +if [[ $(systemctl is-enabled auditd.service) == "enabled" ]] ; then + exit "$XCCDF_RESULT_PASS" +fi +exit "$XCCDF_RESULT_FAIL" + +