Network containment, in detail

Three layers between a probe and a compromise

Most of what's below runs before you'd ever notice something was wrong. This page walks through each layer in the order traffic actually hits it — what it catches, what it deliberately lets through, and why.

01Perimeter — nftables, fail2ban, sshd

The first line is boring on purpose: narrow the attack surface before any detection logic ever runs.

ControlSettingWhy
Password authPasswordAuthentication noRemoves credential-stuffing and brute-force as categories entirely — there's nothing to guess.
Connection rate30/minute burst 15 on new SSH connectionsCaps raw connection volume at the packet level, before sshd even forks.
Per-source capnftables meter, 10 concurrentOne source can't exhaust connection slots on its own.
Auth attemptsMaxAuthTries 3, LoginGraceTime 10Short, bounded window per connection attempt.
Repeat offendersfail2ban: 2 fails / 10 min → 24h ban; recidive jail → 7 daysEscalating cost for an IP that keeps coming back.

02Behavioral detection — three counters, not one

A single rate limit misses two realistic attack shapes: spread across many sources, or paced just under the line. Eiciel runs three counters per signal (SSH failures, unexpected inbound connections) to cover all three.

TierCatchesLogic
Per-source burstOne IP hammering fastShort window, grouped by busiest single source
Distributed burstA botnet spread across many IPsSame short window, but counted globally with a minimum-distinct-source floor
Sustained / pacedAn attacker staying just under the burst threshold, for a long timeA separate long window (default one hour) with its own, higher total threshold
# the fix, re-tested against the exact attack that used to evade it EVENT: ssh-distributed high 1000 failed SSH across 500 sources in 900s AUTO-TRIGGER: ssh-distributed high 1000 failed SSH across 500 sources RESULT: FIRED (2 times)

Any tier crossing its threshold triggers full containment — not a ban, not a log line. The whole point is that you don't have to be watching.

03Unconditional tripwires — one event, no threshold

Behavioral counters are for noisy, probing attacks. Some actions don't need a pattern to be suspicious — a single occurrence is enough.

Audit keyFires on
sudoersAny write to /etc/sudoers or /etc/sudoers.d/
module_loadA kernel module load
ssh_keysA change to the SSH host keys
eiciel_scripts / watcher_tamperTampering with Eiciel's own scripts or watcher process
eiciel_secrets_readOpening the sealed-secrets file, successful or not
isolation_liftRunning nft to undo containment itself

Each of these runs under auditd, which reports from the kernel — not something a compromised userland process can quietly skip.

04Two factors to reach root

Entering the box and controlling it are two different events, gated by two different secrets on two different channels.

IFS= read -r code || true code="$(printf '%s' "$code" | tr -d '[:space:]')" [ -n "$code" ] || exit 1 # blank input: fail closed [[ "$code" =~ ^[0-9]{6}$ ]] || exit 1 # malformed: fail closed pyotp.TOTP(secret).verify(code, valid_window=1) # real check, no bypass

A 95-second replay cache sits behind the check itself, so a captured valid code can't be reused even once.

→ See these detectors run against real attack traffic