Files
Mateusz Suski 7757020014
CI Pipeline / lint-ansible (push) Waiting to run
CI Pipeline / test-python (push) Waiting to run
CI Pipeline / validate-docker (push) Waiting to run
CI Pipeline / security-scan (push) Waiting to run
CI Pipeline / documentation (push) Waiting to run
CI Pipeline / integration-test (push) Blocked by required conditions
feat: Add comprehensive enterprise Linux infrastructure portfolio with Ansible, Python, and ELK stack
2026-04-29 23:14:14 +00:00

139 lines
4.2 KiB
YAML

---
- name: Apply Security Patches and Updates
hosts: all
become: true
gather_facts: true
vars:
patch_window_start: "02:00"
patch_window_end: "04:00"
reboot_required: false
security_only: true
pre_tasks:
- name: Check patch window
assert:
that: ansible_date_time.hour|int >= patch_window_start.split(':')[0]|int and ansible_date_time.hour|int < patch_window_end.split(':')[0]|int
fail_msg: "Current time {{ ansible_date_time.hour }}:{{ ansible_date_time.minute }} is outside patch window {{ patch_window_start }}-{{ patch_window_end }}"
when: enforce_patch_window | default(true) | bool
- name: Create patch backup
file:
path: "/var/backups/pre-patch-{{ ansible_date_time.iso8601 }}"
state: directory
- name: Backup package list
command: dpkg --get-selections
register: package_backup
changed_when: false
- name: Save package backup
copy:
content: "{{ package_backup.stdout }}"
dest: "/var/backups/pre-patch-{{ ansible_date_time.iso8601 }}/packages.list"
tasks:
- name: Update package cache
apt:
update_cache: yes
cache_valid_time: 300
when: ansible_os_family == "Debian"
- name: Check for available updates
command: apt list --upgradable 2>/dev/null | grep -v "Listing..." | wc -l
register: updates_available
changed_when: false
when: ansible_os_family == "Debian"
- name: Apply security updates only
apt:
upgrade: dist
update_cache: yes
when: security_only and ansible_os_family == "Debian"
- name: Apply all updates
apt:
upgrade: dist
update_cache: yes
when: not security_only and ansible_os_family == "Debian"
- name: Check if reboot required
stat:
path: /var/run/reboot-required
register: reboot_required_file
when: ansible_os_family == "Debian"
- name: Set reboot flag
set_fact:
reboot_required: "{{ reboot_required_file.stat.exists | default(false) }}"
- name: Restart services after patching
service:
name: "{{ item }}"
state: restarted
loop:
- sshd
- fail2ban
- unattended-upgrades
ignore_errors: true
- name: Update monitoring agent
include_role:
name: monitoring_agent_update
when: "'monitoring' in group_names"
- name: Verify critical services
service:
name: "{{ item }}"
state: started
loop:
- systemd-journald
- systemd-logind
- cron
ignore_errors: true
- name: Run post-patch health checks
uri:
url: http://localhost/health
method: GET
status_code: 200
register: health_result
ignore_errors: true
when: "'webservers' in group_names"
post_tasks:
- name: Generate patch report
template:
src: templates/patch_report.j2
dest: "/var/log/patch_report_{{ ansible_date_time.iso8601 }}.log"
vars:
patch_status: "{{ 'SUCCESS' if health_result.status == 200 else 'WARNING' }}"
updates_applied: "{{ updates_available.stdout | default('0') }}"
reboot_needed: "{{ reboot_required }}"
- name: Send patch notification
mail:
to: "{{ patch_notification_email | default('infra-team@company.com') }}"
subject: "Patch Report - {{ inventory_hostname }}"
body: |
Patch completed for {{ inventory_hostname }}
Updates applied: {{ updates_applied }}
Reboot required: {{ reboot_required }}
Health check: {{ 'PASSED' if health_result.status == 200 else 'FAILED' }}
See /var/log/patch_report_{{ ansible_date_time.iso8601 }}.log for details
when: patch_notification_email is defined
ignore_errors: true
- name: Schedule reboot if required
command: shutdown -r +5 "Rebooting for security patches"
when: reboot_required and auto_reboot | default(false) | bool
async: 600
poll: 0
handlers:
- name: restart monitoring
service:
name: "{{ monitoring_service | default('prometheus-node-exporter') }}"
state: restarted
when: "'monitoring' in group_names"