Files
n0mad1k 040fa12705 Split base hardening packages into required and optional
software-properties-common removed — dropped from Debian 13 (trixie).
unattended-upgrades and apt-listchanges moved to optional task with
ignore_errors so missing packages don't fail the entire deployment.
2026-03-10 10:59:06 -04:00

213 lines
6.4 KiB
YAML

---
# Base server hardening — applied to all deployments
# Covers: updates, firewall, fail2ban, SSH hardening
- name: Base Server Hardening
hosts: all
become: true
vars:
_ssh_port: "{{ ssh_port | default('22') }}"
ssh_allow_password: false
tasks:
# ─── System Updates ─────────────────────────────────────────────────
- name: Update apt cache
apt:
update_cache: true
cache_valid_time: 3600
when: ansible_os_family == "Debian"
- name: Upgrade all packages
apt:
upgrade: safe
when: ansible_os_family == "Debian"
- name: Install essential packages
apt:
name:
- ufw
- fail2ban
- curl
- wget
- gnupg
- ca-certificates
state: present
when: ansible_os_family == "Debian"
- name: Install optional hardening packages
apt:
name:
- unattended-upgrades
- apt-listchanges
state: present
when: ansible_os_family == "Debian"
ignore_errors: true
# ─── UFW Firewall ───────────────────────────────────────────────────
- name: Set UFW default deny incoming
ufw:
direction: incoming
policy: deny
- name: Set UFW default allow outgoing
ufw:
direction: outgoing
policy: allow
- name: Allow SSH through UFW
ufw:
rule: allow
port: "{{ _ssh_port }}"
proto: tcp
- name: Enable UFW
ufw:
state: enabled
# ─── Fail2ban ───────────────────────────────────────────────────────
- name: Configure fail2ban jails
copy:
dest: /etc/fail2ban/jail.local
content: |
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
banaction = ufw
[sshd]
enabled = true
port = {{ _ssh_port }}
filter = sshd
backend = systemd
maxretry = 3
bantime = 7200
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 5
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600
mode: "0644"
notify: restart fail2ban
- name: Enable fail2ban
service:
name: fail2ban
state: started
enabled: true
# ─── SSH Hardening ──────────────────────────────────────────────────
- name: Disable SSH password authentication
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PasswordAuthentication"
line: "PasswordAuthentication no"
when: not ssh_allow_password
notify: restart sshd
- name: Disable SSH root login with password
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?PermitRootLogin"
line: "PermitRootLogin prohibit-password"
notify: restart sshd
- name: Disable SSH X11 forwarding
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?X11Forwarding"
line: "X11Forwarding no"
notify: restart sshd
- name: Set SSH MaxAuthTries
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?MaxAuthTries"
line: "MaxAuthTries 3"
notify: restart sshd
- name: Set SSH ClientAliveInterval
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?ClientAliveInterval"
line: "ClientAliveInterval 300"
notify: restart sshd
- name: Set SSH ClientAliveCountMax
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?ClientAliveCountMax"
line: "ClientAliveCountMax 2"
notify: restart sshd
- name: Set SSH MaxStartups
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?MaxStartups"
line: "MaxStartups 10:30:100"
notify: restart sshd
- name: Set SSH LoginGraceTime
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^#?LoginGraceTime"
line: "LoginGraceTime 60"
notify: restart sshd
# ─── Automatic Security Updates ─────────────────────────────────────
- name: Enable unattended upgrades for security
copy:
dest: /etc/apt/apt.conf.d/20auto-upgrades
content: |
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
mode: "0644"
when: ansible_os_family == "Debian"
# ─── Kernel Hardening ───────────────────────────────────────────────
- name: Apply sysctl hardening
sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: true
reload: true
loop:
- { key: "net.ipv4.conf.all.rp_filter", value: "1" }
- { key: "net.ipv4.conf.default.rp_filter", value: "1" }
- { key: "net.ipv4.icmp_echo_ignore_broadcasts", value: "1" }
- { key: "net.ipv4.conf.all.accept_redirects", value: "0" }
- { key: "net.ipv4.conf.default.accept_redirects", value: "0" }
- { key: "net.ipv6.conf.all.accept_redirects", value: "0" }
- { key: "net.ipv6.conf.default.accept_redirects", value: "0" }
- { key: "net.ipv4.conf.all.send_redirects", value: "0" }
- { key: "net.ipv4.conf.default.send_redirects", value: "0" }
handlers:
- name: restart fail2ban
service:
name: fail2ban
state: restarted
- name: restart sshd
service:
name: sshd
state: restarted