recipe_fail2ban.ts

Recipe for a fail2ban jail.local.

fail2ban_jail builds the content of /etc/fail2ban/jail.local — the [DEFAULT] + [sshd] jail config a hardened host carries. The defaults are a complete baseline; callers only override a value to diverge intentionally.

Recipes are imported at config eval time inside fgro eval's sandbox, which has no network, no writes, and no environment, and where the clock and randomness throw. This module is therefore a pure function: it only assembles a string from its arguments — no I/O, no clock, no randomness, no imports beyond types. The output is deterministic for given inputs (stable ordering, trailing newline), so it stays a reliable content-addressed plan artifact.

The caller wraps the result in a file resource, e.g. zap.file({id: 'fail2ban-jail', path: '/etc/fail2ban/jail.local', content: {type: 'inline', content: fail2ban_jail()}}).

view source

Declarations
#

2 declarations

fail2ban_jail
#

recipe_fail2ban.ts view source

(options?: Fail2banJailOptions | undefined): string import {fail2ban_jail} from '@fuzdev/zap/recipe_fail2ban.js';

Build the fail2ban jail.local text for options.

Writes a [DEFAULT] section with the global ban/find/retry tunables and the banaction, and a stricter [sshd] jail reading the journal, or sshd_logpath when one is given. jail.local is read after the distro's jail.d/*.conf, so its values win over a packaged default, such as Debian's nftables banaction or Alpine's alpine-sshd filter.

options?

optional

returns

string

the complete jail.local text, terminated by a trailing newline.

Fail2banJailOptions
#

recipe_fail2ban.ts view source

Fail2banJailOptions import type {Fail2banJailOptions} from '@fuzdev/zap/recipe_fail2ban.js';

Options for fail2ban_jail.

Every field defaults to the shared baseline, so fail2ban_jail() takes no argument for the common case: a Debian or Ubuntu host whose sshd logs to the journal and whose firewall is ufw (iptables).

ban_time?

[DEFAULT] bantime — how long a banned host stays banned. Defaults to '1h'.

type string

find_time?

[DEFAULT] findtime — the window failures are counted within. Defaults to '10m'.

type string

max_retry?

[DEFAULT] maxretry — failures within find_time before a ban. Defaults to 5.

type number

sshd_max_retry?

[sshd] maxretry — sshd-specific failure threshold. Defaults to 3.

type number

sshd_ban_time?

[sshd] bantime — sshd-specific ban duration. Defaults to '24h'.

type string

banaction?

[DEFAULT] banaction — the fail2ban action that blocks a banned address, which has to drive the firewall the host has. Defaults to 'iptables-multiport', for a ufw host (ufw depends on iptables, not on the nft command Debian's own nftables default needs). Pass 'nftables' on an nftables host such as the one alpine_web_firewall sets up, which has no iptables. Without the command the action names, fail2ban counts and lists a ban but blocks nothing.

type string

sshd_logpath?

The file fail2ban watches for sshd auth failures. Unset, the jail reads the systemd journal (backend = systemd), where sshd logs on Debian and Ubuntu with or without rsyslog. On Alpine there is no journal: BusyBox syslog writes everything to '/var/log/messages', so pass that (and ensure the syslog service is enabled); the jail then reads the file with the sshd filter set to read BusyBox's lines. fail2ban refuses to start a jail whose logpath doesn't exist ("Have not found any log file").

type string