--- # -------------------------------------------------------------- # Ansible playbook: Harden a Fedora 44 server & install Fail2Ban # -------------------------------------------------------------- # Requirements: # - Ansible >= 2.14 # - A reachable Fedora 44 host with SSH access (password or key) # - `sudo` rights for the control user (via become: true) # -------------------------------------------------------------- - name: Harden Fedora 44 & install Fail2Ban hosts: all become: true # elevates to root for package/service ops vars: # ---- Tunables ------------------------------------------------- # Change these to match your environment fail2ban_port: "22" # default SSH jail; can be "http","https",etc. fail2ban_maxretry: 3 # how many attempts before ban fail2ban_bantime: 3600 # seconds (1 h) # ----------------------------------------------------------------- # Ensure we are on Fedora 44 (you can relax this if you wish) fedora_release: "44" tasks: # -------------------------------------------------------------- # Verify OS version (informational, can be removed) # -------------------------------------------------------------- - name: Gather os fact ansible.builtin.debug: var: ansible_distribution_version - name: Ensure we are running Fedora {{ fedora_release }} ansible.builtin.assert: that: - ansible_distribution == "Fedora" - ansible_distribution_version == fedora_release fail_msg: "This playbook targets Fedora {{ fedora_release }} only." success_msg: "Running on the correct Fedora version." # -------------------------------------------------------------- # Update / upgrade all packages # -------------------------------------------------------------- - name: Update all packages to latest versions ansible.builtin.dnf: name: "*" state: latest update_cache: true # -------------------------------------------------------------- # Install essential hardening packages # -------------------------------------------------------------- - name: Install fail2ban, firewalld, and sudo ansible.builtin.dnf: name: - fail2ban - firewalld - sudo state: present # -------------------------------------------------------------- # Start & enable firewalld (default-deny all, allow SSH) # -------------------------------------------------------------- - name: Start and enable firewalld ansible.builtin.systemd: name: firewalld state: started enabled: true - name: Allow SSH service through firewalld ansible.builtin.command: cmd: firewall-cmd --permanent --add-service=ssh changed_when: false # idempotent check handled by firewall_cmd - name: Reload firewalld to apply rules ansible.builtin.command: cmd: firewall-cmd --reload changed_when: false # -------------------------------------------------------------- # Harden SSH (disable root login, enforce key‑only auth) # -------------------------------------------------------------- - name: Ensure SSH config directory exists ansible.builtin.file: path: /etc/ssh/sshd_config.d state: directory mode: "0755" - name: Disable root login via SSH ansible.builtin.lineinfile: path: /etc/ssh/sshd_config.d/00-disable-root.conf create: true mode: "0644" line: "PermitRootLogin no" state: present - name: Enforce password-auth disabled (key-only) ansible.builtin.lineinfile: path: /etc/ssh/sshd_config.d/00-key-only.conf create: true mode: "0644" line: "PasswordAuthentication no" state: present - name: Require MFA (optional) — add if you use Duo, etc. ansible.builtin.lineinfile: path: /etc/ssh/sshd_config.d/00-mfa.conf create: true mode: "0644" line: "AuthenticationMethods publickey,keyboard-interactive:pam" state: present - name: Restart sshd to apply changes ansible.builtin.service: name: sshd state: restarted # -------------------------------------------------------------- # Configure Fail2Ban # -------------------------------------------------------------- - name: template fail2ban jail.local ansible.builtin.template: src: jail.local.j2 dest: /etc/fail2ban/jail.local mode: "0644" notify: Restart fail2ban - name: Ensure fail2ban is started & enabled ansible.builtin.service: name: fail2ban state: started enabled: true # -------------------------------------------------------------- # (Optional) Install & configure unattended‑security updates # -------------------------------------------------------------- - name: Install dnf-automatic (security-only) ansible.builtin.dnf: name: dnf-automatic state: present - name: Enable security-only automatic updates ansible.builtin.lineinfile: path: /etc/dnf/automatic.conf regexp: "^update_type" line: "update_type = security" state: present - name: Enable and start dnf-automatic.timer ansible.builtin.systemd: name: "@dnf-automatic.timer" state: started enabled: true # -------------------------------------------------------------- # Log rotation for security‑relevant logs # -------------------------------------------------------------- - name: Ensure rsyslog is running ansible.builtin.service: name: rsyslog state: started enabled: true - name: Add logrotate rule for fail2ban logs ansible.builtin.lineinfile: path: /etc/logrotate.d/fail2ban create: true mode: "0644" content: | /var/log/fail2ban/*.log { daily rotate 7 compress missingok notifempty postrotate /usr/bin/fail2ban-client reload >/dev/null 2>&1 || true endscript } # -------------------------------------------------------------- # 9 Handlers # -------------------------------------------------------------- handlers: - name: Restart fail2ban ansible.builtin.service: name: fail2ban state: restarted