This site is being rebuilt and some pages are out of date. For current details, write to reach@inorbit.hr. This notice goes away when the rebuild is done.

No analytics unless you allow it, no tracking. This site keeps in your browser the language you pick, the theme, its colour, which site you chose, the currency on the pricing page and that you closed this notice; signing in adds session cookies. The legal page has the details.

Sign in

← Back to Platform

RFC 0029open2026-10-03

The agent, a data plane in your own network

A program a company runs in its own network that dials out and runs checks, load and faults there, under a local policy that wins, with secrets that stay in the company.

Problem

Connections (RFC 0018) name where each call starts: our cloud, or a data plane inside a company's network. Our cloud can only reach what is public, and should only test what its owner has proved is theirs (RFC 0030). Everything an engineer actually worries about, the database behind the API, the queue, the internal service, the node on a private network, is out of its reach. Reaching it needs a program on their side.

Such a program is asked harder questions than a website. Before it is allowed into a production network, a security team wants to know:

  1. What exactly is this binary? Who built it, from which source, with which dependencies, and which known vulnerabilities affect it. The EU Cyber Resilience Act turns most of that into an obligation for software sold in the EU: reporting actively exploited vulnerabilities applies since 2026-09-11, the rest from 2027-12-11 (Regulation (EU) 2024/2847).
  2. Can we host it ourselves? Many companies install nothing from the internet; every image and package comes through their own registry.
  3. What can it do, and who decides? Not the vendor's console alone.
  4. Where do our secrets go? Ideally nowhere.
  5. When does it change? When they say so.

And the people who run it want it not to be another afternoon of configuration.

Proposal

The agent is one program, iohr-agent, built from public source in the inorbithr/dataplane repository. A company runs it as a container in its cluster, as a service on a machine, or on a laptop through iohr agent (RFC 0028). It is the data-plane executor of connections: the console decides what should happen, the agent does it where the systems are, and reports what happened.

It only dials out

The agent opens one connection to the platform's API host over HTTPS and keeps it open; the platform sends work down it and results come back up. Nothing listens for the internet on the company's side, so there is no inbound firewall rule to request. When the connection drops, work stops and nothing new starts until it is back.

A diagram is drawn here in the RFCs product; this page does not show diagrams yet.

Enrollment and identity

  • A person creates an enrollment in the console (or iohr agent enroll): a one-time token, valid for an hour, bound to their account and an environment name such as staging.
  • The agent presents it once, makes its own key pair on the machine, and receives a short-lived certificate in exchange. It renews the certificate itself; no long-lived secret sits on disk after enrollment.
  • An agent can be revoked in the console and is cut off within seconds, as tokens are (RFC 0016). Companies that run SPIFFE can give it a workload identity of their own (SPIFFE) instead.

A diagram is drawn here in the RFCs product; this page does not show diagrams yet.

Bound to verified domains

An agent serves the domains its account has proved (RFC 0030). Enrolling one, in the console's wizard or with iohr agent enroll, names the verified domains it is for; the domain wizard leads straight into it. Before the agent acts on a named host, the platform confirms the name is inside one of those domains and that the domain is still verified, and the agent checks the same against the list it was given. A domain that stops being verified stops the agent's work on it within a day. Addresses with no public name, such as a bare private address or db.internal, cannot be proved by DNS; the agent reaches them only when its local policy names them.

The local policy always wins

The agent reads a policy file that lives with it, owned by the company:

  • which networks and hosts it may reach, which is the allowlist RFC 0018 says replaces our address rules on a data plane;
  • which kinds of work it may do (checks, load, which faults), with ceilings on rates, durations and concurrency;
  • which environments it serves, so a staging agent cannot be pointed at production.

Anything the console asks for outside the policy is refused by the agent and the refusal is shown in the console. The console can propose a policy change; only a person with access to the agent's machine applies it.

Credentials stay in the company

For connections the agent runs, the console holds a reference, never a secret: a path in the company's own secret store (HashiCorp Vault, , a cloud secret manager, an environment variable). The agent resolves it at the moment of the call and forgets it after. Our vault (RFC 0018) remains for connections our cloud runs.

A small local admin page

On its own machine the agent serves a read-only page, reachable only from there or from the cluster: is it connected, which policy is loaded, what has it done in the last day, what has it sent to the platform (counts and kinds, never content), and how to stop it. The same facts are a command (iohr agent status).

Configuration is generated, not written

iohr agent init asks what it needs (environment, which services to reach, which secret store), writes the policy and the configuration, and sends them to the platform to be checked before the agent starts, the way the chaos tool checks a scenario today. Nothing starts on a configuration that fails the check.

Observable in the company's own tools

The agent exports its own traces, metrics and logs over OpenTelemetry to the company's collector, so it shows up where their other services do (OpenTelemetry). What it sends to us is the results of the work it was given: timings, status codes, counts and verdicts, never request or response bodies.

Releases a security team can verify

What How
Format OCI first: a container image and a chart in a registry, mirrored by the company if it likes; then a static binary as .deb and .rpm with a unit
Signatures made without long-lived keys by the release workflow's identity (Sigstore cosign), checkable by a cluster's admission policy
Provenance SLSA build level 3 (SLSA)
Contents an SBOM per artifact (CycloneDX) and a statement of which known vulnerabilities affect it (OpenVEX)
Advisories published in a machine-readable format (CSAF)
Support the same policy as the SDKs: before 1.0 the latest release; from 1.0 security fixes for each major for at least five years

The laptop channels the command line uses (Homebrew, winget, an installer) are not the agent's; on a laptop it arrives as an extension.

Updates when the company says so

Each agent follows a channel (stable, fast) or a pinned version. The console shows which agents are behind and which advisories affect them. An upgrade happens when a person approves it, in a window they set, or never on its own if the company says so. The previous version is kept for a rollback.

What it does, in order

  1. Checks on the services it may reach: the surfaces the chaos tool checks today (REST, gRPC, server-sent events, WebSocket, MQTT, GraphQL, MCP), including the security probes (RFC 0031).
  2. Load, open loop, within the policy's ceilings.
  3. Faults through a proxy: a service is routed through the agent, which adds latency, errors and dropped connections on command, with a budget and an expiry. No root access, no kernel modules.
  4. in namespaces the policy names: restart a pod, shift capacity.
  5. Later, and only with evidence it is needed, deeper faults below the application.

Alternatives considered

Only test from our cloud. No program to install, and blind to everything that is not public, which is most of what fails.

An agent that listens for us. Easier to build and a firewall exception every security team has to approve. Dialing out avoids the question.

Our vault holds every secret and sends it to the agent. One place to manage, and every secret crosses the company's boundary. Keeping them where they are is what a bank asks first.

Fault injection through the kernel first. More realistic faults, and root access on production machines from day one. The proxy proves the value without asking for it.

Ship it like the command line, through Homebrew and winget. The right channels for a laptop tool; the agent runs on servers, where images, charts and system packages are what a platform team installs.

Decision

Open. Proposed: one agent that dials out, enrolls once into short-lived certificates, obeys a local policy that wins over the console, reads credentials from the company's own secret store, reports results and never content, exports its own telemetry, and ships as signed OCI artifacts with provenance, SBOM, vulnerability statements and advisories, updated only when the company approves.

Publication

The repository carries the source, the security policy and the release verification guide. The developer docs gain an agent section: install with , as a package or as an extension; the policy reference; verifying a release; what the agent sends. The console gains Agents under Reliability (RFC 0031).

Status log

  • 2026-10-03: opened, as the data-plane executor RFC 0018 names, with RFC 0028 (extensions), 0030 (domains) and 0031 (reliability in the console).
  • 2026-10-03: an agent is bound at enrollment to verified domains (RFC 0030) and acts on named hosts only inside them; unnamed private addresses need the local policy.
  • 2026-10-03: the first agent is built in inorbithr/dataplane (pull request open, not released). It covers enrollment, the outbound session, the local policy on every job, checks over HTTP, TCP, TLS and gRPC health, and secret references for Vault, , environment variables and files. It also ships the admin page, OpenTelemetry export, the image, chart and system packages, and the extension artifact. Two points differ from the proposal above. Identity is not a certificate: the agent signs short-lived assertions with its own key and receives 15-minute access tokens, and the key is EC P-256 because our identity provider accepts no Ed25519 assertions. Provenance reaches SLSA build level 2 for now: level 3 needs a separate build workflow that iohr must also accept as a signer.
  • 2026-10-03: the control plane is built (agents service, docs/agents/README.md). Enrollment is a one-time token (an hour, kept as its SHA-256) bound to verified domains; the agent's identity is an OAuth 2.0 client authenticating with a key made on its machine (private_key_jwt, ES256: the identity provider refuses Ed25519 assertions) and fifteen-minute access tokens, in place of a certificate. The session is a WebSocket at /v1/agents/session, which the gateway bridges to a gRPC stream of the agents service, so services keep speaking gRPC only. Revoking closes the session within a second and deletes the client. The console gains Agents with an enroll wizard and a check run through an agent; jobs to named hosts outside the agent's verified domains are refused before they are sent.
  • 2026-10-03: the public writes honour Idempotency-Key (RFC 0033). Revoking an agent and running a check happen once per key, so a retried check sends no second job. Making an enrollment does not, because its answer is a one-time token that is never stored; enrolling does not either, because that route has no verified caller.
  • 2026-10-07: Checked: the control plane (#145) runs in agents at dab02d1a; the agent ships from inorbithr/dataplane, releases not checked here. Step 4, which RFC 0074.5 waits on, is not built. Open.
  • 2026-10-08: RFC 0100 (the console in the agent, licensed features) proposes that the agent serve the whole console, with writes, and act as its own control plane when there is no platform. This RFC's small, read-only local page and "the console decides, the agent does" are marked for the owner's decision (RFC 0100, D1); unchanged until then.

This document mentions

Mentioned in

← Back to Platform