VPC
Banyan uses WireGuard to create a Virtual Private Cloud (VPC) for secure communication between components (engine, agent, CLI). Each component generates a WireGuard keypair during init, and the engine validates public keys against a whitelist.
Secured by WireGuard® — All control plane and container traffic encrypted end-to-end.
How it works
There are two distinct phases: init time (one-time setup) and runtime (ongoing operation).
Init-time flow
During init, each component generates a WireGuard keypair. The admin then copies agent/CLI public keys to the engine’s whitelisted keys directory:
sequenceDiagram
participant Admin
participant Engine as banyan-engine
participant Agent as banyan-agent
participant CLI as banyan-cli
Note over Admin,Engine: Step 1: Engine init
Admin->>Engine: banyan-engine init
Engine->>Engine: Generate X25519 keypair
Engine->>Engine: Save private key + public key to config
Engine->>Engine: Create /etc/banyan/whitelisted-keys/
Note over Admin,Agent: Step 2: Agent init
Admin->>Agent: banyan-agent init
Agent->>Agent: Generate X25519 keypair
Agent->>Agent: Save private key + public key to config
Agent->>Agent: Display public key
Note over Admin,Engine: Step 3: Whitelist agent key
Admin->>Engine: Copy agent public key to engine
Note right of Admin: echo '<pubkey>' > /etc/banyan/whitelisted-keys/worker-1.pub
Note over Admin,CLI: Step 4: CLI init
Admin->>CLI: banyan-cli init
CLI->>CLI: Generate X25519 keypair
CLI->>CLI: Save private key + public key to config
CLI->>CLI: Display public key
Note over Admin,Engine: Step 5: Whitelist CLI key
Admin->>Engine: Copy CLI public key to engine
Note right of Admin: echo '<pubkey>' > /etc/banyan/whitelisted-keys/cli-1.pub
Note over Admin,Engine: Step 6: Start engine
Admin->>Engine: sudo systemctl start banyan-engine
Engine->>Engine: Load all *.pub from whitelisted-keys/
Engine->>Engine: Start gRPC server with pubkey auth
Runtime flow
After init, all communication uses the public key in gRPC metadata:
sequenceDiagram
participant Agent as banyan-agent
participant Engine as banyan-engine
Agent->>Engine: gRPC call + public key in x-banyan-public-key header
Engine->>Engine: Look up public key in whitelist
alt Key found in whitelist
Engine->>Engine: Process RPC
Engine-->>Agent: Response
else Key not found
Engine-->>Agent: Unauthenticated error
end
Config files
After initialization, each component stores its keypair:
Engine (/etc/banyan/banyan.yaml):
engine: wg_private_key: "base64-encoded-private-key" wg_public_key: "base64-encoded-public-key" whitelisted_keys_dir: "/etc/banyan/whitelisted-keys" grpc_port: "50051" store_backend: "etcd"Agent (/etc/banyan/banyan.yaml):
agent: engine_host: "192.168.1.10" engine_port: "50051" wg_private_key: "base64-encoded-private-key" wg_public_key: "base64-encoded-public-key"CLI (/etc/banyan/banyan.yaml):
cli: engine_host: "192.168.1.10" engine_port: "50051" wg_private_key: "base64-encoded-private-key" wg_public_key: "base64-encoded-public-key"Key management
- Generate: Running
initon any component generates a new X25519 keypair. - Whitelist: Copy the public key (displayed during init) to the engine’s whitelisted keys directory as a
.pubfile. - Revoke: Delete the
.pubfile from the engine’s whitelisted keys directory and restart the engine. - Rotate: Re-run
initon the component to generate a new keypair, then update the.pubfile on the engine.
Whitelisting keys
After running init on an agent or CLI, copy the displayed public key to the engine:
# On the agent machine (after banyan-agent init)cat /etc/banyan/banyan.yaml | grep wg_public_key# Output: wg_public_key: "abc123..."
# On the engine machinesudo banyan-engine add-client --name worker-1 --pubkey 'abc123...'Or copy directly between machines:
# From agent to enginessh engine-host "echo '$(grep wg_public_key /etc/banyan/banyan.yaml | awk '{print $2}')' > /etc/banyan/whitelisted-keys/worker-1.pub"The filename (minus .pub) becomes the agent’s display name in logs.
Non-interactive init
All init commands can be run non-interactively by pre-writing the config file:
# Write config firstcat > /etc/banyan/banyan.yaml <<EOFagent: engine_host: "192.168.1.10" engine_port: "50051"EOF
# Run init (generates keypair, skips prompts since config exists)sudo banyan-agent initWireGuard control tunnel
When the engine’s WireGuard public key is provided during agent/CLI init, Banyan creates a wg-control WireGuard interface that encrypts all gRPC traffic at the network layer. No TLS is needed — the tunnel handles encryption transparently.
Control plane tunnel (wg-control): Engine (10.200.0.1) <-> Agent (10.200.X.Y) # encrypted gRPC Engine (10.200.0.1) <-> CLI (10.200.X.Y) # encrypted gRPC
Data plane tunnel (banyan-wg): Agent <-> Agent # encrypted container trafficHow it works:
- Engine generates a keypair during
banyan-engine initand displays its public key. - Agents/CLI provide the engine’s public key during their
init. - On start, each component creates a
wg-controlinterface with a deterministic tunnel IP derived from its public key. - gRPC traffic routes through the tunnel automatically.
- If the tunnel is unavailable (e.g., WireGuard not installed), components fall back to direct TCP with public key metadata auth.
Port: 51821/UDP on the engine (agents/CLI connect to this port).
Config fields:
agent: engine_wg_public_key: "engine-public-key-base64" # enables control tunnel
cli: engine_wg_public_key: "engine-public-key-base64" # enables control tunnelSecurity properties
| Property | How |
|---|---|
| No passwords or shared secrets | Each component has a unique keypair. No cluster-wide password. |
| Keys are standard X25519 | Same format as WireGuard. 32 bytes, base64-encoded. |
| Dual-purpose keypair | Same key for gRPC auth (control plane) and WireGuard tunnels (data plane). |
| Per-component revocation | Delete a single .pub file to revoke access for one agent/CLI. |
| No token storage in etcd | Public keys are stored as flat files on the engine. No etcd dependency for auth. |
| Private keys never leave the machine | Only the public key is copied to the engine. |
| Control plane encryption | When enabled, all gRPC traffic is encrypted via WireGuard tunnel. |