--- # ================================================================================================= # READ THIS BEFORE TRUSTING THIS FILE: it does NOT constrain the WireGuard listener. # ================================================================================================= # Every other platform namespace in this repo (crafty, headlamp, homepage, runbooks) ships an # explicit default-deny baseline as defense in depth, because Kyverno's generator only covers # `app-namespace=true` namespaces. This file keeps that convention — but it would be dishonest to # leave it at that, because the convention does not actually bite here: # # THE `wireguard` DaemonSet RUNS WITH hostNetwork: true, SO IT HAS NO CILIUM ENDPOINT, AND NO # NetworkPolicy OR CiliumNetworkPolicy APPLIES TO IT — NEITHER THIS ONE NOR ANY OTHER. # # That is the documented reason restrict-host-namespaces forbids hostNetwork in app namespaces at # all ("a pod on hostNetwork bypasses the CNI (Cilium) datapath and therefore ESCAPES the # default-deny NetworkPolicy fabric -- it is the most direct way to defeat R-NET-01"). Here that # escape is the deliberate, required design (daemonset.yaml explains why: without it, remote # clients carry a pod identity and are 403'd by every Gateway hostname). A CiliumNetworkPolicy # admitting `world` to udp/51820 would therefore be theatre: it would read as the control that # protects this port, and it would be enforcing nothing. So there isn't one. # # WHAT ACTUALLY PROTECTS THE EXPOSED PORT, then, since the CNI does not: # 1. WireGuard's cryptographic peer authentication. A packet whose key is not in peers.conf gets # NO REPLY — see README "Why this is safe to expose". This is the real control. # 2. The SOHO router's forward: only udp/51820 is forwarded inbound, to one node. # 3. The blast radius once authenticated is deliberately the whole LAN — that IS the requirement # ("clients should reach the entire local network"). README "What a client can reach" states # the consequence in full, including reach to the nodes' own control plane, and gives the # narrowing recipe for an operator who wants less than that. # # WHAT THIS FILE IS STILL FOR: it is the namespace's standing posture for any FUTURE pod-networked # workload added here (a metrics exporter is the likely one — README "Not built"). Without it, such # a pod would be born unrestricted, because Kyverno will not generate a baseline in a namespace # that is not labelled `app-namespace=true`, and this one deliberately is not. apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny namespace: vpn-ingress labels: homelab.keithjackson.dev/baseline: default-deny spec: podSelector: {} policyTypes: - Ingress - Egress ingress: [] egress: - to: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: kube-system ports: - protocol: UDP port: 53 - protocol: TCP port: 53