Operator answers folded into the specs: - OQ-3 VPN: ExpressVPN, cluster-controlled SINGLE shared in-cluster tunnel (OpenVPN UDP / non-TCP), rules enforced outside the service. New ADR-0012 supersedes ADR-0008 (Gluetun-sidecar default dropped). Central kill-switch. - OQ-1 WAN/edge: one commercial WAN, no multi-ISP plans; dumb SOHO edge (no VLAN/VPN/services). Multi-WAN out of scope; segmentation + VPN in-cluster; edge = NAT + manual port-forward. Gateway VIP resolved to Cilium L2 announcement. T-3.3 marked won't-do. - OQ-2 storage: bulk media lives outside the cluster (backing TBD, non-blocking) via a 'bulk' external-mount indirection; Plex metadata DB stays on Longhorn. Split out a separate OQ-BKP for the off-cluster DR backup target (Phase 4). - OQ-4 refined: wildcard record covers reachability but NOT ACME DNS-01 (needs TXT-write access) and does not match *.home.* depth. Still OPEN: Cloudflare API token (Option A) vs acme-dns delegation (Option B). T-2.4/T-2.5 blocked. Updated: docs 00,01,03,04,08,09; ADR-0008/0012 + index; task board. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
47 lines
2.8 KiB
Markdown
47 lines
2.8 KiB
Markdown
# ADR-0008 — VPN egress model: Gluetun sidecar (default) + Cilium Egress Gateway
|
|
- Status: **Superseded by [ADR-0012](adr-0012-vpn-egress-single-expressvpn-gateway.md)** (2026-08-15)
|
|
- Date: 2026-08-15
|
|
- Serves: R-NET-05, R-NET-06, R-NET-07
|
|
- Supersedes: —
|
|
|
|
> **Superseded.** OQ-3 resolved to ExpressVPN + a **single shared in-cluster tunnel** with rules
|
|
> enforced outside the service. The Gluetun-sidecar-per-pod default below is no longer the model; see
|
|
> [ADR-0012](adr-0012-vpn-egress-single-expressvpn-gateway.md). Retained for history.
|
|
|
|
## Context
|
|
A subset of services (sonarr, radarr, jackett, qbittorrent) must egress **only** through a commercial
|
|
VPN, with a **kill-switch** guaranteeing no leak to the plain internet if the tunnel drops. Egress
|
|
class must be a declarative service property (`egress: vpn`) that doesn't force a workload rewrite.
|
|
|
|
## Decision
|
|
Adopt a **two-pattern** model behind the single `egress: vpn` contract, with **Gluetun sidecar as the
|
|
default** for the initial catalog:
|
|
- **Default — Pattern A: Gluetun sidecar per pod.** A Gluetun container holds the WireGuard/OpenVPN
|
|
tunnel; the app shares its network namespace. Gluetun's built-in **firewall kill-switch** blocks
|
|
all non-tunnel egress by default — satisfying R-NET-06 intrinsically and per-service.
|
|
- **Available — Pattern B: central VPN egress gateway + Cilium Egress Gateway.** One (HA) gateway
|
|
holds the tunnel; Cilium Egress Gateway steers `vpn`-labeled pods through it, with policy denying
|
|
any fallback to the internet path. Use when tunnel count must be minimized.
|
|
|
|
The service-facing contract is identical for both: declare `egress: vpn`; the platform wires the
|
|
chosen pattern. Kill-switch behavior is a hard acceptance gate for both.
|
|
|
|
## Alternatives considered
|
|
- **Central gateway only** — fewer tunnels but a shared failure domain and more complex kill-switch
|
|
guarantees across the fabric; kept as Pattern B, not the default.
|
|
- **Node-level policy routing / per-node VPN** — couples egress to node identity, harder to reason
|
|
about per-service; rejected as the primary model.
|
|
- **App-native VPN config** — rejected: not declarative, not uniform, easy to misconfigure and leak.
|
|
|
|
## Consequences
|
|
- Per-service isolation and an intrinsic kill-switch out of the box (Pattern A).
|
|
- More sidecars/tunnels at scale (Pattern A) — Pattern B is the escape hatch if the VPN provider
|
|
limits concurrent tunnels/egress IPs (OQ-3).
|
|
- Kill-switch must be **fault-tested** (tunnel forced down ⇒ zero internet egress) as a standing
|
|
acceptance gate, not a one-time check ([03](../docs/03-networking-isolation-and-egress.md), R-NET-06).
|
|
- VPN credentials are SOPS-encrypted (ADR-0007). WireGuard preferred over OpenVPN where supported.
|
|
|
|
## Open questions
|
|
- **OQ-3** — VPN provider/protocol and concurrent-tunnel/egress-IP limits (drives Pattern A vs B and
|
|
gateway HA).
|