Add three-model CNI adapter pattern to HFL-Kedge integration doc

New §8 documenting how Kedge CNI operates identically across all three
Substrate deployment models (container-first, KVM/QEMU, multikernel).
Covers the substrate:network WIT adapter, per-model attach-workload
resolution, GovernedNetworkPolicy installation path, and the invariant
that the same CNI binary works unchanged across all models.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Tyler King 2026-02-26 19:38:12 -05:00
parent 6058e62348
commit eca07a45d5

View file

@ -417,3 +417,82 @@ Quartermaster receives the `submit-proposal` RPC with the `RequestToken` in meta
| Service token | `RequestToken` is valid, single-use, unexpired | Userspace (Quartermaster/Bascule) | RPC rejected with `PermissionDenied` |
Five independent checks, three distinct trust domains (pod kernel, pod userspace, remote service), two cryptographic validations (SAT, RequestToken). No single point of compromise grants unauthorized access.
---
## 8. Three-Model Adapter Pattern
Kedge CNI operates identically across all three Substrate deployment models. The CNI binary is a thin adapter that marshals between the Kubernetes CNI JSON contract and `substrate:network` WIT host function calls. Only the host-side implementation of those WIT calls varies.
### 8.1 The Adapter
The CNI binary delegates all real work to three WIT calls:
| CNI Operation | WIT Call |
|---------------|----------|
| `CNI ADD` | `substrate:network/workload-network.attach-workload()` |
| `CNI DEL` | `substrate:network/workload-network.detach-workload()` |
| `CNI CHECK` | `substrate:network/workload-network.check-workload()` |
The `substrate:network@0.1.0` WIT package (`substrate/wit/substrate-network.wit`) defines four interfaces: `workload-network` (attach/detach/check), `routing` (governed BGP/OSPF), `firewall` (identity-based flow policy), and `telemetry` (governed flow records).
### 8.2 Model A: Container-First (Vanilla Linux)
This is the Phase 1 deployment. Single Linux kernel. All components are userspace processes.
When Kedge calls `attach-workload`:
1. WASM governance Component evaluates policy (is this pod authorized for the requested networks?)
2. WASM Component assigns identity (SAT binding for the network interface)
3. eBPF program installs flow policy in `shell_map` BPF map (§2)
4. Creates memif interface into VPP's processing graph
5. VPP handles data plane — packets never touch the kernel network stack
6. Returns IP + routes to kubelet via CNI JSON result
VPP runs as a userspace process pinned to dedicated cores. NICs are assigned via VFIO/UIO (kernel bypass). FRR runs as a separate process for BGP/OSPF routing. The `substrate:network` WIT Components replace any VPP/FRR management interface — there is no vyconf, no SSH, no CLI.
### 8.3 Model B: KVM/QEMU (Legacy)
Each role kernel is a VM. The Network VM runs VyOS/VPP.
When Kedge calls `attach-workload`:
1. Call crosses virtio-vsock to the Network VM
2. Same WASM + eBPF logic runs inside the VM
3. VPP inside the Network VM configures a virtio-net interface
4. Returns IP to kubelet
Model B is supported for compatibility but is not the recommended production data plane. The virtio serialization overhead undermines DPDK's zero-copy advantage.
### 8.4 Model C: Multikernel/Bifrost (Target)
Multiple minimal Linux kernels on bare metal, each owning dedicated CPU cores and devices via IOMMU.
When Kedge calls `attach-workload`:
1. Governance evaluation runs in **Workload Kernel** (same kernel as kubelet/Kedge)
2. Only datapath operations cross the IPI bus to the **Network Kernel**: "create memif 10.0.1.5, policies: [...]"
3. Network Kernel's VPP adds interface to its processing graph
4. Network Kernel's eBPF installs flow policy
5. Shared memory data path connects Workload Kernel ↔ Network Kernel (zero-copy)
6. Returns IP to kubelet
**Key design decision:** Governance evaluation stays in the Workload Kernel. Only the result (interface creation + flow policies) crosses the IPI bus. This keeps the governance plane local, minimizes IPI traffic, and means the Network Kernel only handles datapath operations.
The Network Kernel image is based on a stripped VyOS distribution: VPP + DPDK (data plane, owns NICs via IOMMU), FRR (control plane routing), WASM runtime + `substrate:network` Components (governance plane), eBPF programs (flow policy enforcement + telemetry). Stripped: vyconf, SSH server, web UI — replaced by WIT host functions accessed via IPI bus.
### 8.5 GovernedNetworkPolicy Installation Path
When SPIRE issues an SVID for a pod, the `ssh-credential-composer` embeds a `network-policy@guildhouse.dev` SSH certificate extension containing the SHA-256 hash of the applied GovernedNetworkPolicy. At CNI ADD time:
1. Kedge reads the policy hash from the pod's SVID
2. Kedge calls `attach-workload` with the policy reference in `governance-context`
3. The WASM governance Component resolves the policy hash to a full `GovernedNetworkPolicy` (identity-based, SAT-claim-scoped firewall rules)
4. The Component calls `substrate:network/firewall.install-flow-policy` for each rule
5. eBPF programs in the VPP graph enforce the installed policies at wire speed
The trust chain is continuous: SPIRE attests workload → composer embeds governance context → Kedge reads context → host functions install governed policy → eBPF enforces → Chronicle notarizes.
### 8.6 The Invariant
The same Go binary (`cmd/kedge-cni/main.go`) runs unchanged across all three models. The `substrate:network` WIT interface is the stable boundary. What changes between models is the host function implementation — memif vs. virtio vs. IPI — but the CNI adapter never sees this. The `ShellProgrammer` trait (shell-primitive.md §7) absorbs the model difference at the enforcement layer, and the WIT runtime absorbs it at the network operations layer.