# FIPS Kubernetes sidecar — example Pod manifest # # WARNING: The Secret below contains a placeholder nsec. Replace it with your # real key before applying. Do NOT commit real keys to version control. # Generate a fresh key with: openssl rand -hex 32 # # Apply: # kubectl apply -f pod.yaml # # Requirements on the node: # - /dev/net/tun must exist (standard on all modern Linux kernels) # - The container runtime must honour NET_ADMIN (true for containerd/CRI-O # with default settings; may require a RuntimeClass tweak for gVisor) # # Kubernetes version: 1.28+ # ----------------------------------------------------------------------------- # Secret — node identity # Replace the nsec value with your real key (hex or nsec1 bech32). # In production, manage this with a secrets operator (External Secrets, # Sealed Secrets, Vault Agent, etc.) rather than a plaintext manifest. # ----------------------------------------------------------------------------- apiVersion: v1 kind: Secret metadata: name: fips-identity type: Opaque stringData: nsec: "replace-this-with-your-hex-or-nsec1-secret-key" --- apiVersion: v1 kind: Pod metadata: name: fips-sidecar-example labels: app: fips-sidecar-example spec: # Containers in the same Pod share the same network namespace automatically. # The fips sidecar creates fips0; the app container sees it immediately. # # Start order: initContainers run first, then all containers start # concurrently. If your app needs the TUN interface to be ready before it # starts, use a readiness probe on the sidecar and a dependency in the app # (or use a startup init container that waits for fips0 to appear). # net.ipv6.* sysctls are namespaced per-pod in Linux. Declaring them here # allows the fips sidecar entrypoint to set them at runtime via sysctl(8). # bindv6only=0 means apps listening on 0.0.0.0 will also receive IPv6 # connections arriving via fips0, without needing to be rewritten. # These are "unsafe" sysctls and require the kubelet --allowed-unsafe-sysctls # flag or a corresponding RuntimeClass / PodSecurityPolicy exception. securityContext: sysctls: - name: net.ipv6.conf.all.disable_ipv6 value: "0" - name: net.ipv6.conf.default.disable_ipv6 value: "0" - name: net.ipv6.bindv6only value: "0" volumes: - name: tun-device hostPath: path: /dev/net/tun type: CharDevice # Optional: mount a pre-built fips.yaml instead of generating from env. # - name: fips-config # configMap: # name: fips-config containers: # ----------------------------------------------------------------------- # FIPS sidecar — owns the network namespace setup # ----------------------------------------------------------------------- - name: fips image: your-registry.example.com/fips-sidecar:latest imagePullPolicy: Always securityContext: capabilities: add: - NET_ADMIN # required: TUN creation and iptables runAsNonRoot: false # fips needs root for iptables/TUN runAsUser: 0 volumeMounts: - name: tun-device mountPath: /dev/net/tun env: # --- Identity (required) --- - name: FIPS_NSEC valueFrom: secretKeyRef: name: fips-identity key: nsec # --- Single peer shorthand --- # Remove these and use FIPS_PEERS_JSON below for multiple peers. - name: FIPS_PEER_NPUB value: "" # e.g. npub1abc... - name: FIPS_PEER_ADDR value: "" # e.g. 203.0.113.10:2121 - name: FIPS_PEER_ALIAS value: "gateway" - name: FIPS_PEER_TRANSPORT value: "udp" # --- Multiple peers via JSON (overrides single-peer vars when non-empty) --- # - name: FIPS_PEERS_JSON # value: | # [ # {"npub":"npub1abc...","alias":"gw1","addr":"203.0.113.10:2121","transport":"udp"}, # {"npub":"npub1def...","alias":"gw2","addr":"198.51.100.5:2121","transport":"udp"} # ] # --- Transport tuning --- - name: FIPS_UDP_BIND value: "0.0.0.0:2121" # Uncomment to enable TCP transport (useful on networks that block UDP): # - name: FIPS_TCP_BIND # value: "0.0.0.0:8443" # --- TUN interface --- - name: FIPS_TUN_NAME value: "fips0" - name: FIPS_TUN_MTU value: "1280" # --- Network isolation --- # "false" — fips0 is added alongside normal cluster networking. eth0 # continues to work as usual (services, DNS, other pods all reachable). # "true" — eth0 is locked to FIPS transport only; app can only talk # via fips0. Use for high-security mesh-only deployments. - name: FIPS_ISOLATE value: "false" # Adjust if your CNI names the pod interface differently (e.g. ens3, net1). - name: FIPS_POD_IFACE value: "eth0" # --- DNS --- # Set to "false" if you manage pod DNS externally. - name: FIPS_REWRITE_DNS value: "true" # --- Logging --- - name: RUST_LOG value: "info" ports: - name: fips-udp containerPort: 2121 protocol: UDP # - name: fips-tcp # containerPort: 8443 # protocol: TCP readinessProbe: exec: command: ["fipsctl", "show", "status"] initialDelaySeconds: 5 periodSeconds: 10 failureThreshold: 3 livenessProbe: exec: command: ["fipsctl", "show", "status"] initialDelaySeconds: 15 periodSeconds: 30 failureThreshold: 3 resources: requests: cpu: "50m" memory: "32Mi" limits: cpu: "500m" memory: "128Mi" # ----------------------------------------------------------------------- # App container — shares the network namespace created by the fips sidecar # ----------------------------------------------------------------------- - name: app image: your-app:latest imagePullPolicy: IfNotPresent # No special capabilities needed — app uses fips0 like a normal interface. securityContext: runAsNonRoot: true # The app sees: lo, eth0 (isolated by iptables), fips0 (mesh). # All outbound traffic from the app flows through fips0. # DNS resolution for .fips names works via dnsmasq on 127.0.0.1. command: ["sleep", "infinity"] # replace with your actual workload command resources: requests: cpu: "100m" memory: "64Mi" limits: cpu: "1000m" memory: "512Mi" # Restart policy for the Pod. Use "Always" for long-running workloads. restartPolicy: Always