From 9ac57401274ba29708f8f9d4adfc7749af307b78 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Fri, 11 Apr 2025 11:20:44 +0100 Subject: [PATCH 1/3] updated features facts and audit fetch Signed-off-by: Mark Bolwell --- defaults/main.yml | 4 ---- tasks/audit_only.yml | 8 -------- tasks/fetch_audit_output.yml | 20 ++++++++++---------- tasks/main.yml | 14 ++++++++------ templates/etc/ansible/compliance_facts.j2 | 1 + 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/defaults/main.yml b/defaults/main.yml index 1049208..19015b6 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -106,10 +106,6 @@ audit_conf_dest: "/opt" # Where the audit logs are stored audit_log_dir: '/opt' -## Ability to collect and take audit files moving to a centralised 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 avaiable for these to occur. ## options are diff --git a/tasks/audit_only.yml b/tasks/audit_only.yml index 008d358..845d9d9 100644 --- a/tasks/audit_only.yml +++ b/tasks/audit_only.yml @@ -10,14 +10,6 @@ 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 | Show Audit Summary when: audit_only ansible.builtin.debug: diff --git a/tasks/fetch_audit_output.yml b/tasks/fetch_audit_output.yml index c6f7b5e..563b699 100644 --- a/tasks/fetch_audit_output.yml +++ b/tasks/fetch_audit_output.yml @@ -2,7 +2,7 @@ # Stage to copy audit output to a centralised location -- name: "FETCH_AUDIT_FILES | Fetch files and copy to controller" +- name: "POST | FETCH | Fetch files and copy to controller" when: audit_output_collection_method == "fetch" ansible.builtin.fetch: src: "{{ item }}" @@ -17,7 +17,7 @@ # Added this option for continuity but could be changed by adjusting the variable audit_conf_dest # Allowing backup to one location -- name: "FETCH_AUDIT_FILES | Copy files to location available to managed node" +- name: "POST | FETCH | Copy files to location available to managed node" when: audit_output_collection_method == "copy" ansible.builtin.copy: src: "{{ item }}" @@ -25,21 +25,21 @@ mode: 'u-x,go-wx' flat: true failed_when: false - register: discovered_audit_fetch_copy_state + register: discovered_audit_copy_state loop: - - pre_audit_outfile - - post_audit_outfile + - "{{ pre_audit_outfile }}" + - "{{ post_audit_outfile }}" -- name: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" +- name: "POST | FETCH | Fetch files and copy to controller | Warning if issues with fetch_audit_files" when: - - (discovered_audit_fetch_state is defined and not discovered_audit_fetch_state.changed) or - (discovered_audit_copy_state is defined and not discovered_audit_copy_state.changed) + - (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: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" + - 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: "FETCH_AUDIT_FILES | Fetch files and copy to controller | Warning if issues with fetch_audit_files" + - 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: diff --git a/tasks/main.yml b/tasks/main.yml index 636ecc6..70968f3 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -169,13 +169,16 @@ ansible.builtin.import_tasks: file: post_remediation_audit.yml -- name: Add ansible file showing Benchmark and levels applied - when: create_benchmark_facts +- 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 + - name: Create ansible facts directory if audit facts not present ansible.builtin.file: path: "{{ ansible_facts_path }}" state: directory @@ -183,13 +186,13 @@ group: root mode: 'u=rwx,go=rx' - - name: Create ansible facts file + - 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-wx" + mode: 'u-x,go=r' - name: Fetch audit files when: @@ -198,7 +201,6 @@ tags: always ansible.builtin.import_tasks: file: fetch_audit_output.yml - - name: Show Audit Summary when: run_audit tags: run_audit diff --git a/templates/etc/ansible/compliance_facts.j2 b/templates/etc/ansible/compliance_facts.j2 index 4e105ff..43b4628 100644 --- a/templates/etc/ansible/compliance_facts.j2 +++ b/templates/etc/ansible/compliance_facts.j2 @@ -29,6 +29,7 @@ Level_2_workstation_tag_run = true [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 }} From 7f0291fbf297de5973ecf3599b1da8f4ce4659fa Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Fri, 11 Apr 2025 11:40:04 +0100 Subject: [PATCH 2/3] improve container checks Signed-off-by: Mark Bolwell --- tasks/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index 70968f3..e1188b2 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -65,7 +65,8 @@ - name: Setup rules if container when: - ansible_connection == 'docker' or - ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + (ansible_facts.virtualization_type is defined and + ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"]) tags: always block: - name: Discover and set container variable if required From b6fb3c7dcc49c2ab561785c56823aac5a398589d Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Fri, 11 Apr 2025 11:40:11 +0100 Subject: [PATCH 3/3] remove fileglob Signed-off-by: Mark Bolwell --- tasks/prelim.yml | 35 +++++++++++++ tasks/section_5/cis_5.3.3.1.x.yml | 18 +++---- tasks/section_5/cis_5.3.3.2.x.yml | 84 +++++++++++++++---------------- tasks/section_6/cis_6.1.4.1.yml | 13 +++-- 4 files changed, 91 insertions(+), 59 deletions(-) diff --git a/tasks/prelim.yml b/tasks/prelim.yml index 5206b22..813e966 100644 --- a/tasks/prelim.yml +++ b/tasks/prelim.yml @@ -150,6 +150,41 @@ max_int_uid: "{{ prelim_uid_max_id.stdout }}" min_int_gid: "{{ prelim_gid_min_id.stdout }}" +- name: "PRELIM | AUDIT | Capture pam configs related files" + tags: always + ansible.builtin.find: + paths: + - '/usr/share/pam-configs/' + - '/etc/pam.d/' + register: prelim_pam_conf_files + +- name: PRELIM | PATCH | Ensure conf.d directory exists required for 5.3.3.2.x + when: + - ubtu24cis_rule_5_3_3_2_1 or + ubtu24cis_rule_5_3_3_2_6 + tags: always + ansible.builtin.file: + path: "{{ item.path }}" + state: "{{ item.state }}" + owner: root + group: root + mode: 'g-w,o-rwx' + modification_time: preserve + access_time: preserve + register: prelim_pwquality_dummy + changed_when: prelim_pwquality_dummy.diff == "absent" + loop: + - { path: '/etc/security/pwquality.conf.d', state: 'directory' } + - { path: '/etc/security/pwquality.conf.d/cis_dummy.conf', state: 'touch' } + +- name: "PRELIM | AUDIT | Capture pam security related files" + tags: always + ansible.builtin.find: + paths: + - /etc/security/pwquality.conf.d/ + patterns: '*.conf' + register: prelim_pam_pwquality_confs + - name: "PRELIM | AUDIT | Interactive Users" tags: always ansible.builtin.shell: > diff --git a/tasks/section_5/cis_5.3.3.1.x.yml b/tasks/section_5/cis_5.3.3.1.x.yml index 1b05935..727a154 100644 --- a/tasks/section_5/cis_5.3.3.1.x.yml +++ b/tasks/section_5/cis_5.3.3.1.x.yml @@ -28,12 +28,10 @@ - name: "5.3.3.1.1 | PATCH | Ensure password failed attempts lockout is configured | if exists remove deny from faillock line in pam-auth conf files" when: discovered_faillock_deny_files.stdout | length > 0 ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: '(*.pam_faillock.so\s*)deny\s*=\s*\d+\b(.*)' replace: \1\2 - with_fileglob: - - '/usr/share/pam-configs/*' - - '/etc/pam.d/*' + loop: "{{ prelim_pam_conf_files.files }}" - name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured" when: ubtu24cis_rule_5_3_3_1_2 @@ -63,12 +61,10 @@ - name: "5.3.3.1.2 | PATCH | Ensure password unlock time is configured | if exists remove unlock_time from faillock line in pam-auth conf files" when: discovered_faillock_unlock_files.stdout | length > 0 ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: '(*.pam_faillock.so\s*)unlock_time\s*=\s*\b(.*)' replace: \1\2 - with_fileglob: - - '/usr/share/pam-configs/*' - - '/etc/pam.d/*' + loop: "{{ prelim_pam_conf_files.files }}" - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account" when: ubtu24cis_rule_5_3_3_1_3 @@ -98,9 +94,7 @@ - name: "5.3.3.1.3 | PATCH | Ensure password failed attempts lockout includes root account | if exists remove unlock_time from faillock line in pam-auth conf files" when: discovered_faillock_rootlock_files.stdout | length > 0 ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: '(*.pam_faillock.so\s*)(even_deny_root\b|root_unlock_time\s*=\s*\d+\b)(.*)' replace: \1\3 - with_fileglob: - - '/usr/share/pam-configs/*' - - '/etc/pam.d/*' + loop: "{{ prelim_pam_conf_files.files }}" diff --git a/tasks/section_5/cis_5.3.3.2.x.yml b/tasks/section_5/cis_5.3.3.2.x.yml index 33268a1..4846b41 100644 --- a/tasks/section_5/cis_5.3.3.2.x.yml +++ b/tasks/section_5/cis_5.3.3.2.x.yml @@ -11,15 +11,15 @@ - pam block: - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Remove difok from conf files except expected file" - when: item != ubtu24cis_passwd_difok_file + when: "ubtu24cis_passwd_difok_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'difok\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.1 | PATCH | Ensure password number of changed characters is configured | Ensure difok file exists" ansible.builtin.template: @@ -40,15 +40,15 @@ - pam block: - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Remove minlen from conf files except expected file" - when: item != ubtu24cis_passwd_minlen_file + when: "ubtu24cis_passwd_minlen_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'minlen\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.2 | PATCH | Ensure minimum password length is configured | Ensure minlen file exists" ansible.builtin.template: @@ -69,15 +69,15 @@ - pam block: - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Remove pwd complex settings from conf files except expected file" - when: item != ubtu24cis_passwd_complex_file + when: "ubtu24cis_passwd_complex_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: '(minclass|[dulo]credit)\s*=\s*(-\d|\d+)\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.3 | PATCH | Ensure password complexity is configured | Ensure complexity file exists" ansible.builtin.template: @@ -98,15 +98,15 @@ - pam block: - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Remove maxrepeat settings from conf files except expected file" - when: item != ubtu24cis_passwd_maxrepeat_file + when: "ubtu24cis_passwd_maxrepeat_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'maxrepeat\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.4 | PATCH | Ensure password same consecutive characters is configured | Ensure maxrepeat file exists" ansible.builtin.template: @@ -127,15 +127,15 @@ - pam block: - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Remove maxsequence settings from conf files except expected file" - when: item != ubtu24cis_passwd_maxsequence_file + when: "ubtu24cis_passwd_maxsequence_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'maxsequence\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.5 | PATCH | Ensure password maximum sequential characters is configured | Ensure maxsequence file exists" ansible.builtin.template: @@ -156,15 +156,15 @@ - pam block: - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Remove dictcheck settings from conf files except expected file" - when: item != ubtu24cis_passwd_dictcheck_file + when: "ubtu24cis_passwd_dictcheck_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'dictcheck\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.6 | PATCH | Ensure password dictionary check is enabled | Ensure dictcheck file exists" ansible.builtin.template: @@ -185,15 +185,15 @@ - pam block: - name: "5.3.3.2.7 | PATCH | Ensure password quality checking is enforced | Remove quality enforcement settings from conf files except expected file" - when: item != ubtu24cis_passwd_quality_enforce_file + when: "ubtu24cis_passwd_quality_enforce_file not in item.path" ansible.builtin.replace: - path: "{{ item }}" + path: "{{ item.path }}" regexp: 'enforcing\s*=\s*\d+\b' replace: '' - with_fileglob: - - '/etc/security/pwquality.conf' - - '/etc/security/pwquality.conf.d/*.conf' - - '/etc/pam.d/common-password' + with_items: + - "{{ prelim_pam_pwquality_confs.files }}" + - { path: '/etc/security/pwquality.conf'} + - { path: '/etc/pam.d/common-password' } - name: "5.3.3.2.7 | PATCH | Ensure password quality checking is enforced | Ensure quality enforcement file exists" ansible.builtin.template: diff --git a/tasks/section_6/cis_6.1.4.1.yml b/tasks/section_6/cis_6.1.4.1.yml index 5d3d70c..2b4a629 100644 --- a/tasks/section_6/cis_6.1.4.1.yml +++ b/tasks/section_6/cis_6.1.4.1.yml @@ -30,11 +30,14 @@ loop: "{{ discovered_logfiles.stdout_lines }}" - name: "6.1.4.1 | PATCH | Ensure access to all logfiles has been configured | change permissions" + when: + - discovered_system_logfiles.stdout_lines is defined + - item == "/var/log/btmp" + - item == "/var/log/utmp" + - item == "/var/log/wtmp" + - item == "/var/log/lastlog" + - "'sssd' in item or 'SSSD' in item" ansible.builtin.file: path: "{{ item }}" mode: 'ug-x,o-wx' - with_fileglob: - - "/var/log/*tmp" - - "/var/log/lastlog*" - - "/var/log/sssd*" - - "/var/log/SSSD*" + loop: "{{ discovered_system_logfiles.stdout_lines }}"