Files
fips/examples/k8s-sidecar
Johnathan Corgan 507086e39d docs: refresh tutorials, how-to, design, reference, and examples for v0.4.0
Pre-cut documentation pass for the 0.4.0 release, verified against current source.

Corrections:
- fipsctl: stale 'show identities'/'show node' -> 'show status'
  (host-a-service, run-as-unprivileged-user)
- mesh address derivation: first 16 bytes of SHA-256(pubkey) with the leading
  byte set to 0xfd, not a fixed fd97: prefix (reach-mesh-services,
  ipv6-adapter-walkthrough)
- gateway control socket mode 0660 -> 0770 (troubleshoot-gateway)
- Tor example: add advertised_port: 8443 so the published port matches the
  prose (enable-nostr-discovery)
- bloom mesh-size estimate rewritten to the OR-union-of-peer-filters algorithm;
  plus mtu deep-link, gateway pool wording, and a NAT failure-mode line
- examples: delete orphaned nostr-rs-relay config, accept inbound to the local
  8443 TCP listener, fix fd::/8 -> fd00::/8 typos, dotless wireguard alias

Additions:
- new Nym mixnet transport section (fips-transport-layer) and the architecture
  transport list
- new LAN/mDNS discovery section (fips-nostr-discovery)
- reference docs: Nym transport, LAN discovery, and new control/stats surfaces;
  drop ble from the connect transport list
2026-06-14 15:14:05 +00:00
..

FIPS Kubernetes Sidecar

Run FIPS as a sidecar container in a Kubernetes Pod, injecting the FIPS mesh network interface into every other container in the Pod. All containers in the Pod share the same network namespace, so once the sidecar creates fips0 it is immediately visible to the app container(s) without any further configuration.

Quick Start

# 1. Build the sidecar image
cd examples/k8s-sidecar
./scripts/build.sh --tag fips-k8s-sidecar:latest

# 2. Push to your registry (replace with your own)
docker tag fips-k8s-sidecar:latest registry.example.com/fips-k8s-sidecar:latest
docker push registry.example.com/fips-k8s-sidecar:latest

# 3. Create the identity secret
kubectl create secret generic fips-identity \
  --from-literal=nsec=$(openssl rand -hex 32)

# 4. Deploy
kubectl apply -f pod.yaml

How It Works

In Kubernetes, all containers in a Pod share the same network namespace. The fips sidecar:

  1. Generates /etc/fips/fips.yaml from environment variables.
  2. Rewrites /etc/resolv.conf to route .fips DNS through dnsmasq (which forwards .fips names to the FIPS daemon's built-in DNS resolver and everything else to the original cluster DNS).
  3. Applies iptables isolation rules so that the pod's physical interface (eth0) only carries FIPS transport traffic.
  4. Starts dnsmasq and then execs the FIPS daemon.

The app container starts concurrently and immediately sees lo, eth0, and fips0. DNS for <npub>.fips names resolves to fd00::/8 addresses via the dnsmasq → FIPS daemon pipeline.

┌────────────────────────────────────────────────────┐
│ Kubernetes Pod (shared network namespace)           │
│                                                     │
│ ┌─────────────────┐   ┌───────────────────────────┐│
│ │  fips (sidecar) │   │  app container(s)         ││
│ │                 │   │                           ││
│ │  fips daemon    │   │  your workload            ││
│ │  fipsctl        │   │  sees: lo, eth0, fips0    ││
│ │  dnsmasq        │   │                           ││
│ └─────────────────┘   └───────────────────────────┘│
│                                                     │
│ Interfaces:                                         │
│   lo    — loopback (unrestricted)                   │
│   eth0  — pod CNI interface (iptables: FIPS only)   │
│   fips0 — FIPS TUN (fd00::/8, unrestricted)           │
└────────────────────────────────────────────────────┘

Network Isolation

FIPS_ISOLATE controls whether the sidecar locks down eth0:

Value Behaviour
false (default) fips0 is added alongside normal cluster networking. eth0 continues to work — services, DNS, other pods, and the internet are all reachable as normal. Application traffic to FIPS mesh peers uses fips0.
true All traffic on eth0 is dropped except FIPS transport (UDP 2121). The app container can only communicate via fips0. Use this for deployments where the workload must never bypass the mesh.

Common gotcha: if you deploy the sidecar and find that services or other pods are suddenly unreachable, check that FIPS_ISOLATE is not set to true. The mesh-only mode is intentionally strict and will break normal cluster connectivity.

Requirements

Requirement Notes
NET_ADMIN capability Required for TUN creation and iptables
/dev/net/tun HostPath volume mount (see pod.yaml)
Linux kernel ≥ 4.9 Standard on all current distributions
No gVisor / kata-containers Requires real kernel TUN support

Environment Variables

Variable Default Description
FIPS_NSEC (required) Node secret key (hex or nsec1 bech32)
FIPS_PEER_NPUB (empty) Single peer npub
FIPS_PEER_ADDR (empty) Single peer transport address (host:port)
FIPS_PEER_ALIAS peer Single peer alias
FIPS_PEER_TRANSPORT udp Single peer transport type
FIPS_PEERS_JSON (empty) JSON array of peer objects (overrides single-peer vars). Note: the included parser handles simple host:port addresses only; IPv6 addresses with brackets may not parse correctly.
FIPS_UDP_BIND 0.0.0.0:2121 UDP transport bind address
FIPS_UDP_PORT (from FIPS_UDP_BIND) UDP port for iptables rules
FIPS_TCP_BIND (disabled) TCP transport bind address
FIPS_TUN_NAME fips0 TUN interface name
FIPS_TUN_MTU 1280 TUN MTU
FIPS_ISOLATE false Apply iptables isolation (blocks all eth0 traffic except FIPS transport)
FIPS_POD_IFACE eth0 Pod physical interface name
FIPS_REWRITE_DNS true Rewrite /etc/resolv.conf
RUST_LOG info FIPS log level

Multiple Peers

Use FIPS_PEERS_JSON to configure more than one peer:

- 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"}
    ]

Each object supports the keys: npub (required), addr (required), alias, transport, priority.

Alternatively, mount a hand-crafted fips.yaml and set FIPS_NSEC to anything (the mount takes precedence because the entrypoint writes to /etc/fips/fips.yaml which is then overridden by the volume):

volumes:
  - name: fips-config
    configMap:
      name: my-fips-config
containers:
  - name: fips
    volumeMounts:
      - name: fips-config
        mountPath: /etc/fips/fips.yaml
        subPath: fips.yaml

JSON Parsing Limitations

FIPS_PEERS_JSON supports parsing with a simple awk-based parser. It handles common host:port addresses but does not support IPv6 addresses with brackets (e.g., [::1]:2121) or values containing embedded commas/colons. For complex configs, install jq in the container and modify the entrypoint, or use a mounted fips.yaml.

Files

File Purpose
Dockerfile Builds the sidecar image
entrypoint.sh Generates config, rewrites DNS, applies iptables, starts fips
pod.yaml Example Pod manifest (single app container + fips sidecar)
scripts/build.sh Compiles FIPS and builds the Docker image

Troubleshooting

FIPS_NSEC is required — The secret was not injected. Verify the secretKeyRef name and key match the secret you created with kubectl create secret.

fips0 not visible in app container — Check that the fips sidecar started successfully: kubectl logs <pod> -c fips. The sidecar must start and run the daemon before fips0 appears. Add a startup probe or postStart lifecycle hook to your app container if you need to wait.

iptables errors — The NET_ADMIN capability and /dev/net/tun volume mount are both required. Verify they are present in the Pod spec.

.fips DNS not resolving — Check that FIPS_REWRITE_DNS=true and that dnsmasq started: kubectl exec <pod> -c fips -- pgrep dnsmasq. Verify the FIPS DNS listener: kubectl exec <pod> -c fips -- fipsctl show status.

CNI uses a different interface name — Set FIPS_POD_IFACE to match your CNI's interface name (e.g. ens3, net1 for Multus secondary interfaces).

gVisor / kata-containers — These sandboxed runtimes intercept syscalls and do not support AF_PACKET or /dev/net/tun in the same way as a standard kernel. Use a standard RuntimeClass for FIPS sidecar pods.