Added IAM Profile standard
This commit is contained in:
235
canon/standards/iam-profile_v0.1.md
Normal file
235
canon/standards/iam-profile_v0.1.md
Normal file
@@ -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.
|
||||
@@ -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"
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user