92 lines
5.4 KiB
Markdown
92 lines
5.4 KiB
Markdown
# Authority Revocation Bundle
|
|
|
|
The Authority service exports revocation information as an offline-friendly JSON document plus a detached JWS signature. Operators can mirror the bundle alongside Concelier exports to ensure air-gapped scanners receive the latest token, subject, and client revocations.
|
|
|
|
## File layout
|
|
|
|
| Artefact | Description |
|
|
| --- | --- |
|
|
| `revocation-bundle.json` | Canonical JSON document describing revoked entities. Validates against [`etc/authority/revocation_bundle.schema.json`](../../etc/authority/revocation_bundle.schema.json). |
|
|
| `revocation-bundle.json.jws` | Detached JWS signature covering the exact UTF-8 bytes of `revocation-bundle.json`. |
|
|
| `revocation-bundle.json.sha256` | Hex-encoded SHA-256 digest used by mirror automation (optional but recommended). |
|
|
|
|
All hashes and signatures are generated after applying the deterministic formatting rules below.
|
|
|
|
## Deterministic formatting rules
|
|
|
|
- JSON is serialised with UTF-8 encoding, 2-space indentation, and lexicographically sorted object keys.
|
|
- Arrays are sorted by deterministic keys:
|
|
- Top-level `revocations` sorted by (`category`, `id`, `revokedAt`).
|
|
- Nested arrays (`scopes`) sorted ascending, unique enforced.
|
|
- Numeric values (`sequence`) are emitted without leading zeros.
|
|
- Timestamps use UTC ISO-8601 format with `Z` suffix.
|
|
|
|
Consumers MUST treat the combination of `schemaVersion` and `sequence` as a monotonic feed. Bundles with older `sequence` values are ignored unless `bundleId` differs and `issuedAt` is newer (supporting replay detection).
|
|
|
|
## Revocation entry categories
|
|
|
|
| Category | Description | Required fields |
|
|
| --- | --- | --- |
|
|
| `token` | A single OAuth token (access, refresh, device, authorization code). | `tokenType`, `clientId`, `revokedAt`, optional `subjectId` |
|
|
| `subject` | All credentials issued to a subject (user/service account). | `subjectId`, `revokedAt` |
|
|
| `client` | Entire OAuth client registration is revoked. | `clientId`, `revokedAt` |
|
|
| `key` | Signing/encryption key material revoked. | `id`, `revokedAt` |
|
|
|
|
`reason` is a machine-friendly code (`compromised`, `rotation`, `policy`, `lifecycle`, etc). `reasonDescription` may include a short operator note.
|
|
|
|
## Detached JWS workflow
|
|
|
|
1. Serialise `revocation-bundle.json` using the deterministic rules.
|
|
2. Compute SHA-256 digest; write to `revocation-bundle.json.sha256`.
|
|
3. Sign using ES256 (default) with the configured Authority signing key. The JWS header uses:
|
|
```json
|
|
{
|
|
"alg": "ES256",
|
|
"kid": "{signingKeyId}",
|
|
"provider": "{providerName}",
|
|
"typ": "application/vnd.stellaops.revocation-bundle+jws",
|
|
"b64": false,
|
|
"crit": ["b64"]
|
|
}
|
|
```
|
|
4. Persist the detached signature payload to `revocation-bundle.json.jws` (per RFC 7797).
|
|
|
|
Verification steps:
|
|
|
|
1. Validate `revocation-bundle.json` against the schema.
|
|
2. Re-compute SHA-256 and compare with `.sha256` (if present).
|
|
3. Resolve the signing key from JWKS (`/.well-known/jwks.json`) or the offline key bundle, preferring the provider declared in the JWS header (`provider` falls back to `default`).
|
|
4. Verify the detached JWS using the resolved provider. The CLI mirrors Authority resolution, so builds compiled with `StellaOpsCryptoSodium=true` automatically use the libsodium provider when advertised; otherwise verification downgrades to the managed fallback.
|
|
|
|
### CLI verification workflow
|
|
|
|
Use the bundled CLI command before distributing a bundle:
|
|
|
|
```bash
|
|
stellaops auth revoke verify \
|
|
--bundle artifacts/revocation-bundle.json \
|
|
--signature artifacts/revocation-bundle.json.jws \
|
|
--key etc/authority/signing/authority-public.pem \
|
|
--verbose
|
|
```
|
|
|
|
The verifier performs three checks:
|
|
|
|
1. Prints the computed digest in `sha256:<hex>` format. Compare it with the exported `.sha256` artefact.
|
|
2. Confirms the detached JWS header advertises `b64: false`, captures the provider hint, and that the algorithm matches the Authority configuration (ES256 unless overridden).
|
|
3. Registers the supplied PEM key with the crypto provider registry and validates the signature (falling back to the managed provider when the hinted provider is unavailable).
|
|
|
|
A zero exit code means the bundle is ready for mirroring/import. Non-zero codes signal missing arguments, malformed JWS payloads, or signature mismatches; regenerate or re-sign the bundle before distribution.
|
|
|
|
## Example
|
|
|
|
The repository contains an [example bundle](revocation-bundle-example.json) demonstrating a mixed export of token, subject, and client revocations. Use it as a reference for integration tests and tooling.
|
|
|
|
## Operations Quick Reference
|
|
|
|
- `stella auth revoke export` emits a canonical JSON bundle, `.sha256` digest, and detached JWS signature in one command. Use `--output` to write into your mirror staging directory.
|
|
- `stella auth revoke verify` validates a bundle using cached JWKS or an offline PEM key, honours the `provider` metadata embedded in the signature, and reports digest mismatches before distribution.
|
|
- `POST /internal/revocations/export` provides the same payload for orchestrators that already talk to the bootstrap API.
|
|
- `POST /internal/signing/rotate` rotates JWKS material without downtime; always export a fresh bundle afterward so downstream mirrors receive signatures from the new `kid`.
|
|
- Offline Kit automation should mirror `revocation-bundle.json*` alongside Concelier exports so agents ingest revocations during the same sync pass.
|