--- # ============================================================================= # Security Audit and Compliance Playbook # ============================================================================= # # This playbook performs comprehensive security audits across all managed hosts # including configuration compliance, vulnerability checks, and security posture # assessment. # # Usage: # ansible-playbook playbooks/security_audit.yml # ansible-playbook playbooks/security_audit.yml --limit production # ansible-playbook playbooks/security_audit.yml --tags selinux,firewall # # Tags: # audit - All audit tasks # selinux - SELinux status checks # apparmor - AppArmor status checks # firewall - Firewall configuration checks # ssh - SSH configuration audit # packages - Package and update checks # users - User and permission audits # network - Network security checks # compliance - Compliance verification # report - Generate audit reports # # ============================================================================= - name: Security Audit and Compliance Check hosts: all become: true gather_facts: true vars: audit_timestamp: "{{ ansible_date_time.iso8601 }}" audit_report_dir: "./reports/security_audit/{{ ansible_date_time.date }}" failed_checks: [] pre_tasks: - name: Create audit report directory file: path: "{{ audit_report_dir }}" state: directory mode: '0755' delegate_to: localhost become: false run_once: true tags: [always] - name: Display audit banner debug: msg: - "=========================================" - "Security Audit Starting" - "=========================================" - "Host: {{ inventory_hostname }}" - "Environment: {{ environment | default('unknown') }}" - "Timestamp: {{ audit_timestamp }}" - "=========================================" tags: [always] tasks: # ========================================================================= # SELinux Audit (RHEL/CentOS/Rocky/Alma) # ========================================================================= - name: Check SELinux status command: getenforce register: audit_selinux_status changed_when: false failed_when: false when: ansible_os_family == "RedHat" tags: [audit, selinux, compliance] - name: Verify SELinux is enforcing assert: that: - audit_selinux_status.stdout == "Enforcing" fail_msg: "SELinux is not in enforcing mode (current: {{ audit_selinux_status.stdout }})" success_msg: "SELinux is enforcing" when: ansible_os_family == "RedHat" ignore_errors: true register: audit_selinux_check tags: [audit, selinux, compliance] - name: Check SELinux denials shell: ausearch -m avc -ts recent 2>/dev/null | wc -l register: audit_selinux_denials changed_when: false failed_when: false when: ansible_os_family == "RedHat" tags: [audit, selinux] # ========================================================================= # AppArmor Audit (Debian/Ubuntu) # ========================================================================= - name: Check AppArmor status command: aa-status --json register: audit_apparmor_status changed_when: false failed_when: false when: ansible_os_family == "Debian" tags: [audit, apparmor, compliance] - name: Verify AppArmor is enabled assert: that: - "'profiles' in audit_apparmor_status.stdout" fail_msg: "AppArmor is not properly enabled" success_msg: "AppArmor is enabled and active" when: ansible_os_family == "Debian" ignore_errors: true register: audit_apparmor_check tags: [audit, apparmor, compliance] # ========================================================================= # Firewall Audit # ========================================================================= - name: Check firewalld status (RHEL) systemd: name: firewalld state: started check_mode: true register: audit_firewalld_status when: ansible_os_family == "RedHat" tags: [audit, firewall, compliance] - name: Get firewalld configuration (RHEL) command: firewall-cmd --list-all register: audit_firewalld_config changed_when: false when: ansible_os_family == "RedHat" tags: [audit, firewall] - name: Check UFW status (Debian) command: ufw status verbose register: audit_ufw_status changed_when: false when: ansible_os_family == "Debian" tags: [audit, firewall, compliance] - name: Verify firewall is active (Debian) assert: that: - "'Status: active' in audit_ufw_status.stdout" fail_msg: "UFW firewall is not active" success_msg: "UFW firewall is active" when: ansible_os_family == "Debian" ignore_errors: true register: audit_ufw_check tags: [audit, firewall, compliance] # ========================================================================= # SSH Configuration Audit # ========================================================================= - name: Check SSH configuration for security settings shell: sshd -T 2>/dev/null | grep -E "^(permitrootlogin|passwordauthentication|gssapiauthentication|maxauthtries)" register: audit_ssh_config changed_when: false tags: [audit, ssh, compliance] - name: Verify SSH hardening settings assert: that: - "'permitrootlogin no' in audit_ssh_config.stdout.lower()" - "'passwordauthentication no' in audit_ssh_config.stdout.lower()" fail_msg: "SSH is not properly hardened" success_msg: "SSH configuration meets security requirements" ignore_errors: true register: audit_ssh_check tags: [audit, ssh, compliance] # ========================================================================= # Package and Update Audit # ========================================================================= - name: Check for available security updates (Debian) shell: apt list --upgradable 2>/dev/null | grep -i security | wc -l register: audit_debian_updates changed_when: false when: ansible_os_family == "Debian" tags: [audit, packages] - name: Check for available security updates (RHEL) shell: dnf updateinfo list security 2>/dev/null | grep -E "^(Important|Critical)" | wc -l register: audit_rhel_updates changed_when: false when: ansible_os_family == "RedHat" tags: [audit, packages] - name: Verify unattended-upgrades is enabled (Debian) systemd: name: unattended-upgrades state: started check_mode: true register: audit_unattended_upgrades when: ansible_os_family == "Debian" tags: [audit, packages, compliance] - name: Verify dnf-automatic is enabled (RHEL) systemd: name: dnf-automatic.timer state: started check_mode: true register: audit_dnf_automatic when: ansible_os_family == "RedHat" tags: [audit, packages, compliance] # ========================================================================= # User and Permission Audit # ========================================================================= - name: Check for users with UID 0 (root-equivalent) shell: awk -F':' '($3 == 0) { print $1 }' /etc/passwd register: audit_uid0_users changed_when: false tags: [audit, users, compliance] - name: Verify only root has UID 0 assert: that: - audit_uid0_users.stdout_lines == ['root'] fail_msg: "Multiple users with UID 0 detected: {{ audit_uid0_users.stdout_lines }}" success_msg: "Only root has UID 0" ignore_errors: true register: audit_uid0_check tags: [audit, users, compliance] - name: Check for users with empty passwords shell: awk -F':' '($2 == "" || $2 == "!") { print $1 }' /etc/shadow register: audit_empty_passwords changed_when: false failed_when: false tags: [audit, users, compliance] - name: Check sudoers configuration command: visudo -c register: audit_sudoers changed_when: false failed_when: false tags: [audit, users] - name: Find world-writable files shell: find / -xdev -type f -perm -0002 -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null | head -20 register: audit_world_writable changed_when: false failed_when: false async: 60 poll: 5 tags: [audit, users] # ========================================================================= # Network Security Audit # ========================================================================= - name: Check listening ports shell: ss -tulpn | grep LISTEN register: audit_listening_ports changed_when: false tags: [audit, network] - name: Check for promiscuous network interfaces shell: ip link show | grep -i promisc register: audit_promisc_interfaces changed_when: false failed_when: false tags: [audit, network] - name: Verify IP forwarding is disabled (unless router) sysctl: name: net.ipv4.ip_forward value: '0' check_mode: true register: audit_ip_forward tags: [audit, network, compliance] # ========================================================================= # Audit Logging # ========================================================================= - name: Check auditd status systemd: name: auditd state: started check_mode: true register: audit_auditd_status tags: [audit, compliance] - name: Check audit log size stat: path: /var/log/audit/audit.log register: audit_log_stat tags: [audit] # ========================================================================= # File Integrity Monitoring # ========================================================================= - name: Check if AIDE is installed package: name: aide state: present check_mode: true register: audit_aide_installed tags: [audit, compliance] - name: Check AIDE database exists stat: path: /var/lib/aide/aide.db register: audit_aide_db when: audit_aide_installed.changed == false tags: [audit] # ========================================================================= # Compliance Checks # ========================================================================= - name: Verify timezone is set to UTC command: timedatectl show --property=Timezone --value register: audit_timezone changed_when: false tags: [audit, compliance] - name: Verify NTP is synchronized command: timedatectl show --property=NTPSynchronized --value register: audit_ntp_sync changed_when: false tags: [audit, compliance] - name: Check kernel parameters (sysctl) command: sysctl -a register: audit_sysctl changed_when: false tags: [audit, compliance] post_tasks: # ========================================================================= # Generate Audit Report # ========================================================================= - name: Generate audit report template: src: ../templates/security_audit_report.j2 dest: "{{ audit_report_dir }}/{{ inventory_hostname }}_audit_report.txt" delegate_to: localhost become: false when: false # Enable when template is created tags: [report] - name: Display audit summary debug: msg: - "=========================================" - "Security Audit Summary" - "=========================================" - "Host: {{ inventory_hostname }}" - "Environment: {{ environment | default('unknown') }}" - "" - "=== Security Modules ===" - "{% if ansible_os_family == 'RedHat' %}SELinux: {{ audit_selinux_status.stdout | default('N/A') }}{% endif %}" - "{% if ansible_os_family == 'Debian' %}AppArmor: Active{% endif %}" - "" - "=== Firewall ===" - "{% if ansible_os_family == 'RedHat' %}Firewalld: {{ 'Active' if audit_firewalld_status is not failed else 'Inactive' }}{% endif %}" - "{% if ansible_os_family == 'Debian' %}UFW: {{ 'Active' if 'Status: active' in audit_ufw_status.stdout else 'Inactive' }}{% endif %}" - "" - "=== SSH Security ===" - "Root Login: {{ 'Disabled' if 'permitrootlogin no' in audit_ssh_config.stdout.lower() else 'ENABLED - ACTION REQUIRED' }}" - "Password Auth: {{ 'Disabled' if 'passwordauthentication no' in audit_ssh_config.stdout.lower() else 'ENABLED - ACTION REQUIRED' }}" - "" - "=== Updates ===" - "{% if ansible_os_family == 'Debian' %}Security updates available: {{ audit_debian_updates.stdout }}{% endif %}" - "{% if ansible_os_family == 'RedHat' %}Critical/Important updates: {{ audit_rhel_updates.stdout }}{% endif %}" - "" - "=== Users ===" - "UID 0 users: {{ audit_uid0_users.stdout_lines | join(', ') }}" - "" - "=== Audit Logging ===" - "Auditd: {{ 'Active' if audit_auditd_status is not failed else 'Inactive' }}" - "AIDE: {{ 'Installed' if audit_aide_installed.changed == false else 'Not Installed' }}" - "" - "=== Compliance ===" - "Timezone: {{ audit_timezone.stdout }}" - "NTP Sync: {{ audit_ntp_sync.stdout }}" - "" - "Report saved to: {{ audit_report_dir }}" - "=========================================" tags: [always] # ============================================================================= # Audit Report # ============================================================================= # Reports are saved to: ./reports/security_audit//_audit_report.txt # =============================================================================