- Introduced AGENTS.md, README.md, TASKS.md, and implementation_plan.md for Vexer, detailing mission, responsibilities, key components, and operational notes. - Established similar documentation structure for Vulnerability Explorer and Zastava modules, including their respective workflows, integrations, and observability notes. - Created risk scoring profiles documentation outlining the core workflow, factor model, governance, and deliverables. - Ensured all modules adhere to the Aggregation-Only Contract and maintain determinism and provenance in outputs.
11 KiB
Authority DPoP & mTLS Implementation Plan (2025-10-19)
Purpose
- Provide the implementation blueprint for AUTH-DPOP-11-001 and AUTH-MTLS-11-002.
- Unify sender-constraint validation across Authority, downstream services, and clients.
- Capture deterministic, testable steps that unblock UI/Signer guilds depending on DPoP/mTLS hardening.
Scope
- Token endpoint validation, issuance, and storage changes inside
StellaOps.Authority. - Shared security primitives consumed by Authority, Scanner, Signer, CLI, and UI.
- Operator-facing configuration, auditing, and observability.
- Out of scope: PoE enforcement (Signer) and CLI/UI client UX; those teams consume the new capabilities.
Status update (2025-10-19):
ValidateDpopProofHandler,AuthorityClientCertificateValidator, and the supporting storage/audit plumbing now live insrc/Authority/StellaOps.Authority. DPoP proofs populatecnf.jkt, mTLS bindings enforce certificate thumbprints viacnf.x5t#S256, and token documents persist the sender constraint metadata. In-memory nonce issuance is wired (Redis implementation to follow). Documentation and configuration references were updated (docs/11_AUTHORITY.md). Targeted unit/integration tests were added; running the broader test suite is currently blocked by pre-existingStellaOps.Concelier.Storage.Mongobuild errors.Status update (2025-10-20): Redis-backed nonce configuration is exposed through
security.senderConstraints.dpop.noncewith sample YAML (etc/authority.yaml.sample) and architecture docs refreshed. Operator guide now includes concrete Redis/required audiences snippet; nonce challenge regression remains covered byValidateDpopProof_IssuesNonceChallenge_WhenNonceMissing.Status update (2025-10-23): mTLS enforcement now honours
security.senderConstraints.mtls.enforceForAudiences, automatically rejecting non-mTLS clients targeting audiences such assigner. Certificate bindings validate thumbprint, issuer, subject, serial number, and SAN values, producing deterministic error codes for operators. Introspection responses includecnf.x5t#S256, and new unit tests cover audience enforcement, binding mismatches, and bootstrap storage. Docs/sample config updated accordingly.
Design Summary
- Extract the existing Scanner
DpopProofValidatorstack into a sharedStellaOps.Auth.Securitylibrary used by Authority and resource servers. - Extend Authority configuration (
authority.yaml) with strongly-typedsenderConstraints.dpopandsenderConstraints.mtlssections (map to sample already shown in architecture doc). - Require DPoP proofs on
/tokenwhen the registered client policy issenderConstraint=dpop; bind issued access tokens viacnf.jkt. - Introduce Authority-managed nonce issuance for “high value” audiences (default:
signer,attestor) with Redis-backed persistence and deterministic auditing. - Enable OAuth 2.0 mTLS (RFC 8705) by storing certificate bindings per client, requesting client certificates at TLS termination, and stamping
cnf.x5t#S256into issued tokens plus introspection output. - Surface structured logs and counters for both DPoP and mTLS flows; provide integration tests that cover success, replay, invalid proof, and certificate mismatch cases.
AUTH-DPOP-11-001 — Proof Validation & Nonce Handling
Shared validator
- Move
DpopProofValidator, option types, and replay cache interfaces fromStellaOps.Scanner.Coreinto a new assemblyStellaOps.Auth.Security. - Provide pluggable caches:
InMemoryDpopReplayCache(existing) and newRedisDpopReplayCache(leveraging the Authority Redis connection). - Ensure the validator exposes the validated
SecurityKey,jti, andiatso Authority can construct thecnfclaim and compute nonce expiry.
Configuration model
- Extend
StellaOpsAuthorityOptions.Securitywith aSenderConstraintsproperty containing:Dpop(enabled,allowedAlgorithms,maxAgeSeconds,clockSkewSeconds,replayWindowSeconds,noncesettings withenabled,ttlSeconds,requiredAudiences,maxIssuancePerMinute).Mtls(enabled,requireChainValidation,clientCaBundle,allowedSubjectPatterns,allowedSanTypes).
- Bind from YAML (
authority.security.senderConstraints.*) while preserving backwards compatibility (defaults keep both disabled).
Token endpoint pipeline
- Introduce a scoped OpenIddict handler
ValidateDpopProofHandlerinserted beforeValidateClientCredentialsHandler. - Determine the required sender constraint from client metadata:
- Add
AuthorityClientMetadataKeys.SenderConstraintstoringdpopormtls. - Optionally allow per-client overrides for nonce requirement.
- Add
- When
dpopis required:- Read the
DPoPheader from the ASP.NET request, reject withinvalid_token+WWW-Authenticate: DPoP error="invalid_dpop_proof"if absent. - Call the shared validator with method/URI. Enforce algorithm allowlist and
iatwindow from options. - Persist the
jktthumbprint plus replay cache state in the OpenIddict transaction (AuthorityOpenIddictConstants.DpopKeyThumbprintProperty,DpopIssuedAtProperty). - When the requested audience intersects
SenderConstraints.Dpop.Nonce.RequiredAudiences, requirenoncein the proof; on first failure respond with HTTP 401,error="use_dpop_nonce", and includeDPoP-Nonceheader (see nonce note below). Cache the rejection reason for audit logging.
- Read the
Nonce service
- Add
IDpopNonceStorewith methodsIssueAsync(audience, clientId, jkt)andTryConsumeAsync(nonce, audience, clientId, jkt). - Default implementation
RedisDpopNonceStorestoring SHA-256 hashes of nonces keyed byaudience:clientId:jkt. TTL comes fromSenderConstraints.Dpop.Nonce.Ttl. - Create helper
DpopNonceIssuerused byValidateDpopProofHandlerto issue nonces when missing/expired, enforcing issuance rate limits (per options) and tagging audit/log records. - On successful validation (nonce supplied and consumed) stamp metadata into the transaction for auditing.
- Update
ClientCredentialsHandlersto observe nonce enforcement: when a nonce challenge was sent, emit structured audit withnonce_issued,audiences, andretry.
Token issuance
- In
HandleClientCredentialsHandler, if the transaction contains a validated DPoP key:- Build
cnf.jktusing thumbprint from validator. - Include
auth_time/dpop_jtias needed for diagnostics. - Persist the thumbprint alongside token metadata in Mongo (extend
AuthorityTokenDocumentwithSenderConstraint,KeyThumbprint,Noncefields).
- Build
Auditing & observability
- Emit new audit events:
authority.dpop.proof.validated(success/failure, clientId, audience, thumbprint, nonce status, jti).authority.dpop.nonce.issuedandauthority.dpop.nonce.consumed.
- Metrics (Prometheus style):
authority_dpop_validations_total{result,reason}.authority_dpop_nonce_issued_total{audience}andauthority_dpop_nonce_fails_total{reason}.
- Structured logs include
authority.sender_constraint=dpop,authority.dpop_thumbprint,authority.dpop_nonce.
Testing
- Unit tests for the handler pipeline using fake OpenIddict transactions.
- Replay/nonce tests with in-memory and Redis stores.
- Integration tests in
StellaOps.Authority.Testscovering:- Valid DPoP proof issuing
cnf.jkt. - Missing header → challenge with nonce.
- Replayed
jtirejected. - Invalid nonce rejected even after issuance.
- Valid DPoP proof issuing
- Contract tests to ensure
/.well-known/openid-configurationadvertisesdpop_signing_alg_values_supportedanddpop_nonce_supportedwhen enabled.
AUTH-MTLS-11-002 — Certificate-Bound Tokens
Configuration model
- Reuse
SenderConstraints.Mtlsdescribed above; include:enforceForAudienceslist (defaultssigner,attestor,scheduler).certificateRotationGraceSecondsfor overlap.allowedClientCertificateAuthoritiesabsolute paths.
Kestrel/TLS pipeline
- Configure Kestrel with
ClientCertificateMode.AllowCertificateglobally and implement middleware that enforces certificate presence only when the resolved client requires mTLS. - Add
IAuthorityClientCertificateValidatorthat validates presented certificate chain, SANs (dns,uri, optional SPIFFE), and thumbprint matches one of the stored bindings. - Cache validation results per connection id to avoid rehashing on every request.
Client registration & storage
- Extend
AuthorityClientDocumentwithList<AuthorityClientCertificateBinding>containing:Thumbprint,SerialNumber,Subject,NotBefore,NotAfter,Sans,CreatedAt,UpdatedAt,Label.
- Provide admin API mutations (
/admin/clients/{id}/certificates) for ops tooling (deferred implementation but schema ready). - Update plugin provisioning store (
StandardClientProvisioningStore) to map descriptors with certificate bindings andsenderConstraint. - Persist binding state in Mongo migrations (index on
{clientId, thumbprint}).
Token issuance & introspection
- Add a transaction property capturing the validated client certificate thumbprint.
HandleClientCredentialsHandler:- When mTLS required, ensure certificate info present; reject otherwise.
- Stamp
cnfclaim:principal.SetClaim("cnf", JsonSerializer.Serialize(new { x5t#S256 = thumbprint })). - Store binding metadata in issued token document for audit.
- Update
ValidateAccessTokenHandlerand introspection responses to surfacecnf.x5t#S256. - Ensure refresh tokens (if ever enabled) copy the binding data.
Auditing & observability
- Audit events:
authority.mtls.handshake(success/failure, clientId, thumbprint, issuer, subject).authority.mtls.binding.missingwhen a required client posts without a cert.
- Metrics:
authority_mtls_handshakes_total{result}.authority_mtls_certificate_rotations_total.
- Logs include
authority.sender_constraint=mtls,authority.mtls_thumbprint,authority.mtls_subject.
Testing
- Unit tests for certificate validation rules (SAN mismatches, expiry, CA trust).
- Integration tests running Kestrel with test certificates:
- Successful token issuance with bound certificate.
- Request without certificate →
invalid_client. - Token introspection reveals
cnf.x5t#S256. - Rotation scenario (old + new cert allowed during grace window).
Implementation Checklist
DPoP work-stream
- Extract shared validator into
StellaOps.Auth.Security; update Scanner references. - Introduce configuration classes and bind from YAML/environment.
- Implement nonce store (Redis + in-memory), handler integration, and OpenIddict transaction plumbing.
- Stamp
cnf.jkt, audit events, and metrics; update Mongo documents and migrations. - Extend docs:
docs/modules/authority/architecture.md,docs/security/audit-events.md,docs/security/rate-limits.md, CLI/UI references.
mTLS work-stream
- Extend client document/schema and provisioning stores with certificate bindings + sender constraint flag.
- Configure Kestrel/middleware for optional client certificates and validation service.
- Update token issuance/introspection to honour certificate bindings and emit
cnf.x5t#S256. - Add auditing/metrics and integration tests (happy path + failure).
- Refresh operator documentation (
docs/modules/authority/operations/backup-restore.md,docs/modules/authority/operations/monitoring.md, sampleauthority.yaml) to cover certificate lifecycle.
Both streams should conclude with dotnet test src/Authority/StellaOps.Authority/StellaOps.Authority.sln and documentation cross-links so dependent guilds can unblock UI/Signer work.