control plane

the control plane is the network coordinator. it is itself an attested agent that verifies nodes, routes traffic, and maintains the ledger.

status

responsibilities

settlement model (planned)

pricing and routing

attestation

endpoints

current

endpoint description
GET /health service health
GET /v1/tunnel websocket for agents
GET /v1/resolve/{app} proxy routing (public)
POST /v1/proxy/{app} forward over ws tunnel
GET /v1/apps admin list (auth required)
GET /v1/apps/{app} admin detail

draft ledger endpoints

websocket protocol

agent registers:

{
  "type": "register",
  "repo": "org/repo",
  "release_tag": "v0.1.3",
  "app_name": "myapp",
  "network": "forge-1",
  "agent_id": "uuid"
}

control plane challenges:

{
  "type": "attest_request",
  "nonce": "<hex>",
  "deadline_s": 30,
  "reason": "register"
}

agent responds:

{
  "type": "attest_response",
  "nonce": "<hex>",
  "quote": "<base64>",
  "report_data": "<hex>",
  "measurements": {}
}

health heartbeat:

{"type": "health", "status": "pass"}

networks

network policy use case
forge-1 sealed only production
sandbox-1 unsealed ok development

configuration

# server bind
EE_CONTROL_BIND=0.0.0.0
EE_CONTROL_PORT=8088

# attestation
EE_ALLOWLIST_ASSET=agent-attestation-allowlist.json
EE_PCCS_URL=https://pccs.example.com
EE_ATTEST_INTERVAL_SEC=3600
EE_ATTEST_DEADLINE_SEC=30

# registration
EE_REGISTRATION_TTL_DAYS=30
EE_REGISTRATION_WARN_DAYS=3

# auth
EE_ADMIN_TOKEN=secret
EE_GITHUB_TOKEN=ghp_xxx
EE_LAUNCHER_TOKEN=launcher_secret
EE_UPTIME_TOKEN=uptime_secret

# proxy
EE_PROXY_BIND=0.0.0.0
EE_PROXY_PORT=9090

# ledger
EE_DB_PATH=control_plane/data/control-plane.db
EE_HEALTH_TIMEOUT_SEC=120

run locally

python -m venv .venv
source .venv/bin/activate
pip install -r control_plane/requirements.txt
python control_plane/server.py

with docker:

docker compose -f control_plane/docker-compose.yml up --build

optional: update cloudflare dns via api (a/aaaa for control, control-direct, *.app):

export CLOUDFLARE_API_TOKEN=...
export CLOUDFLARE_ZONE=easyenclave.com
python control_plane/scripts/cloudflare_dns.py --ip 1.2.3.4 --proxied --dry-run

or enable auto-update on startup:

EE_DNS_UPDATE_ON_START=true
EE_DNS_AUTO_IP=true
EE_DNS_PROXIED=true
CLOUDFLARE_API_TOKEN=...
CLOUDFLARE_ZONE=easyenclave.com

proxy setup

the resolve endpoint returns backend status for your proxy:

curl https://control.easyenclave.com/v1/resolve/myapp
{
  "app_name": "myapp",
  "status": "active",
  "endpoint": "wss://...",
  "sealed": true,
  "last_attest": "2024-01-15T10:30:00Z"
}

use nginx or another proxy to route based on this response.

if you proxy through cloudflare, use ssl/tls “full (strict)” so it connects to your origin over https. websockets are supported.

for wildcard tls on *.app, caddy uses cloudflare dns challenge and requires CLOUDFLARE_API_TOKEN (dns edit) in the control plane env.

agent connection

agents connect outbound (no inbound ports needed):

EE_CONTROL_WS=wss://control-direct.easyenclave.com:8088/v1/tunnel \
EE_REPO=owner/repo \
EE_RELEASE_TAG=v0.1.3 \
EE_APP_NAME=myapp \
EE_NETWORK=forge-1 \
EE_BACKEND_URL=http://127.0.0.1:8080 \
python agent/agent.py

next