305 lines
12 KiB
YAML
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 %}
|