--- id: canon-iam-profile type: standard title: "IAM Profile v0.1" domain: custodian status: superseded version: "0.1" created: "2026-05-02" updated: "2026-05-22" scope: all-hubs superseded_by: net-kingdom/canon/standards/iam-profile_v0.2.md --- # IAM Profile v0.1 > Superseded 2026-05-22. The canonical core/platform IAM Profile is now > owned by net-kingdom at `canon/standards/iam-profile_v0.2.md`, with > ownership and version governance recorded in > `docs/adr/ADR-0011-iam-profile-ownership-and-version-governance.md`. > This v0.1 all-hubs draft remains historical Custodian context only; > hub-specific scopes such as `hub:*`, `ops:*`, and `fin:*` are downstream > extensions of the NetKingdom core profile. ## 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.