# Pod-egress routing into the Netbird mesh. # # The existing per-namespace `router` Deployments (NBRoutingPeer CRs - # gitlab, vault, argocd, nextcloud, etc.) are INBOUND-only infrastructure: # they let external Netbird peers reach into those namespaces' services. # Nothing programs the reverse - no node ever gets a route sending pod # traffic OUT through any of those router pods' wt0 interfaces. Confirmed # 2026-08-17 while debugging CrowdSec's CAPI enrollment: `ip route get # 100.108.113.41` on a node running a pod that needed to reach the VPS's # Netbird IP just showed the plain LAN default gateway - none of the # "connected" router pods were ever actually in the path, and a tcpdump on # their wt0 during live attempts showed zero packets. # # This DaemonSet is the missing outbound half: one netbird client per node, # running with hostNetwork so its wt0 interface lives directly in the node's # real network namespace (avoiding all the SNAT/forwarding complexity a # pod-netns subnet router would need), plus a sidecar that adds a host route # sending 100.108.0.0/16 out via that interface. Once packets leave a node # via wt0 with a real Netbird-mesh source identity, return routing already # works via the same route-advertisement mechanism the inbound routers use. # # hostNetwork requires infrastructure/kyverno/policies/netbird-egress-exception.yaml # - a scoped PolicyException to the disallow-host-namespaces STIG policy, # not a broad exclusion. See that file for the full justification. apiVersion: apps/v1 kind: DaemonSet metadata: name: netbird-egress namespace: netbird labels: app.kubernetes.io/name: netbird-egress spec: selector: matchLabels: app.kubernetes.io/name: netbird-egress template: metadata: labels: app.kubernetes.io/name: netbird-egress annotations: # Same reasoning as netbird-cluster-router: ztunnel iptables rules # interfere with WireGuard packet forwarding. ambient.istio.io/redirection: disabled spec: hostNetwork: true dnsPolicy: ClusterFirstWithHostNet containers: - name: netbird image: netbirdio/netbird:0.66.0 imagePullPolicy: IfNotPresent env: - name: NB_SETUP_KEY valueFrom: secretKeyRef: name: netbird-router-setup-key key: setup-key - name: NB_MANAGEMENT_URL value: "https://netbird.kube.huskypup.net" securityContext: capabilities: add: - NET_ADMIN resources: requests: cpu: 25m memory: 64Mi limits: memory: 128Mi # Adds the host route sending mesh-bound traffic out via wt0 once # the netbird container brings the interface up. Re-asserts on a # loop since wt0 can be recreated on reconnect (route otherwise # silently disappears with it). - name: route-manager image: alpine:3.20 command: - sh - -c - | apk add --no-cache iproute2 >/dev/null 2>&1 while true; do if ip link show wt0 >/dev/null 2>&1; then ip route replace 100.108.0.0/16 dev wt0 2>/dev/null fi sleep 10 done securityContext: capabilities: add: - NET_ADMIN resources: requests: cpu: 10m memory: 32Mi limits: memory: 64Mi terminationGracePeriodSeconds: 30