Resolve Concelier/Excititor merge conflicts
This commit is contained in:
@@ -1,106 +1,106 @@
|
||||
# Authority Threat Model (STRIDE)
|
||||
|
||||
> Prepared by Security Guild — 2025-10-12. Scope covers Authority host, Standard plug-in, CLI, bootstrap workflow, and offline revocation distribution.
|
||||
|
||||
## 1. Scope & Method
|
||||
|
||||
- Methodology: STRIDE applied to primary Authority surfaces (token issuance, bootstrap, revocation, operator tooling, plug-in extensibility).
|
||||
- Assets in scope: identity credentials, OAuth tokens (access/refresh), bootstrap invites, revocation manifests, signing keys, audit telemetry.
|
||||
- Out of scope: Third-party IdPs federated via OpenIddict (tracked separately in SEC6 backlog).
|
||||
|
||||
## 2. Assets & Entry Points
|
||||
|
||||
| Asset / Surface | Description | Primary Actors |
|
||||
|-----------------|-------------|----------------|
|
||||
| Token issuance APIs (`/token`, `/authorize`) | OAuth/OIDC endpoints mediated by OpenIddict | CLI, UI, automation agents |
|
||||
| Bootstrap channel | Initial admin invite + bootstrap CLI workflow | Platform operators |
|
||||
| Revocation bundle | Offline JSON + detached JWS consumed by agents | Feedser, Agents, Zastava |
|
||||
| Plug-in manifests | Standard plug-in configuration and password policy overrides | Operators, DevOps |
|
||||
| Signing keys | ES256 signing keys backing tokens and revocation manifests | Security Guild, HSM/KeyOps |
|
||||
| Audit telemetry | Structured login/audit stream persisted to Mongo/observability stack | SOC, SecOps |
|
||||
|
||||
## 3. Trust Boundaries
|
||||
|
||||
| Boundary | Rationale | Controls |
|
||||
|----------|-----------|----------|
|
||||
| TB1 — Public network ↔️ Authority ingress | Internet/extranet exposure for `/token`, `/authorize`, `/bootstrap` | TLS 1.3, reverse proxy ACLs, rate limiting (SEC3.A / CORE8.RL) |
|
||||
| TB2 — Authority host ↔️ Mongo storage | Credential store, revocation state, audit log persistence | Authenticated Mongo, network segmentation, deterministic serializers |
|
||||
| TB3 — Authority host ↔️ Plug-in sandbox | Plug-ins may override password policy and bootstrap flows | Code signing, manifest validation, restart-time loading only |
|
||||
| TB4 — Operator workstation ↔️ CLI | CLI holds bootstrap secrets and revocation bundles | OS keychain storage, MFA on workstations, offline kit checksum |
|
||||
| TB5 — Authority ↔️ Downstream agents | Revocation bundle consumption, token validation | Mutual TLS (planned), detached JWS signatures, bundle freshness checks |
|
||||
|
||||
## 4. Data Flow Diagrams
|
||||
|
||||
### 4.1 Runtime token issuance
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Client Tier
|
||||
CLI[StellaOps CLI]
|
||||
UI[UI / Automation]
|
||||
end
|
||||
subgraph Perimeter
|
||||
RP[Reverse Proxy / WAF]
|
||||
end
|
||||
subgraph Authority
|
||||
AUTH[Authority Host]
|
||||
PLGIN[Standard Plug-in]
|
||||
STORE[(Mongo Credential Store)]
|
||||
end
|
||||
CLI -->|OAuth password / client creds| RP --> AUTH
|
||||
UI -->|OAuth flows| RP
|
||||
AUTH -->|PasswordHashOptions + Secrets| PLGIN
|
||||
AUTH -->|Verify / Persist hashes| STORE
|
||||
STORE -->|Rehash needed| AUTH
|
||||
AUTH -->|Access / refresh token| RP --> Client Tier
|
||||
```
|
||||
|
||||
### 4.2 Bootstrap & revocation
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Operator
|
||||
OPS[Operator Workstation]
|
||||
end
|
||||
subgraph Authority
|
||||
AUTH[Authority Host]
|
||||
STORE[(Mongo)]
|
||||
end
|
||||
subgraph Distribution
|
||||
OFFKIT[Offline Kit Bundle]
|
||||
AGENT[Authorized Agent / Feedser]
|
||||
end
|
||||
OPS -->|Bootstrap CLI (`stellaops auth bootstrap`)| AUTH
|
||||
AUTH -->|One-time invite + Argon2 hash| STORE
|
||||
AUTH -->|Revocation export (`stellaops auth revoke export`)| OFFKIT
|
||||
OFFKIT -->|Signed JSON + .jws| AGENT
|
||||
AGENT -->|Revocation ACK / telemetry| AUTH
|
||||
```
|
||||
|
||||
## 5. STRIDE Analysis
|
||||
|
||||
| Threat | STRIDE Vector | Surface | Risk (L×I) | Existing Controls | Gaps / Actions | Owner |
|
||||
|--------|---------------|---------|------------|-------------------|----------------|-------|
|
||||
| Spoofed revocation bundle | Spoofing | TB5 — Authority ↔️ Agents | Med×High | Detached JWS signature (planned), offline kit checksums | Finalise signing key registry & verification script (SEC4.B/SEC4.HOST); add bundle freshness requirement | Security Guild (follow-up: **SEC5.B**) |
|
||||
| Parameter tampering on `/token` | Tampering | TB1 — Public ingress | Med×High | ASP.NET model validation, OpenIddict, rate limiter (CORE8.RL) | Tampered requests emit `authority.token.tamper` audit events (`request.tampered`, unexpected parameter names) correlating with `/token` outcomes (SEC5.C) | Security Guild + Authority Core (follow-up: **SEC5.C**) |
|
||||
| Bootstrap invite replay | Repudiation | TB4 — Operator CLI ↔️ Authority | Low×High | One-time bootstrap tokens, Argon2id hashing on creation | Invites expire automatically and emit audit events on consumption/expiration (SEC5.D) | Security Guild |
|
||||
| Token replay by stolen agent | Information Disclosure | TB5 | Med×High | Signed revocation bundles, device fingerprint heuristics, optional mTLS | Monitor revocation acknowledgement latency via Zastava and tune replay alerting thresholds | Security Guild + Zastava (follow-up: **SEC5.E**) |
|
||||
| Privilege escalation via plug-in override | Elevation of Privilege | TB3 — Plug-in sandbox | Med×High | Signed plug-ins, restart-only loading, configuration validation | Add static analysis on manifest overrides + runtime warning when policy weaker than host | Security Guild + DevOps (follow-up: **SEC5.F**) |
|
||||
| Offline bundle tampering | Tampering | Distribution | Low×High | SHA256 manifest, signed bundles (planned) | Add supply-chain attestation for Offline Kit, publish verification CLI in docs | Security Guild + Ops (follow-up: **SEC5.G**) |
|
||||
| Failure to log denied tokens | Repudiation | TB2 — Authority ↔️ Mongo | Med×Med | Serilog structured events (partial), Mongo persistence path (planned) | Finalise audit schema (SEC2.A) and ensure `/token` denies include subject/client/IP fields | Security Guild + Authority Core (follow-up: **SEC5.H**) |
|
||||
|
||||
Risk scoring uses qualitative scale (Low/Med/High) for likelihood × impact; mitigation priority follows High > Med > Low.
|
||||
|
||||
## 6. Follow-up Backlog Hooks
|
||||
|
||||
| Backlog ID | Linked Threat | Summary | Target Owners |
|
||||
|------------|---------------|---------|---------------|
|
||||
| SEC5.B | Spoofed revocation bundle | Complete libsodium/Core signing integration and ship revocation verification script. | Security Guild + Authority Core |
|
||||
| SEC5.C | Parameter tampering on `/token` | Finalise audit contract (`SEC2.A`) and add request tamper logging. | Security Guild + Authority Core |
|
||||
| SEC5.D | Bootstrap invite replay | Implement expiry enforcement + audit coverage for unused bootstrap invites. | Security Guild |
|
||||
| SEC5.E | Token replay by stolen agent | Coordinate Zastava alerting with the new device fingerprint heuristics and surface stale revocation acknowledgements. | Security Guild + Zastava |
|
||||
| SEC5.F | Plug-in override escalation | Static analysis of plug-in manifests; warn on weaker password policy overrides. | Security Guild + DevOps |
|
||||
| SEC5.G | Offline bundle tampering | Extend Offline Kit build to include attested manifest + verification CLI sample. | Security Guild + Ops |
|
||||
| SEC5.H | Failure to log denied tokens | Ensure audit persistence for all `/token` denials with correlation IDs. | Security Guild + Authority Core |
|
||||
|
||||
Update `src/StellaOps.Cryptography/TASKS.md` (Security Guild board) with the above backlog entries to satisfy SEC5.A exit criteria.
|
||||
# Authority Threat Model (STRIDE)
|
||||
|
||||
> Prepared by Security Guild — 2025-10-12. Scope covers Authority host, Standard plug-in, CLI, bootstrap workflow, and offline revocation distribution.
|
||||
|
||||
## 1. Scope & Method
|
||||
|
||||
- Methodology: STRIDE applied to primary Authority surfaces (token issuance, bootstrap, revocation, operator tooling, plug-in extensibility).
|
||||
- Assets in scope: identity credentials, OAuth tokens (access/refresh), bootstrap invites, revocation manifests, signing keys, audit telemetry.
|
||||
- Out of scope: Third-party IdPs federated via OpenIddict (tracked separately in SEC6 backlog).
|
||||
|
||||
## 2. Assets & Entry Points
|
||||
|
||||
| Asset / Surface | Description | Primary Actors |
|
||||
|-----------------|-------------|----------------|
|
||||
| Token issuance APIs (`/token`, `/authorize`) | OAuth/OIDC endpoints mediated by OpenIddict | CLI, UI, automation agents |
|
||||
| Bootstrap channel | Initial admin invite + bootstrap CLI workflow | Platform operators |
|
||||
| Revocation bundle | Offline JSON + detached JWS consumed by agents | Concelier, Agents, Zastava |
|
||||
| Plug-in manifests | Standard plug-in configuration and password policy overrides | Operators, DevOps |
|
||||
| Signing keys | ES256 signing keys backing tokens and revocation manifests | Security Guild, HSM/KeyOps |
|
||||
| Audit telemetry | Structured login/audit stream persisted to Mongo/observability stack | SOC, SecOps |
|
||||
|
||||
## 3. Trust Boundaries
|
||||
|
||||
| Boundary | Rationale | Controls |
|
||||
|----------|-----------|----------|
|
||||
| TB1 — Public network ↔️ Authority ingress | Internet/extranet exposure for `/token`, `/authorize`, `/bootstrap` | TLS 1.3, reverse proxy ACLs, rate limiting (SEC3.A / CORE8.RL) |
|
||||
| TB2 — Authority host ↔️ Mongo storage | Credential store, revocation state, audit log persistence | Authenticated Mongo, network segmentation, deterministic serializers |
|
||||
| TB3 — Authority host ↔️ Plug-in sandbox | Plug-ins may override password policy and bootstrap flows | Code signing, manifest validation, restart-time loading only |
|
||||
| TB4 — Operator workstation ↔️ CLI | CLI holds bootstrap secrets and revocation bundles | OS keychain storage, MFA on workstations, offline kit checksum |
|
||||
| TB5 — Authority ↔️ Downstream agents | Revocation bundle consumption, token validation | Mutual TLS (planned), detached JWS signatures, bundle freshness checks |
|
||||
|
||||
## 4. Data Flow Diagrams
|
||||
|
||||
### 4.1 Runtime token issuance
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Client Tier
|
||||
CLI[StellaOps CLI]
|
||||
UI[UI / Automation]
|
||||
end
|
||||
subgraph Perimeter
|
||||
RP[Reverse Proxy / WAF]
|
||||
end
|
||||
subgraph Authority
|
||||
AUTH[Authority Host]
|
||||
PLGIN[Standard Plug-in]
|
||||
STORE[(Mongo Credential Store)]
|
||||
end
|
||||
CLI -->|OAuth password / client creds| RP --> AUTH
|
||||
UI -->|OAuth flows| RP
|
||||
AUTH -->|PasswordHashOptions + Secrets| PLGIN
|
||||
AUTH -->|Verify / Persist hashes| STORE
|
||||
STORE -->|Rehash needed| AUTH
|
||||
AUTH -->|Access / refresh token| RP --> Client Tier
|
||||
```
|
||||
|
||||
### 4.2 Bootstrap & revocation
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Operator
|
||||
OPS[Operator Workstation]
|
||||
end
|
||||
subgraph Authority
|
||||
AUTH[Authority Host]
|
||||
STORE[(Mongo)]
|
||||
end
|
||||
subgraph Distribution
|
||||
OFFKIT[Offline Kit Bundle]
|
||||
AGENT[Authorized Agent / Concelier]
|
||||
end
|
||||
OPS -->|Bootstrap CLI (`stellaops auth bootstrap`)| AUTH
|
||||
AUTH -->|One-time invite + Argon2 hash| STORE
|
||||
AUTH -->|Revocation export (`stellaops auth revoke export`)| OFFKIT
|
||||
OFFKIT -->|Signed JSON + .jws| AGENT
|
||||
AGENT -->|Revocation ACK / telemetry| AUTH
|
||||
```
|
||||
|
||||
## 5. STRIDE Analysis
|
||||
|
||||
| Threat | STRIDE Vector | Surface | Risk (L×I) | Existing Controls | Gaps / Actions | Owner |
|
||||
|--------|---------------|---------|------------|-------------------|----------------|-------|
|
||||
| Spoofed revocation bundle | Spoofing | TB5 — Authority ↔️ Agents | Med×High | Detached JWS signature (planned), offline kit checksums | Finalise signing key registry & verification script (SEC4.B/SEC4.HOST); add bundle freshness requirement | Security Guild (follow-up: **SEC5.B**) |
|
||||
| Parameter tampering on `/token` | Tampering | TB1 — Public ingress | Med×High | ASP.NET model validation, OpenIddict, rate limiter (CORE8.RL) | Tampered requests emit `authority.token.tamper` audit events (`request.tampered`, unexpected parameter names) correlating with `/token` outcomes (SEC5.C) | Security Guild + Authority Core (follow-up: **SEC5.C**) |
|
||||
| Bootstrap invite replay | Repudiation | TB4 — Operator CLI ↔️ Authority | Low×High | One-time bootstrap tokens, Argon2id hashing on creation | Invites expire automatically and emit audit events on consumption/expiration (SEC5.D) | Security Guild |
|
||||
| Token replay by stolen agent | Information Disclosure | TB5 | Med×High | Signed revocation bundles, device fingerprint heuristics, optional mTLS | Monitor revocation acknowledgement latency via Zastava and tune replay alerting thresholds | Security Guild + Zastava (follow-up: **SEC5.E**) |
|
||||
| Privilege escalation via plug-in override | Elevation of Privilege | TB3 — Plug-in sandbox | Med×High | Signed plug-ins, restart-only loading, configuration validation | Add static analysis on manifest overrides + runtime warning when policy weaker than host | Security Guild + DevOps (follow-up: **SEC5.F**) |
|
||||
| Offline bundle tampering | Tampering | Distribution | Low×High | SHA256 manifest, signed bundles (planned) | Add supply-chain attestation for Offline Kit, publish verification CLI in docs | Security Guild + Ops (follow-up: **SEC5.G**) |
|
||||
| Failure to log denied tokens | Repudiation | TB2 — Authority ↔️ Mongo | Med×Med | Serilog structured events (partial), Mongo persistence path (planned) | Finalise audit schema (SEC2.A) and ensure `/token` denies include subject/client/IP fields | Security Guild + Authority Core (follow-up: **SEC5.H**) |
|
||||
|
||||
Risk scoring uses qualitative scale (Low/Med/High) for likelihood × impact; mitigation priority follows High > Med > Low.
|
||||
|
||||
## 6. Follow-up Backlog Hooks
|
||||
|
||||
| Backlog ID | Linked Threat | Summary | Target Owners |
|
||||
|------------|---------------|---------|---------------|
|
||||
| SEC5.B | Spoofed revocation bundle | Complete libsodium/Core signing integration and ship revocation verification script. | Security Guild + Authority Core |
|
||||
| SEC5.C | Parameter tampering on `/token` | Finalise audit contract (`SEC2.A`) and add request tamper logging. | Security Guild + Authority Core |
|
||||
| SEC5.D | Bootstrap invite replay | Implement expiry enforcement + audit coverage for unused bootstrap invites. | Security Guild |
|
||||
| SEC5.E | Token replay by stolen agent | Coordinate Zastava alerting with the new device fingerprint heuristics and surface stale revocation acknowledgements. | Security Guild + Zastava |
|
||||
| SEC5.F | Plug-in override escalation | Static analysis of plug-in manifests; warn on weaker password policy overrides. | Security Guild + DevOps |
|
||||
| SEC5.G | Offline bundle tampering | Extend Offline Kit build to include attested manifest + verification CLI sample. | Security Guild + Ops |
|
||||
| SEC5.H | Failure to log denied tokens | Ensure audit persistence for all `/token` denials with correlation IDs. | Security Guild + Authority Core |
|
||||
|
||||
Update `src/StellaOps.Cryptography/TASKS.md` (Security Guild board) with the above backlog entries to satisfy SEC5.A exit criteria.
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
{
|
||||
"$schema": "../../etc/authority/revocation_bundle.schema.json",
|
||||
"schemaVersion": "1.0.0",
|
||||
"issuer": "https://auth.stella-ops.example",
|
||||
"bundleId": "6f9d08bfa0c24a0a9f7f59e6c17d2f8e8bca2ef34215c3d3ba5a9a1f0fbe2d10",
|
||||
"issuedAt": "2025-10-12T15:00:00Z",
|
||||
"validFrom": "2025-10-12T15:00:00Z",
|
||||
"sequence": 42,
|
||||
"signingKeyId": "authority-signing-20251012",
|
||||
"revocations": [
|
||||
{
|
||||
"id": "7ad4f3d2c21b461d9b3420e1151be9c4",
|
||||
"category": "token",
|
||||
"tokenType": "access_token",
|
||||
"clientId": "feedser-cli",
|
||||
"subjectId": "user:ops-admin",
|
||||
"reason": "compromised",
|
||||
"reasonDescription": "Access token reported by SOC automation run R-2045.",
|
||||
"revokedAt": "2025-10-12T14:32:05Z",
|
||||
"scopes": [
|
||||
"feedser:export",
|
||||
"feedser:jobs"
|
||||
],
|
||||
"fingerprint": "AD35E719C12204D7E7C92ED3F6DEBF0A44642D41AAF94233F9A47E183F4C5F18",
|
||||
"metadata": {
|
||||
"reportId": "R-2045",
|
||||
"source": "soc-automation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "user:departed-vendor",
|
||||
"category": "subject",
|
||||
"subjectId": "user:departed-vendor",
|
||||
"reason": "lifecycle",
|
||||
"revokedAt": "2025-10-10T18:15:00Z",
|
||||
"metadata": {
|
||||
"ticket": "HR-8821"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ci-runner-legacy",
|
||||
"category": "client",
|
||||
"clientId": "ci-runner-legacy",
|
||||
"reason": "rotation",
|
||||
"revokedAt": "2025-10-09T11:00:00Z",
|
||||
"expiresAt": "2025-11-01T00:00:00Z",
|
||||
"metadata": {
|
||||
"replacement": "ci-runner-2025"
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"generator": "stellaops-authority@1.4.0",
|
||||
"jobId": "revocation-export-20251012T1500Z"
|
||||
}
|
||||
}
|
||||
{
|
||||
"$schema": "../../etc/authority/revocation_bundle.schema.json",
|
||||
"schemaVersion": "1.0.0",
|
||||
"issuer": "https://auth.stella-ops.example",
|
||||
"bundleId": "6f9d08bfa0c24a0a9f7f59e6c17d2f8e8bca2ef34215c3d3ba5a9a1f0fbe2d10",
|
||||
"issuedAt": "2025-10-12T15:00:00Z",
|
||||
"validFrom": "2025-10-12T15:00:00Z",
|
||||
"sequence": 42,
|
||||
"signingKeyId": "authority-signing-20251012",
|
||||
"revocations": [
|
||||
{
|
||||
"id": "7ad4f3d2c21b461d9b3420e1151be9c4",
|
||||
"category": "token",
|
||||
"tokenType": "access_token",
|
||||
"clientId": "concelier-cli",
|
||||
"subjectId": "user:ops-admin",
|
||||
"reason": "compromised",
|
||||
"reasonDescription": "Access token reported by SOC automation run R-2045.",
|
||||
"revokedAt": "2025-10-12T14:32:05Z",
|
||||
"scopes": [
|
||||
"concelier:export",
|
||||
"concelier:jobs"
|
||||
],
|
||||
"fingerprint": "AD35E719C12204D7E7C92ED3F6DEBF0A44642D41AAF94233F9A47E183F4C5F18",
|
||||
"metadata": {
|
||||
"reportId": "R-2045",
|
||||
"source": "soc-automation"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "user:departed-vendor",
|
||||
"category": "subject",
|
||||
"subjectId": "user:departed-vendor",
|
||||
"reason": "lifecycle",
|
||||
"revokedAt": "2025-10-10T18:15:00Z",
|
||||
"metadata": {
|
||||
"ticket": "HR-8821"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ci-runner-legacy",
|
||||
"category": "client",
|
||||
"clientId": "ci-runner-legacy",
|
||||
"reason": "rotation",
|
||||
"revokedAt": "2025-10-09T11:00:00Z",
|
||||
"expiresAt": "2025-11-01T00:00:00Z",
|
||||
"metadata": {
|
||||
"replacement": "ci-runner-2025"
|
||||
}
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"generator": "stellaops-authority@1.4.0",
|
||||
"jobId": "revocation-export-20251012T1500Z"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,91 @@
|
||||
# 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`](../../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 Feedser exports so agents ingest revocations during the same sync pass.
|
||||
# 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.
|
||||
|
||||
Reference in New Issue
Block a user