Episode 10: hardening - firewall rules Docker cannot bypass, Caddy access log and rate limiting, fail2ban in the right chain
- hardening/: ufw after.rules block for DOCKER-USER (ctorigdstport, not dport), fail2ban jail.local with sshd (systemd backend) and caddy-probes (chain DOCKER-USER), filter for the JSON access log, sshd hardening.conf, README with the order and the two traps measured in the episode - caddy/Dockerfile: xcaddy build with caddy-ratelimit, compose builds the image - Caddyfile: common snippet (JSON access log, Server header stripped), vault /admin 404, rate_limit zones on the vault token endpoint and the git login form - HARDENING.md: firewall and fail2ban sections rewritten around what the port scan saw Claude-Session: https://claude.ai/code/session_017iP581CYtPfxdZYPPAyWZA
This commit is contained in:
parent
ccbddab46c
commit
bed41cfaf3
12 changed files with 319 additions and 16 deletions
29
hardening/ufw-after.rules
Normal file
29
hardening/ufw-after.rules
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# episode 10 - paste this block at the END of /etc/ufw/after.rules
|
||||
# (and the same block in /etc/ufw/after6.rules for IPv6).
|
||||
#
|
||||
# Why: Docker publishes ports by DNAT in the FORWARD path, not INPUT. ufw only
|
||||
# filters INPUT, so `ufw deny incoming` does NOT close a published container
|
||||
# port - it stays wide open. DOCKER-USER is the one chain Docker runs first in
|
||||
# FORWARD and never flushes on its own, so the fix goes here.
|
||||
#
|
||||
# The catch inside the catch: DNAT rewrites the destination port to the
|
||||
# container's port BEFORE this chain sees the packet. Matching --dport would
|
||||
# match the wrong (translated) port. So match the ORIGINAL published port with
|
||||
# conntrack --ctorigdstport instead.
|
||||
#
|
||||
# Only eth0 (the public NIC) is filtered. wt0 (the NetBird mesh) and the docker
|
||||
# bridges are left alone on purpose - a rule without `-i eth0` here breaks the
|
||||
# mesh route to n8n (episode 8) and traffic between containers.
|
||||
#
|
||||
# Replace eth0 with your public interface, and the port list with what you
|
||||
# actually publish.
|
||||
*filter
|
||||
:DOCKER-USER - [0:0]
|
||||
-A DOCKER-USER -i eth0 -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
|
||||
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 80 -j RETURN
|
||||
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 443 -j RETURN
|
||||
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 2222 -j RETURN
|
||||
-A DOCKER-USER -i eth0 -p udp -m conntrack --ctorigdstport 443 -j RETURN
|
||||
-A DOCKER-USER -i eth0 -p udp -m conntrack --ctorigdstport 3478 -j RETURN
|
||||
-A DOCKER-USER -i eth0 -j DROP
|
||||
COMMIT
|
||||
Loading…
Add table
Add a link
Reference in a new issue