Skip to content

Bundle refresh

Adding or removing a client shouldn’t mean rebuilding infrastructure. Bundle refresh is the runtime counterpart of Add a client without redeploying: a running adapter picks up new signed trust material and signed policy without an image rebuild, upstream change, or adapter code change.

flowchart LR
  subgraph Deploy["Deployment path"]
    D["adapter Deployment / Service / NetworkPolicy"]
  end
  subgraph Refresh["Bundle refresh path"]
    R["signed trust + policy bundle objects"]
  end
  D -->|"owns runtime resources"| K["adapter"]
  R -->|"owns trust/policy material + refresh signal"| K

The deployment path owns runtime resources. The refresh path owns bundle material and the refresh signal that makes the adapter read new mounted files. Keeping them separate avoids accidental infrastructure changes during a trust update.

  1. Validate trust material and policy bundle shape.
  2. Verify signatures with the configured bundle-signing public key.
  3. Review the diff for route, issuer, key, source, freshness, and signer-class changes.
  4. Preserve unrelated issuer/key/source entries unless an explicit removal is intended.
  5. Update only the mounted bundle objects.
  6. Trigger an adapter refresh or rollout so the projected files are read again.

It should not change the adapter image, containers, volumes, replicas, Service, upstream, networking, broker configuration, or cloud infrastructure.

trustplane bundle merge-source appends a client public key to trust material and a matching source rule to the selected route:

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 \
--source-type oidc_jwks \
--issuer https://issuer.example.com/external-jwks \
--trust-domain example.external \
--kid example-client-2 \
--public-key "$CLIENT_PUBLIC_KEY_B64URL" \
--route-id example.orders.read \
--subject-exact external:jwks:example-client-2 \
--required-key-binding software

Then sign the merged outputs before using them with adapter signature enforcement:

Terminal window
trustplane bundle sign \
--trust-material trust-material.merged.json \
--out trust-material.merged.signed.json \
--signer-issuer local://bundle-signer \
--kid bundle-signing-key-1 \
--private-key "$BUNDLE_SIGNING_PRIVATE_KEY_B64URL"
trustplane bundle sign \
--policy-bundle trustplane.bundle.merged.json \
--out trustplane.bundle.merged.signed.json \
--signer-issuer local://bundle-signer \
--kid bundle-signing-key-1 \
--private-key "$BUNDLE_SIGNING_PRIVATE_KEY_B64URL"

trustplane bundle remove-source removes a trusted key and matching route source selector while preserving unrelated trust material and route policy. Because removal is destructive, it requires explicit confirmation:

Terminal window
trustplane bundle remove-source \
--trust-material trust-material.json \
--policy-bundle trustplane.bundle.json \
--out-trust-material trust-material.removed.json \
--out-policy-bundle trustplane.bundle.removed.json \
--issuer https://issuer.example.com/external-jwks \
--trust-domain example.external \
--kid example-client-2 \
--route-id example.orders.read \
--subject-exact external:jwks:example-client-2 \
--confirm-remove \
--revoke

--revoke appends local revocation metadata for the removed key/source. Denial takes effect when you refresh the adapter with the replacement signed bundle. This does not add a hosted revocation workflow, database, approval system, or managed distribution service.

Step Expected
Unknown client key before publish deny
Publish reviewed, signed trust material and policy new client accepted, no image rebuild
Signed business request after publish allow
Duplicate replay deny (jti_replay)
Tampered path deny (request_binding_mismatch)
Wrong audience deny
Wrong route deny
Removed source after refresh deny
  • realtime routes require a current bundle view and fail closed when the mounted file view is stale or unknown.
  • bounded routes allow a known bundle age up to max_staleness_seconds, then fail closed.
  • offline-ok routes explicitly allow stale/offline bundle use for lower-risk cases.