Skip to content

Brownfield APIs

Most APIs worth protecting already exist, and in an API-key world onboarding a new partner to one of them usually means a config/secret change and a deploy. TrustPlane Auth makes that a data change instead: you onboard a brand-new caller to a protected route by publishing trust material — without rebuilding or redeploying the adapter, and with no hosted service.

This is the property that makes TrustPlane Auth operationally cheap: trust is data, not code.

flowchart LR
  K["New client: gen-key"] --> M["bundle merge-source<br/>(append key + source rule)"]
  M --> P["Publish/mount merged bundles"]
  P --> R["Adapter reloads bundle"]
  R --> OK["New client's signed GET /orders allowed"]
  style M fill:#1f2937,stroke:#818cf8,color:#fff

The adapter image, Deployment, and Service all stay exactly the same. Only the bundle changes.

Step 1 — Generate the new client’s key

Section titled “Step 1 — Generate the new client’s key”
Terminal window
trustplane gen-key
# keep the private key on the client; share only the PUBLIC key (base64url)

Step 2 — Merge the new client into existing bundles

Section titled “Step 2 — Merge the new client into existing bundles”

trustplane bundle merge-source appends the new public key to your trust material and a matching source rule to the route — preserving everything already there:

Terminal window
trustplane bundle merge-source \
--trust-material trust-material.json \
--policy-bundle trustplane.bundle.json \
--out-trust-material trust-material.merged.json \
--out-policy-bundle trustplane.bundle.merged.json \
--issuer https://issuer.acme.demo/external-jwks \
--trust-domain acme.demo.external \
--kid hosted-demo-client-2 \
--public-key "$CLIENT_PUBLIC_KEY_B64URL" \
--route-id acme.demo.orders.read \
--subject-exact external:jwks:hosted-demo-client-2 \
--required-key-binding software
  • Existing issuers, keys, routes, and sources are preserved by default.
  • A duplicate kid or matching selector is rejected unless you pass --replace-existing.
  • The command writes full merged bundle files you can review before publishing.

Step 3 — Verify the “before” state denies

Section titled “Step 3 — Verify the “before” state denies”

Before publishing, the new client’s key is unknown, so the adapter denies it. With the local adapter this is source_*_mismatch or an unknown-key denial.

Step 4 — Publish or mount the merged bundles

Section titled “Step 4 — Publish or mount the merged bundles”
  • Locally: point the adapter at the merged files (or replace the mounted files); the adapter reads fresh bundle material on reload.
  • Deployed adapter: refresh the mounted signed bundle objects through your reviewed deployment process, then roll or signal the adapter so the projected files are re-read — without changing the adapter image. See Bundle refresh and key lifecycle.

Step 5 — Verify the “after” state allows

Section titled “Step 5 — Verify the “after” state allows”

The new client signs GET /orders with its key and the adapter now allows it. Replay, tampered path, wrong audience, and wrong route still deny.

  • Append-only by default. Destructive replacement is an explicit --replace-existing.
  • Local removal exists. Use trustplane bundle remove-source with --confirm-remove to remove a trusted key and matching route source selector while preserving unrelated entries.
  • Local revocation metadata is optional. Add --revoke when you want the reviewed output to append local revocation metadata for the removed key/source. Managed hosted revocation is future TrustPlane Control work.
  • No persistent principal is created. This is policy-based acceptance, not enrollment; persistent principals, approvals, and managed revocation are out of scope for this runtime.