--- # 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