4
0
Fork 0

Merge pull request #355 from ansible-lockdown/devel

Merge latest into devel
This commit is contained in:
jjoympg 2025-07-02 10:50:59 -04:00 committed by GitHub
commit 25b4bb780c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 424 additions and 174 deletions

View file

@ -7,6 +7,7 @@
types: [opened, reopened, synchronize]
branches:
- devel
- benchmark*
paths:
- '**.yml'
- '**.sh'

View file

@ -7,6 +7,7 @@
types: [opened, reopened, synchronize]
branches:
- main
- latest
paths:
- '**.yml'
- '**.sh'
@ -23,6 +24,7 @@
# A workflow run is made up of one or more jobs
# that can run sequentially or in parallel
jobs:
# This workflow contains a single job that tests the playbook
playbook-test:
# The type of runner that the job will run on

View file

@ -41,12 +41,12 @@ repos:
- id: detect-secrets
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.0
rev: v8.27.2
hooks:
- id: gitleaks
- repo: https://github.com/ansible-community/ansible-lint
rev: v25.1.3
rev: v25.6.1
hooks:
- id: ansible-lint
name: Ansible-lint
@ -65,7 +65,7 @@ repos:
# - ansible-core>=2.10.1
- repo: https://github.com/adrienverge/yamllint.git
rev: v1.35.1 # or higher tag
rev: v1.37.1 # or higher tag
hooks:
- id: yamllint
name: Check YAML Lint

View file

@ -1,5 +1,27 @@
# Changes to rhel9CIS
## 2.0.2 - Based on CIS v2.0.0
- Update to audit_only to allow fetching results
- resolved false warning for fetch audit
- fix root user check
- Improved documentation and variable compilation for crypto policies
- Addresses #318 - Thank you @kodebach & @bgro
- Improved logic for 5.2.4 to exclude rhel9cis_sudoers_exclude_nopasswd_list in pre-check tasks/main.yml
## 2.0.1 - Based on CIS v2.0.0
- Thanks to @polski-g several issues and improvements added
- Improved testing for 50-redhat.conf for ssh
- 5.1.x regexp improvements
- Improved root password check
- egrep command changed to grep -E
## 2.0.0 - Based on CIS v2.0.0
- #322, #325 - thanks to @mindrb
- #320 - thanks to @anup-ad
## 1.1.6 - Based on CIS v1.0.0
- #190 - thanks to @ipruteanu-sie

View file

@ -69,7 +69,7 @@ This is managed using tags:
- level2-server
- level2-workstation
The control found in defaults main also need to reflect this as this control the testing thet takes place if you are using the audit component.
The control found in defaults main also need to reflect this as this control the testing that takes place if you are using the audit component.
## Coming from a previous release

View file

@ -1,7 +1,8 @@
---
# defaults file for rhel9-cis
# WARNING:
# These values may be overriden by other vars-setting options(e.g. like the below 'container_vars_file'), as explained here:
# These values may be overridden by other vars-setting options(e.g. like the below 'container_vars_file'), as explained here:
# https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable
# Run the OS validation check
@ -11,7 +12,7 @@ os_check: true
# Disruption is high
## Run tests that are considered higher risk and could have a system impact if not properly tested
## Default false
## Will be fine if clean new unconfigured build
## Will be fine if clean new un-configured build
rhel9cis_disruption_high: false
## Switching on/off specific baseline sections
@ -33,6 +34,10 @@ rhel9cis_section7: true
rhel9cis_level_1: true
rhel9cis_level_2: true
# Create managed not custom local_facts files
create_benchmark_facts: true
ansible_facts_path: /etc/ansible/facts.d
## Section 1.6 - Mandatory Access Control
# This variable governs whether SELinux is disabled or not. If SELinux is NOT DISABLED by setting
# 'rhel9cis_selinux_disable' to 'true', the 1.6 subsection will be executed.
@ -41,7 +46,7 @@ rhel9cis_selinux_disable: false
# UEFI boot('/etc/grub2-efi.cfg') or in case of BIOS legacy-boot('/etc/grub2.cfg').
rhel9cis_legacy_boot: false
## Benchmark name used by audting control role
## Benchmark name used by auditing control role
# The audit variable found at the base
## metadata for Audit benchmark
benchmark_version: 'v2.0.0'
@ -82,7 +87,7 @@ audit_capture_files_dir: /some/location to copy to on control node
# How to retrieve audit binary
# Options are copy or download - detailed settings at the bottom of this file
# you will need to access to either github or the file already dowmloaded
# you will need to access to either github or the file already downloaded
get_audit_binary_method: download
## if get_audit_binary_method - copy the following needs to be updated for your environment
@ -97,7 +102,7 @@ audit_content: git
# If using either archive, copy, get_url:
## Note will work with .tar files - zip will require extra configuration
### If using get_url this is expecting github url in tar.gz format e.g.
### https://github.com/ansible-lockdown/UBUNTU22-CIS-Audit/archive/refs/heads/benchmark-v1.0.0.tar.gz
### https://github.com/ansible-lockdown/RHEL9-CIS-Audit/archive/refs/heads/benchmark-v1.0.0.tar.gz
audit_conf_source: "some path or url to copy from"
# Destination for the audit content to be placed on managed node
@ -107,6 +112,20 @@ audit_conf_dest: "/opt"
# Where the audit logs are stored
audit_log_dir: '/opt'
## Ability to collect and take audit files moving to a centralized location
# This enables the collection of the files from the host
fetch_audit_output: false
# Method of getting,uploading the summary files
## Ensure access and permissions are available for these to occur.
## options are
# fetch - fetches from server and moves to location on the ansible controller (could be a mount point available to controller)
# copy - copies file to a location available to the managed node
audit_output_collection_method: fetch
# Location to put the audit files
audit_output_destination: /opt/audit_summaries/
### Goss Settings ##
####### END ########
@ -495,7 +514,7 @@ rhel9cis_rule_7_2_9: true
## Section 1 vars
## Ability to enabe debug on mounts to assist in troubleshooting
## Ability to enable debug on mounts to assist in troubleshooting
# Mount point changes are set based upon facts created in Prelim
# these then build the variable and options that is passed to the handler to set the mount point for the controls in section1.
rhel9cis_debug_mount_data: false
@ -561,15 +580,15 @@ rhel9cis_crypto_policy: 'DEFAULT'
## Control 1.6
# This variable contains the value of the crypto policy module(combinations of policies and
# sub-policies) to be allowed as default setting. Allowed options are defined in 'vars/main.yml' file,
# using 'rhel9cis_allowed_crypto_policies_modules' variable.
rhel9cis_crypto_policy_module: ''
# using those listed in the 'rhel9cis_allowed_crypto_policies_modules' variable.
rhel9cis_additional_crypto_policy_module: ''
## Controls:
# - 1.7.1 - Ensure message of the day is configured properly
# - 1.7.2 - Ensure local login warning banner is configured properly
# - 1.7.3 - Ensure remote login warning banner is configured properly
# This variable stores the content for the Warning Banner(relevant for issue, issue.net, motd).
rhel9cis_warning_banner: Authorized uses only. All activity may be monitored and reported.
rhel9cis_warning_banner: Authorized users only. All activity may be monitored and reported.
# End Banner
## Control 1.8.x - Settings for GDM
@ -703,23 +722,24 @@ rhel9cis_bluetooth_mask: false
rhel9cis_ipv6_required: true
## 3.1.2 wireless network requirements
# if wireless adapetr found allow network manager to be installed
# if wireless adapter found allow network manager to be installed
rhel9cis_install_network_manager: false
rhel9cis_network_manager_package_name: NetworkManager
# 3.3 System network parameters (host only OR host and router)
# This variable governs whether specific CIS rules
# concerned with acceptance and routing of packages are skipped.
rhel9cis_is_router: false
# This variable governs if the task which updates sysctl(including sysctl reload) is executed.
# NOTE: The current default value is likely to be overriden by other further tasks(via 'set_fact').
# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact').
rhel9cis_sysctl_update: false
# This variable governs if the task which flushes the IPv4 routing table is executed(forcing subsequent connections to
# use the new configuration).
# NOTE: The current default value is likely to be overriden by other further tasks(via 'set_fact').
# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact').
rhel9cis_flush_ipv4_route: false
# This variable governs if the task which flushes the IPv6 routing table is executed(forcing subsequent connections to
# use the new configuration).
# NOTE: The current default value is likely to be overriden by other further tasks(via 'set_fact').
# NOTE: The current default value is likely to be overridden by other further tasks(via 'set_fact').
rhel9cis_flush_ipv6_route: false
# Section 4 vars
@ -871,13 +891,13 @@ rhel9cis_authselect_pkg_update: false # NOTE the risks if system is using SSSD
# To create a new profile (best for greenfield fresh sites not configured)
# This allows creation of a custom profile using an existing one to build from
# will only create if profiel does not already exist
# will only create if profile does not already exist
## options true or false
rhel9cis_authselect_custom_profile_create: true
## Controls:
# - 5.3.2.1 - Ensure custom authselect profile is used
# Settings in place now will fail, they are placeholders from the control example. Due to the way many multiple
# options and ways to configure this control needs to be enabled and settings adjusted to minimise risk.
# options and ways to configure this control needs to be enabled and settings adjusted to minimize risk.
# This variable configures the name of the custom profile to be created and selected.
# To be changed from default - cis_example_profile
@ -1027,14 +1047,14 @@ rhel9cis_bash_umask: '0027' # 0027 or more restrictive
# These are discovered via logins.def if set true
rhel9cis_discover_int_uid: true
# This variable sets the minimum number from which to search for UID
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has
# been set to `true`.
min_int_uid: 1000
### Controls:
# - Ensure local interactive user home directories exist
# - Ensure local interactive users own their home directories
# This variable sets the maximum number at which the search stops for UID
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# Note that the value will be dynamically overwritten if variable `rhel9cis_discover_int_uid` has
# been set to `true`.
max_int_uid: 65533

View file

@ -186,7 +186,7 @@
- name: Update Crypto Policy
ansible.builtin.set_fact:
rhel9cis_full_crypto_policy: "{{ rhel9cis_crypto_policy }}{% if rhel9cis_crypto_policy_module | length > 0 %}{{ rhel9cis_crypto_policy_module }}{% endif %}"
rhel9cis_full_crypto_policy: "{{ rhel9cis_crypto_policy }}{{ rhel9cis_crypto_policy_module }}{% if rhel9cis_additional_crypto_policy_module | length > 0 %}:{{ rhel9cis_additional_crypto_policy_module }}{% endif %}"
notify: Set Crypto Policy
- name: Set Crypto Policy

View file

@ -1,27 +1,17 @@
---
- name: Audit_Only | Create local Directories for hosts
when: fetch_audit_files
ansible.builtin.file:
mode: 'u+x,go-w'
path: "{{ audit_capture_files_dir }}/{{ inventory_hostname }}"
recurse: true
state: directory
delegate_to: localhost
become: false
- name: Audit_only | Get audits from systems and put in group dir
when: fetch_audit_files
ansible.builtin.fetch:
dest: "{{ audit_capture_files_dir }}/{{ inventory_hostname }}/"
flat: true
mode: 'go-wx'
src: "{{ pre_audit_outfile }}"
- name: Audit_only | Fetch audit files
when:
- fetch_audit_output
- audit_only
ansible.builtin.import_tasks:
file: fetch_audit_output.yml
- name: Audit_only | Show Audit Summary
when: audit_only
ansible.builtin.debug:
msg: "{{ audit_results.split('\n') }}"
- name: Audit_only | Stop Playbook Audit Only selected
- name: Audit_only | Stop task for host as audit_only selected
when: audit_only
ansible.builtin.meta: end_play
ansible.builtin.meta: end_host

View file

@ -7,6 +7,7 @@
- name: "POST | AUDITD | Set supported_syscalls variable"
ansible.builtin.shell: ausyscall --dump | awk '{print $2}'
changed_when: false
check_mode: false
failed_when: discovered_auditd_syscalls.rc not in [ 0, 1 ]
register: discovered_auditd_syscalls

View file

@ -0,0 +1,47 @@
---
# Stage to copy audit output to a centralised location
- name: "POST | FETCH | Fetch files and copy to controller"
when: audit_output_collection_method == "fetch"
ansible.builtin.fetch:
src: "{{ item }}"
dest: "{{ audit_output_destination }}"
flat: true
changed_when: true
failed_when: false
register: discovered_audit_fetch_state
loop:
- "{{ pre_audit_outfile }}"
- "{{ post_audit_outfile }}"
become: false
# Added this option for continuity but could be changed by adjusting the variable audit_conf_dest
# Allowing backup to one location
- name: "POST | FETCH | Copy files to location available to managed node"
when: audit_output_collection_method == "copy"
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ audit_output_destination }}"
mode: 'u-x,go-wx'
flat: true
failed_when: false
register: discovered_audit_copy_state
loop:
- "{{ pre_audit_outfile }}"
- "{{ post_audit_outfile }}"
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
when:
- (audit_output_collection_method == "fetch" and not discovered_audit_fetch_state.changed) or
(audit_output_collection_method == "copy" and not discovered_audit_copy_state.changed)
block:
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
ansible.builtin.debug:
msg: "Warning!! Unable to write to localhost {{ audit_output_destination }} for audit file copy"
- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files"
vars:
warn_control_id: "FETCH_AUDIT_FILES"
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -61,7 +61,7 @@
- crypto
- NIST800-53R5_SC-6
ansible.builtin.assert:
that: rhel9cis_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules
that: rhel9cis_additional_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules
fail_msg: "Crypto policy module is not a permitted version"
success_msg: "Crypto policy module is a permitted version"
@ -101,10 +101,9 @@
- name: "Check account is not locked for {{ ansible_env.SUDO_USER }} | Assert local account not locked" # noqa name[template]
ansible.builtin.assert:
that:
- not prelim_ansible_user_password_set.stdout.startswith("!")
that: (not prelim_ansible_user_password_set.stdout.startswith("!")) or (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list)
fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} is locked - It can break access"
success_msg: "The local account is not locked for {{ ansible_env.SUDO_USER }} user"
success_msg: "The local account {{ ansible_env.SUDO_USER }} is not locked or included in the exception list for rule 5.2.4"
- name: "Check authselect profile is selected"
when: rhel9cis_allow_authselect_updates
@ -116,7 +115,7 @@
fail_msg: "You still have the default name for your authselect profile"
- name: "Check authselect profile is selected | Check current profile"
ansible.builtin.shell: authselect list
ansible.builtin.command: authselect list
changed_when: false
failed_when: prelim_authselect_current_profile.rc not in [ 0, 1 ]
register: prelim_authselect_current_profile
@ -132,8 +131,9 @@
- rule_5.4.2.4
block:
- name: "Ensure root password is set"
ansible.builtin.shell: passwd -S root | egrep -e "(Password set, SHA512 crypt|Password locked)"
ansible.builtin.shell: passwd -S root | grep -E "(Password set, SHA512 crypt|Password locked)"
changed_when: false
failed_when: prelim_root_passwd_set.rc not in [ 0, 1 ]
register: prelim_root_passwd_set
- name: "Ensure root password is set"
@ -209,11 +209,46 @@
- name: "Run post_remediation audit"
when: run_audit
tags: always
ansible.builtin.import_tasks:
file: post_remediation_audit.yml
- name: Add ansible file showing Benchmark and levels applied if audit details not present
when:
- create_benchmark_facts
- (post_audit_summary is defined) or
(ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined)
tags:
- always
- benchmark
block:
- name: Create ansible facts directory if audit facts not present
ansible.builtin.file:
path: "{{ ansible_facts_path }}"
state: directory
owner: root
group: root
mode: 'u=rwx,go=rx'
- name: Create ansible facts file and levels applied if audit facts not present
ansible.builtin.template:
src: etc/ansible/compliance_facts.j2
dest: "{{ ansible_facts_path }}/compliance_facts.fact"
owner: root
group: root
mode: 'u-x,go=r'
- name: Fetch audit files
when:
- fetch_audit_output
- run_audit
tags: always
ansible.builtin.import_tasks:
file: fetch_audit_output.yml
- name: "Show Audit Summary"
when: run_audit
tags: always
ansible.builtin.debug:
msg: "{{ audit_results.split('\n') }}"

View file

@ -4,15 +4,15 @@
tags: always
block:
- name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Parse /etc/passwd"
ansible.builtin.command: cat /etc/passwd
ansible.builtin.shell: cat /etc/passwd | grep -v '^#'
changed_when: false
check_mode: false
register: prelim_passwd_file_audit
register: prelim_capture_passwd_file
- name: "PRELIM | 5.5.2 | 6.2.7 | 6.2.8 | 6.2.20 | Split passwd entries"
- name: "PRELIM | 5.4.2 | 7.2.8 | Split passwd entries"
ansible.builtin.set_fact:
rhel9cis_passwd: "{{ prelim_passwd_file_audit.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}"
loop: "{{ prelim_passwd_file_audit.stdout_lines }}"
prelim_captured_passwd_data: "{{ prelim_capture_passwd_file.stdout_lines | map('regex_replace', ld_passwd_regex, ld_passwd_yaml) | map('from_yaml') | list }}"
loop: "{{ prelim_capture_passwd_file.stdout_lines }}"
vars:
ld_passwd_regex: >-
^(?P<id>[^:]*):(?P<password>[^:]*):(?P<uid>[^:]*):(?P<gid>[^:]*):(?P<gecos>[^:]*):(?P<dir>[^:]*):(?P<shell>[^:]*)

View file

@ -33,7 +33,7 @@
when: audit_format == "documentation"
block:
- name: Post Audit | Capture audit data if documentation format
ansible.builtin.shell: tail -2 "{{ pre_audit_outfile }}" | tac | tr '\n' ' '
ansible.builtin.shell: tail -2 "{{ post_audit_outfile }}" | tac | tr '\n' ' '
changed_when: false
register: post_audit_summary

View file

@ -4,9 +4,7 @@
# List users in order to look files inside each home directory
- name: "PRELIM | Include audit specific variables"
when:
- run_audit or audit_only
- setup_audit
when: run_audit or audit_only or setup_audit
tags:
- setup_audit
- run_audit
@ -14,24 +12,30 @@
file: audit.yml
- name: "PRELIM | Include pre-remediation audit tasks"
when:
- run_audit or audit_only
- setup_audit
when: run_audit or audit_only or setup_audit
tags: run_audit
ansible.builtin.import_tasks: pre_remediation_audit.yml
- name: "PRELIM | AUDIT | Interactive Users"
tags: always
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $1 }'
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $1":"$3":"$6 }'
changed_when: false
register: prelim_interactive_usernames
check_mode: false
register: prelim_interactive_users_raw
- name: "PRELIM | AUDIT | Interactive Users (reformat)"
tags: always
ansible.builtin.set_fact:
prelim_interactive_users: "{{ prelim_interactive_users | default([]) + [dict([('username', item.split(':')[0]), ('uid', item.split(':')[1]), ('home', item.split(':')[2])])] }}"
loop: "{{ prelim_interactive_users_raw.stdout_lines }}"
- name: "PRELIM | AUDIT | Interactive User accounts home directories"
tags: always
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $6 }'
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false" && $7 != "/dev/null") { print $6 }'
changed_when: false
check_mode: false
register: prelim_interactive_users_home
- name: "PRELIM | AUDIT | Interactive UIDs"
@ -39,6 +43,7 @@
ansible.builtin.shell: >
grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $3 }'
changed_when: false
check_mode: false
register: prelim_interactive_uids
- name: "PRELIM | AUDIT | Capture /etc/password variables"
@ -64,6 +69,7 @@
ansible.builtin.shell: |
mount | awk '{print $1, $3, $5, $6}'
changed_when: false
check_mode: false
register: prelim_mount_output
- name: PRELIM | AUDIT | Section 1.1 | Retrieve mount options - build fact # This is inherited and used in mountpoints tasks
@ -100,6 +106,7 @@
ansible.builtin.command: rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' # noqa command-instead-of-module
changed_when: false
failed_when: false
check_mode: false
register: prelim_check_gpg_imported
- name: "PRELIM | AUDIT | Import gpg keys | Check Package" # noqa command-instead-of-module
@ -200,7 +207,7 @@
tags:
- always
block:
- name: "PRELIM | AUDIT | Discover is wirelss adapter on system"
- name: "PRELIM | AUDIT | Discover is wireless adapter on system"
ansible.builtin.command: find /sys/class/net/*/ -type d -name wireless
register: discover_wireless_adapters
changed_when: false
@ -243,6 +250,14 @@
mode: 'go-rwx'
state: touch
- name: "PRELIM | PATCH | sshd_config.d/50-redhat.conf exists"
when:
- rhel9cis_rule_5_1_10 or
rhel9cis_rule_5_1_11
ansible.builtin.stat:
path: /etc/ssh/sshd_config.d/50-redhat.conf
register: prelim_sshd_50_redhat_file
- name: "PRELIM | AUDIT | Capture pam security related files"
tags: always
ansible.builtin.find:
@ -298,6 +313,7 @@
tags: always
ansible.builtin.shell: grep ^log_file /etc/audit/auditd.conf | awk '{ print $NF }'
changed_when: false
check_mode: false
register: prelim_auditd_logfile
- name: "PRELIM | AUDIT | Audit conf and rules files | list files"
@ -320,24 +336,29 @@
patterns: '*.conf,*.rules'
register: prelim_auditd_conf_files
- name: "PRELIM | AUDIT | Discover Interactive UID MIN and MIN from logins.def"
- name: "PRELIM | AUDIT | Discover Interactive UID_MIN and UID_MAX from /etc/login.defs"
when: rhel9cis_discover_int_uid
tags: always
block:
- name: "PRELIM | AUDIT | Capture UID_MIN information from logins.def"
ansible.builtin.shell: grep -w "^UID_MIN" /etc/login.defs | awk '{print $NF}'
- name: "PRELIM | AUDIT | Capture UID_MIN from /etc/login.defs"
ansible.builtin.command: awk '/^UID_MIN/ {print $2}' /etc/login.defs
changed_when: false
failed_when: false
check_mode: false
register: prelim_uid_min_id
- name: "PRELIM | AUDIT | Capture UID_MAX information from logins.def"
ansible.builtin.shell: grep -w "^UID_MAX" /etc/login.defs | awk '{print $NF}'
- name: "PRELIM | AUDIT | Capture UID_MAX from /etc/login.defs"
ansible.builtin.command: awk '/^UID_MAX/ {print $2}' /etc/login.defs
changed_when: false
failed_when: false
check_mode: false
register: prelim_uid_max_id
- name: "PRELIM | AUDIT | Set Fact for interactive uid/gid"
ansible.builtin.set_fact:
prelim_min_int_uid: "{{ prelim_uid_min_id.stdout }}"
prelim_max_int_uid: "{{ prelim_uid_max_id.stdout }}"
- name: "PRELIM | AUDIT | Set facts for interactive UID/GID ranges"
tags: always
ansible.builtin.set_fact:
prelim_min_int_uid: "{{ prelim_uid_min_id.stdout | default(min_int_uid) }}"
prelim_max_int_uid: "{{ prelim_uid_max_id.stdout | default(max_int_uid) }}"
- name: "PRELIM | AUDIT | Gather the package facts after prelim"
tags:

View file

@ -21,12 +21,12 @@
register: discovered_home_mount
- name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Absent"
when: discovered_dev_shm_mount is undefined
when: discovered_home_mount is undefined
ansible.builtin.debug:
msg: "Warning!! {{ required_mount }} is not mounted on a separate partition"
- name: "1.1.2.3.1 | AUDIT | Ensure /home is a separate partition | Present"
when: discovered_dev_shm_mount is undefined
when: discovered_home_mount is undefined
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -22,12 +22,12 @@
register: discovered_var_mount
- name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Absent"
when: discovered_dev_shm_mount is undefined
when: discovered_var_mount is undefined
ansible.builtin.debug:
msg: "Warning!! {{ required_mount }} is not mounted on a separate partition"
- name: "1.1.2.4.1 | AUDIT | Ensure /var is a separate partition | Present"
when: discovered_dev_shm_mount is undefined
when: discovered_var_mount is undefined
ansible.builtin.import_tasks:
file: warning_facts.yml

View file

@ -106,7 +106,7 @@
warn_control_id: '1.3.1.6'
block:
- name: "1.3.1.6 | AUDIT | Ensure no unconfined services exist | Find the unconfined services"
ansible.builtin.shell: ps -eZ | grep unconfined_service_t | egrep -vw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
ansible.builtin.shell: ps -eZ | grep unconfined_service_t | grep -Evw "tr|ps|egrep|bash|awk" | tr ':' ' ' | awk '{ print $NF }'
register: discovered_unconf_services
failed_when: false
changed_when: false

View file

@ -57,7 +57,7 @@
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Build Options"
when: item not in discovered_efi_fstab.stdout
ansible.builtin.set_fact:
efi_mount_opts_addition: "{{ efi_mount_opts_addition + ',' + item }}"
efi_mount_opts_addition: "{{ efi_mount_opts_addition + ',' + item }}"
loop: "{{ efi_mount_options }}"
- name: "1.4.2 | PATCH | Ensure permissions on bootloader config are configured | efi based system | Add mount options"

View file

@ -25,7 +25,7 @@
when:
- not rhel9cis_autofs_services
- rhel9cis_autofs_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: autofs
enabled: false
@ -57,7 +57,7 @@
when:
- not rhel9cis_avahi_server
- rhel9cis_avahi_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -90,7 +90,7 @@
when:
- not rhel9cis_dhcp_server
- rhel9cis_dhcp_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -123,7 +123,7 @@
when:
- not rhel9cis_dns_server
- rhel9cis_dns_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: named.service
enabled: false
@ -153,7 +153,7 @@
when:
- not rhel9cis_dnsmasq_server
- rhel9cis_dnsmasq_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: dnsmasq.service
enabled: false
@ -184,7 +184,7 @@
when:
- not rhel9cis_samba_server
- rhel9cis_samba_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: smb.service
enabled: false
@ -215,7 +215,7 @@
when:
- not rhel9cis_ftp_server
- rhel9cis_ftp_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: vsftpd.service
enabled: false
@ -249,7 +249,7 @@
when:
- not rhel9cis_message_server
- rhel9cis_message_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -285,7 +285,7 @@
when:
- not rhel9cis_nfs_server
- rhel9cis_nfs_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: nfs-server.service
enabled: false
@ -302,7 +302,7 @@
- nis
- NIST800-53R5_CM-7
- rule_2.1.10
notify: Systemd_daemon_reload
notify: Systemd daemon reload
block:
- name: "2.1.10 | PATCH | Ensure nis server services are not in use | Remove package"
when:
@ -344,7 +344,7 @@
when:
- not rhel9cis_print_server
- rhel9cis_print_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -378,7 +378,7 @@
when:
- not rhel9cis_rpc_server
- rhel9cis_rpc_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -412,7 +412,7 @@
when:
- not rhel9cis_rsync_server
- rhel9cis_rsync_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -445,7 +445,7 @@
when:
- not rhel9cis_snmp_server
- rhel9cis_snmp_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: snmpd.service
enabled: false
@ -476,7 +476,7 @@
when:
- not rhel9cis_telnet_server
- rhel9cis_telnet_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: telnet.socket
enabled: false
@ -506,7 +506,7 @@
when:
- not rhel9cis_tftp_server
- rhel9cis_tftp_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: "{{ item }}"
enabled: false
@ -540,7 +540,7 @@
when:
- not rhel9cis_squid_server
- rhel9cis_squid_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: squid.service
enabled: false
@ -580,7 +580,7 @@
when:
- not rhel9cis_httpd_server
- rhel9cis_httpd_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: httpd.service
enabled: false
@ -591,7 +591,7 @@
when:
- not rhel9cis_nginx_server
- rhel9cis_nginx_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: ngnix.service
enabled: false
@ -621,7 +621,7 @@
when:
- not rhel9cis_xinetd_server
- rhel9cis_xinetd_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: xinetd.service
enabled: false
@ -657,7 +657,7 @@
- postfix
- NIST800-53R5_CM-7
- rule_2.1.21
notify: Restart_postfix
notify: Restart postfix
ansible.builtin.lineinfile:
path: /etc/postfix/main.cf
regexp: "^(#)?inet_interfaces"

View file

@ -39,7 +39,7 @@
warn_control_id: '3.1.2'
block:
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Check for network-manager tool"
when: "'network-manager' in ansible_facts.packages"
when: "rhel9cis_network_manager_package_name in ansible_facts.packages"
ansible.builtin.command: nmcli radio wifi
changed_when: false
failed_when: false
@ -48,19 +48,19 @@
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Disable wireless if network-manager installed"
when:
- "'network-manager' in ansible_facts.packages"
- "rhel9cis_network_manager_package_name in ansible_facts.packages"
- "'enabled' in discovered_wifi_status.stdout"
ansible.builtin.command: nmcli radio all off
changed_when: discovered_nmcli_radio_off.rc == 0
register: discovered_nmcli_radio_off
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Warn about wireless if network-manager not installed"
when: "'network-manager' not in ansible_facts.packages"
when: "rhel9cis_network_manager_package_name not in ansible_facts.packages"
ansible.builtin.debug:
msg: "Warning!! You need to disable wireless interfaces manually since network-manager is not installed"
- name: "3.1.2 | PATCH | Ensure wireless interfaces are disabled | Set warning count"
when: "'network-manager' not in ansible_facts.packages"
when: "rhel9cis_network_manager_package_name not in ansible_facts.packages"
ansible.builtin.import_tasks:
file: warning_facts.yml
@ -86,7 +86,7 @@
when:
- not rhel9cis_bluetooth_service
- rhel9cis_bluetooth_mask
notify: Systemd_daemon_reload
notify: Systemd daemon reload
ansible.builtin.systemd:
name: bluetooth.service
enabled: false

View file

@ -6,7 +6,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- permissions
- rule_5.1.1
- NIST800-53R5_AC-3
@ -23,7 +23,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- permissions
- rule_5.1.2
- NIST800-53R5_AC-3
@ -53,7 +53,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.3
- NIST800-53R5_AC-3
- NIST800-53R5_MP-2
@ -166,7 +166,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.7
- NIST800-53R5_AC-3
- NIST800-53R5_MP-2
@ -195,6 +195,8 @@
path: "{{ rhel9cis_sshd_config_file }}"
regexp: "^DenyUsers"
line: "DenyUsers {{ rhel9cis_sshd_denyusers }}"
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -213,7 +215,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.8
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -231,7 +233,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.9
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -261,7 +263,7 @@
- level2-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.10
- NIST800-53R5_CM-7
block:
@ -274,9 +276,10 @@
notify: Restart sshd
- name: "5.1.10 | PATCH | Ensure sshd DisableForwarding is enabled | override"
when: prelim_sshd_50_redhat_file.stat.exists
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/50-redhat.conf
regexp: ^(?i)(#|)\s*X11Forwarding
regexp: (?i)^(#|)\s*X11Forwarding
line: 'X11Forwarding {{ rhel9cis_sshd_x11forwarding }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -287,7 +290,7 @@
- level1-server
- level1-workstation
- patch
- sshs
- sshd
- rule_5.1.11
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -296,9 +299,10 @@
- NIST800-53R5_IA-5
block:
- name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | redhat file"
when: prelim_sshd_50_redhat_file.stat.exists
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config.d/50-redhat.conf
regexp: ^(?i)(#|)\s*GSSAPIAuthentication
regexp: (?i)^(#|)\s*GSSAPIAuthentication
line: GSSAPIAuthentication no
validate: sshd -t -f %s
notify: Restart sshd
@ -306,7 +310,7 @@
- name: "5.1.11 | PATCH | Ensure sshd GSSAPIAuthentication is disabled | ssh config"
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*GSSAPIAuthentication
regexp: (?i)^(#|)\s*GSSAPIAuthentication
line: GSSAPIAuthentication no
validate: sshd -t -f %s
notify: Restart sshd
@ -317,7 +321,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.12
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -326,7 +330,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*HostbasedAuthentication
regexp: (?i)^(#|)\s*HostbasedAuthentication
line: 'HostbasedAuthentication no'
validate: sshd -t -f %s
notify: Restart sshd
@ -337,7 +341,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.13
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -346,8 +350,10 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*IgnoreRhosts
regexp: (?i)^(#|)\s*IgnoreRhosts
line: 'IgnoreRhosts yes'
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -357,13 +363,15 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.14
- NIST800-53R5_CM-6
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*LoginGraceTime
regexp: (?i)^(#|)\s*LoginGraceTime
line: "LoginGraceTime {{ rhel9cis_sshd_logingracetime }}"
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -373,15 +381,17 @@
- level1-server
- level1-workstation
- patch
- sshs
- sshd
- rule_5.1.15
- NIST800-53R5_AU-3
- NIST800-53R5_AU-12
- NIST800-53R5_SI-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*LogLevel
regexp: (?i)^(#|)\s*LogLevel
line: 'LogLevel {{ rhel9cis_ssh_loglevel }}'
insertbefore: "^Match"
firstmatch: true
validate: sshd -t -f %s
notify: Restart sshd
@ -391,7 +401,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.16
- NIST800-53R5_AU-3
ansible.builtin.lineinfile:
@ -407,7 +417,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.17
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -416,7 +426,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*MaxStartups
regexp: (?i)^(#|)\s*MaxStartups
line: 'MaxStartups {{ rhel9cis_ssh_maxstartups }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -427,7 +437,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.18
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -436,7 +446,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*MaxSessions
regexp: (?i)^(#|)\s*MaxSessions
line: 'MaxSessions {{ rhel9cis_ssh_maxsessions }}'
validate: sshd -t -f %s
notify: Restart sshd
@ -447,7 +457,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.19
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -456,7 +466,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*PermitEmptyPasswords
regexp: (?i)^(#|)\s*PermitEmptyPasswords
line: 'PermitEmptyPasswords no'
validate: sshd -t -f %s
notify: Restart sshd
@ -467,14 +477,14 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.20
- NIST800-53R5_AC-6
block:
- name: "5.1.20 | PATCH | Ensure sshd PermitRootLogin is disabled | config file"
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*PermitRootLogin
regexp: (?i)^(#|)\s*PermitRootLogin
line: 'PermitRootLogin no'
validate: sshd -t -f %s
notify: Restart sshd
@ -491,7 +501,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.21
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -500,7 +510,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*PermitUserEnvironment
regexp: (?i)^(#|)\s*PermitUserEnvironment
line: 'PermitUserEnvironment no'
validate: sshd -t -f %s
notify: Restart sshd
@ -511,7 +521,7 @@
- level1-server
- level1-workstation
- patch
- ssh
- sshd
- rule_5.1.22
- NIST800-53R5_CM-1
- NIST800-53R5_CM-2
@ -520,7 +530,7 @@
- NIST800-53R5_IA-5
ansible.builtin.lineinfile:
path: "{{ rhel9cis_sshd_config_file }}"
regexp: ^(?i)(#|)\s*UsePAM
regexp: (?i)^(#|)\s*UsePAM
line: 'UsePAM yes'
validate: sshd -t -f %s
notify: Restart sshd

View file

@ -23,7 +23,7 @@
- rhel9cis_disruption_high
ansible.builtin.replace:
path: "/etc/pam.d/{{ item }}-auth"
regexp: ^(\s*auth\s+(requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$)
regexp: ^(\s*auth\s+(?:requisite|required|sufficient)\s+pam_faillock\.so)(.*)\s+deny\s*=\s*\S+(.*$)
replace: \1 \2\3
loop:
- password

View file

@ -29,7 +29,7 @@
- name: "5.4.1.1 | PATCH | Ensure password expiration is 365 days or less | Set existing users PASS_MAX_DAYS"
when:
- discovered_max_days.stdout_lines | length > 0
- item in prelim_interactive_usernames.stdout
- item in prelim_interactive_users | map(attribute='username') | list
- rhel9cis_force_user_maxdays
ansible.builtin.user:
name: "{{ item }}"
@ -60,7 +60,7 @@
- name: "5.4.1.2 | PATCH | Ensure minimum password days is configured | Set existing users PASS_MIN_DAYS"
when:
- discovered_min_days.stdout_lines | length > 0
- item in prelim_interactive_usernames.stdout
- item in prelim_interactive_users | map(attribute='username') | list
- rhel9cis_force_user_mindays
ansible.builtin.user:
name: "{{ item }}"
@ -91,7 +91,7 @@
- name: "5.4.1.3 | PATCH | Ensure password expiration warning days is configured | Set existing users WARN_DAYS"
when:
- discovered_warn_days.stdout_lines | length > 0
- item in prelim_interactive_usernames.stdout
- item in prelim_interactive_users | map(attribute='username') | list
- rhel9cis_force_user_warnage
ansible.builtin.command: "chage --warndays {{ rhel9cis_pass['warn_age'] }} {{ item }}"
changed_when: true
@ -140,7 +140,7 @@
register: discovered_passwdlck_user_list
- name: "5.4.1.5 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts"
when: item in prelim_interactive_usernames.stdout
when: item in prelim_interactive_users | map(attribute='username') | list
ansible.builtin.command: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}"
changed_when: true
loop: "{{ discovered_passwdlck_user_list.stdout_lines }}"

View file

@ -195,7 +195,7 @@
- name: "5.4.2.7 | PATCH | Ensure system accounts do not have a valid login shell"
when:
- rhel9cis_rule_5_4_2_7
- "item.id not in prelim_interactive_usernames.stdout"
- "item.id not in prelim_interactive_users | map(attribute='username')"
- item.id not in rhel9cis_system_users_shell
- "'root' not in item.id"
- rhel9cis_disruption_high
@ -212,7 +212,7 @@
ansible.builtin.user:
name: "{{ item.id }}"
shell: /usr/sbin/nologin
loop: "{{ rhel9cis_passwd }}"
loop: "{{ prelim_captured_passwd_data }}"
loop_control:
label: "{{ item.id }}"
@ -220,7 +220,7 @@
when:
- rhel9cis_rule_5_4_2_8
- rhel9cis_disruption_high
- "item.id not in prelim_interactive_usernames.stdout"
- "item.id not in prelim_interactive_users | map(attribute='username')"
- "'root' not in item.id"
tags:
- level1-server
@ -235,6 +235,6 @@
ansible.builtin.user:
name: "{{ item.id }}"
password_lock: true
loop: "{{ rhel9cis_passwd }}"
loop: "{{ prelim_captured_passwd_data }}"
loop_control:
label: "{{ item.id }}"

View file

@ -58,6 +58,10 @@
dest: /var/lib/aide/aide.db.gz
remote_src: true
mode: 'ug-wx,o-rwx'
register: aide_db_cp
failed_when:
- not ansible_check_mode
- aide_db_cp.failed
- name: "6.1.2 | PATCH | Ensure filesystem integrity is regularly checked"
when:
@ -119,4 +123,7 @@
/usr/sbin/aureport 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/autrace p+i+n+u+g+s+b+acl+xattrs+sha512
validate: aide -D --config %s
register: aide_file_integrity_check
failed_when:
- not ansible_check_mode
- aide_file_integrity_check.failed

View file

@ -96,15 +96,20 @@
- rule_6.2.1.4
block:
- name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when rsyslog"
when: rhel9cis_syslog == "rsyslog"
when:
- rhel9cis_syslog == "rsyslog"
- "'systemd-journald' in ansible_facts.packages"
ansible.builtin.systemd:
name: systemd-journald
state: stopped
enabled: false
- name: "6.2.1.4 | PATCH | Ensure only one logging system is in use | when journald"
when: rhel9cis_syslog == "journald"
when:
- rhel9cis_syslog == "journald"
- "'rsyslog' in ansible_facts.packages"
ansible.builtin.systemd:
name: rsyslog
state: stopped
enabled: false
register: discovered_rsyslog_service

View file

@ -35,7 +35,7 @@
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: 'URL=', line: 'URL={{ rhel9cis_remote_log_server }}'}
- { regexp: 'URL=', line: 'URL={{ rhel9cis_journal_upload_url }}'}
- { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ rhel9cis_journal_upload_serverkeyfile }}'}
- { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ rhel9cis_journal_servercertificatefile }}'}
- { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ rhel9cis_journal_trustedcertificatefile }}'}

View file

@ -50,7 +50,7 @@
- name: "6.2.2.3 | PATCH | Ensure journald Compress is configured | comment out current entries"
ansible.builtin.replace:
path: /etc/systemd/journald.conf
regexp: ^(?i)(\s*compress=)
regexp: (?i)(\s*compress=)
replace: '#\1'
- name: "6.2.2.4 | PATCH | Ensure journald Storage is configured"
@ -76,5 +76,5 @@
- name: "6.2.2.4 | PATCH | Ensure journald Storage is configured | comment out current entries"
ansible.builtin.replace:
path: /etc/systemd/journald.conf
regexp: ^(?i)(\s*storage=)
regexp: (?i)(\s*storage=)
replace: '#\1'

View file

@ -20,7 +20,9 @@
file: cis_6.2.2.x.yml
- name: "SECTION | 6.2.3 | Configure rsyslog"
when: rhel9cis_syslog == 'rsyslog'
when:
- rhel9cis_syslog == 'rsyslog'
- rhel9cis_rsyslog_ansiblemanaged
ansible.builtin.import_tasks:
file: cis_6.2.3.x.yml

View file

@ -220,7 +220,7 @@
- name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names"
when: discovered_group_check.stdout | length > 0
ansible.builtin.debug:
msg: "Warning!! The following group names are duplicates: {{ discovered_group_group_check.stdout_lines }}"
msg: "Warning!! The following group names are duplicates: {{ discovered_group_check.stdout_lines }}"
- name: "7.2.7 | AUDIT | Ensure no duplicate group names exist | Set warning count"
when: discovered_group_check.stdout | length > 0
@ -243,7 +243,7 @@
state: directory
owner: "{{ item.id }}"
group: "{{ item.gid }}"
loop: "{{ rhel9cis_passwd | selectattr('uid', '>=', prelim_min_int_uid | int) | selectattr('uid', '<=', prelim_max_int_uid | int) | list }}"
loop: "{{ prelim_captured_passwd_data | selectattr('uid', '>=', prelim_min_int_uid | int) | selectattr('uid', '<=', prelim_max_int_uid | int) | list }}"
loop_control:
label: "{{ item.id }}"
@ -256,7 +256,7 @@
etype: group
permissions: rx
state: present
loop: "{{ prelim_interactive_users_home.stdout_lines }}"
loop: "{{ prelim_interactive_users | map(attribute='home') | list }}"
- name: "7.2.8 | PATCH | Ensure local interactive user home directories are configured | Set other ACL"
when: not system_is_container
@ -266,7 +266,7 @@
etype: other
permissions: 0
state: present
loop: "{{ prelim_interactive_users_home.stdout_lines }}"
loop: "{{ prelim_interactive_users | map(attribute='home') | list }}"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured"
when:
@ -286,8 +286,8 @@
vars:
warn_control_id: '7.2.9'
block:
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Check for files"
ansible.builtin.shell: find /home/ -name "\.*"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured"
ansible.builtin.shell: find {{ prelim_interactive_users_home.stdout_lines | list | join(' ') }} -name "\.*" -type f
changed_when: false
failed_when: discovered_homedir_hidden_files.rc not in [ 0, 1 ]
check_mode: false
@ -296,25 +296,63 @@
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Warning on files found"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- rhel9cis_dotperm_ansiblemanaged
- not rhel9cis_dotperm_ansiblemanaged
ansible.builtin.debug:
msg:
- "Warning!! We have discovered group or world-writable dot files on your system and this host is configured for manual intervention. Please investigate these files further."
- "Warning!! Please investigate that hidden files found in users home directories match control requirements."
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Set warning count"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Set warning count"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- rhel9cis_dotperm_ansiblemanaged
- not rhel9cis_dotperm_ansiblemanaged
ansible.builtin.import_tasks:
file: warning_facts.yml
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Changes files if configured"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- rhel9cis_dotperm_ansiblemanaged
ansible.builtin.file:
path: '{{ item }}'
mode: 'go-w'
owner: "{{ rhel9cis_passwd | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ rhel9cis_passwd | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
with_items: "{{ discovered_homedir_hidden_files.stdout_lines }}"
block:
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured .bash_history & .netrc"
when:
- discovered_homedir_hidden_files.stdout | length > 0
- item | basename in ['.bash_history','.netrc']
ansible.builtin.file:
path: "{{ item }}"
mode: 'u-x,go-rwx'
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files if configured file mode"
ansible.builtin.file:
path: '{{ item }}'
mode: 'u-x,go-wx'
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | Changes files ownerships"
ansible.builtin.file:
path: "{{ item }}"
owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
failed_when: discovered_dot_bash_history_to_change.state not in '[ file, absent ]'
register: discovered_dot_bash_history_to_change
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | PATCH | Ensure local interactive user dot files access is configured | Changes files if configured"
ansible.builtin.file:
path: '{{ item }}'
mode: 'go-w'
owner: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='uid') | last }}"
group: "{{ prelim_captured_passwd_data | selectattr('dir', 'in', prelim_interactive_users_home.stdout_lines) | selectattr('dir', 'in', item) | map(attribute='gid') | last }}"
with_items: "{{ discovered_homedir_hidden_files.stdout_lines }}"
- name: "7.2.9 | AUDIT | Ensure local interactive user dot files access is configured | rename .forward or .rhosts files"
when:
- item | basename in ['.forward','.rhosts']
- item is not search ("CIS")
ansible.builtin.command: "mv {{ item }} {{ item }}_CIS_TOBEREVIEWED"
changed_when: true
loop: "{{ discovered_homedir_hidden_files.stdout_lines }}"

View file

@ -34,7 +34,7 @@ rhel9cis_selinux_disable: {{ rhel9cis_selinux_disable }}
# UEFI boot('/etc/grub2-efi.cfg') or in case of BIOS legacy-boot('/etc/grub2.cfg').
rhel9cis_legacy_boot: {{ rhel9cis_legacy_boot }}
## Benchmark name used by audting control role
## Benchmark name used by auditing control role
# The audit variable found at the base
## metadata for Audit benchmark
benchmark_version: 'v2.0.0'
@ -151,7 +151,7 @@ rhel9cis_rule_1_8_8: {{ rhel9cis_rule_1_8_8 }}
rhel9cis_rule_1_8_9: {{ rhel9cis_rule_1_8_9 }}
rhel9cis_rule_1_8_10: {{ rhel9cis_rule_1_8_10 }}
# Section 2 rules are controling Services (Special Purpose Services, and service clients)
# Section 2 rules are controlling Services (Special Purpose Services, and service clients)
## Configure Server Services
rhel9cis_rule_2_1_1: {{ rhel9cis_rule_2_1_1 }}
rhel9cis_rule_2_1_2: {{ rhel9cis_rule_2_1_2 }}
@ -625,21 +625,21 @@ rhel9cis_authselect_custom_profile_name: {{ rhel9cis_authselect_custom_profile_n
# These are discovered via logins.def if set true
rhel9cis_discover_int_uid: {{ rhel9cis_discover_int_uid }}
# This variable sets the minimum number from which to search for UID
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# Note that the value will be dynamically overwritten if variable `discover_int_uid` has
# been set to `true`.
min_int_uid: 1000
### Controls:
# - Ensure local interactive user home directories exist
# - Ensure local interactive users own their home directories
# This variable sets the maximum number at which the search stops for UID
# Note that the value will be dynamically overwritten if variable `dicover_int_uid` has
# Note that the value will be dynamically overwritten if variable `discover_int_uid` has
# been set to `true`.
max_int_uid: 65533
## Section6 vars
## Control 6.1.2 AIDE schedule
# how aide sceduler runs can be one of cron or timer
# how aide scheduler runs can be one of cron or timer
rhel9cis_aide_scan: {{ rhel9cis_aide_scan }}
# These are the crontab settings for periodical checking of the filesystem's integrity using AIDE.

View file

@ -0,0 +1,40 @@
# CIS Hardening Carried out
# Added as part of ansible-lockdown CIS baseline
# provided by Mindpoint Group - A Tyto Athene Company
[lockdown_details]
# Benchmark release
Benchmark_release = CIS-{{ benchmark_version }}
Benchmark_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }}
# If options set (doesn't mean it ran all controls)
level_1_hardening_enabled = {{ rhel9cis_level_1 }}
level_2_hardening_enabled = {{ rhel9cis_level_2 }}
{% if ansible_run_tags | length > 0 %}
# If tags used to stipulate run level
{% if 'level1-server' in ansible_run_tags %}
Level_1_Server_tag_run = true
{% endif %}
{% if 'level2-server' in ansible_run_tags %}
Level_2_Server_tag_run = true
{% endif %}
{% if 'level1-workstation' in ansible_run_tags %}
Level_1_workstation_tag_run = true
{% endif %}
{% if 'level2-workstation' in ansible_run_tags %}
Level_2_workstation_tag_run = true
{% endif %}
{% endif %}
[lockdown_audit_details]
{% if run_audit %}
# Audit run
audit_run_date = {{ '%Y-%m-%d - %H:%M:%S' | ansible.builtin.strftime }}
audit_file_local_location = {{ audit_log_dir }}
{% if not audit_only %}
audit_summary = {{ post_audit_results }}
{% endif %}
{% if fetch_audit_output %}
audit_files_centralized_location = {{ audit_output_destination }}
{% endif %}
{% endif %}

View file

@ -1,4 +1,4 @@
# This is a subpolicy to disable weak ciphers
# for the SSH protocol (libssh and OpenSSH)
# Carried out as part of CIS Benchmark rules combined 1.6.6 and 5.1.4
cipher@SSH ={% if rhel9cis_rule_1_6_6 %} -CHACHA20-POLY1305{% endif %}{% if rhel9cis_rule_5_1_5 %} -3DES-CBC -AES-128-CBC -AES-192-CBC -AES-256-CBC{% endif %}
cipher@SSH ={% if rhel9cis_rule_1_6_6 %} -CHACHA20-POLY1305{% endif %}{% if rhel9cis_rule_5_1_4 %} -3DES-CBC -AES-128-CBC -AES-192-CBC -AES-256-CBC{% endif %}

View file

@ -7,10 +7,16 @@ rhel9cis_allowed_crypto_policies:
- 'FUTURE'
- 'FIPS'
# Following is left blank for ability to build string
rhel9cis_crypto_policy_module: ''
# Do not adjust these are recognized as part of the CIS benchmark and used during testing
rhel9cis_allowed_crypto_policies_modules:
# Recognized by CIS as possible extra options
- 'OSPP'
- 'AD-SUPPORT'
- 'AD-SUPPORT-LEGACY'
# The following are already included in 1.6.x controls
- 'NO-SHA1'
- 'NO-SSHCBC'
- 'NO-SSHETM'
@ -22,6 +28,9 @@ rhel9cis_allowed_crypto_policies_modules:
warn_control_list: ""
warn_count: 0
# list of dicts of interactive users, filled in during prelim.yml
prelim_interactive_users: []
# Default empty values for 1.4.2
efi_mount_opts_addition: ''