The module gains a runtime carrying only the fail2ban client with the daemon's socket shared in, serving status/banned/ban/unban and its own fail2ban_settings. It declares jailing, so the controller's composition lands in jail.d/mesh.conf and filter.d; mailu, route-proxy and gitea log to the journal and declare a jail reading it by container name. The base is strict: three in a day for a day, twice banned in two weeks for four; the mesh's range stays never banned.
159 lines
6.6 KiB
JSON
159 lines
6.6 KiB
JSON
{
|
|
"module": "fail2ban",
|
|
"version": "1",
|
|
"capabilities": [
|
|
"firewall"
|
|
],
|
|
"claims": [
|
|
{
|
|
"name": "node-intrusion-prevention",
|
|
"scope": "node",
|
|
"serves": [
|
|
"status",
|
|
"banned",
|
|
"ban",
|
|
"unban"
|
|
]
|
|
}
|
|
],
|
|
"tools": [
|
|
"fail2ban_settings"
|
|
],
|
|
"own-secrets": {
|
|
"broker": "${dir:mesh-state}/broker"
|
|
},
|
|
"jailing": {
|
|
"into": "/etc/fail2ban/jail.d/mesh.conf",
|
|
"filter-into": "/etc/fail2ban/filter.d"
|
|
},
|
|
"resources": [
|
|
{
|
|
"id": "package",
|
|
"type": "package",
|
|
"package": "fail2ban"
|
|
},
|
|
{
|
|
"id": "jail-d",
|
|
"type": "directory",
|
|
"path": "/etc/fail2ban/jail.d",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "action-d",
|
|
"type": "directory",
|
|
"path": "/etc/fail2ban/action.d",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "filter-d",
|
|
"type": "directory",
|
|
"path": "/etc/fail2ban/filter.d",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "run-dir",
|
|
"type": "directory",
|
|
"path": "/var/run/fail2ban",
|
|
"mode": "0755"
|
|
},
|
|
{
|
|
"id": "mesh-state",
|
|
"type": "directory",
|
|
"mode": "0700",
|
|
"place": "mesh"
|
|
},
|
|
{
|
|
"id": "jail-local",
|
|
"type": "file",
|
|
"path": "/etc/fail2ban/jail.local",
|
|
"mode": "0644",
|
|
"content": "[INCLUDES]\n\nbefore = paths-arch.conf\n\n[DEFAULT]\n\n# Never act on the machine itself or on a tunnel peer: the mesh's private range is\n# ${machine:mesh-range}, named here rather than written as a value the module cannot\n# know (novox/hq ADR 0112). Without this, fail2ban could ban the mesh's own nodes.\nignoreip = 127.0.0.1/8 ::1 ${machine:mesh-range}\n\n# Three failures in a day ban for a day (novox/hq ADR 0179). The attackers this mesh sees pace\n# themselves at one try every ten minutes, under any ten-minute window; a day's window counts\n# them, and a day's ban costs a person who mistyped three times once, from one address, while\n# the mesh's own range is never banned at all.\nbantime = 1d\nfindtime = 1d\nmaxretry = 3\n\n# Ban through iptables, not through a firewall front-end the machine may not have. ufw is\n# installed on two of this mesh's machines and absent on the other two, and fail2ban finds out\n# only at ban time: the service reports healthy, the jail counts the attempt, the ban command\n# exits 127, and nothing is blocked. Proven on 2026-09-28 -- 'ufw: command not found' on a\n# machine the mesh reported as protected.\n#\n# The action below is this module's own, already used by the recidive jail on every machine\n# here, and it bans in DOCKER-USER as well as INPUT, so a container's published port is\n# covered too.\nbanaction = iptables-allports-dualchain\nbanaction_allports = iptables-allports-dualchain\n\n[sshd]\nenabled = true\nport = ssh\nlogpath = %(sshd_log)s\nbackend = %(sshd_backend)s\n"
|
|
},
|
|
{
|
|
"id": "jail-sshd",
|
|
"type": "file",
|
|
"path": "/etc/fail2ban/jail.d/sshd.conf",
|
|
"mode": "0644",
|
|
"content": "[sshd]\nenabled = true\nport = ssh\nlogpath = %(sshd_log)s\nbackend = %(sshd_backend)s\nmaxretry = 3\nfindtime = 1d\nbantime = 1d\n"
|
|
},
|
|
{
|
|
"id": "log",
|
|
"type": "file",
|
|
"path": "/var/log/fail2ban.log",
|
|
"mode": "0640",
|
|
"create-once": true,
|
|
"content": ""
|
|
},
|
|
{
|
|
"id": "jail-recidive",
|
|
"type": "file",
|
|
"path": "/etc/fail2ban/jail.d/recidive.conf",
|
|
"mode": "0644",
|
|
"content": "[recidive]\nenabled = true\nlogpath = /var/log/fail2ban.log\n# Ban in both INPUT (host services like SSH) and DOCKER-USER (container services)\nbanaction = iptables-allports-dualchain\n# Banned twice in two weeks, by any jail, is banned for four (novox/hq ADR 0179).\nbantime = 4w\nfindtime = 2w\nmaxretry = 2\n"
|
|
},
|
|
{
|
|
"id": "action-dualchain",
|
|
"type": "file",
|
|
"path": "/etc/fail2ban/action.d/iptables-allports-dualchain.conf",
|
|
"mode": "0644",
|
|
"content": "# Fail2Ban action: ban in both INPUT and DOCKER-USER chains\n# Used by recidive to block repeat offenders from both host and Docker services\n\n[INCLUDES]\n\nbefore = iptables.conf\n\n[Definition]\n\ntype = allports\n\nactionstart = { <iptables> -C f2b-<name> -j <returntype> >/dev/null 2>&1; } || { <iptables> -N f2b-<name> || true; <iptables> -A f2b-<name> -j <returntype>; }\n { <iptables> -C INPUT -p <protocol> -j f2b-<name> >/dev/null 2>&1; } || { <iptables> -I INPUT -p <protocol> -j f2b-<name>; }\n { <iptables> -C DOCKER-USER -p <protocol> -j f2b-<name> >/dev/null 2>&1; } || { <iptables> -I DOCKER-USER -p <protocol> -j f2b-<name>; }\n\nactionstop = <iptables> -D INPUT -p <protocol> -j f2b-<name> 2>/dev/null || true\n <iptables> -D DOCKER-USER -p <protocol> -j f2b-<name> 2>/dev/null || true\n <iptables> -F f2b-<name>\n <iptables> -X f2b-<name>\n\nactioncheck = <iptables> -n -L f2b-<name> >/dev/null\n\nactionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>\n\nactionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>\n\n[Init]\n\nchain = INPUT\nname = default\nprotocol = tcp\nblocktype = REJECT --reject-with icmp-port-unreachable\nreturntype = RETURN\nlockingopt = -w\niptables = iptables <lockingopt>\n\n[Init?family=inet6]\n\nblocktype = REJECT --reject-with icmp6-port-unreachable\niptables = ip6tables <lockingopt>\n"
|
|
},
|
|
{
|
|
"id": "logrotate",
|
|
"type": "file",
|
|
"path": "/etc/logrotate.d/fail2ban",
|
|
"mode": "0644",
|
|
"content": "/var/log/fail2ban.log {\n missingok\n notifempty\n postrotate\n /usr/bin/fail2ban-client flushlogs >/dev/null || true\n endscript\n}\n"
|
|
},
|
|
{
|
|
"id": "run",
|
|
"type": "service",
|
|
"unit": "fail2ban.service",
|
|
"state": "running",
|
|
"boot": "enabled",
|
|
"restart-on": [
|
|
"jail-local",
|
|
"jail-sshd",
|
|
"jail-recidive",
|
|
"action-dualchain",
|
|
"composed-jails"
|
|
]
|
|
},
|
|
{
|
|
"id": "runtime",
|
|
"type": "container",
|
|
"name": "mesh-fail2ban",
|
|
"artifact": "runtime",
|
|
"network": "host",
|
|
"volumes": [
|
|
"${dir:mesh-state}/broker:/run/secrets/broker:ro",
|
|
"/var/run/fail2ban:/var/run/fail2ban"
|
|
],
|
|
"env": {
|
|
"MESH_BROKER_FILE": "/run/secrets/broker"
|
|
}
|
|
}
|
|
],
|
|
"build": {
|
|
"on": [
|
|
{
|
|
"arg": "BUILD_BASE",
|
|
"module": "mesh-tools",
|
|
"artifact": "build"
|
|
},
|
|
{
|
|
"arg": "RUNTIME_BASE",
|
|
"module": "mesh-tools",
|
|
"artifact": "runtime"
|
|
}
|
|
],
|
|
"artifacts": [
|
|
{
|
|
"name": "runtime",
|
|
"kind": "image",
|
|
"from": "Dockerfile"
|
|
}
|
|
]
|
|
}
|
|
}
|