# Issuer Directory Architecture > **Status:** Initial service scaffold (Sprint 100 – Identity & Signing) ## 1. Purpose Issuer Directory centralises trusted VEX/CSAF publisher metadata so downstream services (VEX Lens, Excititor, Policy Engine) can resolve issuer identity, active keys, and trust weights. The initial milestone delivers tenant-scoped CRUD APIs with audit logging plus bootstrap import for CSAF publishers. ## 2. Runtime Topology - **Service name:** `stellaops/issuer-directory` - **Framework:** ASP.NET Core minimal APIs (`net10.0`) - **Persistence:** MongoDB (`issuer-directory.issuers`, `issuer-directory.issuer_keys`, `issuer-directory.issuer_audit`) - **AuthZ:** StellaOps resource server scopes (`issuer-directory:read`, `issuer-directory:write`, `issuer-directory:admin`) - **Audit:** Every create/update/delete emits an audit record with actor, reason, and context. - **Bootstrap:** On startup, the service imports `data/csaf-publishers.json` into the global tenant (`@global`) and records a `seeded` audit the first time each publisher is added. - **Key lifecycle:** API validates Ed25519 public keys, X.509 certificates, and DSSE public keys, enforces future expiries, deduplicates fingerprints, and records audit entries for create/rotate/revoke actions. ``` Clients ──> Authority (DPoP/JWT) ──> IssuerDirectory WebService ──> MongoDB │ └─> Audit sink (Mongo) ``` ## 3. Configuration Configuration is resolved via `IssuerDirectoryWebServiceOptions` (section name `IssuerDirectory`). The default YAML sample lives at `etc/issuer-directory.yaml.sample` and exposes: ```yaml IssuerDirectory: telemetry: minimumLogLevel: Information authority: enabled: true issuer: https://authority.example.com/realms/stellaops requireHttpsMetadata: true audiences: - stellaops-platform readScope: issuer-directory:read writeScope: issuer-directory:write adminScope: issuer-directory:admin tenantHeader: X-StellaOps-Tenant seedCsafPublishers: true csafSeedPath: data/csaf-publishers.json Mongo: connectionString: mongodb://localhost:27017 database: issuer-directory issuersCollection: issuers issuerKeysCollection: issuer_keys auditCollection: issuer_audit ``` ## 4. API Surface (v0) | Method | Route | Scope | Description | |--------|-------|-------|-------------| | `GET` | `/issuer-directory/issuers` | `issuer-directory:read` | List tenant issuers (optionally include global seeds). | | `GET` | `/issuer-directory/issuers/{id}` | `issuer-directory:read` | Fetch a single issuer by identifier. | | `POST` | `/issuer-directory/issuers` | `issuer-directory:write` | Create a tenant issuer. Requires `X-StellaOps-Tenant` header and optional `X-StellaOps-Reason`. | | `PUT` | `/issuer-directory/issuers/{id}` | `issuer-directory:write` | Update issuer metadata/endpoints/tags. | | `DELETE` | `/issuer-directory/issuers/{id}` | `issuer-directory:admin` | Delete issuer (records audit). | | `GET` | `/issuer-directory/issuers/{id}/keys` | `issuer-directory:read` | List issuer keys (tenant + optional `@global` seeds). | | `POST` | `/issuer-directory/issuers/{id}/keys` | `issuer-directory:write` | Add a signing key (validates format, deduplicates fingerprint, audits). | | `POST` | `/issuer-directory/issuers/{id}/keys/{keyId}/rotate` | `issuer-directory:write` | Retire an active key and create a replacement atomically. | | `DELETE` | `/issuer-directory/issuers/{id}/keys/{keyId}` | `issuer-directory:admin` | Revoke a key (status → revoked, audit logged). | Payloads follow the contract in `Contracts/IssuerDtos.cs` and align with domain types (`IssuerRecord`, `IssuerMetadata`, `IssuerEndpoint`). ## 5. Dependencies & Reuse - `StellaOps.IssuerDirectory.Core` — domain model (`IssuerRecord`, `IssuerKeyRecord`) + application services. - `StellaOps.IssuerDirectory.Infrastructure` — MongoDB persistence, audit sink, seed loader. - `StellaOps.IssuerDirectory.WebService` — minimal API host, authentication wiring. - Shared libraries: `StellaOps.Configuration`, `StellaOps.Auth.ServerIntegration`. ## 6. Testing - Unit coverage for issuer CRUD (`IssuerDirectoryServiceTests`) and key lifecycle (`IssuerKeyServiceTests`) in `StellaOps.IssuerDirectory.Core.Tests`. - Test infrastructure leverages `FakeTimeProvider` for deterministic timestamps and in-memory fakes for repository + audit sink. ## 7. Observability - **Metrics.** `issuer_directory_changes_total` (labels: `tenant`, `issuer`, `action`) tracks issuer create/update/delete events; `issuer_directory_key_operations_total` (labels: `tenant`, `issuer`, `operation`, `key_type`) covers key create/rotate/revoke flows; `issuer_directory_key_validation_failures_total` (labels: `tenant`, `issuer`, `reason`) captures validation/verification failures. The WebService exports these via OpenTelemetry (`StellaOps.IssuerDirectory` meter). - **Logs.** Service-level `ILogger` instrumentation records structured entries for issuer CRUD, key lifecycle operations, and validation failures; audit logs remain the authoritative trail. ## 8. Roadmap (next milestones) 1. **Key management APIs (ISSUER-30-002)** — manage signing keys, enforce expiry, integrate with KMS. 2. **Trust weight overrides (ISSUER-30-003)** — expose policy-friendly trust weighting with audit trails. 3. **SDK integration (ISSUER-30-004)** — supply cached issuer metadata to VEX Lens and Excititor clients. 4. **Observability & Ops (ISSUER-30-005/006)** — metrics, dashboards, deployment automation, offline kit. --- *Document owner: Issuer Directory Guild*