Control Plane — Security¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
Identity¶
- Humans authenticate at the Authorization Server (OpenIddict, canonical ADR-0101) and reach the Control Plane with a bearer token through GW-01 or, from the Studio, a delegated token through GW-03. The Control Plane validates signature, audience, expiry and the tenant claim; it never issues tokens (
ApiTokenServiceis external-canonical for that reason). - Services authenticate with workload identities: the runtime worker, the Studio BFF, partner agents (A2A) and generated products carry SPIFFE-style identities issued by the Authorization Server. A per-run token derived from the lease authorizes the runtime's calls for one attempt only.
- Platform admin is a tenant-wide claim of the Identity Platform; the six project roles are memberships in
ProjectService.
Tenancy¶
Canonical ADR-0100 modes are selected per installation (Multitenancy:DeploymentKind): SharedDb with NHibernate tenant filters by default, DatabasePerTenant and ResidencySilo for regulated tenants, DedicatedSingleTenant on-prem. Every table carries TenantId; every query runs under the request's trusted tenant; every event carries tenantId in the envelope. Platform-published assets belong to the platform tenant and are readable by all.
Roles and permissions (ADR-0015, D18)¶
| Capability | Requester | Reviewer | Asset maintainer | Operator | Workspace admin | Platform admin | Observer |
|---|---|---|---|---|---|---|---|
| Submit and cancel own runs | yes | yes | yes | yes | |||
| Decide approvals (not own runs) | yes | yes | break-glass with reason | ||||
| Submit and validate release candidates | yes | yes | |||||
| Publish, deprecate, move aliases (after Reviewer approval) | yes | yes | |||||
| Freeze and unfreeze environments | yes | yes | yes | ||||
| Memberships, delegations, source scope, close project | yes | yes | |||||
| Budgets and thresholds (only tighter than platform) | yes | yes | |||||
| Subscription and invoices | yes | read | |||||
| Read everything in scope | yes | yes | yes | yes | yes | yes | yes |
Separation of duties: a Reviewer or Workspace admin never decides an approval of a run they requested; an Asset maintainer never approves their own release. Delegations are time-bound, same-or-lesser role, with a reason, revocable and audited. Project policy overrides only tighten platform policy.
Scopes¶
factory.projects.{read,write,admin,delegate}, factory.assets.{read,write,publish}, factory.runs.{read,submit,cancel}, factory.approvals.{read,decide}, factory.usage.{read,admin}, factory.commercial.{read,admin}, factory.agents.{discover,invoke}, factory.health.read, factory.meta.read. A route lists its scope on the APIs catalog; the gateway enforces presence, the module enforces the role behind it.
Action classes and approvals (D21)¶
| Class | Autonomous | Needs approval |
|---|---|---|
| read, sandbox | yes | |
| shared-write, external, production, publication | one approval per action bound to the exact proposal version | |
| spend | below the threshold | above the threshold, bound to the estimate |
The environment class raises the class of an action (Production environments make writes production actions); a Frozen environment refuses them altogether. Decisions are validated against the policy revision in force at decision time, and the proposal hash guarantees that what was approved is what runs.
Secrets and credentials¶
No Factory table stores a credential. Host secrets live in Key Vault and are mounted through workload identity; integration credentials are references to BC-16 connections and, later, short-lived credentials from the Secret Broker (BC-40). Manifest signing keys rotate yearly, store and transport credentials quarterly, payment-provider credentials half-yearly (see each service's security section).
Data classification and logging (D31)¶
| Data | Classification | Handling |
|---|---|---|
| Projects, memberships, releases, runs, usage | internal | tenant-isolated, 1-year default retention, export in open formats |
| Subscription and invoices | confidential | commercial scope only, 7-year retention |
| Prompts, model responses, artifact content | tenant data | never logged by the Control Plane; referenced by hash and artifact id |
| Audit trail | restricted | append-only in BC-19, 7 years, redacted identifiers |
Audit¶
Every command, decision, alias move, freeze, delegation and subscription change is published on the envelope and consumed by AuditService (BC-19). The audit entry names actor, scope, action, target version and reason; it is the evidence a tenant exports on request.
Threats the design answers¶
- Prompt injection cannot change scope, release or policy: those are pinned from trusted context, not from model output.
- A stale decision cannot authorize a changed proposal: requests are version-bound and become
Stale. - A lost lease cannot commit a second outcome: fencing tokens reject the late holder.
- A moved alias cannot alter an accepted run: aliases select at submission only.
- A partner agent cannot exceed its tenant's membership: A2A tasks run with the caller's delegated scope and are budget-reserved like any run.