Files
homelab-optimized/ansible/automation/playbooks/security_updates.yml
Gitea Mirror Bot ca723d77b9
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-20 00:50:49 UTC
2026-04-20 00:50:49 +00:00

319 lines
11 KiB
YAML

---
# Security Updates Playbook
# Automated security patches and system updates
# Usage: ansible-playbook playbooks/security_updates.yml
# Usage: ansible-playbook playbooks/security_updates.yml -e "reboot_if_required=true"
# Usage: ansible-playbook playbooks/security_updates.yml -e "security_only=true"
- name: Apply Security Updates
hosts: "{{ host_target | default('debian_clients') }}"
gather_facts: yes
become: yes
vars:
security_only: "{{ security_only | default(true) }}"
reboot_if_required: "{{ reboot_if_required | default(false) }}"
backup_before_update: "{{ backup_before_update | default(true) }}"
max_reboot_wait: "{{ max_reboot_wait | default(300) }}"
update_docker: "{{ update_docker | default(false) }}"
tasks:
- name: Check if host is reachable
ping:
register: ping_result
- name: Create update log directory
file:
path: "/var/log/ansible_updates"
state: directory
mode: '0755'
- name: Get pre-update system info
shell: |
echo "=== PRE-UPDATE SYSTEM INFO ==="
echo "Date: {{ ansible_date_time.iso8601 }}"
echo "Host: {{ inventory_hostname }}"
echo "Kernel: $(uname -r)"
echo "Uptime: $(uptime)"
echo ""
echo "=== CURRENT PACKAGES ==="
dpkg -l | grep -E "(linux-image|linux-headers)" || echo "No kernel packages found"
echo ""
echo "=== SECURITY UPDATES AVAILABLE ==="
apt list --upgradable 2>/dev/null | grep -i security || echo "No security updates available"
echo ""
echo "=== DISK SPACE ==="
df -h /
echo ""
echo "=== RUNNING SERVICES ==="
systemctl list-units --type=service --state=running | head -10
register: pre_update_info
changed_when: false
- name: Display update plan
debug:
msg: |
🔒 SECURITY UPDATE PLAN
=======================
🖥️ Host: {{ inventory_hostname }}
📅 Date: {{ ansible_date_time.date }}
🔐 Security Only: {{ security_only }}
🔄 Reboot if Required: {{ reboot_if_required }}
💾 Backup First: {{ backup_before_update }}
🐳 Update Docker: {{ update_docker }}
{{ pre_update_info.stdout }}
- name: Backup critical configs before update
shell: |
backup_dir="/var/backups/pre-update-{{ ansible_date_time.epoch }}"
mkdir -p "$backup_dir"
echo "Creating pre-update backup..."
# Backup critical system configs
cp -r /etc/ssh "$backup_dir/" 2>/dev/null || echo "SSH config backup failed"
cp -r /etc/nginx "$backup_dir/" 2>/dev/null || echo "Nginx config not found"
cp -r /etc/systemd "$backup_dir/" 2>/dev/null || echo "Systemd config backup failed"
# Backup package list
dpkg --get-selections > "$backup_dir/package_list.txt"
# Backup Docker configs if they exist
if [ -d "/opt/docker" ]; then
tar -czf "$backup_dir/docker_configs.tar.gz" /opt/docker 2>/dev/null || echo "Docker config backup failed"
fi
echo "✅ Backup created at $backup_dir"
ls -la "$backup_dir"
register: backup_result
when: backup_before_update | bool
- name: Update package cache
apt:
update_cache: yes
cache_valid_time: 0
register: cache_update
- name: Check for available security updates
shell: |
apt list --upgradable 2>/dev/null | grep -c security || echo "0"
register: security_updates_count
changed_when: false
- name: Check for kernel updates
shell: |
apt list --upgradable 2>/dev/null | grep -E "(linux-image|linux-headers)" | wc -l
register: kernel_updates_count
changed_when: false
- name: Apply security updates only
apt:
upgrade: safe
autoremove: yes
autoclean: yes
register: security_update_result
when:
- security_only | bool
- security_updates_count.stdout | int > 0
- name: Apply all updates (if not security only)
apt:
upgrade: dist
autoremove: yes
autoclean: yes
register: full_update_result
when:
- not security_only | bool
- name: Update Docker (if requested)
block:
- name: Add Docker GPG key
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
state: present
- name: Add Docker repository
apt_repository:
repo: "deb [arch=amd64] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"
state: present
- name: Update Docker packages
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: latest
register: docker_update_result
- name: Restart Docker service
systemd:
name: docker
state: restarted
enabled: yes
when: docker_update_result.changed
when: update_docker | bool
- name: Check if reboot is required
stat:
path: /var/run/reboot-required
register: reboot_required_file
- name: Display reboot requirement
debug:
msg: |
🔄 REBOOT STATUS
================
Reboot Required: {{ reboot_required_file.stat.exists }}
Kernel Updates: {{ kernel_updates_count.stdout }}
Auto Reboot: {{ reboot_if_required }}
- name: Create update report
shell: |
report_file="/var/log/ansible_updates/update_report_{{ ansible_date_time.epoch }}.txt"
echo "🔒 SECURITY UPDATE REPORT - {{ inventory_hostname }}" > "$report_file"
echo "=================================================" >> "$report_file"
echo "Date: {{ ansible_date_time.iso8601 }}" >> "$report_file"
echo "Host: {{ inventory_hostname }}" >> "$report_file"
echo "Security Only: {{ security_only }}" >> "$report_file"
echo "Reboot Required: {{ reboot_required_file.stat.exists }}" >> "$report_file"
echo "" >> "$report_file"
echo "=== PRE-UPDATE INFO ===" >> "$report_file"
echo "{{ pre_update_info.stdout }}" >> "$report_file"
echo "" >> "$report_file"
echo "=== UPDATE RESULTS ===" >> "$report_file"
{% if security_only %}
{% if security_update_result is defined %}
echo "Security updates applied: {{ security_update_result.changed }}" >> "$report_file"
{% endif %}
{% else %}
{% if full_update_result is defined %}
echo "Full system update applied: {{ full_update_result.changed }}" >> "$report_file"
{% endif %}
{% endif %}
{% if update_docker and docker_update_result is defined %}
echo "Docker updated: {{ docker_update_result.changed }}" >> "$report_file"
{% endif %}
echo "" >> "$report_file"
echo "=== POST-UPDATE INFO ===" >> "$report_file"
echo "Kernel: $(uname -r)" >> "$report_file"
echo "Uptime: $(uptime)" >> "$report_file"
echo "Available updates: $(apt list --upgradable 2>/dev/null | wc -l)" >> "$report_file"
{% if backup_before_update %}
echo "" >> "$report_file"
echo "=== BACKUP INFO ===" >> "$report_file"
echo "{{ backup_result.stdout }}" >> "$report_file"
{% endif %}
cat "$report_file"
register: update_report
- name: Notify about pending reboot
debug:
msg: |
⚠️ REBOOT REQUIRED
===================
Host: {{ inventory_hostname }}
Reason: System updates require reboot
Kernel updates: {{ kernel_updates_count.stdout }}
Manual reboot command: sudo reboot
Or run with: -e "reboot_if_required=true"
when:
- reboot_required_file.stat.exists
- not reboot_if_required | bool
- name: Reboot system if required and authorized
reboot:
reboot_timeout: "{{ max_reboot_wait }}"
msg: "Rebooting for security updates"
pre_reboot_delay: 10
when:
- reboot_required_file.stat.exists
- reboot_if_required | bool
register: reboot_result
- name: Wait for system to come back online
wait_for_connection:
timeout: "{{ max_reboot_wait }}"
delay: 30
when: reboot_result is defined and reboot_result.changed
- name: Verify services after reboot
ansible.builtin.systemd:
name: "{{ item }}"
loop:
- ssh
- docker
- tailscaled
register: service_checks
failed_when: false
changed_when: false
when: reboot_result is defined and reboot_result.changed
- name: Final security check
shell: |
echo "=== FINAL SECURITY STATUS ==="
echo "Available security updates: $(apt list --upgradable 2>/dev/null | grep -c security || echo '0')"
echo "Reboot required: $([ -f /var/run/reboot-required ] && echo 'Yes' || echo 'No')"
echo "Last update: {{ ansible_date_time.iso8601 }}"
echo ""
echo "=== SYSTEM HARDENING CHECK ==="
echo "SSH root login: $(grep PermitRootLogin /etc/ssh/sshd_config | head -1 || echo 'Not configured')"
echo "Firewall status: $(ufw status | head -1 || echo 'UFW not available')"
echo "Fail2ban status: $(systemctl is-active fail2ban 2>/dev/null || echo 'Not running')"
echo "Automatic updates: $(systemctl is-enabled unattended-upgrades 2>/dev/null || echo 'Not configured')"
register: final_security_check
changed_when: false
- name: Display update summary
debug:
msg: |
✅ SECURITY UPDATE COMPLETE - {{ inventory_hostname }}
=============================================
📅 Update Date: {{ ansible_date_time.date }}
🔐 Security Only: {{ security_only }}
🔄 Reboot Performed: {{ reboot_result.changed if reboot_result is defined else 'No' }}
{{ update_report.stdout }}
{{ final_security_check.stdout }}
{% if post_reboot_verification is defined %}
🔍 POST-REBOOT VERIFICATION:
{{ post_reboot_verification.stdout }}
{% endif %}
📄 Full report: /var/log/ansible_updates/update_report_{{ ansible_date_time.epoch }}.txt
🔍 Next Steps:
- Monitor system stability
- Check service functionality
- Review security hardening: ansible-playbook playbooks/security_audit.yml
=============================================
- name: Send update notification (if configured)
debug:
msg: |
📧 UPDATE NOTIFICATION
Host: {{ inventory_hostname }}
Status: Updates applied successfully
Reboot: {{ 'Required' if reboot_required_file.stat.exists else 'Not required' }}
Security updates: {{ security_updates_count.stdout }}
when: send_notifications | default(false) | bool