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]>
This commit is contained in:
jakman85andClaude Opus 4.8 committed 2026-08-15 23:16:33 -05:00
1 parent fdca4305cf
commit 2cca9beac7
8 files changed
+86 -23

No files matched your search

+2 -1
View File
@@ -53,4 +53,5 @@ serves. **Do not edit an accepted decision in place** — supersede it with a ne
| [0009](adr-0009-automated-image-updates.md) | Automated updates: Flux image automation + Renovate | Accepted | R-UPD-01..03 |
| [0010](adr-0010-conformance-testing.md) | Conformance testing: automated, reproducible, behavior-based | Accepted | R-TEST-01..06 |
| [0011](adr-0011-test-tooling-kyverno-chainsaw.md) | Conformance test tooling: Kyverno + Chainsaw | Accepted | R-TEST-01..05 |
| [0012](adr-0012-vpn-egress-single-expressvpn-gateway.md) | VPN egress: single shared in-cluster ExpressVPN gateway | Accepted | R-NET-05/06/07 |
| [0012](adr-0012-vpn-egress-single-expressvpn-gateway.md) | VPN egress: single shared in-cluster ExpressVPN gateway | ~~Superseded by 0013~~ | R-NET-05/06/07 |
| [0013](adr-0013-vpn-provider-pia-gluetun-wireguard.md) | VPN provider: PIA via Gluetun (WireGuard + port forwarding) | Accepted | R-NET-05/06/07 |
@@ -1,9 +1,14 @@
# ADR-0012 — VPN egress: single shared in-cluster ExpressVPN gateway
- Status: Accepted
- Status: **Superseded by [ADR-0013](adr-0013-vpn-provider-pia-gluetun-wireguard.md)** (2026-08-15)
- Date: 2026-08-15
- Serves: R-NET-05, R-NET-06, R-NET-07
- Supersedes: [ADR-0008](adr-0008-vpn-egress-model.md)
> **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](adr-0013-vpn-provider-pia-gluetun-wireguard.md). 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):
@@ -0,0 +1,53 @@
# ADR-0013 — VPN provider: PIA via Gluetun (WireGuard + native port forwarding)
- Status: Accepted
- Date: 2026-08-15
- Serves: R-NET-05, R-NET-06, R-NET-07
- Supersedes: [ADR-0012](adr-0012-vpn-egress-single-expressvpn-gateway.md)
## Context
ADR-0012 kept the operator's required model — a single shared in-cluster VPN gateway with rules
enforced outside the service — but named **ExpressVPN** as the provider, which forced a custom
OpenVPN-UDP setup because ExpressVPN is **not a first-class containerized (Gluetun) provider**. The
operator has since **turned off ExpressVPN auto-renew and purchased Private Internet Access (PIA)**,
which *is* first-class in Gluetun. The egress **model is unchanged**; only the provider, client, and
protocol change — so ADR-0012 is superseded.
## Decision
The single shared in-cluster VPN gateway runs **Gluetun** configured for **PIA** over **WireGuard**,
with Gluetun's **native automated port forwarding** for qBittorrent:
- **Provider/client:** PIA via the **Gluetun** container as the gateway VPN client (Gluetun provides
the built-in **kill-switch/firewall**, health checks, and auto-reconnect).
- **Protocol:** **WireGuard** (UDP) — satisfies "non-TCP, UDP or better" and is a strict upgrade over
ExpressVPN's OpenVPN-UDP.
- **Credentials:** just the **PIA username/password**, stored **SOPS-encrypted** ([ADR-0007](adr-0007-secrets-sops-age.md)).
No manual `.ovpn` extraction (the ExpressVPN prerequisite is gone).
- **Port forwarding:** Gluetun native (`VPN_PORT_FORWARDING=on`, provider `private internet
access`) on a **PF-enabled PIA region**; a small **port-sync helper** (e.g. `qbittorrent-natmap`)
writes the assigned port into qBittorrent so it tracks reconnects — keeping it hands-off (R-UPD).
- **Model retained from ADR-0012:** one shared tunnel; `vpn`-class pods steered through the gateway
with **no independent egress path**; **central kill-switch (fail-closed)**; rules enforced outside
the service; gateway run **active/standby**; alert on tunnel state.
## Alternatives considered
- **ExpressVPN (ADR-0012)** — dropped: not Gluetun-native, needed a custom OpenVPN workaround; and the
operator's subscription is lapsing.
- **ProtonVPN** — equally good fit (Gluetun-native NAT-PMP PF, WireGuard); viable if PIA
disappoints, but the operator has purchased PIA.
- **AirVPN** — WireGuard works in Gluetun but automated PF is not integrated (static port only);
less hands-off.
- **Mullvad** — no port forwarding since 2023 → degraded qBittorrent seeding; rejected for this
torrent-adjacent stack.
## Consequences
- **Simpler and cleaner than ADR-0012:** the gateway is a stock Gluetun container (env-var config),
not a bespoke OpenVPN build; kill-switch and port forwarding are built in.
- **PF caveat:** PIA port forwarding is available only on **specific PF-enabled server regions** and
the assigned port can change on reconnect → the **port-sync helper** and a PF-capable region are
required; alert if PF acquisition fails.
- Single shared egress IP + single failure domain remain (mitigated by active/standby + alerting).
- Credentials are a single SOPS-encrypted PIA username/password; rotation = re-encrypt + commit.
- Kill-switch + correct-egress-IP + PF remain **fault-injection acceptance tests** in dev/test
(R-TEST-05, [14](../docs/14-testing-and-conformance.md)).
- If PIA proves unsatisfactory, **ProtonVPN** is the pre-vetted fallback (superseding ADR, operator
decision).