Turn the vpn-killswitch scaffold into a runnable SAFETY-CRITICAL L3 test for R-NET-06 under ADR-0015 (node-level host OpenVPN tunnel steered by Cilium Egress Gateway with a host nftables kill-switch), replacing the obsolete in-cluster gluetun design. - fixtures/vpn-and-internet-pods.yaml: two egress-class probe pods + documented RBAC/PodSecurity/namespace requirements for node-level fault injection. - vpn-killswitch/chainsaw-test.yaml: GIVEN healthy tunnel (vpn egress != WAN); WHEN the host `vpn-egress-tunnel` systemd unit is STOPPED via a privileged, hostPID, node-pinned nsenter Job THEN vpn-class egress is blackholed (curl fails, never returns the WAN IP = no leak) while internet-class is unaffected; WHEN restarted THEN vpn egress recovers. spec-level `finally` ALWAYS runs an idempotent start Job (self-healing) so a mid-test failure never leaves the gateway tunnel down. - incluster/rbac.yaml: grant the runner least-privilege for the delivered tests (namespaces create/delete/patch for the PSA relabel, pods/services/configmaps/ pods-exec/pods-log, batch/jobs) and replace the gluetun-scale rule with the ADR-0015 host-systemd mechanism note (privilege via PodSecurity, not RBAC). Offline validation: python yaml parse (all docs), `run.sh --lint` (structural), `run.sh --coverage-only --strict-coverage` (no tag/annotation drift; R-NET-05/06/ 07 covered, R-NET-06 has its L3 test), yamllint. No live apply, no cluster run. Co-Authored-By: Claude Opus 4.8 <[email protected]>
69 lines
3.2 KiB
YAML
69 lines
3.2 KiB
YAML
# =============================================================================
|
|
# Fixture for the vpn-killswitch L3 fault-injection test (R-NET-06, ADR-0015).
|
|
#
|
|
# Two probe workloads — identical to the egress-class fixture — plus the two
|
|
# node-pinned PRIVILEGED fault Jobs that STOP / START the host `vpn-egress-tunnel`
|
|
# systemd unit on the egress-gateway node. Under ADR-0015 the VPN tunnel is HOST
|
|
# infrastructure (OpenVPN split-tunnel on the node), NOT an in-cluster gluetun pod,
|
|
# so "force the tunnel down" means stopping a host systemd service — which requires
|
|
# entering the host namespaces (nsenter -t 1) from a privileged, hostPID pod pinned
|
|
# to that node.
|
|
#
|
|
# The Jobs are authored here as fixtures (not applied by this file directly) so the
|
|
# test can `apply` the stop Job at the fault point and the start Job in `finally`.
|
|
# They are pinned to the gateway node via nodeSelector; hostPID + privileged are
|
|
# required so nsenter can reach PID 1's mount/uts/ipc/net/pid namespaces and run the
|
|
# host `systemctl`.
|
|
#
|
|
# ---------------------------------------------------------------------------------
|
|
# NAMESPACE / PodSecurity / RBAC REQUIREMENTS (see incluster/rbac.yaml):
|
|
# * The namespace these Jobs run in MUST permit privileged + hostPID pods. Chainsaw
|
|
# runs each test in an ephemeral namespace that inherits the platform default
|
|
# (pod-security.kubernetes.io/enforce=restricted), which FORBIDS both. The test
|
|
# therefore relabels its OWN ephemeral namespace to `enforce=privileged` BEFORE
|
|
# applying these Jobs (and it is torn down with the namespace). This is scoped to
|
|
# the single per-test namespace — the platform default stays restricted.
|
|
# * If a cluster-wide Kyverno "disallow-privileged"/"disallow-host-namespaces"
|
|
# policy is in force, the conformance test namespace (prefix `chainsaw-conf-`)
|
|
# MUST be in that policy's exclusion set, or these Jobs are the documented, sole
|
|
# sanctioned exception for node-level fault injection (R-SEC-02 audit item).
|
|
# * The runner ServiceAccount (conformance-runner) needs: namespaces patch (to set
|
|
# the PSA label), and jobs create/delete/get/list/watch (to drive the fault).
|
|
# * The Job PODS run under the ephemeral namespace's `default` ServiceAccount and
|
|
# need NO Kubernetes API permissions — they act on the HOST via nsenter, not the
|
|
# API. Their power comes from PodSecurity (privileged) + hostPID, not RBAC.
|
|
# =============================================================================
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: egress-internet
|
|
labels:
|
|
app: egress-test
|
|
homelab.keithjackson.dev/egress-class: internet
|
|
spec:
|
|
containers:
|
|
- name: curl
|
|
image: curlimages/curl:8.11.1
|
|
command: ["sleep", "3600"]
|
|
resources:
|
|
requests: { cpu: 10m, memory: 16Mi }
|
|
limits: { memory: 32Mi }
|
|
restartPolicy: Never
|
|
---
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: egress-vpn
|
|
labels:
|
|
app: egress-test
|
|
homelab.keithjackson.dev/egress-class: vpn
|
|
spec:
|
|
containers:
|
|
- name: curl
|
|
image: curlimages/curl:8.11.1
|
|
command: ["sleep", "3600"]
|
|
resources:
|
|
requests: { cpu: 10m, memory: 16Mi }
|
|
limits: { memory: 32Mi }
|
|
restartPolicy: Never
|