cmd/clawkercp (PID 1) inside the clawker-controlplane Docker container. It is the authoritative supervisor for every clawker-managed agent on the host — it owns the agent identity registry, the egress firewall lifecycle, the eBPF program lifetime, and the CP↔agent command channel.
You normally won’t think about the control plane. The first time any clawker command needs it (clawker firewall status, clawker run, clawker controlplane agents, …), the CLI brings it up transparently. The clawker controlplane verb group exists for debugging, upgrades, and recovery — not day-to-day use.
The control plane is not the firewall. The firewall (Envoy + CoreDNS + eBPF) is one of several subsystems CP manages. Disabling the firewall via
settings.yaml does not disable the control plane — CP, mTLS, and the agent registry continue to run for any other clawker container. See the Firewall guide for the firewall itself.What CP Does
The CP container is a single binary,clawkercp, running as PID 1. Inside it:
- Ory auth stack — Hydra (OAuth2 token issuer,
client_credentials+private_key_jwtES256), Kratos (identity), and Oathkeeper (HTTP auth proxy) are subprocess-managed by the same PID. Token validation is fail-closed. - AdminService gRPC (mTLS + OAuth2 JWT, default port
7443on host loopback) — the 13-method firewall control surface (FirewallInit,FirewallEnable,FirewallAddRules,FirewallSyncRoutes,FirewallBypass, …) plusListAgents(uniform admin scope) andGetSystemTime(public-scope, no bearer token required — used by the clock-sync readiness gate). Every CLIclawker firewall *andclawker controlplane agentscall goes through this RPC. - AgentService gRPC (mTLS, default in-container port
7444, reachable only overclawker-net) — the surface clawkerd uses to register itself with CP and hold open a long-lived Session. - Agent registry — a sqlite database persisted on the host XDG data dir, keyed by SHA-256 of the agent’s mTLS leaf cert thumbprint plus container ID. CP is the sole writer; reads go through
ListAgents. The registry survives CP restarts. - Overseer event bus + worldview — in-process typed pub/sub topics carrying container lifecycle (start/stop/destroy/rename), agent session lifecycle (connecting/connected/failed/broken), and trust verdict events. Each domain (agent, firewall, …) subscribes and projects events into its own thread-safe worldview store — there is no shared cross-domain state.
- Docker events feeder — subscribes to the local Docker daemon’s event stream (with reconnect), projects managed-label-filtered events onto the overseer bus.
- Agent watcher + clean self-shutdown — polls Docker every 30s for
purpose=agent, managed=truecontainers. After drain-to-zero (60s grace period elapsed AND 2 consecutive zero-count polls), it fires an ordered drain callback:actionQueue.Close→ graceful gRPC stop → cancel bypass timers → Stack stop →netlogger.Stop(drains the eBPF egress event pipeline and flushes the OTLP BatchProcessor BEFORE BPF maps go away) → DNS GC stop → eBPFFlushAll→ exit code 0. Theon-failurerestart policy does not retrigger. - eBPF egress event emitter (netlogger) — drains a BPF ringbuf populated at every cgroup/connect/sendmsg/sock_create decision and emits OTLP log records on the same mTLS-gated infra lane the CP zerolog bridge uses. Distinct
service.name=ebpf-egressso OpenSearch routes the stream to its own index. Degrades toevent=netlogger_unavailable(no panics) when the collector is unreachable; firewall enforcement is unaffected. See Egress Observability for the record shape. - Aggregate
/healthz— host-loopback HTTP onHealthPort(default7080) probes every internal service port before returning 200. Used by bothclawker controlplane statusand the host-side bootstrap to confirm readiness.
Container Privileges
The CP container runs with elevated permissions because it is the host-side supervisor that loads kernel-attached eBPF programs and brings up the sibling firewall containers (Envoy, CoreDNS) on your behalf. The full privilege set is:
These privileges are not extended to agent containers. The agent container itself runs fully unprivileged:
cap_add: [], the docker-default seccomp and AppArmor profiles, no /sys/fs/bpf or /sys/fs/cgroup mount, no Docker socket. The agent’s blast radius is bounded by its own container; CP’s privileges exist only to enforce that boundary, not to relax it.
Guarantees
- eBPF programs have a deterministic owner. BPF cgroup programs and pinned maps survive the CP container’s death (they’re under
/sys/fs/bpf). Without a supervisor, rule changes would silently fail and bypass timers would never expire. CP is the single owner — its drain callback is the only clean exit path that detaches and flushes eBPF state. - Agent identity is auditable. Every clawkerd instance binds itself to CP via mTLS Register before any privileged operation. The cert thumbprint is captured server-side from the live TLS handshake — agents cannot self-attest.
clawker controlplane agentslists every binding, including which container holds which identity. - Containment is real. Because CP holds a long-lived Session to every agent’s
clawkerd, it can dispatch commands (init steps, MCP setup, shutdown signals) into a compromised container without re-authenticating each time. - Auth is centralized. Hydra issues short-lived OAuth2 tokens for every CLI↔CP gRPC call, signed by the CLI-issued auth material. The CLI is the root of trust; CP only validates.
How CP Boots
Two paths bring CP up:- Transparent bootstrap — the first CLI call that needs CP (most firewall commands, container creation, anything that opens an
AdminClient) callsManager.Start(packagecontrolplane/manager) under a host-side mutex. Steps: ensure the CP image exists with a content-derived tag (clawker-controlplane:bin-<sha>, built on demand from the embedded binaries),ContainerCreateonclawker-netwith a static IP,ContainerStart, then pollhttp://127.0.0.1:<HealthPort>/healthzuntil 200 or timeout. Idempotent — re-runs are no-ops once/healthzis green. - Break-glass —
clawker controlplane upcalls the sameManager.Startpath explicitly, useful when you want to bring CP up without triggering a side-effect command.
clawker CLI itself (clawkercp, ebpf-manager). There’s no separate image to pull. See Installation for the BPF toolchain requirements when building from source.
On every boot, CP reads firewall.enable from settings and — when enabled (the default) — starts the Envoy + CoreDNS firewall stack before reporting ready, so a green /healthz means the firewall is actually enforcing. That covers boots no CLI command observes, like Docker’s restart policy resurrecting a crashed CP. A failed stack bringup fails CP startup (the container exits non-zero): running half-protected would leave agents either unusable (their egress redirected at a dead proxy) or, worse, silently unenforced while you believe the firewall is on. The CLI surfaces the exit with a pointer at docker logs clawker-controlplane; fix the cause and rerun, or disable the firewall in settings to run unprotected.
Networking
CP joinsclawker-net with a deterministic static IP computed by replacing the gateway’s last octet with 202 — so e.g. 192.168.215.202 on a default Docker bridge with gateway 192.168.215.1. The CLI talks to it over host loopback for AdminClient (mTLS gRPC on port 7443) and /healthz (plain HTTP on port 7080). The agent listener (7444) is only reachable from other containers on clawker-net.
When CP brings up the firewall, it places Envoy at <network>.200 and CoreDNS at <network>.201 on the same network (last-octet replacement, same scheme). Agent containers join clawker-net with --dns pointing at CoreDNS so DNS resolution is filtered from the very first lookup.
CLI Surface
Allclawker controlplane subcommands are break-glass — useful for debugging, upgrades, and recovery, not normal use.
The
clawker auth group manages the CLI-side auth material CP depends on:
See the full reference: clawker controlplane, clawker auth.
Verifying CP Is Up
Container: stopped and the health and firewall fields are omitted. Bringing CP back up:
Settings
CP-related ports and behavior live undercontrol_plane: in settings.yaml (~/.config/clawker/settings.yaml). See Configuration → control_plane for the schema. The defaults work out of the box; override only if a port conflicts:
hydra_admin_port, kratos_public_port, kratos_admin_port, oathkeeper_api_port) are container-internal — they are not published to the host. hydra_public_port and oathkeeper_port are published to 127.0.0.1 on the host. All ports appear in settings so the in-container subprocesses agree on their port assignments.
Troubleshooting
CP container won’t start. Rundocker logs clawker-controlplane (CP panic traces and Ory subprocess output land here, not in clawker’s rotating logs). The most common causes: stale port bindings from a half-killed previous run (clawker controlplane down then retry), or auth material out of sync (try clawker auth rotate).
clawker run / clawker container start fails with cp clock sync deadline exceeded (Docker Desktop).
Before starting a container, the CLI brings the control plane to full readiness — which includes waiting until CP’s clock (the Docker Desktop LinuxKit VM clock, where CP runs) has caught up to the host clock. The gate requires full convergence (zero leeway): CP’s clock must reach the host instant. If it doesn’t converge within ~30s the command fails with:
iat against CP’s clock with zero leeway — so exchanging it against a still-lagging CP clock would earn a Hydra Token used before issued 500. Rather than re-mint or skew-correct, the gate waits for the CP clock to reach the host before letting the container start, so nothing unusable is baked in: the baked assertion stays valid, and once the VM clock catches up a plain retry of clawker run / clawker container start succeeds — no need to delete and recreate. Wait a few seconds for the VM clock to catch up and retry, or restart Docker Desktop to force a resync. (The earlier symptom of this drift — that Hydra Token used before issued 500 at container start — is now caught by this pre-start gate instead.)
clawker firewall * commands hang or fail with connection refused.
CP isn’t running or /healthz is not green. clawker controlplane status confirms. clawker controlplane up brings it back.
Agents appear in clawker ps but not in clawker controlplane agents.
The agent’s clawkerd hasn’t completed the Register handshake with CP — either CP wasn’t running when the container started, or the agent’s mTLS material is invalid. docker logs clawker.<project>.<agent> (look for event=register_failed or TLS handshake errors) and clawker auth rotate are the typical recovery steps.
Want to know what CP is up to in real time.
The host-side CP log file is ~/.local/state/clawker/logs/clawker-controlplane.log (rotated). Stack traces from a CP panic land on the CP container’s stderr (docker logs clawker-controlplane), not in this file — so if the rotating log is silent but agents are misbehaving, check docker logs first.
See Also
- Firewall — egress enforcement (one of CP’s managed subsystems)
- Container Internals — what
clawkerd(PID 1 inside each agent container) does, and how it talks to CP - Credentials — credential forwarding mechanisms unrelated to CP
clawker controlplane— full CLI referenceclawker auth— auth material rotation