Files
home-network-k3s/decisions/adr-0012-vpn-egress-single-expressvpn-gateway.md
T
jakman85andClaude Opus 4.8 2cca9beac7 Switch VPN provider ExpressVPN -> PIA (ADR-0013 supersedes ADR-0012)
Operator turned off ExpressVPN auto-renew and purchased PIA. The single-shared-
gateway model is retained; provider/client/protocol change to PIA via Gluetun
over WireGuard with native port forwarding (qbittorrent-natmap port-sync).
Simpler than ExpressVPN: no custom OpenVPN config, just PIA user/pass
SOPS-encrypted; Gluetun provides the built-in kill-switch.

Updated: ADR-0013 (new) + ADR-0012 superseded + index; docs 00,01,03,07;
task board (T-3.2p/T-3.2, OQ-3).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-15 23:16:33 -05:00

3.9 KiB

ADR-0012 — VPN egress: single shared in-cluster ExpressVPN gateway

  • Status: Superseded by ADR-0013 (2026-08-15)
  • Date: 2026-08-15
  • Serves: R-NET-05, R-NET-06, R-NET-07
  • Supersedes: ADR-0008

Superseded. The single-shared-gateway model here is retained, but the operator moved off ExpressVPN to PIA (Gluetun-native, WireGuard, port forwarding). Only the provider/client/ protocol changed — see ADR-0013. Retained for history.

Context

ADR-0008 offered two VPN-egress patterns (Gluetun sidecar per pod as default, central gateway as alternative) and left the provider open (OQ-3). The operator has now specified (OQ-3):

  • Provider is ExpressVPN; the cluster must provision and control the connection (nothing on the edge router — the edge is a dumb SOHO device with no VPN, OQ-1).
  • Protocol must not be TCP; UDP or better is required, data must be protected.
  • A single shared VPN connection is preferred over per-service sidecars, so network rules are enforced outside the service.

This changes the decision, so ADR-0008 is superseded.

Decision

Adopt a single, shared, in-cluster VPN egress gateway as the mandated model (ADR-0008's "Pattern B" becomes the only pattern; the per-service Gluetun sidecar default is dropped):

  • One VPN egress gateway (HA-capable Deployment, run active/standby) holds a single ExpressVPN tunnel using a non-TCP protocol: OpenVPN UDP (via ExpressVPN's manual OpenVPN-UDP config), or Lightway-UDP if a containerizable client proves viable. The cluster — not the edge — provisions and controls the tunnel.
  • vpn-class pods are steered through the gateway (Cilium Egress Gateway / routing) and have no independent egress path. The kill-switch (fail-closed) and egress allow rules are enforced at the gateway + namespace/policy level — outside each service. A service is merely labeled egress: vpn; it cannot leak on its own even if misconfigured.
  • Credentials (ExpressVPN manual OpenVPN config + manual-config username/password) are stored SOPS-encrypted (ADR-0007).
  • The egress: internet | vpn service contract is unchanged (R-NET-07).

Alternatives considered

  • ADR-0008 Pattern A (Gluetun sidecar per pod) — rejected per OQ-3: puts VPN inside each service (rules enforced in the service), multiplies tunnels, and isn't the operator's preferred single- connection model.
  • VPN on the edge router — impossible: the SOHO edge has no VPN capability (OQ-1); the cluster must own the tunnel.
  • WireGuard — ExpressVPN does not offer WireGuard; OpenVPN UDP (or Lightway-UDP) is the non-TCP path.
  • OpenVPN TCP — rejected: operator requires non-TCP.

Consequences

  • Rules enforced outside the service (operator's goal); one tunnel to manage; simpler per-service workloads (no sidecars).
  • Single shared egress IP for all vpn services and a single failure domain → mitigate with active/standby gateway and tunnel-state alerting (10).
  • ExpressVPN is not a first-class containerized provider: expect a custom OpenVPN-UDP setup (e.g. gluetun custom-provider mode or a purpose-built OpenVPN client), and the operator must obtain the manual OpenVPN config + manual credentials. Tunnel + kill-switch must be validated in dev/test (fault-injection test, R-TEST-05).
  • Exact pod→gateway steering (Cilium Egress Gateway vs routing/SNAT) is a WS-NET implementation detail; the kill-switch acceptance test is the gate (14).
  • If ExpressVPN containerization proves impractical, revisit provider choice via a superseding ADR (escalation to the operator — agents may not change this decision themselves).