diff --git a/canon/standards/iam-profile_v0.1.md b/canon/standards/iam-profile_v0.1.md new file mode 100644 index 0000000..529ca29 --- /dev/null +++ b/canon/standards/iam-profile_v0.1.md @@ -0,0 +1,235 @@ +--- +id: canon-iam-profile +type: standard +title: "IAM Profile v0.1" +domain: custodian +status: draft +version: "0.1" +created: "2026-05-02" +updated: "2026-05-02" +scope: all-hubs +--- + +# IAM Profile v0.1 + +## Purpose + +This standard defines the identity and access-management contract shared by +Custodian hubs and services. It gives hub-core, dev-hub, ops-hub, fin-hub, and +domain services one predictable OIDC profile without binding them to one +deployment topology. + +The reference provider is NetKingdom SSO: Keycloak as the OIDC provider, with +privacyIDEA-backed MFA for human authentication. Local development may use a +file-backed OIDC provider if it exposes the same contract. + +## Design Principles + +- Hubs trust OIDC tokens, not provider-specific session state. +- Human and service identities are distinct. +- Authorization decisions use explicit claims and scopes. +- Local development degrades gracefully without weakening production rules. +- Emergency access is auditable, time-bounded, and never silent. + +## Discovery Contract + +Every IAM profile implementation MUST expose standard OIDC discovery: + +```text +GET /.well-known/openid-configuration +``` + +The discovery response MUST include: + +- `issuer` +- `authorization_endpoint` +- `token_endpoint` +- `jwks_uri` +- `userinfo_endpoint` +- `end_session_endpoint` when supported +- `scopes_supported` +- `response_types_supported` +- `grant_types_supported` +- `id_token_signing_alg_values_supported` + +Services MUST validate tokens against the advertised `issuer` and `jwks_uri`. +Key material MUST be cacheable, but services MUST tolerate key rotation. + +## Required Flows + +### Human Interactive Flow + +Human users authenticate through Authorization Code + PKCE. + +Required properties: + +- PKCE is mandatory for browser or CLI login. +- MFA is mandatory for privileged roles in production. +- Access tokens are short-lived. +- Refresh tokens are allowed only for trusted clients with explicit rotation. + +### Service Account Flow + +Hub-to-hub and service-to-service traffic uses client credentials or a +provider-supported service-account equivalent. + +Required properties: + +- Service accounts are named after the service and environment. +- Service credentials are stored through the credential-management standard, + not in plaintext config. +- Tokens include an audience that identifies the target hub or service. +- Service accounts receive only the scopes required for their role. + +## Required Claims + +Access tokens accepted by hubs MUST provide: + +| Claim | Meaning | +|---|---| +| `iss` | OIDC issuer URL | +| `sub` | Stable subject identifier | +| `aud` | Intended audience; MUST include the receiving hub/service | +| `exp` | Expiry timestamp | +| `iat` | Issued-at timestamp | +| `scope` or `scp` | Granted scopes | +| `preferred_username` | Human-readable username for human identities | +| `roles` or `realm_access.roles` | Role names used for hub authorization | + +Recommended claims: + +| Claim | Meaning | +|---|---| +| `email` | Contact identity for humans | +| `name` | Display name | +| `groups` | Organization/group membership | +| `azp` | Authorized party/client id | + +Services MUST NOT infer privilege from `email`, display name, or group naming +conventions alone. Privilege comes from explicit roles and scopes. + +## Required Scopes + +The following scopes form the shared vocabulary: + +| Scope | Purpose | +|---|---| +| `openid` | Required for OIDC login | +| `profile` | Basic user profile | +| `email` | Email claim where appropriate | +| `hub:read` | Read hub state | +| `hub:write` | Mutate ordinary hub state | +| `hub:admin` | Administrative hub operations | +| `hub:message` | Send and manage inter-agent/hub messages | +| `hub:capability` | Request, accept, and update capability requests | +| `hub:repo` | Register and update managed repository metadata | +| `ops:read` | Read operational state | +| `ops:write` | Mutate operational records | +| `fin:read` | Read financial state | +| `fin:write` | Mutate financial records | + +High-impact scopes such as `hub:admin`, `ops:write`, and `fin:write` MUST be +issued only to MFA-authenticated humans or narrowly scoped service accounts. + +## Role Vocabulary + +The minimum shared roles are: + +| Role | Meaning | +|---|---| +| `viewer` | Read-only orientation | +| `operator` | Operational changes within an assigned domain | +| `steward` | Cross-domain governance and escalation | +| `admin` | IAM and hub administration | +| `service` | Non-human service identity | +| `emergency` | Temporary break-glass identity | + +Hubs MAY define local roles, but shared integrations MUST map them back to this +vocabulary when communicating across hubs. + +## Token Lifecycle + +Recommended production defaults: + +| Token | Lifetime | Notes | +|---|---|---| +| Access token | 5-15 minutes | Short-lived; bearer token | +| Refresh token | 8-12 hours | Rotated; revoked on logout or suspicion | +| Service token | 5-30 minutes | Reissued by client credentials | + +Services MUST reject expired tokens and tokens with invalid issuer, audience, or +signature. Clock skew tolerance SHOULD be small, normally no more than 60 +seconds. + +## Hub-to-Hub Service Account Pattern + +Each hub receives one service account per environment: + +```text +svc-dev-hub-prod +svc-ops-hub-prod +svc-fin-hub-prod +svc-dev-hub-dev +``` + +Service accounts: + +- authenticate with client credentials or equivalent workload identity +- carry the `service` role +- carry only the scopes required by the calling hub +- are rotated through the credential-management standard +- are never shared between environments + +Example: dev-hub forwarding a deployment event to ops-hub should use a +dev-hub service account with `ops:write` scoped to the event-ingestion endpoint, +not an all-purpose admin token. + +## Local Development Profile + +A local file-backed provider MAY be used when Keycloak/privacyIDEA is +unavailable. It MUST: + +- expose OIDC discovery +- issue signed JWTs +- support deterministic test users and service accounts +- use local-only issuer URLs by default +- clearly mark tokens as development tokens through issuer or audience +- never be accepted by production hubs + +This profile exists to keep hub development possible without cluster +dependency; it is not a production identity system. + +## Human Override and Emergency Access + +Emergency access is allowed only as a break-glass path. + +Requirements: + +- Emergency identities are disabled by default. +- Activation requires a human-recorded decision or incident reference. +- Tokens are short-lived and carry the `emergency` role. +- Every emergency action emits a progress event or ops incident timeline entry. +- Emergency access is reviewed after use and then disabled again. + +Emergency access MUST NOT bypass audit logging. + +## Validation Checklist + +A service conforms to this profile when: + +- It reads OIDC discovery rather than hardcoding endpoints. +- It validates issuer, audience, expiry, and signature. +- It checks explicit roles/scopes for authorization. +- It supports Authorization Code + PKCE for human login. +- It supports service-account tokens for hub-to-hub calls. +- It rejects local-development issuers in production. +- It logs emergency access with a durable audit trail. + +## Open Questions + +- Whether `roles` or `realm_access.roles` becomes the canonical role claim for + all hubs, or whether adapters normalize both. +- Whether hub-to-hub event forwarding should use audience-per-hub or + audience-per-endpoint. +- Whether production service accounts eventually move from client credentials + to Kubernetes workload identity. diff --git a/workplans/CUST-WP-0025-fos-hub-bootstrap.md b/workplans/CUST-WP-0025-fos-hub-bootstrap.md index 567b62a..b8f67dd 100644 --- a/workplans/CUST-WP-0025-fos-hub-bootstrap.md +++ b/workplans/CUST-WP-0025-fos-hub-bootstrap.md @@ -104,7 +104,7 @@ This test becomes the template for hub-core auth middleware. ```task id: CUST-WP-0025-T04 -status: todo +status: done priority: medium state_hub_task_id: "69acc880-394b-478a-94f0-476c9cbc1bc6" ```