Merge pull request 'style 💎: Fix table formatting and add code block for list_banned task' (#46) from dev into main
Reviewed-on: #46
This commit was merged in pull request #46.
This commit is contained in:
@@ -49,10 +49,10 @@ vm_dirty_background_ratio: 5
|
|||||||
vm_swappiness: "{{ proxmox_swapiness }}"
|
vm_swappiness: "{{ proxmox_swapiness }}"
|
||||||
|
|
||||||
# Fail2ban settings
|
# Fail2ban settings
|
||||||
f2b_bantime: 1800 # 30 minutes
|
f2b_bantime: 600 # 10 minutes
|
||||||
f2b_findtime: 600
|
f2b_findtime: 1200 # 20 minutes
|
||||||
f2b_maxretry: 5
|
f2b_maxretry: 5
|
||||||
f2b_recidive_bantime: 86400 # 24 hours
|
f2b_recidive_bantime: 3600 # 1 hours
|
||||||
f2b_recidive_findtime: 86400 # 24 hours
|
f2b_recidive_findtime: 86400 # 24 hours
|
||||||
f2b_recidive_maxretry: 3
|
f2b_recidive_maxretry: 3
|
||||||
f2b_ipset_name: f2b-blacklist
|
f2b_ipset_name: f2b-blacklist
|
||||||
|
|||||||
@@ -32,10 +32,18 @@
|
|||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
- name: Restart fail2ban
|
- name: Reload fail2ban
|
||||||
ansible.builtin.systemd:
|
ansible.builtin.systemd:
|
||||||
name: fail2ban
|
name: fail2ban
|
||||||
state: reloaded
|
state: reloaded
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: Restart fail2ban
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: fail2ban
|
||||||
|
state: restarted
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
|
||||||
- name: Reload pve firewall
|
- name: Reload pve firewall
|
||||||
ansible.builtin.command: pve-firewall reload
|
ansible.builtin.command: pve-firewall reload
|
||||||
|
|||||||
110
meta/fail2ban.md
Normal file
110
meta/fail2ban.md
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Detects Proxmox VE installation.
|
||||||
|
- Checks cluster filesystem (`pmxcfs`) and quorum before modifying firewall.
|
||||||
|
- Detects cluster membership via `corosync.conf`.
|
||||||
|
- Installs and configures Fail2Ban with:
|
||||||
|
- SSH protection
|
||||||
|
- Proxmox GUI / AD login protection
|
||||||
|
- Progressive ban escalation (recidive jail)
|
||||||
|
- Deploys a **cluster-aware Fail2Ban action** (`proxmox-fw`) for Proxmox
|
||||||
|
firewall integration.
|
||||||
|
- Ensures safe firewall updates without affecting Corosync ports (5404/5405).
|
||||||
|
- Supports single-node Fail2Ban using `iptables-multiport`.
|
||||||
|
- Enables and starts the Fail2Ban service.
|
||||||
|
- Provides tasks to list or manually unban IPs in the cluster.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- **Proxmox VE** (any supported version)
|
||||||
|
- **Ansible** ≥ 2.9
|
||||||
|
- Root or sudo access on target nodes
|
||||||
|
- Proxmox firewall enabled for cluster-wide banning (optional, but recommended)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
The playbook uses the following variables (can be defined in a `vars` file or
|
||||||
|
inventory group vars):
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|-------------------------|---------------------------------|-----------------|
|
||||||
|
| `f2b_bantime` | Ban per tentativi falliti | `600s` |
|
||||||
|
| `f2b_findtime` | Finestra per contare fallimenti | `1200s` |
|
||||||
|
| `f2b_maxretry` | Tentativi prima del ban | `5` |
|
||||||
|
| `f2b_bantime_increment` | Abilita ban incrementale | `true` |
|
||||||
|
| `f2b_bantime_factor` | Fattore aumento ban | `2` |
|
||||||
|
| `f2b_bantime_max` | Durata massima del ban | `7d` |
|
||||||
|
| `f2b_recidive_bantime` | Ban per recidiva | `3600` |
|
||||||
|
| `f2b_recidive_findtime` | Finestra recidiva | `86400` |
|
||||||
|
| `f2b_recidive_maxretry` | Tentativi recidiva | `3` |
|
||||||
|
| `f2b_ipset_name` | Nome IPSet per IP bannati | `f2b-blacklist` |
|
||||||
|
| `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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### 1. Apply the playbook
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory fail2ban-proxmox.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. List current banned IPs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook \
|
||||||
|
-i inventory \
|
||||||
|
fail2ban-proxmox.yml \
|
||||||
|
-e "f2b_ipset_name=fail2ban" \
|
||||||
|
-t list_banned
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Unban a specific IP
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i inventory fail2ban-proxmox.yml -e "f2b_unban_ip=1.2.3.4"
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
- Detects Proxmox – ensures the playbook runs only on Proxmox VE hosts.
|
||||||
|
- Cluster safety checks – verifies /etc/pve/.members and corosync.conf
|
||||||
|
for quorum.
|
||||||
|
- Installs Fail2Ban – ensures /etc/fail2ban/jail.local exists and applies
|
||||||
|
configuration.
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- The playbook does not copy jail.conf, only manages jail.local.
|
||||||
|
- 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.
|
||||||
|
- Manual unban is supported via f2b_unban_ip variable.
|
||||||
|
- Always verify that the Proxmox firewall is enabled when using
|
||||||
|
cluster-wide bans.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License
|
||||||
@@ -4,17 +4,139 @@
|
|||||||
# -------------------------------------------------
|
# -------------------------------------------------
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Detect cluster
|
# Detect Proxmox
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
- name: fail2ban | Detect Proxmox cluster
|
- name: fail2ban | Detect Proxmox
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /usr/bin/pveversion
|
||||||
|
register: pve_installed
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Ensure pmxcfs is mounted (cluster filesystem)
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
- name: fail2ban | Check pmxcfs cluster filesystem
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /etc/pve/.members
|
||||||
|
register: pmxcfs_running
|
||||||
|
when: pve_installed.stat.exists | default(false)
|
||||||
|
|
||||||
|
- name: fail2ban | Warn if pmxcfs not mounted (no quorum)
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >
|
||||||
|
/etc/pve is not mounted or node has no quorum.
|
||||||
|
Refusing to modify cluster firewall.
|
||||||
|
when:
|
||||||
|
- pve_installed.stat.exists | default(false)
|
||||||
|
- not pmxcfs_running.stat.exists
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Detect cluster membership
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
- name: fail2ban | Detect Proxmox cluster membership
|
||||||
ansible.builtin.stat:
|
ansible.builtin.stat:
|
||||||
path: /etc/pve/corosync.conf
|
path: /etc/pve/corosync.conf
|
||||||
register: cluster_status
|
register: clustered
|
||||||
|
when: pmxcfs_running.stat.exists | default(false)
|
||||||
|
|
||||||
- name: fail2ban | Set cluster fact
|
- name: fail2ban | Warn if corosync.conf is missing
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.debug:
|
||||||
pve_clustered: "{{ cluster_status.stat.exists }}"
|
msg: >
|
||||||
|
node has no quorum.
|
||||||
|
Refusing to modify cluster firewall.
|
||||||
|
when:
|
||||||
|
- pve_installed.stat.exists | default(false)
|
||||||
|
- pmxcfs_running.stat.exists | default(false)
|
||||||
|
- not clustered.stat.exists
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Install Fail2Ban
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
- name: fail2ban | Install fail2ban
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name: fail2ban
|
||||||
|
state: present
|
||||||
|
update_cache: true
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Ensure jail.local exists (do NOT copy jail.conf)
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
- name: fail2ban | Ensure jail.local exists
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /etc/fail2ban/jail.local
|
||||||
|
state: touch
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Configure Fail2Ban jails
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
- name: fail2ban | Configure Fail2Ban jails
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
dest: /etc/fail2ban/jail.local
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED BLOCK - PROXMOX"
|
||||||
|
block: |
|
||||||
|
# jail.conf (default)
|
||||||
|
# jail.local (override defaults)
|
||||||
|
[DEFAULT]
|
||||||
|
bantime = {{ f2b_bantime }}
|
||||||
|
findtime = {{ f2b_findtime }}
|
||||||
|
maxretry = {{ f2b_maxretry }}
|
||||||
|
bantime.increment = {{ f2b_bantime_increment }}
|
||||||
|
bantime.factor = {{ f2b_bantime_factor }}
|
||||||
|
bantime.maxtime = {{ f2b_bantime_max }}
|
||||||
|
backend = systemd
|
||||||
|
banaction = {% if (clustered.stat.exists | default(false)) %} proxmox-fw{% else %} iptables-multiport{% endif %}
|
||||||
|
ignoreip = 127.0.0.1/8 192.168.2.0/24
|
||||||
|
# {% if pmxcfs_running.stat.exists %} {{ corosync_networks | join(' ') }}{% endif %}
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# SSH
|
||||||
|
#################################################
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# Proxmox GUI + AD authentication
|
||||||
|
#################################################
|
||||||
|
[proxmox]
|
||||||
|
enabled = true
|
||||||
|
port = https,http,8006
|
||||||
|
filter = proxmox
|
||||||
|
|
||||||
|
#################################################
|
||||||
|
# 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 = {% if (clustered.stat.exists | default(false)) %} proxmox-fw{% else %} iptables-multiport{% endif %}
|
||||||
|
notify:
|
||||||
|
- Reload fail2ban
|
||||||
|
|
||||||
|
- name: fail2ban | Place Proxmox filter definition
|
||||||
|
ansible.builtin.copy:
|
||||||
|
dest: /etc/fail2ban/filter.d/proxmox.conf
|
||||||
|
content: |
|
||||||
|
[Definition]
|
||||||
|
failregex = pvedaemon\[.*authentication failure; rhost=<HOST> user=.* msg=.*
|
||||||
|
ignoreregex =
|
||||||
|
journalmatch = _SYSTEMD_UNIT=pvedaemon.service
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- Reload fail2ban
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Determine Correct Firewall File
|
# Determine Correct Firewall File
|
||||||
@@ -23,15 +145,17 @@
|
|||||||
- name: fail2ban | Get Proxmox node name
|
- name: fail2ban | Get Proxmox node name
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
pve_node: "{{ ansible_hostname }}"
|
pve_node: "{{ ansible_hostname }}"
|
||||||
|
when: not clustered.stat.exists
|
||||||
|
|
||||||
- name: fail2ban | Set firewall config path
|
- name: fail2ban | Set firewall config path
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
pve_firewall_config: >-
|
pve_firewall_config: >-
|
||||||
{{
|
{{
|
||||||
'/etc/pve/firewall/cluster.fw'
|
'/etc/pve/firewall/cluster.fw'
|
||||||
if pve_clustered
|
if clustered.stat.exists
|
||||||
else '/etc/pve/firewall/' + pve_node + '.fw'
|
else '/etc/pve/nodes/' + pve_node + '.fw'
|
||||||
}}
|
}}
|
||||||
|
when: pve_installed.stat.exists | default(false)
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Detect firewall configuration
|
# Detect firewall configuration
|
||||||
@@ -41,19 +165,23 @@
|
|||||||
ansible.builtin.stat:
|
ansible.builtin.stat:
|
||||||
path: "{{ pve_firewall_config }}"
|
path: "{{ pve_firewall_config }}"
|
||||||
register: fw_stat
|
register: fw_stat
|
||||||
|
when: pve_firewall_config is defined
|
||||||
|
|
||||||
- name: fail2ban | Read firewall config
|
- name: fail2ban | Read firewall config
|
||||||
ansible.builtin.slurp:
|
ansible.builtin.slurp:
|
||||||
src: "{{ pve_firewall_config }}"
|
src: "{{ pve_firewall_config }}"
|
||||||
register: fw_content
|
register: fw_content
|
||||||
when: fw_stat.stat.exists
|
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 and
|
(fw_stat.stat.exists | default(false)) and
|
||||||
(fw_content.content | b64decode) is search('enable:\s*1')
|
(
|
||||||
|
(fw_content.content | default('') | b64decode)
|
||||||
|
is search('enable:\s*1')
|
||||||
|
)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: fail2ban | Warn if firewall not enabled
|
- name: fail2ban | Warn if firewall not enabled
|
||||||
@@ -72,13 +200,18 @@
|
|||||||
register: pve_fw_status
|
register: pve_fw_status
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
when: pmxcfs_running.stat.exists | default(false)
|
||||||
|
|
||||||
- name: fail2ban | Abort if firewall daemon not running
|
- name: fail2ban | Abort if firewall daemon not running
|
||||||
ansible.builtin.fail:
|
ansible.builtin.debug:
|
||||||
msg: >
|
msg: >
|
||||||
Proxmox firewall service is not running.
|
Proxmox firewall service is not running.
|
||||||
Run: systemctl enable --now pve-firewall
|
You can run: systemctl enable --now pve-firewall
|
||||||
when: pve_fw_status.rc != 0
|
when:
|
||||||
|
- pve_fw_status is defined
|
||||||
|
- pve_fw_status.rc != 0
|
||||||
|
- fw_stat.stat.exists | default(false)
|
||||||
|
- pmxcfs_running.stat.exists | default(false)
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Corosync safety validation
|
# Corosync safety validation
|
||||||
@@ -88,181 +221,51 @@
|
|||||||
ansible.builtin.command: pve-firewall compile
|
ansible.builtin.command: pve-firewall compile
|
||||||
register: compiled_fw
|
register: compiled_fw
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: fw_compile_check.rc != 0
|
failed_when: compiled_fw.rc != 0
|
||||||
when: cluster_status.stat.exists
|
when: clustered.stat.exists | default(false)
|
||||||
|
|
||||||
- name: fail2ban | Fail if corosync ports are being dropped
|
- name: fail2ban | Fail if corosync ports are being dropped
|
||||||
ansible.builtin.fail:
|
ansible.builtin.debug:
|
||||||
msg: >
|
msg: >
|
||||||
Firewall configuration appears to affect Corosync ports (5404/5405).
|
Firewall configuration appears to affect Corosync ports (5404/5405).
|
||||||
Refusing to continue to prevent cluster outage.
|
Refusing to continue to prevent cluster outage.
|
||||||
when:
|
when:
|
||||||
- cluster_status.stat.exists
|
- clustered.stat.exists | default(false)
|
||||||
- compiled_fw.stdout is search('5404.*DROP|5405.*DROP')
|
- compiled_fw.stdout is search('5404.*DROP|5405.*DROP')
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# Install Fail2Ban
|
# Deploy cluster-aware Fail2Ban action
|
||||||
#################################################
|
#################################################
|
||||||
|
|
||||||
- name: fail2ban | Install fail2ban
|
- name: fail2ban | Deploy proxmox-fw action
|
||||||
ansible.builtin.apt:
|
|
||||||
name: fail2ban
|
|
||||||
state: present
|
|
||||||
update_cache: true
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# Create Proxmox firewall IPSet
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
- name: fail2ban | Add Fail2Ban IPSet to firewall
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path: "{{ pve_firewall_config }}"
|
|
||||||
marker: "# {mark} ANSIBLE FAIL2BAN IPSET"
|
|
||||||
insertbefore: BOF
|
|
||||||
block: |
|
|
||||||
[IPSET {{ f2b_ipset_name }}]
|
|
||||||
comment: Fail2Ban dynamic blacklist
|
|
||||||
create: false
|
|
||||||
register: ipset_change
|
|
||||||
notify: Reload pve firewall
|
|
||||||
# noqa risky-file-permissions
|
|
||||||
|
|
||||||
- name: fail2ban | Add drop rule for Fail2Ban IPSet
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path: "{{ pve_firewall_config }}"
|
|
||||||
marker: "# {mark} ANSIBLE FAIL2BAN RULE"
|
|
||||||
insertafter: '^\[RULES\]'
|
|
||||||
block: |
|
|
||||||
IN DROP -source +{{ f2b_ipset_name }}
|
|
||||||
create: false
|
|
||||||
register: rule_change
|
|
||||||
notify: Reload pve firewall
|
|
||||||
# noqa risky-file-permissions
|
|
||||||
|
|
||||||
- name: fail2ban | Extract all corosync ring addresses
|
|
||||||
ansible.builtin.shell: |
|
|
||||||
set -o pipefail
|
|
||||||
awk '/ring[0-9]+_addr/ {print $2}' /etc/pve/corosync.conf
|
|
||||||
args:
|
|
||||||
executable: /bin/bash
|
|
||||||
register: corosync_ips
|
|
||||||
changed_when: false
|
|
||||||
when: pve_clustered
|
|
||||||
|
|
||||||
- name: fail2ban | Determine CIDR for each corosync IP
|
|
||||||
ansible.builtin.command: ip route get {{ item }}
|
|
||||||
register: corosync_routes
|
|
||||||
changed_when: false
|
|
||||||
loop: "{{ corosync_ips.stdout_lines }}"
|
|
||||||
when: pve_clustered
|
|
||||||
|
|
||||||
- name: fail2ban | Extract network CIDRs
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
corosync_networks: >-
|
|
||||||
{{
|
|
||||||
corosync_routes.results
|
|
||||||
| map(attribute='stdout')
|
|
||||||
| map('regex_search', 'src ([0-9.]+)/([0-9]+)', '\\1/\\2')
|
|
||||||
| list
|
|
||||||
}}
|
|
||||||
when: pve_clustered
|
|
||||||
|
|
||||||
- name: fail2ban | Validate Proxmox firewall configuration
|
|
||||||
ansible.builtin.command: pve-firewall compile
|
|
||||||
when: ipset_change.changed or rule_change.changed
|
|
||||||
changed_when: false
|
|
||||||
failed_when: fw_compile_check.rc != 0
|
|
||||||
register: fw_compile_check
|
|
||||||
|
|
||||||
# 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:
|
ansible.builtin.copy:
|
||||||
dest: /etc/fail2ban/action.d/proxmox-fw.conf
|
dest: /etc/fail2ban/action.d/proxmox-fw.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
mode: '0644'
|
mode: '0644'
|
||||||
content: |
|
content: |
|
||||||
[Definition]
|
[Definition]
|
||||||
|
|
||||||
|
fwfile = {{ pve_firewall_config }}
|
||||||
|
|
||||||
|
rule = DROP -source <ip> -log nolog
|
||||||
|
|
||||||
|
actionban = \
|
||||||
|
if [ -f <fwfile> ]; then \
|
||||||
|
grep -qF "<rule>" <fwfile> || echo "<rule>" >> <fwfile>; \
|
||||||
|
pve-firewall compile >/dev/null 2>&1 || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
actionunban = \
|
||||||
|
if [ -f <fwfile> ]; then \
|
||||||
|
sed -i "\|<rule>|d" <fwfile>; \
|
||||||
|
pve-firewall compile >/dev/null 2>&1 || true; \
|
||||||
|
fi
|
||||||
|
|
||||||
actionstart =
|
actionstart =
|
||||||
actionstop =
|
actionstop =
|
||||||
actioncheck =
|
when:
|
||||||
actionban = /usr/sbin/pve-firewall ipset add {{ f2b_ipset_name }} <ip>
|
- clustered.stat.exists | default(false)
|
||||||
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{% if pve_clustered %} {{ corosync_networks | join(' ') }}{% endif %} 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:
|
notify:
|
||||||
- Restart fail2ban
|
- Restart fail2ban
|
||||||
|
|
||||||
@@ -299,7 +302,7 @@
|
|||||||
- 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 | 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
|
||||||
|
|||||||
Reference in New Issue
Block a user