Files
home-network-k3s-impl/infra/ansible/playbooks/vpn.egress.gateway.yml
T
jakman85andClaude Opus 4.8 2c109e2a31 feat(vpn): node-level split-tunnel egress gateway Ansible role (ADR-0015)
Author the vpn_egress_gateway role + playbook that stands up the NODE-level
PIA OpenVPN tunnel on egress-gateway node(s) — the host half of ADR-0015. The
CiliumEgressGatewayPolicy steering vpn-class pods is separate GitOps against the
same contract (group vpn_egress_gateway, node label
homelab.keithjackson.dev/egress-gateway=true, host iface tun0).

Honors all four ADR-0015 invariants:
- Split-tunnel (inv 1&2): OpenVPN route-noexec + pull-filter ignore
  redirect-gateway => installs no routes; policy routing in a dedicated table
  (51820) with `ip rule from <tun0-addr>` steers ONLY Cilium-SNAT'd vpn-class
  traffic. Node default route stays on the WAN, tunnel up or down.
- Scoped nftables kill-switch (inv 3&4): own inet table, policy accept, drops
  only tunnel-sourced (@vpn_egress_gateway_src set) packets not leaving tun0 =>
  vpn-class fails closed (blackhole), node/internet-class fail open (WAN),
  never matched.

PIA creds + the proven sweden-aes-128-cbc-udp-ip .ovpn come from Ansible vault
(host-side per ADR-0015/docs-07); vault keys documented, no secret values
committed. ansible-lint (production) + yamllint clean. Not deployed: green
conformance is gated on the live tunnel (operator host creds) — see role README.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-24 01:09:19 -05:00

19 lines
1.0 KiB
YAML

---
# Stand up the node-level VPN egress tunnel on the designated egress-gateway node(s)
# (ADR-0015). Host infra — the split-tunnel OpenVPN service + policy routing + scoped
# nftables kill-switch. The CiliumEgressGatewayPolicy that steers vpn-class pods to this
# node's tun0 is authored separately as GitOps (platform/), against the same contract:
# * inventory group `vpn_egress_gateway` (this play's target)
# * k8s node label homelab.keithjackson.dev/egress-gateway=true (set by the role)
# * host tunnel iface tun0 (split-tunnel; never the node default route)
#
# Secrets come from Ansible vault (inventory/group_vars/vpn_egress_gateway/vault.yml):
# vault_vpn_egress_gateway_pia_username, vault_vpn_egress_gateway_pia_password, vault_vpn_egress_gateway_pia_ovpn
# Run: ansible-playbook playbooks/vpn.egress.gateway.yml
- name: Configure the node-level VPN egress gateway
hosts: vpn_egress_gateway
become: true
gather_facts: true # package module + service facts need os facts
roles:
- role: vpn_egress_gateway