Compare commits

...

9 Commits

Author SHA1 Message Date
ded4fb8270 chore 📦: Update file path for non-clustered environments in fail2ban.yml
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 15s
Gitleaks Scan / gitleaks (push) Successful in 5s
Markdown Lint / markdown-lint (push) Successful in 5s
ai-reviews / Review PR (pull_request) Successful in 12s
PR check / Gitleaks (pull_request) Successful in 4s
PR check / lint tests (pull_request) Successful in 15s
PR check / labeler (pull_request) Successful in 3s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 2s
This commit updates the file path configuration for non-clustered environments in the `fail2ban.yml` file. This ensures that the correct paths are used when running fail2ban outside of a clustered environment.
2026-03-02 19:02:18 +01:00
38831f981a refactor ♻️: Check for firewall file existence before debugging
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 12s
Gitleaks Scan / gitleaks (push) Successful in 4s
Markdown Lint / markdown-lint (push) Successful in 5s
ai-reviews / Review PR (pull_request) Successful in 11s
PR check / Gitleaks (pull_request) Successful in 4s
PR check / lint tests (pull_request) Successful in 15s
PR check / labeler (pull_request) Successful in 2s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 2s
Refactored the code to include a conditional check for the existence of the firewall file before proceeding with debugging. This ensures that the debugging process is only initiated when necessary, preventing unnecessary operations and potential errors.
2026-03-01 20:03:52 +01:00
d2761bd840 refactor ♻️: Refactor task names and improve formatting in fail2ban.yml
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 12s
Gitleaks Scan / gitleaks (push) Successful in 4s
Markdown Lint / markdown-lint (push) Successful in 8s
ai-reviews / Review PR (pull_request) Successful in 13s
PR check / Gitleaks (pull_request) Successful in 5s
PR check / lint tests (pull_request) Successful in 16s
PR check / labeler (pull_request) Successful in 2s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 1s
This commit refactors the task names for better readability and consistency. Additionally, it improves the formatting of the YAML file to enhance maintainability.
2026-03-01 12:59:08 +01:00
c8fb6e4c80 feat : Add debug tasks for Proxmox firewall config path and contents
Some checks failed
ansible-lint / Ansible Lint (push) Failing after 13s
Gitleaks Scan / gitleaks (push) Successful in 5s
Markdown Lint / markdown-lint (push) Successful in 5s
ai-reviews / Review PR (pull_request) Successful in 15s
PR check / Gitleaks (pull_request) Successful in 5s
PR check / lint tests (pull_request) Failing after 17s
PR check / labeler (pull_request) Successful in 2s
PR check / handle_failures (pull_request) Successful in 1s
PR check / handle_success (pull_request) Has been skipped
This commit introduces new debug tasks to help diagnose issues related to the Proxmox firewall configuration path and its contents. These tasks will assist in verifying that the paths are correctly set up and that the necessary files are present.
2026-03-01 12:56:54 +01:00
54f3f761c8 chore 📦: Remove commented-out code in fail2ban.yml
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 14s
Gitleaks Scan / gitleaks (push) Successful in 4s
Markdown Lint / markdown-lint (push) Successful in 5s
ai-reviews / Review PR (pull_request) Successful in 12s
PR check / Gitleaks (pull_request) Successful in 5s
PR check / lint tests (pull_request) Successful in 16s
PR check / labeler (pull_request) Successful in 2s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 2s
This commit removes unnecessary commented-out code from the fail2ban.yml file to clean up and simplify the configuration.
2026-03-01 12:05:48 +01:00
3054a97d15 chore 📦: Update build scripts for CI/CD pipeline
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 12s
Gitleaks Scan / gitleaks (push) Successful in 6s
Markdown Lint / markdown-lint (push) Successful in 6s
ai-reviews / Review PR (pull_request) Successful in 13s
PR check / Gitleaks (pull_request) Successful in 5s
PR check / lint tests (pull_request) Successful in 15s
PR check / labeler (pull_request) Successful in 3s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 1s
Refactored the build scripts to improve compatibility with the latest version of the CI/CD tooling and added new tests for edge cases.
2026-03-01 12:00:48 +01:00
752db2b57f style 💎: Fix table formatting and add code block for list_banned task
All checks were successful
ansible-lint / Ansible Lint (push) Successful in 13s
Gitleaks Scan / gitleaks (push) Successful in 5s
Markdown Lint / markdown-lint (push) Successful in 5s
ai-reviews / Review PR (pull_request) Successful in 37s
PR check / Gitleaks (pull_request) Successful in 5s
PR check / lint tests (pull_request) Successful in 15s
PR check / labeler (pull_request) Successful in 2s
PR check / handle_failures (pull_request) Has been skipped
PR check / handle_success (pull_request) Successful in 1s
This commit addresses the formatting issues in the table and adds a code block for the 'list_banned' task to improve readability and clarity.
2026-03-01 10:52:57 +01:00
0004d2bd2d refactor ♻️: Refactor task names and update module references in fail2ban.yml
Some checks failed
ansible-lint / Ansible Lint (push) Successful in 12s
Gitleaks Scan / gitleaks (push) Successful in 4s
Markdown Lint / markdown-lint (push) Failing after 6s
This commit refactors the task names and updates module references in the `fail2ban.yml` file to improve clarity and consistency. It also includes minor text adjustments in `meta/fail2ban.md` to enhance readability and ensure accurate variable descriptions with updated default values.
2026-03-01 10:48:13 +01:00
e44f757b9e refactor ♻️: Refactor and reformat text for better readability
Some checks failed
ansible-lint / Ansible Lint (push) Failing after 17s
Gitleaks Scan / gitleaks (push) Successful in 5s
Markdown Lint / markdown-lint (push) Failing after 5s
This commit refactors the code by improving text formatting and structure to enhance readability, ensuring that the content and functionality remain unchanged.
2026-03-01 10:31:36 +01:00
2 changed files with 88 additions and 64 deletions

View File

@@ -1,6 +1,8 @@
# Fail2Ban Integration with Proxmox Firewall # Fail2Ban Integration with Proxmox Firewall
This Ansible playbook deploys and configures **Fail2Ban** on a Proxmox VE environment, integrating it with the **Proxmox firewall** for cluster-aware IP banning. It supports both single-node and clustered Proxmox setups. This Ansible playbook deploys and configures **Fail2Ban** on a Proxmox VE
environment, integrating it with the **Proxmox firewall** for cluster-aware
IP banning. It supports both single-node and clustered Proxmox setups.
--- ---
@@ -13,7 +15,8 @@ This Ansible playbook deploys and configures **Fail2Ban** on a Proxmox VE enviro
- SSH protection - SSH protection
- Proxmox GUI / AD login protection - Proxmox GUI / AD login protection
- Progressive ban escalation (recidive jail) - Progressive ban escalation (recidive jail)
- Deploys a **cluster-aware Fail2Ban action** (`proxmox-fw`) for Proxmox firewall integration. - Deploys a **cluster-aware Fail2Ban action** (`proxmox-fw`) for Proxmox
firewall integration.
- Ensures safe firewall updates without affecting Corosync ports (5404/5405). - Ensures safe firewall updates without affecting Corosync ports (5404/5405).
- Supports single-node Fail2Ban using `iptables-multiport`. - Supports single-node Fail2Ban using `iptables-multiport`.
- Enables and starts the Fail2Ban service. - Enables and starts the Fail2Ban service.
@@ -32,23 +35,25 @@ This Ansible playbook deploys and configures **Fail2Ban** on a Proxmox VE enviro
## Variables ## Variables
The playbook uses the following variables (can be defined in a `vars` file or inventory group vars): The playbook uses the following variables (can be defined in a `vars` file or
inventory group vars):
| Variable | Description | Default / Notes | | Variable | Description | Default |
|----------|-------------|----------------| |-------------------------|---------------------------------|-----------------|
| `f2b_bantime` | Default ban time for repeated failures | e.g., `600s` | | `f2b_bantime` | Ban per tentativi falliti | `600s` |
| `f2b_findtime` | Time window to check failures | e.g., `1200s`| | `f2b_findtime` | Finestra per contare fallimenti | `1200s` |
| `f2b_maxretry` | Maximum retries before ban | e.g., `5` | | `f2b_maxretry` | Tentativi prima del ban | `5` |
| `f2b_bantime_increment` | Incremental ban time (recidive) | e.g., `true` | | `f2b_bantime_increment` | Abilita ban incrementale | `true` |
| `f2b_bantime_factor` | Factor for incremental ban | e.g., `2` | | `f2b_bantime_factor` | Fattore aumento ban | `2` |
| `f2b_bantime_max` | Maximum ban time | e.g., `7d` | | `f2b_bantime_max` | Durata massima del ban | `7d` |
| `f2b_recidive_bantime` | Ban time for recidive jail | e.g., `3600` | | `f2b_recidive_bantime` | Ban per recidiva | `3600` |
| `f2b_recidive_findtime` | Findtime for recidive jail | e.g., `86400` | | `f2b_recidive_findtime` | Finestra recidiva | `86400` |
| `f2b_recidive_maxretry` | Max retry for recidive jail | e.g., `3` | | `f2b_recidive_maxretry` | Tentativi recidiva | `3` |
| `f2b_ipset_name` | Name of Proxmox IPSet used for banned IPs | e.g., `f2b-blacklist` | | `f2b_ipset_name` | Nome IPSet per IP bannati | `f2b-blacklist` |
| `f2b_unban_ip` | Optional IP to unban manually | Leave undefined if not needed | | `f2b_unban_ip` | IP da sbloccare | `""` |
> All `clustered` and `pmxcfs_running` checks default to `false` to prevent errors on non-clustered or single-node setups. > All `clustered` and `pmxcfs_running` checks default to `false` to prevent
> errors on non-clustered or single-node setups.
--- ---
@@ -63,7 +68,11 @@ ansible-playbook -i inventory fail2ban-proxmox.yml
### 2. List current banned IPs ### 2. List current banned IPs
```bash ```bash
ansible-playbook -i inventory fail2ban-proxmox.yml -e "f2b_ipset_name=fail2ban" -t list_banned ansible-playbook \
-i inventory \
fail2ban-proxmox.yml \
-e "f2b_ipset_name=fail2ban" \
-t list_banned
``` ```
### 3. Unban a specific IP ### 3. Unban a specific IP
@@ -75,20 +84,27 @@ ansible-playbook -i inventory fail2ban-proxmox.yml -e "f2b_unban_ip=1.2.3.4"
## How It Works ## How It Works
- Detects Proxmox ensures the playbook runs only on Proxmox VE hosts. - Detects Proxmox ensures the playbook runs only on Proxmox VE hosts.
- Cluster safety checks verifies /etc/pve/.members and corosync.conf for quorum. - Cluster safety checks verifies /etc/pve/.members and corosync.conf
- Installs Fail2Ban ensures /etc/fail2ban/jail.local exists and applies configuration. for quorum.
- Cluster-aware action for clustered nodes, Fail2Ban bans are added to Proxmox firewall and compiled immediately (pve-firewall compile). - Installs Fail2Ban ensures /etc/fail2ban/jail.local exists and applies
- Single-node fallback uses iptables-multiport for nodes not in a cluster. configuration.
- Corosync protection prevents firewall rules from dropping cluster communication ports (5404/5405). - Cluster-aware action for clustered nodes, Fail2Ban bans are added to
Proxmox firewall and compiled immediately (pve-firewall compile).
- Single-node fallback uses iptables-multiport for nodes not in
a cluster.
- Corosync protection prevents firewall rules from dropping cluster
communication ports (5404/5405).
## Notes & Safety ## Notes & Safety
- The playbook does not copy jail.conf, only manages jail.local. - The playbook does not copy jail.conf, only manages jail.local.
- Firewall rules for clustered nodes are only modified if quorum exists. - Firewall rules for clustered nodes are only modified if quorum exists.
- pve-firewall compile is called safely (>/dev/null 2>&1 || true) to prevent playbook failure on minor compilation warnings. - pve-firewall compile is called safely (>/dev/null 2>&1 || true)
to prevent playbook failure on minor compilation warnings.
- Manual unban is supported via f2b_unban_ip variable. - Manual unban is supported via f2b_unban_ip variable.
- Always verify that the Proxmox firewall is enabled when using cluster-wide bans. - Always verify that the Proxmox firewall is enabled when using
cluster-wide bans.
## License ## License
MIT License MIT License

View File

@@ -8,7 +8,7 @@
################################################# #################################################
- name: fail2ban | Detect Proxmox - name: fail2ban | Detect Proxmox
stat: ansible.builtin.stat:
path: /usr/bin/pveversion path: /usr/bin/pveversion
register: pve_installed register: pve_installed
@@ -80,7 +80,6 @@
- name: fail2ban | Configure Fail2Ban jails - name: fail2ban | Configure Fail2Ban jails
ansible.builtin.blockinfile: ansible.builtin.blockinfile:
dest: /etc/fail2ban/jail.local dest: /etc/fail2ban/jail.local
create: true
marker: "# {mark} ANSIBLE MANAGED BLOCK - PROXMOX" marker: "# {mark} ANSIBLE MANAGED BLOCK - PROXMOX"
block: | block: |
# jail.conf (default) # jail.conf (default)
@@ -95,7 +94,6 @@
backend = systemd backend = systemd
banaction = {% if (clustered.stat.exists | default(false)) %} proxmox-fw{% else %} iptables-multiport{% endif %} banaction = {% if (clustered.stat.exists | default(false)) %} proxmox-fw{% else %} iptables-multiport{% endif %}
ignoreip = 127.0.0.1/8 192.168.2.0/24 ignoreip = 127.0.0.1/8 192.168.2.0/24
# {% if pmxcfs_running.stat.exists %} {{ corosync_networks | join(' ') }}{% endif %}
################################################# #################################################
# SSH # SSH
@@ -154,10 +152,16 @@
{{ {{
'/etc/pve/firewall/cluster.fw' '/etc/pve/firewall/cluster.fw'
if clustered.stat.exists if clustered.stat.exists
else '/etc/pve/nodes/' + pve_node + '.fw' else '/etc/pve/nodes/' + pve_node + '/host.fw'
}} }}
when: pve_installed.stat.exists | default(false) when: pve_installed.stat.exists | default(false)
- name: fail2ban | Show firewall config path
ansible.builtin.debug:
msg: >
WARNING: Proxmox firewall config path is: {{ pve_firewall_config}}
when: pve_firewall_config is defined
################################################# #################################################
# Detect firewall configuration # Detect firewall configuration
################################################# #################################################
@@ -174,15 +178,19 @@
register: fw_content register: fw_content
when: fw_stat.stat.exists | default(false) when: fw_stat.stat.exists | default(false)
- name: fail2ban | Debug config contents
ansible.builtin.debug:
msg: >
{{ fw_content }}
when: fw_stat.stat.exists | default(false)
- 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: >-
{{ {{
(fw_stat.stat.exists | default(false)) and fw_stat.stat.exists and
( (fw_content.content | b64decode)
(fw_content.content | default('') | b64decode) is search('^enable:\s*1$', multiline=True)
is search('enable:\s*1')
)
}} }}
- name: fail2ban | Warn if firewall not enabled - name: fail2ban | Warn if firewall not enabled
@@ -238,7 +246,7 @@
# Deploy cluster-aware Fail2Ban action # Deploy cluster-aware Fail2Ban action
################################################# #################################################
- name: fail2ban-fw | Deploy proxmox-fw action - name: fail2ban | Deploy proxmox-fw action
ansible.builtin.copy: ansible.builtin.copy:
dest: /etc/fail2ban/action.d/proxmox-fw.conf dest: /etc/fail2ban/action.d/proxmox-fw.conf
owner: root owner: root
@@ -266,7 +274,7 @@
actionstart = actionstart =
actionstop = actionstop =
when: when:
- clustered.stat.exists | default(false) - clustered.stat.exists | default(false)
notify: notify:
- Restart fail2ban - Restart fail2ban
@@ -280,35 +288,35 @@
enabled: true enabled: true
state: started state: started
################################################# # #################################################
# List banned IPs cluster-wide # # List banned IPs cluster-wide
################################################# # #################################################
- name: fail2ban | Get banned IPs from Proxmox IPSet # - name: fail2ban | Get banned IPs from Proxmox IPSet
ansible.builtin.command: pve-firewall ipset list {{ f2b_ipset_name }} # ansible.builtin.command: pve-firewall ipset list {{ f2b_ipset_name }}
register: banned_ips # register: banned_ips
changed_when: false # changed_when: false
failed_when: false # failed_when: false
- name: fail2ban | Show banned IPs # - name: fail2ban | Show banned IPs
ansible.builtin.debug: # ansible.builtin.debug:
msg: > # msg: >
Current banned IPs (cluster-wide): # Current banned IPs (cluster-wide):
{{ banned_ips.stdout_lines | default([]) }} # {{ banned_ips.stdout_lines | default([]) }}
################################################# # #################################################
# Manual unban # # Manual unban
################################################# # #################################################
- name: fail2ban | Unban specific IP # - name: fail2ban | Unban specific IP
ansible.builtin.command: > # ansible.builtin.command: >
pve-firewall ipset del {{ f2b_ipset_name }} {{ f2b_unban_ip }} # pve-firewall ipset del {{ f2b_ipset_name }} {{ f2b_unban_ip }}
when: f2b_unban_ip is defined and f2b_unban_ip | length > 0 # when: f2b_unban_ip is defined and f2b_unban_ip | length > 0
register: unban_result # register: unban_result
changed_when: "'removed' in unban_result.stdout or unban_result.rc == 0" # changed_when: "'removed' in unban_result.stdout or unban_result.rc == 0"
failed_when: false # failed_when: false
- name: fail2ban | Report unban result # - name: fail2ban | Report unban result
ansible.builtin.debug: # ansible.builtin.debug:
msg: "Unbanned IP {{ f2b_unban_ip }}" # msg: "Unbanned IP {{ f2b_unban_ip }}"
when: f2b_unban_ip | length > 0 # when: f2b_unban_ip | length > 0