docs 📝: Add Fail2Ban integration tasks to README and directory structure.
Some checks failed
ansible-lint / Ansible Lint (push) Failing after 6s
Gitleaks Scan / gitleaks (push) Successful in 4s
Markdown Lint / markdown-lint (push) Successful in 6s

Updated the README with instructions on integrating Fail2Ban and modified the directory structure to accommodate new files related to this integration.
This commit is contained in:
2026-02-23 19:36:36 +01:00
parent 3afa853d09
commit d3527c14e4
2 changed files with 65 additions and 40 deletions

View File

@@ -27,6 +27,7 @@
| Logrotate protection | ✅ | ✅ | ✅ | | Logrotate protection | ✅ | ✅ | ✅ |
| Powertop auto-tune | ✅ | ✅ | ✅ | | Powertop auto-tune | ✅ | ✅ | ✅ |
| Utilities | ✅ | ✅ | ✅ | | Utilities | ✅ | ✅ | ✅ |
| Fail2Ban Integration | ✅ | ✅ | ✅ |
## 📂 Directory Structure ## 📂 Directory Structure
@@ -40,6 +41,7 @@ ansible_role_proxmox_provision/
├── meta/ # Role metadata ├── meta/ # Role metadata
│ └── main.yml │ └── main.yml
├── tasks/ # Main role tasks ├── tasks/ # Main role tasks
│ ├── fail2ban.yml # Fail2Ban integration tasks
│ ├── logrotate.yml # logrotate setup │ ├── logrotate.yml # logrotate setup
│ ├── main.yml # Core tasks │ ├── main.yml # Core tasks
│ ├── powertop.yml # powertop setup │ ├── powertop.yml # powertop setup
@@ -69,6 +71,7 @@ proxmox_enable_powertop: true
## Logrotate ## Logrotate
proxmox_logrotate_maxsize: "100M" proxmox_logrotate_maxsize: "100M"
proxmox_logrotate_rotate: 7 proxmox_logrotate_rotate: 7
...
``` ```
## Example usage ## Example usage

View File

@@ -3,35 +3,65 @@
# Deploy Fail2Ban integrated with Proxmox Firewall # Deploy Fail2Ban integrated with Proxmox Firewall
# ------------------------------------------------- # -------------------------------------------------
#################################################
# 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 }}"
#################################################
# Determine Correct Firewall File
#################################################
- name: fail2ban | Get Proxmox node name
ansible.builtin.command: hostname
register: pve_node
changed_when: false
- name: fail2ban | Set firewall config path
ansible.builtin.set_fact:
pve_firewall_config: >-
{{
'/etc/pve/firewall/cluster.fw'
if pve_clustered
else '/etc/pve/firewall/' + pve_node.stdout + '.fw'
}}
################################################# #################################################
# Detect firewall configuration # Detect firewall configuration
################################################# #################################################
- name: fail2ban | Check if cluster firewall config exists - name: fail2ban | Check firewall config exists
ansible.builtin.stat: ansible.builtin.stat:
path: /etc/pve/firewall/cluster.fw path: "{{ pve_firewall_config }}"
register: cluster_fw register: fw_stat
- name: fail2ban | Read cluster firewall config - name: fail2ban | Read firewall config
slurp: ansible.builtin.slurp:
src: /etc/pve/firewall/cluster.fw src: "{{ pve_firewall_config }}"
register: cluster_fw_content register: fw_content
when: cluster_fw.stat.exists when: fw_stat.stat.exists
- name: fail2ban | Determine if firewall enabled - name: fail2ban | Determine if firewall enabled
ansible.builtin.set_fact: ansible.builtin.set_fact:
pve_firewall_enabled: >- pve_firewall_enabled: >-
{{ {{
cluster_fw.stat.exists and fw_stat.stat.exists and
(cluster_fw_content.content | b64decode) (fw_content.content | b64decode) is search('enable:\s*1')
is search('enable:\s*1')
}} }}
- name: fail2ban | Abort if firewall not enabled - name: fail2ban | Warn if firewall not enabled
ansible.builtin.fail: ansible.builtin.debug:
msg: > msg: >
Proxmox firewall is not enabled at Datacenter level. WARNING: Proxmox firewall is disabled in configuration.
Enable it before deploying Fail2Ban integration. Fail2Ban will not actively block traffic.
when: not pve_firewall_enabled when: not pve_firewall_enabled
################################################# #################################################
@@ -49,20 +79,7 @@
msg: > msg: >
Proxmox firewall service is not running. Proxmox firewall service is not running.
Run: systemctl enable --now pve-firewall Run: systemctl enable --now pve-firewall
when: "'Status: enabled' not in pve_fw_status.stdout" when: pve_fw_status.rc != 0
#################################################
# 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 # Corosync safety validation
@@ -82,8 +99,7 @@
Refusing to continue to prevent cluster outage. Refusing to continue to prevent cluster outage.
when: when:
- cluster_status.stat.exists - cluster_status.stat.exists
- compiled_fw.stdout is search('5404') - compiled_fw.stdout is search('5404.*DROP|5405.*DROP')
- compiled_fw.stdout is search('DROP')
################################################# #################################################
# Install Fail2Ban # Install Fail2Ban
@@ -96,32 +112,36 @@
update_cache: true update_cache: true
################################################# #################################################
# Create Proxmox firewall IPSet (cluster-wide) # Create Proxmox firewall IPSet
################################################# #################################################
- name: fail2ban | Ensure firewall cluster config exists - name: fail2ban | Ensure firewall directory exists
ansible.builtin.file: ansible.builtin.file:
path: /etc/pve/firewall path: /etc/pve/firewall
state: directory state: directory
when: pve_clustered
- name: fail2ban | Add Fail2Ban IPSet to cluster firewall - name: fail2ban | Add Fail2Ban IPSet to cluster firewall
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
path: /etc/pve/firewall/cluster.fw path: "{{ pve_firewall_config }}"
marker: "# {mark} ANSIBLE FAIL2BAN IPSET" marker: "# {mark} ANSIBLE FAIL2BAN IPSET"
block: | block: |
[IPSET {{ f2b_ipset_name }}] [IPSET {{ f2b_ipset_name }}]
comment: Fail2Ban dynamic blacklist
create: true create: true
when: pve_clustered
- name: fail2ban | Ensure RULES section exists
ansible.builtin.blockinfile:
path: "{{ pve_firewall_config }}"
marker: "# {mark} ANSIBLE RULES HEADER"
block: |
[RULES]
- name: fail2ban | Add drop rule for Fail2Ban IPSet - name: fail2ban | Add drop rule for Fail2Ban IPSet
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
path: /etc/pve/firewall/cluster.fw path: "{{ pve_firewall_config }}"
marker: "# {mark} ANSIBLE FAIL2BAN RULE" marker: "# {mark} ANSIBLE FAIL2BAN RULE"
block: | block: |
[RULES]
IN DROP -source +{{ f2b_ipset_name }} IN DROP -source +{{ f2b_ipset_name }}
when: pve_clustered
- name: fail2ban | Extract corosync ring0 address - name: fail2ban | Extract corosync ring0 address
ansible.builtin.shell: grep ring0_addr /etc/pve/corosync.conf | awk '{print $2}' ansible.builtin.shell: grep ring0_addr /etc/pve/corosync.conf | awk '{print $2}'
@@ -172,7 +192,7 @@
bantime.max = {{ f2b_bantime_max }} bantime.max = {{ f2b_bantime_max }}
backend = systemd backend = systemd
banaction = proxmox-fw banaction = proxmox-fw
ignoreip = 127.0.0.1/8 {{ corosync_ip.stdout | default('') }} 192.168.2.0/24 ignoreip = 127.0.0.1/8{% if pve_clustered %} {{ corosync_ip.stdout }}{% endif %} 192.168.2.0/24
################################################# #################################################
# SSH # SSH
@@ -233,6 +253,8 @@
- name: fail2ban | Reload Proxmox firewall - name: fail2ban | Reload Proxmox firewall
ansible.builtin.command: pve-firewall reload ansible.builtin.command: pve-firewall reload
when: fw_stat.changed or
"'ANSIBLE FAIL2BAN' in fw_content.content | default('')"
changed_when: false changed_when: false
################################################# #################################################