Security model
When you evaluate an authorization system, the question that matters is: what happens when something is stolen? This page walks through the TrustPlane Auth security model threat by threat — stolen passports, stolen keys, on-host compromise, stale revocation material — and is careful to say exactly what each configuration proves and, just as importantly, what it does not prove. Overclaiming security is itself a vulnerability.
The security model
Section titled “The security model”A passport is engineered to be low-value if stolen. Every acceptance decision layers short expiry, request binding, atomic replay consume, and audience/route/source scoping, so a stolen artifact buys an attacker almost nothing:
flowchart TD
S["Attacker steals a passport + proof"] --> Q1{"Still within<br/>its short exp?"}
Q1 -- no --> D1["Denied: expired"]
Q1 -- yes --> Q2{"Replaying the<br/>exact same request?"}
Q2 -- "different request" --> D2["Denied: request_binding_mismatch"]
Q2 -- "same request" --> Q3{"jti already<br/>consumed?"}
Q3 -- yes --> D3["Denied: jti_replay"]
Q3 -- no --> Q4{"Right audience<br/>+ route + source?"}
Q4 -- no --> D4["Denied: source/audience mismatch"]
Q4 -- yes --> A["A tiny window for the<br/>identical request only"]
The residual risk of a stolen passport is: re-sending the identical request, to the identical
audience, within a few seconds, before the legitimate caller’s jti is consumed. That is a
dramatically smaller blast radius than a long-lived API key.
Threat coverage: the key-theft and RAT acceptance matrix
Section titled “Threat coverage: the key-theft and RAT acceptance matrix”TrustPlane Auth uses a precise acceptance matrix. The claim is deliberately exact:
| Scenario | TrustPlane behavior |
|---|---|
| Stolen software key | Attacker can sign — software only proves possession. Mitigated by short expiry, audience/route scoping, and replay, not prevented. |
| Stolen hardware_local / attested_workload key | Off-host key reuse is prevented — the key is non-exportable / bound to an attested workload. |
| Stolen passport (replay) | Blocked by request binding + atomic replay consume. |
| On-host RAT invoking the local broker | Detected/limited via provenance, local policy, audit, and revocation freshness — not claimed to be impossible while the host is fully compromised and the signer is present. |
| Stale bundle after revocation | High-risk routes fail closed on stale material. |
| Insufficient signer class | Denied with insufficient_key_binding. |
The honest version: TrustPlane prevents off-host key reuse only for
hardware_localandattested_workload; it blocks stolen-passport replay via binding + atomic replay; and it detects/limits an on-host RAT through provenance, policy, audit, and freshness. It does not claim a fully compromised host can never invoke a present local signer.
Trust-anchor source tiers
Section titled “Trust-anchor source tiers”Different identity sources prove different things. The frozen source-tier matrix:
| Tier | Policy shape | Proves | Does not prove |
|---|---|---|---|
| Software / JWKS | issuer key + required_key_binding: software |
The passport+proof were signed by a configured software key for an allowed issuer/domain/subject/route/audience | No export resistance, attestation, hardware binding, or cloud-instance proof |
| OIDC / JWKS | OIDC/JWT issuer key + allowed route source | Request came through a configured issuer/key matching route policy | No principal record, no non-portability proof, no K8s/hardware attestation |
Kubernetes SPIFFE/SPIRE attested_workload |
SPIFFE allow policy + required_key_binding: attested_workload via broker profile trustplane-spiffe-spire-k8s-v1 |
Broker verified an X.509-SVID workload identity before issuance; verifier trusts the broker issuer key | Verifier does not re-verify the SVID per request; broker signing key is not claimed hardware/enclave-backed |
| EC2 / Droplet software source | non-K8s issuer + subject prefix (e.g. aws:ec2:us-east-1:) + software |
Non-K8s callers accepted without API keys when policy matches | No AWS IID, Nitro, TPM, enclave, IAM, or SPIRE-on-VM attestation — it is a software source |
| AWS IID / Nitro / hardware / KMS | Not currently supported (not in v0.1) | (planned) stronger attested key custody | Don’t claim these from today’s software/JWKS/EC2 rules |
How attested_workload actually works
Section titled “How attested_workload actually works”sequenceDiagram participant W as Workload pod participant SP as SPIRE Workload API participant B as Broker (sidecar) participant A as Adapter (verifier) participant T as Trust bundle W->>B: Ask for a passport (over pod-local Unix socket) B->>SP: Fetch + verify X.509-SVID (WorkloadIdentitySource) SP-->>B: Valid SVID for spiffe://.../sa/orders-caller Note over B: Identity attested → issue attested_workload passport B-->>W: Passport + transcript-v1 proof W->>A: GET /orders + passport + proof A->>T: Trust the broker issuer key (from bundle) Note over A: Verifier trusts the broker issuer key Note over A: The broker is the attestation authority A-->>W: allow / deny
The crucial subtlety: the broker is the attestation authority. It verifies the SVID once,
at issuance, and the verifier trusts the broker’s issuer key from the bundle.
attested_workload means “workload identity was verified via SVID before issuance” — not
that the broker’s signing key is hardware-backed or non-exportable.
Fail closed by default
Section titled “Fail closed by default”High-risk routes deny on stale bundle / revocation material. Offline behavior is per-route
(freshness_class), never a blanket “fail static.” Multi-replica deployments must use Redis
for replay state — the Helm chart literally refuses to render multi-replica without it.
Replay safety as an ordering property
Section titled “Replay safety as an ordering property”As covered in How it works: all policy checks (route, source,
freshness, provenance/context) run before the replay Consume. An attacker therefore cannot
burn a victim’s one-time jti by spraying unauthorized requests — replay state is only consumed
on an otherwise-valid presentation.
Harden your deployment
Section titled “Harden your deployment”- Verifiers only ever hold public keys. Private keys stay with the issuer/broker/KMS.
- Keep credentials, private keys, live bundle contents, and signed request logs out of git, generated artifacts, command logs, and public documentation.
- Runtime hardening defaults such as non-root images, read-only filesystems, and read-only bundle mounts are covered in the deployment overview.
Next steps
Section titled “Next steps”- See how the standards posture preserves these guarantees in Standards alignment.
- See where OAuth fits without weakening the caller-side contract in OAuth and backend compatibility.