Skip to main content
A Sidecar that knows nothing about a Control Plane reads its config file from disk and runs. Connecting it changes one thing: on boot, it asks the Control Plane what its configuration should be, and from then on the Control Plane owns that configuration.
Deploying many Sidecars with automation? Skip the per-Sidecar token: Service Accounts lets each one authenticate with its Kubernetes or Google service account, and the Control Plane creates it on the first handshake.

The handshake

Four properties fall out of this shape, and they are the reason it looks like this:
  • No session to maintain. The Sidecar loads its configuration into memory and keeps running. A Control Plane that goes down does not take running Sidecars with it. A listener using require_review is the exception: it files each held statement with the Control Plane, and denies that statement while the Control Plane is unreachable.
  • The token is the authentication. There is no second credential and no certificate exchange. A Sidecar can use a service account instead of a token, never both.
  • Ordinary HTTP. A plain request and a plain response. Nothing is tunnelled and nothing bidirectional stays open.
  • Neither side knows the other’s physical address. The Sidecar dials out; the Control Plane never dials in. No inbound firewall rule, no NAT traversal.

Steps

1

Issue a token in the Control Plane

Create a Sidecar registration and copy the token it returns. It is shown once and stored only as a hash, so losing it means registering a new Sidecar.The token identifies this Sidecar and authenticates it — treat it as a credential.
2

Point the Sidecar at the Control Plane

Add the Control Plane’s URL to the Sidecar’s config file. The token is never written to disk — it goes on the command line or in an environment variable:
config.yaml
Or supply both through the environment, which is the shape a Kubernetes deployment wants — mount the secret, set the variables, pass no arguments:
3

Start it

On the first start the Control Plane holds no configuration for this Sidecar. It answers 412, the Sidecar imports the document from your local file, and then serves what the Control Plane sends back. That import happens once.
4

Edit the configuration in the Control Plane from now on

The Control Plane owns the whole document after the import — listeners included. The two are never merged. Listeners left in the local file are ignored, and the Sidecar says so at startup:
--config becomes optional at this point. The URL and the token are enough to start.
5

Confirm what it resolved

The admin API reports the live configuration. It only runs when the configuration names an address for it, so the document the Control Plane serves needs an admin block — there is no default port:
The Sidecar should also appear in the Control Plane’s list, with a recent check-in.

The license

The organization’s license lives on the Control Plane, not on each Sidecar. It rides on the handshake response, and the response carries a header saying the Control Plane owns the decision:
While that header is present, the Sidecar’s own license sources — the --license flag, HOOP_LICENSE and the config file’s license key — are ignored, and it warns at startup that it is ignoring them. A Control Plane whose organization holds no license runs the free tier. A license key authored on a Sidecar’s configuration in the Control Plane is refused. One organization, one license.

Staying in sync

A heartbeat repeats the handshake every minute. A change that only touches rules — guardrails, masking, PII, OPA, a listener’s analyzer block — is applied in place and logged as control plane configuration applied. Connections already open drain under the rules they were accepted with. A change beyond the rules — listeners, audit, admin, log level — logs restart to apply it instead. A failed heartbeat changes nothing. The Sidecar keeps serving the configuration and the license it last received. Reviews do not ride on the heartbeat. A listener using require_review calls the Control Plane once per held statement, and denies the statement when that call fails.

Upgrading

Upgrade the Control Plane first, then the Sidecars. A Sidecar refuses the whole configuration when one key in it is unknown to its version. From 1.210.0 the Control Plane knows what each Sidecar can read:
  • It sends only the settings an admin set. Upgrading the Control Plane alone changes nothing an older Sidecar receives.
  • A save that uses a setting, a rule type or a protocol that a connected Sidecar’s version lacks is refused with 422. The error names the Sidecar and the upgrade it needs. A Sidecar that never connected is checked at its first handshake instead.
  • This covers every Sidecar from 1.162.0.
A Sidecar newer than its Control Plane runs, but cannot use a setting the Control Plane does not know. Its first import fails when its config file uses such a setting, and the Sidecar does not start. Do not roll the Control Plane back below a setting a stored configuration uses: the Control Plane then answers 500 to that Sidecar. When a Sidecar refuses a configuration anyway: The Sidecar page in the Control Plane shows the state, the Sidecar’s version and the reason until a configuration applies. Not applied for longer than a few minutes means the Sidecar is restarting in a loop. Escape hatch. An admin can hand the Sidecar back to its own config file:
The Control Plane then sends only that flag and the license, and the Sidecar runs the config file it was started with. The switch deletes the Control Plane rules imported from this Sidecar that nothing else uses, and unbinds the rest. Send {"configuration": {"load_from_disk": false}} alone to hand it back: the stored configuration is cleared, and the Sidecar imports its config file again.

Troubleshooting


Next

Control Plane

What it manages and why the protocol is this simple.

Install the Control Plane

Docker Compose, Kubernetes and AWS.

Config File Reference

Every source for control_plane_url and the credential, in precedence order.

Service Accounts

No token per Sidecar: one entry per cluster, Sidecars created on first contact.