Files
homelab-optimized/ansible/automation/playbooks/security_audit.yml
Gitea Mirror Bot 4cde3f84d6
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-05 12:40:35 UTC
2026-04-05 12:40:35 +00:00

305 lines
12 KiB
YAML

---
- name: Security Audit and Hardening
hosts: all
gather_facts: yes
vars:
audit_timestamp: "{{ ansible_date_time.iso8601 }}"
security_report_dir: "/tmp/security_reports"
tasks:
- name: Create security reports directory
file:
path: "{{ security_report_dir }}"
state: directory
mode: '0755'
delegate_to: localhost
run_once: true
- name: Check system updates
shell: |
if command -v apt >/dev/null 2>&1; then
apt list --upgradable 2>/dev/null | wc -l
elif command -v yum >/dev/null 2>&1; then
yum check-update --quiet | wc -l
else
echo "0"
fi
register: pending_updates
changed_when: false
ignore_errors: yes
- name: Check for security updates
shell: |
if command -v apt >/dev/null 2>&1; then
apt list --upgradable 2>/dev/null | grep -i security | wc -l
elif command -v yum >/dev/null 2>&1; then
yum --security check-update --quiet 2>/dev/null | wc -l
else
echo "0"
fi
register: security_updates
changed_when: false
ignore_errors: yes
- name: Check SSH configuration
shell: |
echo "=== SSH SECURITY AUDIT ==="
if [ -f /etc/ssh/sshd_config ]; then
echo "SSH Configuration:"
echo "PermitRootLogin: $(grep -E '^PermitRootLogin' /etc/ssh/sshd_config | awk '{print $2}' || echo 'default')"
echo "PasswordAuthentication: $(grep -E '^PasswordAuthentication' /etc/ssh/sshd_config | awk '{print $2}' || echo 'default')"
echo "Port: $(grep -E '^Port' /etc/ssh/sshd_config | awk '{print $2}' || echo '22')"
echo "Protocol: $(grep -E '^Protocol' /etc/ssh/sshd_config | awk '{print $2}' || echo 'default')"
else
echo "SSH config not accessible"
fi
register: ssh_audit
changed_when: false
ignore_errors: yes
- name: Check firewall status
shell: |
echo "=== FIREWALL STATUS ==="
if command -v ufw >/dev/null 2>&1; then
echo "UFW Status:"
ufw status verbose 2>/dev/null || echo "UFW not configured"
elif command -v iptables >/dev/null 2>&1; then
echo "IPTables Rules:"
iptables -L -n | head -20 2>/dev/null || echo "IPTables not accessible"
elif command -v firewall-cmd >/dev/null 2>&1; then
echo "FirewallD Status:"
firewall-cmd --state 2>/dev/null || echo "FirewallD not running"
else
echo "No firewall tools found"
fi
register: firewall_audit
changed_when: false
ignore_errors: yes
- name: Check user accounts
shell: |
echo "=== USER ACCOUNT AUDIT ==="
echo "Users with shell access:"
grep -E '/bin/(bash|sh|zsh)$' /etc/passwd | cut -d: -f1 | sort
echo ""
echo "Users with sudo access:"
if [ -f /etc/sudoers ]; then
grep -E '^[^#]*ALL.*ALL' /etc/sudoers 2>/dev/null | cut -d' ' -f1 || echo "No sudo users found"
fi
echo ""
echo "Recent logins:"
last -n 10 2>/dev/null | head -10 || echo "Login history not available"
register: user_audit
changed_when: false
ignore_errors: yes
- name: Check file permissions
shell: |
echo "=== FILE PERMISSIONS AUDIT ==="
echo "World-writable files in /etc:"
find /etc -type f -perm -002 2>/dev/null | head -10 || echo "None found"
echo ""
echo "SUID/SGID files:"
find /usr -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | head -10 || echo "None found"
echo ""
echo "SSH key permissions:"
if [ -d ~/.ssh ]; then
ls -la ~/.ssh/ 2>/dev/null || echo "SSH directory not accessible"
else
echo "No SSH directory found"
fi
register: permissions_audit
changed_when: false
ignore_errors: yes
- name: Check network security
shell: |
echo "=== NETWORK SECURITY AUDIT ==="
echo "Open ports:"
if command -v netstat >/dev/null 2>&1; then
netstat -tuln | grep LISTEN | head -10
elif command -v ss >/dev/null 2>&1; then
ss -tuln | grep LISTEN | head -10
else
echo "No network tools available"
fi
echo ""
echo "Network interfaces:"
ip addr show 2>/dev/null | grep -E '^[0-9]+:' || echo "Network info not available"
register: network_audit
changed_when: false
ignore_errors: yes
- name: Check system services
shell: |
echo "=== SERVICE SECURITY AUDIT ==="
if command -v systemctl >/dev/null 2>&1; then
echo "Running services:"
systemctl list-units --type=service --state=running --no-legend | head -15
echo ""
echo "Failed services:"
systemctl --failed --no-legend | head -5
else
echo "Systemd not available"
fi
register: service_audit
changed_when: false
ignore_errors: yes
- name: Check Docker security (if available)
shell: |
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
echo "=== DOCKER SECURITY AUDIT ==="
echo "Docker daemon info:"
docker info --format '{{.SecurityOptions}}' 2>/dev/null || echo "Security options not available"
echo ""
echo "Privileged containers:"
docker ps --format "table {{.Names}}\t{{.Status}}" --filter "label=privileged=true" 2>/dev/null || echo "No privileged containers found"
echo ""
echo "Containers with host network:"
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep -E '0\.0\.0\.0|::' | head -5 || echo "No host network containers found"
else
echo "Docker not available or not accessible"
fi
register: docker_audit
changed_when: false
ignore_errors: yes
- name: Calculate security score
set_fact:
security_score:
updates_pending: "{{ pending_updates.stdout | int }}"
security_updates_pending: "{{ security_updates.stdout | int }}"
ssh_root_login: "{{ 'SECURE' if 'no' in ssh_audit.stdout.lower() else 'INSECURE' }}"
ssh_password_auth: "{{ 'SECURE' if 'no' in ssh_audit.stdout.lower() else 'INSECURE' }}"
firewall_active: "{{ 'ACTIVE' if 'active' in firewall_audit.stdout.lower() or 'status: active' in firewall_audit.stdout.lower() else 'INACTIVE' }}"
overall_risk: >-
{{
'HIGH' if (
(security_updates.stdout | int > 5) or
('yes' in ssh_audit.stdout.lower() and 'PermitRootLogin' in ssh_audit.stdout) or
('inactive' in firewall_audit.stdout.lower())
) else 'MEDIUM' if (
(pending_updates.stdout | int > 10) or
(security_updates.stdout | int > 0)
) else 'LOW'
}}
- name: Display security audit report
debug:
msg: |
==========================================
🔒 SECURITY AUDIT REPORT - {{ inventory_hostname }}
==========================================
📊 SECURITY SCORE: {{ security_score.overall_risk }} RISK
🔄 UPDATES:
- Pending Updates: {{ security_score.updates_pending }}
- Security Updates: {{ security_score.security_updates_pending }}
🔐 SSH SECURITY:
- Root Login: {{ security_score.ssh_root_login }}
- Password Auth: {{ security_score.ssh_password_auth }}
🛡️ FIREWALL:
- Status: {{ security_score.firewall_active }}
{{ ssh_audit.stdout }}
{{ firewall_audit.stdout }}
{{ user_audit.stdout }}
{{ permissions_audit.stdout }}
{{ network_audit.stdout }}
{{ service_audit.stdout }}
{{ docker_audit.stdout }}
==========================================
- name: Generate JSON security report
copy:
content: |
{
"timestamp": "{{ audit_timestamp }}",
"hostname": "{{ inventory_hostname }}",
"security_score": {
"overall_risk": "{{ security_score.overall_risk }}",
"updates_pending": {{ security_score.updates_pending }},
"security_updates_pending": {{ security_score.security_updates_pending }},
"ssh_root_login": "{{ security_score.ssh_root_login }}",
"ssh_password_auth": "{{ security_score.ssh_password_auth }}",
"firewall_active": "{{ security_score.firewall_active }}"
},
"audit_details": {
"ssh_config": {{ ssh_audit.stdout | to_json }},
"firewall_status": {{ firewall_audit.stdout | to_json }},
"user_accounts": {{ user_audit.stdout | to_json }},
"file_permissions": {{ permissions_audit.stdout | to_json }},
"network_security": {{ network_audit.stdout | to_json }},
"services": {{ service_audit.stdout | to_json }},
"docker_security": {{ docker_audit.stdout | to_json }}
},
"recommendations": [
{% if security_score.security_updates_pending | int > 0 %}
"Apply {{ security_score.security_updates_pending }} pending security updates",
{% endif %}
{% if security_score.ssh_root_login == "INSECURE" %}
"Disable SSH root login",
{% endif %}
{% if security_score.firewall_active == "INACTIVE" %}
"Enable and configure firewall",
{% endif %}
{% if security_score.updates_pending | int > 20 %}
"Apply system updates ({{ security_score.updates_pending }} pending)",
{% endif %}
"Regular security monitoring recommended"
]
}
dest: "{{ security_report_dir }}/{{ inventory_hostname }}_security_{{ ansible_date_time.epoch }}.json"
delegate_to: localhost
- name: Send security alert for high risk
shell: |
if command -v curl >/dev/null 2>&1; then
curl -d "🚨 HIGH RISK: {{ inventory_hostname }} security audit - {{ security_score.overall_risk }} risk level detected" \
-H "Title: Security Alert" \
-H "Priority: high" \
-H "Tags: security,audit" \
"{{ ntfy_url | default('https://ntfy.sh/REDACTED_TOPIC') }}" || true
fi
when: security_score.overall_risk == "HIGH"
ignore_errors: yes
- name: Summary message
debug:
msg: |
🔒 Security audit complete for {{ inventory_hostname }}
📊 Risk Level: {{ security_score.overall_risk }}
📄 Report saved to: {{ security_report_dir }}/{{ inventory_hostname }}_security_{{ ansible_date_time.epoch }}.json
{% if security_score.overall_risk == "HIGH" %}
🚨 HIGH RISK detected - immediate action required!
{% elif security_score.overall_risk == "MEDIUM" %}
⚠️ MEDIUM RISK - review and address issues
{% else %}
✅ LOW RISK - system appears secure
{% endif %}
Key Issues:
{% if security_score.security_updates_pending | int > 0 %}
- {{ security_score.security_updates_pending }} security updates pending
{% endif %}
{% if security_score.ssh_root_login == "INSECURE" %}
- SSH root login enabled
{% endif %}
{% if security_score.firewall_active == "INACTIVE" %}
- Firewall not active
{% endif %}