SecretBrokerService¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-40 Secret Broker |
| Platform / plane | Governance / Trust & Operations |
| Deployment granularity | module of host · host GovernanceHost |
| Status | target · ConnectSoft.Factory.Governance.Secrets |
| Built from | connectsoft-microservice · libraries: connectsoft-extensions-http-oauth2, connectsoft-extensions-saas-abstractions, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate, connectsoft-extensions-audit-net |
| Decisions | ADR-0015, ADR-0019 |
| Traceability | FR-05 FUX-01 NFR-01 NFR-02 XL-10 XL-13 |
Purpose and responsibilities¶
The original design's preferred pattern (§46): agent requests capability → policy validates → secret broker obtains credential → temporary credential injected into sandbox → credential expires. SecretBrokerService is that broker for the whole Factory: connections (BC-16), model deployments (BC-07), compute pools (BC-41), hosts and webhook schemes own references to secrets held in Key Vault or exchangeable identities; subjects (workload identities bound to a run, attempt, invocation or sandbox lease) receive issuances — short-lived, scoped, delivered once, revoked when the lease ends — after a policy decision. BC-40 was added by the design plan so that secret custody has one owner distinct from connections.
Context and boundaries¶
flowchart LR
S["SecretBrokerService"]
IntegrationService["IntegrationService"] -->|grpc| S
ModelRouterService["ModelRouterService"] -->|grpc| S
ComputePoolService["ComputePoolService"] -->|grpc| S
ToolAdapterService["ToolAdapterService"] -->|grpc| S
KnowledgeIngestionService["KnowledgeIngestionService"] -->|grpc| S
McpServerRegistryService["McpServerRegistryService"] -->|grpc| S
WebhookGatewayService["WebhookGatewayService"] -->|grpc| S
StudioBff["StudioBff"] -->|sync-http| S
S -->|sync-http| ext_key_vault["ext-key-vault"]
S -->|grpc| PolicyEngineService["PolicyEngineService"]
S -->|sync-http| ext_identity_platform["ext-identity-platform"]
S -. "SecretReferenceRegistered" .-> E_SecretReferenceRegistered(("event"))
S -. "SecretRotated" .-> E_SecretRotated(("event"))
S -. "SecretReferenceRevoked" .-> E_SecretReferenceRevoked(("event"))
S -. "CredentialIssued" .-> E_CredentialIssued(("event"))
S -. "CredentialRevoked" .-> E_CredentialRevoked(("event"))
sequenceDiagram
participant X as Tool executor (or gateway, ingestion, connector)
participant P as PolicyEngineService
participant B as SecretBrokerService
participant KV as Key Vault
participant SB as Sandbox
X->>B: Issue (reference, subject, purpose, scope, TTL)
B->>P: Decide (subject may use reference for purpose)
B->>KV: get secret or exchange token
B-->>X: credential delivered once, expires at TTL
X->>SB: inject into sandbox environment
Note over B: Issuance recorded (metadata only), CredentialIssued to audit
SB-->>X: work done, lease ends
X->>B: Revoke (issuance)
Domain model¶
SecretReference — A named reference to a secret held in Key Vault (or an exchangeable identity) with its kind, owner, allowed purposes, rotation policy and state; the value is never here. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
referenceId |
string |
yes | Stable reference used by connections |
tenantId |
string |
yes | |
kind |
enum:SecretKind |
yes | |
vaultRef |
string |
yes | Key Vault secret or key identifier |
ownerKind |
string |
yes | connection |
ownerId |
string |
yes | |
allowedPurposes |
list:string |
yes | source-sync |
maxTtlSeconds |
int |
yes | |
rotationDays |
int |
yes | |
lastRotatedAt |
datetime |
no | |
revoked |
bool |
yes |
Invariants:
- Values are never read into this service's store or logs; the broker holds them in memory only for the duration of an issuance.
- An issuance is allowed only for a purpose in allowedPurposes, for a subject with a policy decision Allow, and with a TTL not above maxTtlSeconds.
- Revoking a reference invalidates every live issuance and emits an event the owners act on.
Events: SecretReferenceRegistered, SecretRotated, SecretReferenceRevoked · Tables: SecretReferences, RotationReceipts · Repository: SecretReferenceRepository
Issuance — One short-lived credential issued to one subject for one purpose and scope — with its expiry, the policy decision that allowed it and the revocation state; the credential itself is delivered once and not stored. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
issuanceId |
guid |
yes | |
tenantId |
string |
yes | |
referenceId |
string |
yes | |
subject |
json |
yes | Workload identity, run, attempt, invocation, sandbox lease |
purpose |
string |
yes | |
scope |
json |
yes | Narrowed scopes, hosts, operations |
policyDecisionId |
guid |
yes | |
state |
enum:IssuanceState |
yes | |
issuedAt |
datetime |
yes | |
expiresAt |
datetime |
yes | |
revokedAt |
datetime |
no |
Invariants:
- A credential is delivered exactly once to the requesting subject over an authenticated channel and expires with the issuance; the broker never re-delivers.
- Issuances outlive neither their lease (attempt, invocation, sandbox) nor maxTtlSeconds; the broker revokes on lease end where the provider supports it.
Events: CredentialIssued, CredentialRevoked · Tables: Issuances · Repository: IssuanceRepository
erDiagram
SecretReference {
string referenceId PK
string tenantId
enum_SecretKind kind
string vaultRef
string ownerKind
string ownerId
list_string allowedPurposes
int maxTtlSeconds
int rotationDays
datetime lastRotatedAt
bool revoked
}
Issuance {
guid issuanceId PK
string tenantId
string referenceId
json subject
string purpose
json scope
guid policyDecisionId
enum_IssuanceState state
datetime issuedAt
datetime expiresAt
datetime revokedAt
}
Entities and value objects¶
None modelled
No entities or value objects are modelled for this item yet.
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Governance store | primary | azure-sql / nhibernate-sqlserver | SecretReferences, RotationReceipts, Issuances |
| Secret store | primary | key-vault / azure-key-vault | — |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.SecretReferences |
SecretReference | 11 | 1 |
dbo.RotationReceipts |
SecretReference | 6 | 0 |
dbo.Issuances |
Issuance | 11 | 2 |
Full DDL: appendix.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
GET |
/factory/secret-references |
ListSecretReferences | factory.secrets.admin |
read | natural | GW-03 | References with kind |
POST |
/factory/secret-references |
RegisterSecretReference | factory.secrets.admin |
production | key-header | GW-03 | Register a reference to a vault secret or an exchangeable identity with owner |
POST |
/factory/secret-references/{referenceId}/rotate |
RotateSecret | factory.secrets.admin |
production | key-header | GW-03 | Record a rotation to a new vault version and revoke live issuances of the old one. |
POST |
/factory/secret-references/{referenceId}/revoke |
RevokeSecretReference | factory.secrets.admin |
production | natural | GW-03 | Revoke a reference and every live issuance. |
GET |
/factory/runs/{runId}/issuances |
ListRunIssuances | factory.runs.read |
read | natural | GW-03 | Credential issuances made for a run (metadata only). |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
SecretBroker |
Issue |
none | internal | shared-write | Issue a short-lived scoped credential for a subject and purpose after a policy decision; delivered once over the authenticated channel. |
SecretBroker |
Revoke |
none | internal | shared-write | Revoke an issuance (lease ended |
SecretBroker |
Verify |
none | internal | external | Verify that a reference resolves and the credential works (read-only probe) without issuing it to the caller. |
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| SecretReferenceRegistered | secret-broker.references.v1.secret-reference-registered |
integration / 1 | SecretReference | AuditService, StudioBff | A reference exists. |
| SecretRotated | secret-broker.references.v1.secret-rotated |
integration / 1 | SecretReference | IntegrationService, ModelRouterService, ComputePoolService, AuditService | A reference moved to a new vault version; old issuances revoked. |
| SecretReferenceRevoked | secret-broker.references.v1.secret-reference-revoked |
integration / 1 | SecretReference | IntegrationService, ModelRouterService, ComputePoolService, ToolAdapterService, AuditService | A reference and its issuances were revoked. |
| CredentialIssued | secret-broker.issuances.v1.credential-issued |
integration / 1 | Issuance | AuditService, DashboardService | A short-lived credential was issued (metadata only). |
| CredentialRevoked | secret-broker.issuances.v1.credential-revoked |
integration / 1 | Issuance | AuditService | An issuance was revoked before expiry. |
SecretReferenceRegistered payload:
| Field | Type | Required | Description |
|---|---|---|---|
referenceId |
string |
yes | |
tenantId |
string |
yes | |
kind |
enum:SecretKind |
yes | |
ownerKind |
string |
yes | |
ownerId |
string |
yes |
SecretRotated payload:
| Field | Type | Required | Description |
|---|---|---|---|
referenceId |
string |
yes | |
tenantId |
string |
yes | |
rotatedAt |
datetime |
yes |
SecretReferenceRevoked payload:
| Field | Type | Required | Description |
|---|---|---|---|
referenceId |
string |
yes | |
tenantId |
string |
yes | |
reason |
string |
yes |
CredentialIssued payload:
| Field | Type | Required | Description |
|---|---|---|---|
issuanceId |
guid |
yes | |
tenantId |
string |
yes | |
referenceId |
string |
yes | |
purpose |
string |
yes | |
runId |
guid |
no | |
expiresAt |
datetime |
yes |
CredentialRevoked payload:
| Field | Type | Required | Description |
|---|---|---|---|
issuanceId |
guid |
yes | |
tenantId |
string |
yes | |
reason |
string |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
Issue |
Issuance | CredentialIssued | |
Revoke |
Issuance | CredentialRevoked | |
RotateSecret |
SecretReference | SecretRotated | |
RevokeSecretReference |
SecretReference | SecretReferenceRevoked |
| Event | Producer | Handler | Purpose |
|---|---|---|---|
| RunCancelled | RunControlService | RevokeRunIssuances |
Revoke live issuances of a cancelled run. |
| LeaseExpired | RunControlService | RevokeLeaseIssuances |
Revoke issuances bound to an expired lease. |
| SandboxReleased | ToolAdapterService | RevokeSandboxIssuances |
Revoke sandbox tokens when the sandbox is released. |
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| ExpirySweeper | schedule */1 * * * * |
CredentialRevoked | fixed | issuanceId |
Marks expired issuances and revokes at providers that support revocation. |
| RotationScheduler | schedule 0 5 * * * |
SecretRotated | fixed | referenceId + day |
Raises rotation tasks for references past their rotation period and auto-rotates kinds the vault can rotate. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Governance:Secrets |
DefaultMaxTtlSeconds |
int | 900 |
yes | no | Default maximum lifetime of an issuance (15 minutes). |
Governance:Secrets |
SandboxTokenTtlSeconds |
int | 1800 |
yes | no | Sandbox token lifetime bound to the lease. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.secrets.issuances |
counter | {issuance} | tenant, kind, purpose, outcome | Issuances and refusals. |
connectsoft.factory.secrets.live_issuances |
updown | {issuance} | tenant, kind | Live credentials. |
connectsoft.factory.secrets.rotation_due |
updown | {reference} | tenant | References past rotation. |
connectsoft.factory.secrets.issue_latency |
histogram | s | kind | Issuance latency on the hot path. |
Security¶
| Authentication | client-credentials |
| Scopes | factory.secrets.admin (References); factory.runs.read (Issuance metadata of a run.) |
| Roles | Operator, PlatformAdmin, Observer |
| Tenant isolation | row-filter |
| Data classification | restricted |
| Max side-effect class | production |
| Secrets | vault-access (key-vault, rotate 30 d) |
Values are in memory only for the duration of an issuance and are delivered once over the authenticated gRPC channel; the service's own vault access is a workload identity rotated every 30 days; a credential detected in a tool result by the redaction rules is revoked immediately and raises a finding.
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ext-key-vault | sync-http | Secret values and key operations; token exchange for workload identities. | fail-fast | yes |
| PolicyEngineService | grpc | Decision per issuance. | fail-fast | yes |
| ext-identity-platform | sync-http | Token exchange and subject validation. | fail-fast | yes |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| IntegrationService | grpc | Connection credentials. | — | yes |
| ModelRouterService | grpc | Provider credentials. | — | yes |
| ComputePoolService | grpc | Pool endpoint credentials. | — | yes |
| ToolAdapterService | grpc | Sandbox and tool credentials. | — | yes |
| KnowledgeIngestionService | grpc | Source credentials. | — | yes |
| McpServerRegistryService | grpc | Handshake credentials. | — | yes |
| WebhookGatewayService | grpc | Signing secrets. | — | yes |
| StudioBff | sync-http | Reference administration. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Key Vault unavailable | vault errors | fail closed; live issuances keep working until expiry; new issuances refused with class transient | none | 15 |
| Issuance leaked in a tool result | redaction detector hit on the result | issuance revoked immediately; finding raised; receipt records the redaction | none | 0 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | module of host · host GovernanceHost |
| Topologies | saas-default, hybrid, on-prem, hybrid-compute |
| Runtime | —; replicas —–— |
| Ports | — |
Current implementation¶
Key Vault with the CSI driver and workload identity is the template estate's secret pattern; ConnectSoft.Extensions.Http.OAuth2 manages tokens for HTTP clients. No broker, references, issuances or lease-bound revocation exist.
Later capabilities¶
Token exchange for every provider that supports workload identity federation (no stored keys at all); automatic rotation for more kinds; secret-expiry forecasting shared with Integration.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-05 |
| FUX | FUX-01 |
| NFR | NFR-01, NFR-02 |
| XL | XL-10, XL-13 |