Control plane
Distribute signed policy to a fleet of brokers and detect audit rollback.
Where to run this
Every command on this page runs from a clone of the AgentBox repository on the trusted host — never inside the agent workspace. If you haven't cloned it yet, start with the quickstart.
Signed policy bundles
Brokers can take policy from a control plane instead of a local file:
| Variable | Purpose |
|---|---|
AGENTGATE_CONTROL_URL | Control plane origin (https required) |
AGENTGATE_BROKER_ID | This broker's ID |
AGENTGATE_CONTROL_TOKEN_FILE | Bearer token (chmod 600) |
AGENTGATE_CONTROL_KEYS_FILE | { "kid": "<Ed25519 public key PEM>" } (chmod 600) |
AGENTGATE_CONTROL_POLL_MS | Poll interval (default 60000) |
Each document is { payload, kid, signature } — an Ed25519 signature over canonical JSON. Payloads carry kind, integer version, issuedAt/expiresAt (at most 7 days apart), and target brokers.
Sign documents
node scripts/sign-bundle.js --key control.pem --kid control1 --config policy.json \
--version 7 --brokers broker-a,broker-b --days 7 --out policy.signed.json
node scripts/sign-bundle.js --key control.pem --kid control1 --revocations revoked.json \
--version 3 --brokers '*' --days 1 --out revocations.signed.jsonFail-closed behavior
- A policy applies only if its version is greater than the last accepted one. Versions persist, so a restart can't be rolled back.
- The broker won't start without a valid policy.
- If fetching fails, the last good policy serves until
expiresAt, then every request gets503 POLICY_EXPIRED. - In assertion mode, an expired revocation list yields
503 REVOCATIONS_EXPIRED. Re-publish revocations — even an empty list — well within their lifetime.
Note
The control plane never holds signing keys. A compromised control plane can withhold updates (brokers then fail closed at expiry) but can't forge policy.
Running the control plane
AGENTGATE_CONTROL_BROKER_TOKENS_FILE=broker-tokens.json \
AGENTGATE_CONTROL_ADMIN_TOKEN_SHA256_FILE=admin-token.sha256 \
AGENTGATE_CONTROL_DATA_DIR=./control-data node src/control-plane.jsOnly token hashes are stored. Production requires AGENTGATE_CONTROL_TLS_CERT_FILE and AGENTGATE_CONTROL_TLS_KEY_FILE. examples/control-plane.compose.yaml runs it read-only, non-root, with capabilities dropped.
API
| Endpoint | Token | Purpose |
|---|---|---|
GET /v1/brokers/:id/policy | broker | Highest-version document for :id or * |
GET /v1/brokers/:id/revocations | broker | Same, for revocations |
POST /v1/brokers/:id/heartbeat | broker | Report versions and audit head; 409 AUDIT_ROLLBACK on regression |
PUT /v1/admin/policy | admin | Store a signed policy (409 STALE_VERSION, 409 SHADOWED_BY_WILDCARD) |
PUT /v1/admin/revocations | admin | Store a signed revocation list |
DELETE /v1/admin/policy/targets/:target | admin | Recover from a mistaken publish |
POST /v1/admin/brokers/:id/reset-rollback | admin | Re-baseline after investigating a rollback |
GET /v1/admin/inventory | admin | Fleet status, stale, rollbackDetected |
Brokers heartbeat at startup and every 60 seconds. Alert on control.audit_rollback_reported, control.heartbeat_failed, bundle.*_rejected, bundle.*_expired, and inventory entries that are stale or rollbackDetected.