This commit adds Fail2ban settings to `defaults/main.yml`, a new task to restart the fail2ban service, and a task file for deploying Fail2Ban integrated with Proxmox Firewall. The new tasks include checks, validations, and configuration to enhance security by blocking malicious IP addresses.
237 lines
7.1 KiB
YAML
237 lines
7.1 KiB
YAML
---
|
|
# -------------------------------------------------
|
|
# Deploy Fail2Ban integrated with Proxmox Firewall
|
|
# -------------------------------------------------
|
|
|
|
#################################################
|
|
# Detect firewall configuration
|
|
#################################################
|
|
|
|
- name: fail2ban | Check if cluster firewall config exists
|
|
ansible.builtin.stat:
|
|
path: /etc/pve/firewall/cluster.fw
|
|
register: cluster_fw
|
|
|
|
- name: fail2ban | Read cluster firewall config
|
|
slurp:
|
|
src: /etc/pve/firewall/cluster.fw
|
|
register: cluster_fw_content
|
|
when: cluster_fw.stat.exists
|
|
|
|
- name: fail2ban | Determine if firewall enabled
|
|
ansible.builtin.set_fact:
|
|
pve_firewall_enabled: >-
|
|
{{
|
|
cluster_fw.stat.exists and
|
|
(cluster_fw_content.content | b64decode)
|
|
is search('enable:\s*1')
|
|
}}
|
|
|
|
- name: fail2ban | Abort if firewall not enabled
|
|
ansible.builtin.fail:
|
|
msg: >
|
|
Proxmox firewall is not enabled at Datacenter level.
|
|
Enable it before deploying Fail2Ban integration.
|
|
when: not pve_firewall_enabled
|
|
|
|
#################################################
|
|
# Validate firewall runtime state
|
|
#################################################
|
|
|
|
- name: fail2ban | Check firewall runtime status
|
|
ansible.builtin.command: pve-firewall status
|
|
register: pve_fw_status
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: fail2ban | Abort if firewall daemon not running
|
|
ansible.builtin.fail:
|
|
msg: >
|
|
Proxmox firewall service is not running.
|
|
Run: systemctl enable --now pve-firewall
|
|
when: "'Status: enabled' not in pve_fw_status.stdout"
|
|
|
|
#################################################
|
|
# Detect cluster
|
|
#################################################
|
|
|
|
- name: fail2ban | Detect Proxmox cluster
|
|
ansible.builtin.stat:
|
|
path: /etc/pve/corosync.conf
|
|
register: cluster_status
|
|
|
|
- name: fail2ban | Set cluster fact
|
|
ansible.builtin.set_fact:
|
|
pve_clustered: "{{ cluster_status.stat.exists }}"
|
|
|
|
#################################################
|
|
# Corosync safety validation
|
|
#################################################
|
|
|
|
- name: fail2ban | Validate corosync firewall rules
|
|
ansible.builtin.command: pve-firewall compile
|
|
register: compiled_fw
|
|
changed_when: false
|
|
failed_when: false
|
|
when: cluster_status.stat.exists
|
|
|
|
- name: fail2ban | Fail if corosync ports are being dropped
|
|
ansible.builtin.fail:
|
|
msg: >
|
|
Firewall configuration appears to affect Corosync ports (5404/5405).
|
|
Refusing to continue to prevent cluster outage.
|
|
when:
|
|
- cluster_status.stat.exists
|
|
- compiled_fw.stdout is search('5404')
|
|
- compiled_fw.stdout is search('DROP')
|
|
|
|
#################################################
|
|
# Install Fail2Ban
|
|
#################################################
|
|
|
|
- name: fail2ban | Install fail2ban
|
|
ansible.builtin.apt:
|
|
name: fail2ban
|
|
state: present
|
|
update_cache: true
|
|
|
|
#################################################
|
|
# Create Proxmox firewall IPSet (cluster-wide)
|
|
#################################################
|
|
|
|
- name: fail2ban | Ensure firewall cluster config exists
|
|
ansible.builtin.file:
|
|
path: /etc/pve/firewall
|
|
state: directory
|
|
when: pve_clustered
|
|
|
|
- name: fail2ban | Add Fail2Ban IPSet to cluster firewall
|
|
ansible.builtin.blockinfile:
|
|
path: /etc/pve/firewall/cluster.fw
|
|
marker: "# {mark} ANSIBLE FAIL2BAN IPSET"
|
|
block: |
|
|
[IPSET {{ f2b_ipset_name }}]
|
|
create: true
|
|
when: pve_clustered
|
|
|
|
- name: fail2ban | Add drop rule for Fail2Ban IPSet
|
|
ansible.builtin.blockinfile:
|
|
path: /etc/pve/firewall/cluster.fw
|
|
marker: "# {mark} ANSIBLE FAIL2BAN RULE"
|
|
block: |
|
|
[RULES]
|
|
IN DROP -source +{{ f2b_ipset_name }}
|
|
when: pve_clustered
|
|
|
|
- name: fail2ban | Extract corosync ring0 address
|
|
ansible.builtin.shell: grep ring0_addr /etc/pve/corosync.conf | awk '{print $2}'
|
|
register: corosync_ip
|
|
changed_when: false
|
|
when: cluster_status.stat.exists
|
|
|
|
# Then automatically whitelist it in Fail2Ban:
|
|
# ignoreip = 127.0.0.1/8 {{ corosync_ip.stdout }}
|
|
|
|
#################################################
|
|
# Create Fail2Ban Proxmox action
|
|
#################################################
|
|
|
|
- name: fail2ban | Create Proxmox firewall action
|
|
ansible.builtin.copy:
|
|
dest: /etc/fail2ban/action.d/proxmox-fw.conf
|
|
mode: '0644'
|
|
content: |
|
|
[Definition]
|
|
actionstart =
|
|
actionstop =
|
|
actioncheck =
|
|
actionban = /usr/sbin/pve-firewall ipset add {{ f2b_ipset_name }} <ip>
|
|
actionunban = /usr/sbin/pve-firewall ipset del {{ f2b_ipset_name }} <ip>
|
|
|
|
#################################################
|
|
# Configure AD-aware jail
|
|
#################################################
|
|
|
|
- name: fail2ban | Ensure jail.d exists
|
|
ansible.builtin.file:
|
|
path: /etc/fail2ban/jail.d
|
|
state: directory
|
|
mode: '0755'
|
|
|
|
- name: fail2ban | Configure Fail2Ban jails
|
|
ansible.builtin.copy:
|
|
dest: /etc/fail2ban/jail.d/proxmox.conf
|
|
mode: '0644'
|
|
content: |
|
|
[DEFAULT]
|
|
bantime = {{ f2b_bantime }}
|
|
findtime = {{ f2b_findtime }}
|
|
maxretry = {{ f2b_maxretry }}
|
|
bantime.increment = {{ f2b_bantime_increment }}
|
|
bantime.factor = {{ f2b_bantime_factor }}
|
|
bantime.max = {{ f2b_bantime_max }}
|
|
backend = systemd
|
|
banaction = proxmox-fw
|
|
ignoreip = 127.0.0.1/8 {{ corosync_ip.stdout | default('') }} 192.168.2.0/24
|
|
|
|
#################################################
|
|
# SSH
|
|
#################################################
|
|
[sshd]
|
|
enabled = true
|
|
journalmatch = _SYSTEMD_UNIT=sshd.service
|
|
|
|
#################################################
|
|
# Proxmox GUI + AD authentication
|
|
#################################################
|
|
[proxmox-auth]
|
|
enabled = true
|
|
port = https,8006
|
|
filter = proxmox-auth
|
|
logpath = /var/log/pveproxy/access.log
|
|
|
|
#################################################
|
|
# Progressive escalation (recidive)
|
|
#################################################
|
|
[recidive]
|
|
enabled = true
|
|
filter = recidive
|
|
logpath = /var/log/fail2ban.log
|
|
bantime = {{ f2b_recidive_bantime }}
|
|
findtime = {{ f2b_recidive_findtime }}
|
|
maxretry = {{ f2b_recidive_maxretry }}
|
|
banaction = proxmox-fw
|
|
notify:
|
|
- Restart fail2ban
|
|
|
|
#################################################
|
|
# AD / Winbind filter
|
|
#################################################
|
|
|
|
- name: fail2ban | Create AD-aware filter
|
|
ansible.builtin.copy:
|
|
dest: /etc/fail2ban/filter.d/proxmox-auth.conf
|
|
mode: '0644'
|
|
content: |
|
|
[Definition]
|
|
failregex = authentication failure; rhost=<HOST>
|
|
pam_unix\(sshd:auth\): authentication failure;.*rhost=<HOST>
|
|
winbind.*authentication for user.*from <HOST> failed
|
|
ignoreregex =
|
|
notify:
|
|
- Restart fail2ban
|
|
|
|
#################################################
|
|
# Enable services
|
|
#################################################
|
|
|
|
- name: fail2ban | Enable fail2ban
|
|
ansible.builtin.systemd:
|
|
name: fail2ban
|
|
enabled: true
|
|
state: started
|
|
|
|
- name: fail2ban | Reload Proxmox firewall
|
|
ansible.builtin.command: pve-firewall reload
|
|
changed_when: false
|