Virtualization, routing, and security
Companion Hub hosts diverse workloads on user-owned hardware: standard web applications, local LLMs and multi-modal models, AI agent sandboxes, full-system virtual machines (macOS, Windows), and confidential DRM-protected applications.
To run these workloads safely on an appliance where the operator has host root access, Hub uses a layered security, networking, and virtualization model. This document details how virtualization works, how traffic is segmented and routed, and how the sandbox and proxy layers enforce security.
flowchart TB
accTitle: Virtualization, routing, and security architecture in Companion Hub
subgraph Clients["Clients & Edge Ingress"]
cf["Cloudflare Edge<br/>Public Web URLs"]
tailnet["Tailscale Mesh<br/>Private VPN (tailnet)"]
lan["Direct LAN / Localhost<br/>127.0.0.1 / Hub IP"]
end
subgraph EdgeNet["Edge Network (ci-hub_edge: 10.128.0.0/29)"]
cfd["cloudflared<br/>10.128.0.3"]
ts["hub-tailscale<br/>10.128.0.4"]
traefik["Traefik v3 Reverse Proxy<br/>10.128.0.2<br/>Headers: ci-hub-edge-headers"]
end
subgraph AuthLayer["Identity & Control Plane"]
hub["ci-hub Core (port 5002)<br/>Forward-Auth Validator<br/>Preflight Device Prober"]
db[("PostgreSQL 14<br/>ci-hub_internal")]
queue["RabbitMQ 4<br/>ci-hub_internal"]
end
subgraph AppRuntimes["Virtualization & Workload Runtimes"]
subgraph Standard["Standard Containers (runc)"]
runcApp["General App / Web UI<br/>Shared Host Kernel"]
aiApp["Inference Engine / Local GPU<br/>Direct /dev/kfd, /dev/dri Passthrough"]
end
subgraph MicroVM["MicroVM Isolation (kata-qemu)"]
agentSandbox["Agent Code Execution<br/>Dedicated Guest Linux Kernel<br/>Requires /dev/kvm"]
end
subgraph TEE["Confidential Containers (kata-cc)"]
cocoApp["Commercial App / DRM Weights<br/>AMD SEV-SNP / Intel TDX<br/>Hardware Encrypted RAM"]
end
subgraph FullVM["QEMU/KVM Virtual Appliances"]
qemuVM["macOS / Windows VM<br/>dockur/windows, dockur/macos<br/>NET_ADMIN + /dev/kvm + TAP Bridge"]
end
end
cf -->|"outbound tunnel"| cfd
tailnet -->|"tailscale serve"| ts
cfd -->|"edge network"| traefik
ts -->|"edge network"| traefik
traefik -->|"forward-auth subrequest"| hub
hub --> db
hub --> queue
traefik -->|"routes by Host header"| runcApp
traefik -->|"routes by Host header"| aiApp
traefik -->|"routes by Host header"| agentSandbox
traefik -->|"routes by Host header"| cocoApp
traefik -->|"routes by Host header"| qemuVM
lan -.->|"bypasses proxy (direct port)"| runcApp
lan -.->|"bypasses proxy (direct port)"| qemuVM1. Virtualization systems
Hub supports four distinct workload execution tiers, matching isolation strength to workload trust and performance requirements:
| Tier | Technology | Kernel Isolation | Hardware Reqs | Primary Workloads |
|---|---|---|---|---|
| Standard Containers | Docker / containerd (runc) | Shared host kernel, cgroups v2, seccomp, namespaces | Any CPU, optional GPU (/dev/dri, /dev/kfd) | Standard web apps, dashboard, local inference sidecars |
| MicroVM Sandboxes | Kata Containers (kata-qemu, kata-fc, kata-clh) | Independent guest Linux kernel inside lightweight hypervisor | Hardware virtualization (/dev/kvm) | Untrusted AI agent tool & code execution sandboxes |
| Confidential Containers | CoCo (kata-cc, kata-qemu-sev/snp/tdx) | Hardware-encrypted guest VM inside Trusted Execution Environment (TEE) | AMD SEV-SNP or Intel TDX + /dev/kvm + KBS | Proprietary agent model weights, commercial apps (Runtime DRM) |
| Virtual Appliances | QEMU/KVM in Container (dockur/windows, dockur/macos) | Full guest OS emulation (Windows, macOS) inside Docker container | /dev/kvm, NET_ADMIN for TAP bridge | Full-desktop legacy OS apps, testing environments |
A. Standard OCI containers (runc)
The default container runtime for Hub apps is runc. Standard containers share the host Linux kernel and rely on Linux namespaces (PID, mount, IPC, UTS, network) and cgroups v2 resource limits.
- Direct hardware acceleration: Host GPUs (
/dev/drifor Intel/NVIDIA/AMD,/dev/kfdfor AMD ROCm) are passed straight through character device nodes with no virtualization penalty. - Low overhead: Zero microVM kernel startup latency; shared page cache with the host OS.
- Unprivileged control plane: The
ci-hubandtraefikcontainers mount/var/run/docker.sock:roread-only andci-hubdrops privileges toCI_HUB_CONTAINER_UID:GID(with supplementaryDOCKER_GID) rather than running withprivileged: true. - Trust boundary: Standard containers protect the host from accidental faults, but do not protect container data or memory from the host root operator.
B. MicroVM isolation (kata-qemu, kata-clh, kata-fc)
When an app or user override sets runtime: "kata-qemu" in docker-compose.json, the container process runs inside a dedicated, isolated virtual machine managed by Kata Containers .
- Independent kernel: The guest has its own Linux kernel and root filesystem. Syscall attacks or kernel vulnerabilities cannot exploit the host kernel.
- Container interface parity: Docker and containerd communicate with the Kata shim (
containerd-shim-kata-v2) via standard OCI APIs, meaning dynamic compose environment injection, ports, and volumes function identically to standard containers. - Agent sandbox safety: In agentic workflows, LLMs generate and execute arbitrary Python, Node.js, and shell code. Running tool execution in a Kata microVM eliminates the historical need for
privileged: trueDocker-in-Docker workarounds.
C. Confidential Containers & runtime DRM (kata-cc)
For commercial apps and proprietary model weights distributed through the CI Marketplace, standard containers provide zero IP protection because host root operators can inspect /var/lib/docker/overlay2 or attach gdb to processes.
Confidential Containers (CoCo) solves this through hardware memory encryption:
- Hardware memory encryption: AMD SEV-SNP (Secure Encrypted Virtualization-Secure Nested Paging) or Intel TDX (Trust Domain Extensions) encrypt guest RAM using hardware-managed cryptographic keys inside the CPU memory controller.
- Encrypted OCI layer streaming: Container images stored on Cloudflare R2 are encrypted at rest with developer keys.
- Remote attestation & KBS: At microVM boot, the hardware security module generates an attestation measurement report verifying CPU firmware and guest enclave integrity. The guest attestation agent sends this to the Key Broker Service (KBS), which releases the layer decryption key directly into the guest microVM enclave.
- Host admin lockout: Even with host root privileges, memory dumps yield only ciphertext. Container filesystems and model weights are decrypted solely within the CPU-protected enclave.
D. Full-system virtual appliances (QEMU/KVM)
Hub runs full desktop operating systems (such as dockur/windows and dockur/macos) inside containerized QEMU instances:
- KVM acceleration: The container binds
/dev/kvmfrom the host. QEMU uses hardware virtualization extensions (Intel VT-x / AMD-V) to execute guest code at near-native speed. - Network bridging: Virtual appliances require
capAdd: ['NET_ADMIN']. On container startup, entrypoint scripts create a virtual bridge (br0) and TAP interface (tap0), attaching the QEMU virtual NIC to the container’s network namespace. - Display redirection: The guest desktop GUI is rendered to an internal VNC/RDP server or web-based noVNC proxy, published on the app’s local port (e.g.,
8006or3389).
E. Proactive virtualization preflight checks
Because Docker returns cryptic device-attach or runtime startup errors when /dev/kvm is missing, Hub enforces a fast-fail preflight check in host-device-preflight.ts during both app install and start:
- Manifest inspection: Scans base
docker-compose.json, architecture overrides, and user overrides (user-config/{store}/{app}/docker-compose.yml) for:- Devices containing
/dev/kvm(bare path orhost:containermapping). - Services declaring
runtime: "kata*",runtime: "kata-cc", or any runtime inCONFIDENTIAL_CONTAINER_RUNTIMES.
- Devices containing
- Device accessibility probe: Verifies that
/dev/kvmexists and has read permissions (fs.promises.access('/dev/kvm', fs.constants.R_OK)). - Friendly failure: If missing or unreadable (common on Docker Desktop for macOS/Windows or nested VMs without virtualization enabled), Hub halts before invoking Docker and raises
createKvmMissingError():“This app needs hardware virtualization (KVM). It is not available on this machine.”
2. Traffic routing architecture
Hub segments network traffic across four Docker networks to prevent cross-app snooping and infrastructure attacks.
flowchart LR
subgraph Edge["Edge Perimeter (ci-hub_edge: 10.128.0.0/29)"]
traefik["Traefik v3<br/>10.128.0.2"]
cfd["cloudflared<br/>10.128.0.3"]
tailscale["hub-tailscale<br/>10.128.0.4"]
end
subgraph AppNet["App Network (ci-hub_network)"]
hub["ci-hub:5002<br/>API & Dashboard"]
app1["App A<br/>10.128.10.x"]
app2["App B<br/>10.128.11.x"]
end
subgraph InternalNet["Private Infrastructure (ci-hub_internal)"]
db[("PostgreSQL 14<br/>127.0.0.1:6543")]
queue["RabbitMQ 4<br/>127.0.0.1:5001"]
end
cfd -->|"trusted IP"| traefik
tailscale -->|"trusted IP"| traefik
traefik -->|"routes HTTP"| app1
traefik -->|"routes HTTP"| app2
traefik -->|"routes HTTP"| hub
app1 -->|"API calls"| hub
app2 -->|"API calls"| hub
hub --> db
hub --> queue
style InternalNet fill:#ffebee,stroke:#c62828,stroke-width:2px
style Edge fill:#e8f5e9,stroke:#2e7d32,stroke-width:2pxA. The 4 network planes
- Edge network (
ci-hub_edge):- Fixed subnet:
10.128.0.0/29(Gateway10.128.0.1, dynamicip_range: 10.128.0.0/31). - Members with fixed IPs: Traefik (
10.128.0.2), Cloudflare Tunnel agentcloudflared(10.128.0.3), and Tailscale sidecarhub-tailscale(10.128.0.4). - Because
ip_rangeis restricted to.0and.1, Docker refuses dynamic IP allocation onci-hub_edge. Apps cannot join this network, and Traefik trusts forwarded visitor client IPs only from10.128.0.3and10.128.0.4.
- Fixed subnet:
- Application network (
ci-hub_network):- The shared application bridge (
gw_priority: 1). Every installed app’s main container joins this network. (Hub also maintains the legacyci-os-hub_networkbridge so stacks installed before theci-hubrename continue resolving.) - Allows apps to reach the Hub backend API at
http://ci-hub:5002(for MCP, model inference, and status reporting) and enables inter-app communication where configured.
- The shared application bridge (
- Private infrastructure network (
ci-hub_internal):- Strictly private network holding PostgreSQL (
ci-hub-db) and RabbitMQ (ci-hub-queue). - No user application can join
ci-hub_internal. Host binds (127.0.0.1:6543and127.0.0.1:5001) are restricted to localhost on the Hub machine.
- Strictly private network holding PostgreSQL (
- Per-app subnet isolation:
- When apps declare their own internal networks, Hub allocates dedicated subnets from
HUB_APP_ALLOCATION_START_CIDR(10.128.10.0/24) throughHUB_APP_ALLOCATION_END_CIDR(10.254.254.0/24). - If Docker reports a subnet collision with existing host routes, Hub’s
docker-network-errors.tsautomatically reclaims and reassigns an unused range.
- When apps declare their own internal networks, Hub allocates dedicated subnets from
B. Ingress routing modes
Traffic reaches applications through three distinct ingress paths:
- Direct port (LAN / Localhost):
- Apps publish ports directly to the host (e.g.,
http://127.0.0.1:{port}orhttp://{hub-ip}:{port}). - Bypasses Traefik entirely.
- For agent apps and apps without native authentication, Hub binds ports to
127.0.0.1by default to prevent unauthorized LAN access.
- Apps publish ports directly to the host (e.g.,
- Cloudflare Gateway (Public Web):
- For apps with exposure set to Public Web, Hub provisions public DNS and routes traffic through the managed Cloudflare Tunnel.
- Outbound tunnel:
cloudflaredconnects outward to Cloudflare Edge. No inbound ports are opened on the user’s router. - Traefik routes inbound requests by matching
Host("app-name.hub.ci.computer").
- Private VPN (Tailscale):
- For apps with exposure set to Private VPN, the
hub-tailscalesidecar publishes routes onto the operator’s tailnet viatailscale serve. - Access requires an authenticated device on the operator’s Tailscale network.
- For apps with exposure set to Private VPN, the
C. Edge header sanitization (ci-hub-edge-headers)
Because Traefik trusts cloudflared as an upstream proxy on ci-hub_edge, any forwarded headers sent by an external visitor would normally be passed through. An attacker could forge X-Real-Ip, X-Forwarded-Uri, or X-Forwarded-Method to bypass per-IP rate limits or trick auth middleware.
Hub places ci-hub-edge-headers@file first in Traefik’s middleware chain:
ci-hub-edge-headers:
headers:
customRequestHeaders:
X-Real-Ip: ""
X-Forwarded-Prefix: ""
X-Forwarded-Uri: ""
X-Forwarded-Method: ""
X-Forwarded-Port: ""
X-Forwarded-Tls-Client-Cert: ""
X-Forwarded-Tls-Client-Cert-Info: ""This strips visitor-supplied headers before any request reaches an app router or the Forward-Auth check.
D. App boot interception (ci-hub-app-starting)
Heavy apps (e.g., large language models or QEMU virtual machines) often take 30 to 120 seconds to boot. By default, Traefik returns a raw 502 Bad Gateway or 504 Gateway Timeout.
Hub attaches ci-hub-app-starting@file as the final middleware on every HTTP router. When a container is starting and cannot yet accept connections, Traefik intercepts the 502/504 and requests the Hub’s starting page handler, rendering a clean, live progress page to the user with status explanations.
3. Security & confinement architecture
Companion Hub employs defense-in-depth across the API, Docker builder, proxy, and container runtime layers.
flowchart TD
accTitle: Security enforcement layers in Companion Hub
Manifest["App Manifest (docker-compose.json)"] --> BuildSink["Compose Builder Validation<br/>(collectServiceSecurityViolations)"]
subgraph SandboxEnforcement["Sandbox Enforcement"]
BuildSink -->|"Denies forbidden host paths"| PathCheck["Reject /, /etc, /var/run, ~ mounts"]
BuildSink -->|"Denies raw block devices"| DevCheck["Reject /dev/sd*, /dev/nvme*, /dev/mem"]
BuildSink -->|"Denies dangerous capabilities"| CapCheck["Drop SYS_ADMIN, SYS_MODULE, privileged"]
BuildSink -->|"Enforces network isolation"| NetCheck["Reject network_mode: host / container:"]
end
subgraph TraefikConfinement["Traefik Confinement"]
TraefikSink["Traefik Labels Builder"] --> LabelCheck["Reject reserved prefixes (ci-hub.*)"]
TraefikSink --> RouteCheck["Prevent cross-app route hijacking"]
TraefikSink --> ChainOrder["Force Hub security middlewares first"]
end
subgraph RuntimeSecurity["Runtime Authentication & Encryption"]
ForwardAuth["Forward Auth Middleware<br/>GET /api/auth/traefik"] --> TokenCheck["Validate Hub/Portal Session"]
TokenCheck --> HeaderSign["HMAC Sign X-CI-Hub-User-* Assertions"]
TEECheck["Confidential MicroVM"] --> MemEncrypt["AMD SEV-SNP / Intel TDX Hardware RAM Encryption"]
endA. Install-sink sandbox enforcement
Hub validates all container configurations in collectServiceSecurityViolations during compose generation. Any violation by an app that does not hold an audited exemption in APP_SECURITY_GRANTS aborts installation:
- Host path mounting restrictions:
- Apps cannot bind-mount host roots or administrative paths:
/,/etc,/var,/var/run,/var/run/docker.sock,/var/lib/docker,/proc,/sys, or~(user home directory). - Dot-segment traversal attacks (e.g.,
/app-data/../../etcor/etc/../etc) are canonicalized and rejected. - Safe exceptions are strictly allowlisted (e.g., read-only timezone mounts
/etc/localtimeand/etc/timezone).
- Apps cannot bind-mount host roots or administrative paths:
- Device passthrough restrictions:
- Raw storage block devices (
/dev/sd*,/dev/nvme*,/dev/vd*,/dev/loop*,/dev/mapper/*) and host memory devices (/dev/mem,/dev/kmem,/dev/port) are denied. - Harmless hardware devices (e.g., Zigbee dongles
/dev/ttyUSB0or capture cards/dev/video0) are allowed, while/dev/kfd(ROCm) and/dev/kvm(virtualization) trigger hardware preflight checks.
- Raw storage block devices (
- Capability dropping:
- Root-equivalent capabilities (
SYS_ADMIN,SYS_MODULE,SYS_RAWIO) andprivileged: trueare blocked by default. - Specific apps requiring network management (e.g., VPN gateways like WireGuard or QEMU VM appliances building TAP interfaces) receive narrow grants (e.g.,
NET_ADMIN) strictly scoped to their container network namespace.
- Root-equivalent capabilities (
- Network mode restrictions:
network_mode: "host"andnetwork_mode: "container:other-container"are forbidden without explicit grants. Host network mode breaks container port isolation, and container network mode allows joining another container’s loopback interface.
B. Traefik label confinement & anti-hijacking
Traefik configuration in Docker is controlled via container labels. In a multi-tenant or marketplace app store, a malicious app manifest could attempt to hijack other apps’ hostnames, drop authentication, or manipulate routing priority.
Hub’s TraefikLabelsBuilder enforces strict confinement:
- Reserved namespace protection: Labels starting with
ci-hub.orci-os-hub.cannot be declared by an app’sextraLabels. - Route name ownership: Traefik router and service names must strictly match the app’s own URN and ID (
CUSTOM_APP_ERROR_TRAEFIK_NAME_NOT_OWN). An app cannot register rules for another app’s hostname. - Mandatory middleware precedence: Via
withHubMiddlewaresFirst(), Hub injects its edge header strip and forward-auth middlewares at the head of every router chain. An app manifest cannot remove or bypass these middlewares.
C. Forward-auth & cryptographic identity assertion
When an app is protected with Require Auth, Traefik intercepts incoming HTTP requests on both the plain HTTP tunnel entrypoint (web) and TLS entrypoint (websecure) and queries Hub’s forward-auth handler at http://ci-hub:5002/api/auth/traefik:
- Session validation: Hub checks the request’s session cookie or Bearer token against PostgreSQL and CI Account OIDC membership.
- Identity injection: If authorized, Hub returns HTTP 200 and issues cryptographically signed headers (forwarded via Traefik’s
authResponseHeaders):X-CI-Hub-User: Authenticated username (email or local username).X-CI-Hub-User-Timestamp: Milliseconds since the Unix epoch when the assertion was signed.X-CI-Hub-User-Signature: Hex-encoded HMAC-SHA256 over${username}\n${timestampMs}, keyed withCI_HUB_FORWARD_AUTH_IDENTITY_SECRET.X-CI-Hub-User-Issuer: User directory URN (urn:ci-hub:<directory_id>).X-CI-Hub-User-Id: Stable user UUID (user.public_id).X-CI-Hub-User-Id-Signature: Hex-encoded HMAC-SHA256 overci-hub-user-id/1\n${issuer}\n${userId}\n${username}\n${timestampMs}, keyed withCI_HUB_FORWARD_AUTH_IDENTITY_SECRET.X-CI-Hub-User-Assertion: Per-app bound assertion formatted as2.<nonce>.<signature>overci-hub-forward-auth/2\n${audience}\n${nonce}\n${timestampMs}\n${username}\n${issuer}\n${userId}, keyed with the target app’s ownCI_HUB_FORWARD_AUTH_ASSERTION_SECRET(whereaudienceis the app URN). When the user and Hub have KERI autonomic identifiers (AIDs), Hub also attachesX-CI-Hub-User-AID,X-CI-Hub-AID, andX-CI-Hub-KEL-Digestand binds them underci-hub-forward-auth/2-aid.
- Signature verification by downstream apps: Downstream apps (such as Companion Memory) verify the HMAC signature using their per-app secret (
CI_HUB_FORWARD_AUTH_ASSERTION_SECRET) or the shared identity secret (CI_HUB_FORWARD_AUTH_IDENTITY_SECRET). Any tampering, replay across apps, or header spoofing causes signature mismatch and request rejection.
Summary checklist
| Component | Technology | Primary Function | Security Role |
|---|---|---|---|
runc | OCI Container Engine | Runs standard applications & AI models | cgroups v2 resource limits, seccomp filters, namespaces |
kata-qemu | MicroVM Hypervisor | Runs untrusted agent code execution | Dedicated guest kernel; immune to host kernel exploits |
kata-cc | Confidential Containers | Runs commercial apps & proprietary weights | Hardware memory encryption (AMD SEV-SNP/Intel TDX), KBS attestation |
| QEMU / KVM | Hardware-Assisted VM | Runs virtual appliances (macOS, Windows) | Near-native CPU virtualization via /dev/kvm; TAP network bridge |
ci-hub_edge | Docker Bridge (10.128.0.0/29) | Transports tunnel and VPN ingress | Fixed IPs for Traefik, cloudflared, and tailscale; blocks app entry |
ci-hub_network | Docker Bridge | Inter-app and Hub API communication | Restricts access to host network while permitting API access |
ci-hub_internal | Isolated Docker Bridge | Dedicated database and message broker | Zero external access; completely hidden from user apps |
| Traefik v3 | Edge Reverse Proxy | Host-based HTTP/HTTPS routing | Enforces TLS floor (TLS 1.2+), strips headers, attaches auth |
| Forward Auth | NestJS Core API | Validates user & device credentials | Injects HMAC-signed identity headers; eliminates plaintext trust |