Files
git.stella-ops.org/docs/security/revocation-bundle.md
Vladimir Moushkov ea1106ce7c up
2025-10-15 10:03:56 +03:00

5.3 KiB

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 Feedser 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.
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:
    {
      "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:

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 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 Feedser exports so agents ingest revocations during the same sync pass.