Files
infra-automation/playbooks/security_audit.yml
ansible cc21e89a78 Add playbook structure, master playbook, and collections requirements
Implement standardized playbook organization with master orchestrator
and Ansible collections requirements for extended functionality.

Playbook Structure:
playbooks/
├── gather_system_info.yml    # System inventory gathering
├── deploy_vm.yml             # VM deployment (placeholder)
├── security_audit.yml        # Security compliance checking (placeholder)
├── maintenance.yml           # Routine maintenance tasks (placeholder)
├── backup.yml                # Backup operations (placeholder)
└── disaster_recovery.yml     # DR procedures (placeholder)

Master Playbook (site.yml):
- Entry point for all infrastructure operations
- Import structure for modular playbook organization
- Tag-based execution for selective operations
- Pre-flight checks and validations
- Comprehensive documentation and usage examples

Collections Requirements (collections/requirements.yml):
- community.general: Essential utilities and modules
- community.libvirt: KVM/libvirt management
- ansible.posix: POSIX system administration
- amazon.aws: AWS infrastructure management (optional)
- Community versions for open-source compatibility

Implemented Playbooks:

1. gather_system_info.yml:
   - Comprehensive system information gathering
   - Uses system_info role
   - Statistics export to ./stats/machines/
   - Health checks and validation
   - Tag support: install, gather, export, validate, health-check

2. Placeholder Playbooks (documented structure):
   - deploy_vm.yml: VM provisioning with deploy_linux_vm role
   - security_audit.yml: CIS benchmark compliance checking
   - maintenance.yml: Updates, cleanup, optimization
   - backup.yml: Backup operations orchestration
   - disaster_recovery.yml: DR procedures and testing

site.yml Master Playbook Features:
- Central orchestration point
- Import-based playbook inclusion
- Tag inheritance and selective execution
- Environment-aware (development, staging, production)
- Pre-flight validation checks
- Error handling and rollback support
- Comprehensive inline documentation

Usage Examples:
```bash
# Run all playbooks
ansible-playbook site.yml

# Run specific playbook
ansible-playbook site.yml --tags gather_info

# Gather system information only
ansible-playbook playbooks/gather_system_info.yml

# Check syntax
ansible-playbook site.yml --syntax-check

# Dry run
ansible-playbook site.yml --check

# Limit to specific hosts
ansible-playbook site.yml -l webservers
```

Collections Management:
- Install: ansible-galaxy collection install -r collections/requirements.yml
- Update: ansible-galaxy collection install -r collections/requirements.yml --upgrade
- Location: ./collections/ (local) and ~/.ansible/collections (user)
- Version pinning for stability
- Community alternatives for RHEL-free deployments

CLAUDE.md Compliance:
 Playbooks in ./playbooks/ directory
 Master playbook (site.yml) at root
 Tag-based execution support
 Modular organization with import_playbook
 Collections requirements documented
 Clear separation: playbooks (lasting) vs plays (temporary)

Benefits:
- Standardized playbook organization
- Easy-to-navigate structure
- Tag-based selective execution
- Collection dependency management
- Scalable to 100+ playbooks
- Clear entry point (site.yml)
- Environment isolation

Next Steps:
1. Install collections: ansible-galaxy collection install -r collections/requirements.yml
2. Implement placeholder playbooks as needed
3. Add role-specific playbooks to playbooks/ directory
4. Create temporary plays in plays/ directory (per CLAUDE.md)
5. Test site.yml orchestration: ansible-playbook site.yml --check

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 01:37:19 +01:00

398 lines
14 KiB
YAML

---
# =============================================================================
# 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/<date>/<hostname>_audit_report.txt
# =============================================================================