diff --git a/docs/pfi/ops-lessons-playbook.md b/docs/pfi/ops-lessons-playbook.md index 5f4a2b3..e8e38d3 100644 --- a/docs/pfi/ops-lessons-playbook.md +++ b/docs/pfi/ops-lessons-playbook.md @@ -271,6 +271,48 @@ address-agnostic; the UniFi end is not. --- +## 10. IPv6 collapses two independent exposure controls into one, and it fails open + +**Rule:** before enabling IPv6 on any segment carrying real hosts, write explicit +default-deny inbound policy for that segment **and verify it from off-net**. +Reading the ruleset is not verification. + +**Why โ€” the asymmetry, which is the part worth internalising.** Under IPv4 with +NAT, exposing an internal host required **two** affirmative acts: a DNAT/port +forward *and* an accept rule. Miss either and the host stays dark. There is no +v4 misconfiguration that accidentally exposes an internal host, because without +the translation there is no path at all. NAT was load-bearing security whether or +not it was designed as such. + +Under IPv6 the path exists inherently โ€” the address is routable from birth. The +firewall is now the *only* control, so two independent things that both had to +succeed become one thing that must not fail. **The failure mode inverts from +fail-closed to fail-open.** + +**Concrete ways it bites:** + +| failure | v4 consequence | v6 consequence | +|---|---|---| +| permissive rule ordered above the deny | harmless, no forward exists | immediate exposure | +| ruleset silently only matches one address family | v4 covered, v6 ungoverned | whole segment on default | +| new VLAN added, firewall not updated | just a VLAN | live on the internet at first RA | +| ISP re-delegates a different prefix | n/a | address-literal rules stop matching | + +**How to apply:** +- Key rules on **interface/zone, not address literals** โ€” a re-delegated prefix + must not be able to silently unmatch a rule. +- Treat "enable v6 on a segment" as a change requiring the policy to exist + *first*, not as a networking toggle followed by cleanup. +- **Verify from outside.** Probe the segment's v6 addresses from off-net and + confirm the denies hold. This is ยง3's "assert the effective value, not the + presence of a substring" applied to firewall policy: a ruleset that *says* + deny is not evidence that packets are dropped. + +Operator position on the ESH fleet (2026-08-19): **no 1:1 inbound pass-through.** +The policy work is writing and proving default-deny, not deciding what to expose. + +--- + ## Superseded claims | date | claim | correction |