new-site/infra/ansible/roles/common/tasks/main.yml
justin 97e8664cbf Add security-updates Ansible role for automated patching
Comprehensive security update automation:

1. Debian OS (unattended-upgrades) — tightened to security-only:
   - Removed general Debian updates (prevents feature/breaking changes)
   - Only Debian-Security origins auto-installed
   - Email admin on every upgrade via ops@performancewest.net
   - Auto-reboot at 4 AM if kernel update requires it
   - needrestart auto-restarts services after library updates

2. Docker CE — major version guard:
   - Patch updates within pinned major version auto-applied
   - Major version jumps held + admin alerted for manual review
   - docker-ce, docker-ce-cli, containerd.io all version-guarded

3. Container base images — daily at 3:30 AM:
   - Pulls latest base images for all docker-compose services
   - Compares image digests — only rebuilds if changed
   - Restarts only affected services (not full stack)
   - Alerts admin on rebuild failures requiring manual intervention
   - Covers both prod and dev compose projects

4. k3s — weekly Sunday at 3:45 AM:
   - Patch updates within current minor auto-applied
   - Minor/major upgrades alert admin for manual review
   - Verifies node Ready status after update
   - Alerts on failures with investigation instructions

5. Admin notifications via SMTP:
   - [INFO] for successful patches
   - [WARNING] for available major upgrades needing review
   - [CRITICAL] for failures requiring immediate intervention
   - Falls back to syslog if SMTP unavailable

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 01:24:57 -05:00

136 lines
3.8 KiB
YAML

---
- name: Update apt cache
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Upgrade all packages
ansible.builtin.apt:
upgrade: safe
- name: Install common packages
ansible.builtin.apt:
name: "{{ common_packages }}"
state: present
- name: Create deploy user
ansible.builtin.user:
name: "{{ deploy_user }}"
shell: /bin/bash
groups: sudo
append: true
create_home: true
state: present
- name: Set authorized key for deploy user
ansible.posix.authorized_key:
user: "{{ deploy_user }}"
key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
state: present
- name: Allow deploy user passwordless sudo
ansible.builtin.copy:
content: "{{ deploy_user }} ALL=(ALL) NOPASSWD:ALL\n"
dest: "/etc/sudoers.d/{{ deploy_user }}"
mode: "0440"
validate: "visudo -cf %s"
- name: Deploy hardened sshd_config
ansible.builtin.template:
src: sshd_config.j2
dest: /etc/ssh/sshd_config
owner: root
group: root
mode: "0600"
validate: "sshd -t -f %s"
notify: Restart sshd
- name: Configure UFW defaults - deny incoming
community.general.ufw:
direction: incoming
policy: deny
- name: Configure UFW defaults - allow outgoing
community.general.ufw:
direction: outgoing
policy: allow
- name: Allow SSH on custom port
community.general.ufw:
rule: allow
port: "{{ ssh_port }}"
proto: tcp
comment: "SSH custom port"
- name: Enable UFW
community.general.ufw:
state: enabled
- name: Enable and start chrony
ansible.builtin.systemd:
name: chrony
enabled: true
state: started
- name: Configure unattended-upgrades — security only
ansible.builtin.copy:
content: |
// SECURITY UPDATES ONLY — no feature upgrades
// General Debian updates excluded to prevent breaking changes
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
// Docker CE security patches (from download.docker.com repo)
"origin=Docker,codename=${distro_codename},label=Docker CE";
};
// Never auto-upgrade these — require manual intervention
Unattended-Upgrade::Package-Blacklist {
"docker-ce";
"docker-ce-cli";
"containerd.io";
"k3s";
};
// Auto-remove unused kernel packages and dependencies
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Reboot at 4 AM if a kernel update requires it
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
// Email admin on upgrades and errors
Unattended-Upgrade::Mail "{{ smtp_admin_email }}";
Unattended-Upgrade::MailReport "on-change";
// Log to syslog
Unattended-Upgrade::SyslogEnable "true";
// Don't auto-upgrade if dpkg --configure is pending (broken state)
Unattended-Upgrade::MinimalSteps "true";
dest: /etc/apt/apt.conf.d/50unattended-upgrades
owner: root
group: root
mode: "0644"
- name: Configure auto-update schedule
ansible.builtin.copy:
content: |
// Run apt update and unattended-upgrade daily
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
dest: /etc/apt/apt.conf.d/20auto-upgrades
owner: root
group: root
mode: "0644"
- name: Enable and start unattended-upgrades
ansible.builtin.systemd:
name: unattended-upgrades
enabled: true
state: started