
# platform = multi_platform_rhel,multi_platform_fedora,multi_platform_ol,multi_platform_rhv,multi_platform_sle,multi_platform_slmicro,multi_platform_ubuntu,multi_platform_almalinux
# reboot = false
# strategy = restrict
# complexity = low
# disruption = low


- 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
      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(( -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*$'
        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/privileged.rules
      ansible.builtin.set_fact: audit_file="/etc/audit/rules.d/privileged.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)(?=.*(?:(?:-S |,)(?:{{ syscalls_per_file[audit_file] | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (?:-k |-F key=)\w+)'
        line: '\1\2\3{{ missing_syscalls | join("\3") }}\4'
        backrefs: yes
        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{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged"
        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(( -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*$'
        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)(?=.*(?:(?:-S |,)(?:{{ syscalls_found | join("|") }}))\b)((?:( -S |,)\w+)+)( -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset (?:-k |-F key=)\w+)'
        line: '\1\2\3{{ missing_syscalls | join("\3") }}\4'
        backrefs: yes
        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{{ syscalls | join(',') }} -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged"
        create: true
        mode: g-rwx,o-rwx
        state: present
      when: syscalls_found | length == 0
