mirror of
https://github.com/jmcorgan/fips.git
synced 2026-07-22 07:48:26 +00:00
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
177 lines
7.8 KiB
Markdown
177 lines
7.8 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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 `exec`s 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.
|
|
|
|
```text
|
|
┌────────────────────────────────────────────────────┐
|
|
│ 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:
|
|
|
|
```yaml
|
|
- 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):
|
|
|
|
```yaml
|
|
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.
|