Authority Threat Model (STRIDE)
Prepared by: Security Guild — 2025-10-12. Scope: Authority host, Standard plug-in, CLI, bootstrap workflow, and offline revocation distribution.
Related: For implementation details, see Authority architecture. Sender-constraint binding (DPoP/mTLS) rollout is tracked in DPoP & mTLS rollout; the offline revocation bundle format is documented in Revocation bundle. Canonical scopes (
StellaOpsScopes) are catalogued in Authority scopes.
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.
- In scope (first-party identity providers): the Standard plug-in plus the LDAP, OIDC, and SAML federation plug-ins (
StellaOps.Authority.Plugin.{Standard,Ldap,Oidc,Saml}). All identity providers are loaded as Authority plug-ins behind the same OpenIddict token-issuance surface; their credential paths inherit the controls in this model. - Out of scope: external relying-party applications that consume issued tokens (they validate via published JWKS / introspection); cross-tenant federation policy is tracked separately under the platform federation scopes (
platform:federation:*).
2. Assets & Entry Points
| Asset / Surface | Description | Primary Actors |
|---|---|---|
Token issuance APIs (/token, /authorize, /introspect, /revoke) | OAuth/OIDC endpoints mediated by OpenIddict (custom endpoint URIs configured in Program.cs) | CLI, UI, automation agents |
| Bootstrap channel | API-key-protected /internal/* HTTP endpoints (/internal/users, /internal/clients, /internal/invites) gated by the X-StellaOps-Bootstrap-Key header and Bootstrap.Enabled | Platform operators |
| Revocation bundle | Offline JSON + detached JWS exported via GET /internal/revocations/export, consumed by agents | Concelier, Agents, Zastava |
| Plug-in manifests | Identity-provider plug-in configuration (Standard/LDAP/OIDC/SAML) and password-policy overrides | Operators, DevOps |
| Signing keys | Signing keys backing tokens and revocation manifests (ES256 default; algorithm configurable via Signing.Algorithm), resolved through ICryptoProviderRegistry | Security Guild, HSM/KeyOps |
| Audit telemetry | Structured login/audit stream persisted to PostgreSQL via AuthorityAuditSink → IAuthorityLoginAttemptStore, with dual-write to the Timeline unified audit sink | SOC, SecOps |
3. Trust Boundaries
| Boundary | Rationale | Controls |
|---|---|---|
| TB1 — Public network ↔️ Authority ingress | Internet/extranet exposure for /token, /authorize, /introspect, /revoke (the /internal/* bootstrap surface is not intended for public exposure) | TLS 1.3, reverse proxy ACLs, partitioned rate limiting (authority-token, authority-authorize, authority-internal limiters in AuthorityRateLimiter; SEC3.A / CORE8.RL) |
| TB2 — Authority host ↔️ PostgreSQL storage | Credential store, revocation state, audit log persistence | Authenticated PostgreSQL, network segmentation, deterministic serializers |
| TB3 — Authority host ↔️ Plug-in sandbox | Identity-provider plug-ins (Standard/LDAP/OIDC/SAML) may override password policy and provisioning flows | Manifest validation, restart-time loading only (no hot reload), registrar warnings when an override weakens the host baseline |
| TB4 — Operator workstation ↔️ Bootstrap API | Bootstrap provisioning and revocation export are HTTP /internal/* calls authenticated with the static X-StellaOps-Bootstrap-Key; the operator CLI consumes issued tokens and bundles | Bootstrap API-key secrecy, Bootstrap.Enabled gate, one-time invite tokens, offline kit checksum |
| TB5 — Authority ↔️ Downstream agents | Revocation bundle consumption, token validation | Sender-constrained tokens (DPoP jkt / mTLS x5t#S256 confirmation claims), detached JWS bundle signatures, bundle sequence + freshness checks |
4. Data Flow Diagrams
4.1 Runtime token issuance
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[(PostgreSQL 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
flowchart LR
subgraph Operator
OPS[Operator Workstation]
end
subgraph Authority
AUTH[Authority Host]
STORE[(PostgreSQL)]
end
subgraph Distribution
OFFKIT[Offline Kit Bundle]
AGENT[Authorized Agent / Concelier]
end
OPS -->|POST /internal/users + X-StellaOps-Bootstrap-Key| AUTH
AUTH -->|One-time invite + Argon2id hash| STORE
AUTH -->|GET /internal/revocations/export (signed bundle + detached JWS)| OFFKIT
OFFKIT -->|Base64 JSON + JWS signature + sha256 digest| 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 over canonical bundle (RevocationBundleSigner, typ=application/vnd.stellaops.revocation-bundle+jws, b64:false/crit:["b64"]) via ICryptoProviderRegistry; per-bundle sha256 digest + monotonic sequence; offline kit checksums | Ship operator-facing verification script/CLI sample and document key registry/rotation for offline consumers (SEC4.B/SEC4.HOST) | 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 ↔️ Bootstrap API | Low×High | One-time invite tokens reserved/released at /internal/users, Argon2id hashing on creation | Invites carry ExpiresAt and are rejected after expiry/consumption, emitting authority.bootstrap.invite.{consumed,expired,rejected} audit events (SEC5.D) | Security Guild |
| Token replay by stolen agent | Information Disclosure | TB5 | Med×High | Sender-constrained tokens bind the token to a proof key — DPoP (cnf.jkt confirmation + nonce) or mTLS (cnf.x5t#S256 certificate thumbprint), applied by AuthoritySenderConstraintHelper; signed revocation bundles | Monitor revocation acknowledgement latency via Zastava and tune replay alerting thresholds; behavioural device-fingerprint heuristics are not yet implemented | Security Guild + Zastava (follow-up: SEC5.E) |
| Privilege escalation via plug-in override | Elevation of Privilege | TB3 — Plug-in sandbox | Med×High | Restart-only plug-in loading, configuration validation (StandardPluginOptions.Validate), runtime registrar warning when an override password policy is weaker than the host baseline (PasswordPolicyOptions.IsWeakerThan) | Add static analysis on plug-in manifests/overrides to catch weakening before deployment | Security Guild + DevOps (follow-up: SEC5.F) |
| Offline bundle tampering | Tampering | Distribution | Low×High | SHA256 manifest; Authority’s revocation bundle itself carries a detached JWS (see “Spoofed revocation bundle”), but whole-Offline-Kit supply-chain attestation is not yet wired | Add supply-chain attestation for the Offline Kit build and publish a verification CLI in docs | Security Guild + Ops (follow-up: SEC5.G) |
| Failure to log denied tokens | Repudiation | TB2 — Authority ↔️ PostgreSQL | Med×Med | AuthorityAuditSink persists every AuthEventRecord to PostgreSQL (IAuthorityLoginAttemptStore.InsertAsync) carrying outcome, correlation ID, subject/client, tenant, and network (remote/forwarded-for/user-agent) fields, with structured logging scope and dual-write to the Timeline audit sink; Standard plug-in credential telemetry (authority.plugin.standard.password_verification) | Require the same audit contract for the federation plug-ins (LDAP/OIDC/SAML) and confirm denial reasons are normalised across grant types | 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.PLG | TB3 — Plug-in sandbox | Standard plug-in mitigations documented: Argon2id bootstrap hashing (with PBKDF2 legacy verification + transparent rehash), password-policy warnings, and credential audit telemetry (plugin.retry_after_seconds, plugin.lockout_until, plugin.failure_code, plugin.rehashed) wired into SOC pipelines. | Security Guild + BE-Auth Plugin |
| SEC5.B | Spoofed revocation bundle | Bundle signing is implemented (RevocationBundleSigner over ICryptoProviderRegistry, ES256 default, detached JWS). Remaining: ship the operator-facing revocation verification script/CLI sample and document key registry/rotation for offline consumers. | Security Guild + Authority Core |
| SEC5.C | Parameter tampering on /token | Implemented: TokenRequestTamperInspector flags unexpected/duplicated parameter names and the grant handlers emit authority.token.tamper audit records (request.tampered) for both the password and client-credentials flows. Remaining: keep the inspector’s known-parameter allow-list in sync with new OpenIddict grant parameters. | Security Guild + Authority Core |
| SEC5.D | Bootstrap invite replay | Implemented: invites carry ExpiresAt, are reserved/released/expired at /internal/users provisioning, and emit authority.bootstrap.invite.{created,consumed,expired,rejected} audit events. Remaining: periodic sweep/expiry telemetry for never-consumed invites. | Security Guild |
| SEC5.E | Token replay by stolen agent | Sender-constraint binding (DPoP/mTLS) is implemented; coordinate Zastava alerting to surface stale revocation acknowledgements. Behavioural device-fingerprint heuristics remain a future enhancement (not yet implemented). | 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 | Implemented: AuthorityAuditSink persists all auth events (including /token denials and authority.token.tamper) to PostgreSQL with correlation IDs. Remaining: enforce the same audit contract across the LDAP/OIDC/SAML federation plug-ins. | Security Guild + Authority Core |
Update src/__Libraries/StellaOps.Cryptography/TASKS.md (Security Guild board) with the above backlog entries to satisfy SEC5.A exit criteria.
6.1 Plugin telemetry status (SEC5.PLG — 2025-11-09)
- Standard plug-in password verification now emits
authority.plugin.standard.password_verificationwith caller correlation IDs, client metadata, tenant IDs, and full network context sourced fromAuthorityCredentialAuditContext. Events classify outcomes via the extendedAuthEventOutcomeset (LockedOut,RequiresFreshAuth,RequiresMfa) so SOC tooling can distinguish lockouts from MFA prompts. - Audit properties were standardised:
plugin.failed_attempts,plugin.lockout_until,plugin.retry_after_seconds,plugin.rehashed, andplugin.failure_codeare present on both the plug-in event and the host-level/tokenrecord.plugin.retry_after_secondsis derived deterministically from the retry window, ensuring consistent rate-limit responses for air-gapped tenants. - Bootstrap mitigations were documented in
docs/dev/31_AUTHORITY_PLUGIN_DEVELOPER_GUIDE.md: Argon2id hashing, enforced password policies, defaultRequirePasswordReset, and registrar warnings when an operator weakens the baseline policy. These measures close the SEC5.PLG action item and provide auditors with evidence hooks for Offline Kit reviews.
