Align IAM Profile consumption with v0.2
Some checks failed
CI / Build and Test (push) Has been cancelled
CI / Lint (push) Has been cancelled

This commit is contained in:
2026-05-22 14:35:30 +02:00
parent 8354485632
commit aa8e3a4e34
7 changed files with 105 additions and 45 deletions

View File

@@ -126,7 +126,7 @@ local diagnostics.
- key-cape / NetKingdom SSO: identity source and coarse claims provider; - key-cape / NetKingdom SSO: identity source and coarse claims provider;
flex-auth consumes the **NetKingdom IAM Profile** flex-auth consumes the **NetKingdom IAM Profile**
(`~/the-custodian/canon/standards/iam-profile_v0.1.md`). (`~/net-kingdom/canon/standards/iam-profile_v0.2.md`).
- Markitect: first protected-system consumer and policy enforcement point. - Markitect: first protected-system consumer and policy enforcement point.
- Topaz: aligned evaluator. Per ADR-003 the standalone core is shaped - Topaz: aligned evaluator. Per ADR-003 the standalone core is shaped
to match Topaz's Rego + directory model from day one; the Topaz to match Topaz's Rego + directory model from day one; the Topaz

View File

@@ -1,14 +1,16 @@
# NetKingdom IAM Profile — flex-auth Consumption Surface # NetKingdom IAM Profile — flex-auth Consumption Surface
Date: 2026-05-16 Date: 2026-05-22
Status: Draft for FLEX-WP-0005 P5.5; binds the input contract for the Status: Aligned with NetKingdom IAM Profile v0.2; binds the input contract
standalone evaluator (FLEX-WP-0002) and every PDP adapter (FLEX-WP-0004). for the standalone evaluator (FLEX-WP-0002) and every PDP adapter
Upstream: `~/the-custodian/canon/standards/iam-profile_v0.1.md`. (FLEX-WP-0004).
Upstream: `~/net-kingdom/canon/standards/iam-profile_v0.2.md`.
## Boundary ## Boundary
The NetKingdom IAM Profile defines the OIDC contract shared across hubs The NetKingdom IAM Profile defines the OIDC contract shared across
and services. flex-auth **consumes verified claims**; it does not platform, tenant, service, and agent principals. flex-auth **consumes
verified claims**; it does not
verify token signatures, fetch JWKS, or terminate OIDC sessions. Those verify token signatures, fetch JWKS, or terminate OIDC sessions. Those
responsibilities belong upstream: responsibilities belong upstream:
@@ -32,17 +34,25 @@ envelope identical to Markitect's `EnterpriseIdentity` shape:
```yaml ```yaml
issuer: <oidc issuer URL> # required issuer: <oidc issuer URL> # required
subject: <stable subject id> # required subject: <stable subject id> # required
principal_type: human | service | emergency tenant: tenant:platform | tenant:<id> # required
principal_type: human | service | agent
audience: [<aud>, ...] # required, non-empty audience: [<aud>, ...] # required, non-empty
authorized_party: <azp or client_id, optional> authorized_party: <azp or client_id, optional>
preferred_username: <string> # required for humans preferred_username: <string> # required for humans
roles: [<role>, ...] # required, non-empty roles: [<role>, ...] # required, non-empty
scopes: [<scope>, ...] # required, non-empty scopes: [<scope>, ...] # required, non-empty
groups: [<group>, ...] # optional; resolved by directory layer groups: [<group>, ...] # required, may be empty
assurance: assurance:
level: aal0 | aal1 | aal2 | aal3 | break_glass
methods: [<method>, ...]
mfa: <bool>
source: <identity or MFA evidence source>
at: <unix timestamp, optional>
acr: <oidc acr value, optional> acr: <oidc acr value, optional>
amr: [<oidc amr value>, ...] # e.g. pwd, otp, mfa, hwk amr: [<oidc amr value>, ...] # tolerated provider-native input
mfa: <bool — derived from amr> agent:
id: <agent id, optional>
mode: autonomous | delegated
directory: directory:
groups_claim_present: <bool> groups_claim_present: <bool>
group_overage: <bool> # Microsoft Entra-style group overage group_overage: <bool> # Microsoft Entra-style group overage
@@ -55,7 +65,7 @@ provenance:
This is the envelope every check API call receives, regardless of This is the envelope every check API call receives, regardless of
which upstream identity provider produced the token. which upstream identity provider produced the token.
## Required Claims (per IAM Profile §"Required Claims") ## Required Claims (per IAM Profile v0.2 "Core Claims")
flex-auth treats the following as hard requirements. Missing any flex-auth treats the following as hard requirements. Missing any
produces a `validation_error` before the request reaches a policy produces a `validation_error` before the request reaches a policy
@@ -68,9 +78,13 @@ package.
| `aud` | `audience` | Must include the flex-auth instance or the protected system. | | `aud` | `audience` | Must include the flex-auth instance or the protected system. |
| `exp` | (validated upstream) | flex-auth tolerates ≤60s clock skew per profile §"Token Lifecycle". | | `exp` | (validated upstream) | flex-auth tolerates ≤60s clock skew per profile §"Token Lifecycle". |
| `iat` | (validated upstream) | Same. | | `iat` | (validated upstream) | Same. |
| `tenant` | `tenant` | Required for platform/tenant boundary decisions. |
| `principal_type` | `principal_type` | `human`, `service`, or `agent`; emergency is a role plus `assurance.level=break_glass`. |
| `groups` | `groups` | Required, possibly empty; overage is handled by directory resolvers. |
| `scope` or `scp` | `scopes` | At least one scope required. Empty scope is a hard fail. | | `scope` or `scp` | `scopes` | At least one scope required. Empty scope is a hard fail. |
| `preferred_username` | `preferred_username` | Required for `principal_type=human`. Optional for service accounts. | | `roles` | `roles` | Canonical role source. At least one role required by current flex-auth policy fixtures. |
| `roles` or `realm_access.roles` or `resource_access.<client>.roles` | `roles` | Union of all three sources. At least one role required. | | `assurance` | `assurance` | Required normalized evidence object with level, methods, mfa, and source. |
| `preferred_username` | `preferred_username` | Required for `principal_type=human`. Optional for service and agent principals. |
## Recommended Claims ## Recommended Claims
@@ -78,7 +92,6 @@ package.
| --- | --- | --- | | --- | --- | --- |
| `email` | `claims.email` | Contact identity; **never** used for authorization decisions. | | `email` | `claims.email` | Contact identity; **never** used for authorization decisions. |
| `name` | `claims.name` | Display only. | | `name` | `claims.name` | Display only. |
| `groups` | `groups` (after resolution) | Authorization input; subject to freshness/overage. |
| `azp` | `authorized_party` | Distinguishes service-account client from impersonating client. | | `azp` | `authorized_party` | Distinguishes service-account client from impersonating client. |
| `acr` | `assurance.acr` | Authentication context class; gates high-trust scopes. | | `acr` | `assurance.acr` | Authentication context class; gates high-trust scopes. |
| `amr` | `assurance.amr` | Authentication methods; `otp`/`mfa`/`hwk` lift `assurance.mfa` to true. | | `amr` | `assurance.amr` | Authentication methods; `otp`/`mfa`/`hwk` lift `assurance.mfa` to true. |
@@ -87,29 +100,31 @@ package.
flex-auth normalizes — protected systems never see the variation. flex-auth normalizes — protected systems never see the variation.
- **Role claim location.** Three OIDC providers ship roles in three - **Role claim location.** IAM Profile v0.2 makes top-level `roles`
places: top-level `roles`, Keycloak's `realm_access.roles`, and canonical. During migration, flex-auth may also accept Keycloak's
Keycloak's per-client `resource_access.<client>.roles`. flex-auth `realm_access.roles` and `resource_access.<client>.roles`, but those
unions all three. are provider-native compatibility inputs.
- **Scope encoding.** `scope` (space-separated string) and `scp` - **Scope encoding.** `scope` (space-separated string) and `scp`
(array) both accepted; both produce the same `scopes` array. (array) both accepted; both produce the same `scopes` array.
- **Audience encoding.** `aud` as a single string or as an array; - **Audience encoding.** `aud` as a single string or as an array;
flex-auth always normalizes to an array. flex-auth always normalizes to an array.
- **MFA signal.** Either an explicit `mfa: true` claim or any of - **MFA signal.** IAM Profile v0.2 uses `assurance.mfa` and
`otp`/`mfa`/`hwk` in `amr` produces `assurance.mfa = true`. `assurance.level`. Legacy/provider-native `amr` and `acr` are
tolerated as inputs to the normalized assurance object.
## Principal-Type Detection ## Principal-Type Detection
flex-auth classifies the principal by: IAM Profile v0.2 supplies `principal_type` directly. flex-auth uses that
claim as normative input. Legacy fixtures may be classified by:
1. If `client_id` is set and `service` is in `roles``service`. 1. If `client_id` is set and `service` is in `roles``service`.
2. If `azp` starts with `svc-` or `service` is in `roles``service`. 2. If `azp` starts with `svc-` or `service` is in `roles``service`.
3. If `emergency` is in `roles``emergency`. 3. If agent metadata is present`agent`.
4. Otherwise → `human`. 4. Otherwise → `human`.
This matches Markitect's `NetKingdomIdentityClaimsAdapter._principal_type` This matches Markitect's `NetKingdomIdentityClaimsAdapter._principal_type`
and follows IAM Profile §"Hub-to-Hub Service Account Pattern" (service as a compatibility path. New claim envelopes should not force flex-auth
accounts named `svc-*` and carrying the `service` role). to infer principal type.
## Group Overage and Freshness ## Group Overage and Freshness
@@ -140,7 +155,9 @@ Per IAM Profile §"Local Development Profile":
Per IAM Profile §"Human Override and Emergency Access": Per IAM Profile §"Human Override and Emergency Access":
- `emergency` is a first-class `principal_type`. - Emergency access is represented as a human, service, or agent
principal with an `emergency`/`break-glass` role and
`assurance.level: break_glass`.
- Every decision involving an emergency principal MUST record a - Every decision involving an emergency principal MUST record a
`record_emergency` obligation in the decision envelope. `record_emergency` obligation in the decision envelope.
- Policy packages MAY allow emergency principals; flex-auth's audit - Policy packages MAY allow emergency principals; flex-auth's audit
@@ -154,11 +171,11 @@ the validation steps above in Python. flex-auth's Go implementation
(FLEX-WP-0002 P2.4) mirrors its behavior and stays in sync via (FLEX-WP-0002 P2.4) mirrors its behavior and stays in sync via
contract tests against the fixtures in `examples/claims/`. contract tests against the fixtures in `examples/claims/`.
## Open Items ## Compatibility Notes
- Whether `roles` becomes canonical and `realm_access.roles` becomes - `roles` is canonical in IAM Profile v0.2. `realm_access.roles` and
legacy is still listed as an open question in IAM Profile v0.1. As `resource_access.<client>.roles` remain tolerated provider-native inputs
of 2026-05-16 flex-auth normalizes both with no preference. while Keycloak mappings are updated.
- `Workload identity` (Kubernetes service-account tokens, GCP/AWS - Workload identity may enter through a documented token-exchange path,
workload-identity federation) is not yet in the IAM Profile. but the normalized envelope still carries `principal_type: service` or
flex-auth's service-account handling is currently OIDC-only. `principal_type: agent`, `tenant`, and `assurance`.

View File

@@ -1,6 +1,6 @@
# examples/claims/ # examples/claims/
Contract fixtures for the NetKingdom IAM Profile v0.1 claim shapes Contract fixtures for the NetKingdom IAM Profile v0.2 claim shapes
flex-auth must accept. Each file is the *raw verified claim map* as flex-auth must accept. Each file is the *raw verified claim map* as
flex-auth receives it from the upstream identity layer (key-cape or flex-auth receives it from the upstream identity layer (key-cape or
Keycloak); flex-auth's normalization produces the same Keycloak); flex-auth's normalization produces the same
@@ -11,10 +11,10 @@ surface.
| Fixture | Provider | Demonstrates | | Fixture | Provider | Demonstrates |
| --- | --- | --- | | --- | --- | --- |
| `key-cape-lightweight.yaml` | key-cape lightweight mode | Profile-conformant minimum: single audience, top-level `roles` array, single-factor `amr=pwd`. | | `key-cape-lightweight.yaml` | key-cape lightweight mode | Profile-conformant minimum: single audience, top-level `roles` array, explicit tenant/principal/assurance. |
| `keycloak-heavy.yaml` | Keycloak production | Full variation set: `realm_access.roles` + `resource_access.<client>.roles`, scope as space-separated string, MFA via `amr=otp`, multiple audiences. | | `keycloak-heavy.yaml` | Keycloak production | Full variation set: canonical `roles`, provider-native role sources, scope as space-separated string, MFA assurance, multiple audiences. |
| `service-account.yaml` | Either provider | Hub-to-hub service account; `service` + `operator` roles, no `preferred_username`, narrow scope. | | `service-account.yaml` | Either provider | Service account; `principal_type: service`, `service` + `operator` roles, no `preferred_username`, narrow scope. |
| `emergency.yaml` | Either provider | Break-glass human identity; `emergency` role, short expiry, hardware MFA, audit-trail metadata in an `emergency` claim. | | `emergency.yaml` | Either provider | Break-glass human identity; `emergency` role, `assurance.level: break_glass`, short expiry, audit-trail metadata in an `emergency` claim. |
| `keycloak-group-overage.yaml` | Entra/Keycloak | Group-claim overage signal (`hasgroups: true`); flex-auth's directory resolver fetches the full set. | | `keycloak-group-overage.yaml` | Entra/Keycloak | Group-claim overage signal (`hasgroups: true`); flex-auth's directory resolver fetches the full set. |
These fixtures are loaded by the standalone evaluator's contract tests These fixtures are loaded by the standalone evaluator's contract tests

View File

@@ -2,9 +2,9 @@
# expiry, emergency role, requires MFA per the profile, and triggers # expiry, emergency role, requires MFA per the profile, and triggers
# durable audit recording on every flex-auth decision that involves it. # durable audit recording on every flex-auth decision that involves it.
# #
# Reference: NetKingdom IAM Profile v0.1 §"Human Override and Emergency # Reference: NetKingdom IAM Profile v0.2 "Emergency And Break-Glass
# Access". flex-auth maps this to principal_type=emergency and emits a # Access". flex-auth maps the emergency role plus break_glass assurance to
# `record_emergency` obligation on every decision. # a `record_emergency` obligation on every decision.
iss: https://sso.netkingdom.example/realms/netkingdom iss: https://sso.netkingdom.example/realms/netkingdom
sub: f1c4f64e-2c0c-4cda-8c9f-9f3f8f3a2b0e sub: f1c4f64e-2c0c-4cda-8c9f-9f3f8f3a2b0e
@@ -13,6 +13,8 @@ aud:
exp: 1767226200 # iat + 10 minutes; emergency tokens are short-lived exp: 1767226200 # iat + 10 minutes; emergency tokens are short-lived
iat: 1767225600 iat: 1767225600
auth_time: 1767225595 auth_time: 1767225595
tenant: tenant:platform
principal_type: human
azp: ops-console azp: ops-console
preferred_username: ada preferred_username: ada
email: ada@netkingdom.example email: ada@netkingdom.example
@@ -20,11 +22,22 @@ scope: openid profile hub:admin
roles: roles:
- emergency - emergency
- admin - admin
groups:
- /platform/stewards
amr: amr:
- pwd - pwd
- otp - otp
- hwk - hwk
acr: "3" acr: "3"
assurance:
level: break_glass
methods:
- pwd
- otp
- hwk
mfa: true
source: keycloak
at: 1767225595
emergency: emergency:
incident_id: INC-2026-0042 incident_id: INC-2026-0042
authorized_by: "team:platform-stewards" authorized_by: "team:platform-stewards"

View File

@@ -2,8 +2,8 @@
# authenticated human user. Profile-conformant minimum: required claims # authenticated human user. Profile-conformant minimum: required claims
# only, single audience, simple roles list, OIDC standard amr values. # only, single audience, simple roles list, OIDC standard amr values.
# #
# Reference: docs/iam-profile-consumption.md, NetKingdom IAM Profile v0.1 # Reference: docs/iam-profile-consumption.md, NetKingdom IAM Profile v0.2
# §"Required Claims" and §"Local Development Profile". # "Core Claims" and "Local Development Profile".
iss: https://idp.netkingdom.local/keycape iss: https://idp.netkingdom.local/keycape
sub: user-7f9e2b sub: user-7f9e2b
@@ -11,6 +11,8 @@ aud:
- flex-auth - flex-auth
exp: 4102444800 # 2100-01-01, kept far-future for stable fixtures exp: 4102444800 # 2100-01-01, kept far-future for stable fixtures
iat: 1767225600 # 2026-01-01 iat: 1767225600 # 2026-01-01
tenant: tenant:platform
principal_type: human
preferred_username: ada preferred_username: ada
email: ada@netkingdom.local email: ada@netkingdom.local
name: Ada Lovelace name: Ada Lovelace
@@ -22,3 +24,10 @@ amr:
acr: "1" acr: "1"
groups: groups:
- /markitect/readers - /markitect/readers
assurance:
level: aal1
methods:
- pwd
mfa: false
source: key-cape
at: 1767225600

View File

@@ -14,6 +14,8 @@ aud:
exp: 4102444800 exp: 4102444800
iat: 1767225600 iat: 1767225600
auth_time: 1767225590 auth_time: 1767225590
tenant: tenant:platform
principal_type: human
azp: markitect-cli azp: markitect-cli
preferred_username: ada preferred_username: ada
email: ada@netkingdom.example email: ada@netkingdom.example
@@ -22,6 +24,8 @@ name: Ada Lovelace
given_name: Ada given_name: Ada
family_name: Lovelace family_name: Lovelace
scope: openid profile email hub:read hub:write hub:capability scope: openid profile email hub:read hub:write hub:capability
roles:
- operator
realm_access: realm_access:
roles: roles:
- default-roles-netkingdom - default-roles-netkingdom
@@ -40,4 +44,12 @@ amr:
- pwd - pwd
- otp - otp
acr: "2" acr: "2"
assurance:
level: aal2
methods:
- pwd
- otp
mfa: true
source: keycloak
at: 1767225590
sid: 4c0a3a8a-3a47-4f2f-8e89-9e5f9b0a0a0a sid: 4c0a3a8a-3a47-4f2f-8e89-9e5f9b0a0a0a

View File

@@ -3,8 +3,7 @@
# operation it performs. No preferred_username (service identities are # operation it performs. No preferred_username (service identities are
# named after the service and environment per the profile). # named after the service and environment per the profile).
# #
# Reference: NetKingdom IAM Profile v0.1 §"Service Account Flow" and # Reference: NetKingdom IAM Profile v0.2 "Service Account Flow".
# §"Hub-to-Hub Service Account Pattern".
iss: https://sso.netkingdom.example/realms/netkingdom iss: https://sso.netkingdom.example/realms/netkingdom
sub: svc-markitect-tool-prod sub: svc-markitect-tool-prod
@@ -12,9 +11,19 @@ aud:
- flex-auth - flex-auth
exp: 4102444800 exp: 4102444800
iat: 1767225600 iat: 1767225600
tenant: tenant:platform
principal_type: service
azp: svc-markitect-tool-prod azp: svc-markitect-tool-prod
client_id: svc-markitect-tool-prod client_id: svc-markitect-tool-prod
scope: hub:read hub:capability scope: hub:read hub:capability
roles: roles:
- service - service
- operator - operator
groups: []
assurance:
level: aal1
methods:
- client_secret
mfa: false
source: keycloak
at: 1767225600