Enterprise access control integration

This commit is contained in:
2026-05-04 15:32:54 +02:00
parent ffab98be10
commit 5ecb52aece
9 changed files with 838 additions and 3 deletions

View File

@@ -139,6 +139,22 @@ to future backend storage.
## Adapter Boundaries
Enterprise IAM integration is covered in
`docs/enterprise-access-control-integration.md`. In that architecture,
Markitect is the policy enforcement point for Markdown knowledge results, while
NetKingdom/key-cape-compatible OIDC supplies identity claims and external
policy engines can act as policy decision points.
Identity and directory integration use these provider-neutral boundaries:
- `IdentityClaimsAdapter` validates OIDC/JWT/SAML material and returns
normalized `EnterpriseIdentity`.
- `DirectoryGroupResolver` resolves group overage or stale directory claims
through SCIM/Graph/LDAP/Keycloak-style adapters.
- `EnterprisePolicyMapper` maps canonical enterprise roles, scopes, and groups
to `PolicySubject` labels, trust zones, and allowed actions.
- `DecisionLogStore` persists durable audit records for policy decisions.
Relationship policies use `RelationshipPolicyAdapter`:
```text

View File

@@ -0,0 +1,335 @@
# Enterprise Access-Control Integration
Date: 2026-05-04
## Purpose
This note explains how Markitect's access-control gateway should integrate with
enterprise IAM while respecting the local NetKingdom/key-cape direction.
The answer is yes: trust zones and access groups can map to canonical directory
group membership, but Markitect should not trust raw AD group names directly.
The enterprise shape should be:
```text
OIDC/SAML/SCIM identity and directory plane
-> canonical subject claims
-> policy map and/or policy decision point
-> Markitect policy gateway
-> filtered document/query/context results
```
Markitect is the policy enforcement point for Markdown knowledge results. It
should validate and normalize identity data through adapters, then call a policy
decision point through the existing policy interfaces.
## Canonical Enterprise Shape
The canonical enterprise pattern is the PEP/PDP/PIP/PAP split:
| Component | Markitect fit |
| --- | --- |
| PEP: policy enforcement point | `AccessPolicyGateway` at query, search, context, workflow, export, and assisted-prompt boundaries. |
| PDP: policy decision point | Local label policy for development; OpenFGA/SpiceDB, OPA/Rego, Cedar, or enterprise authorization service through adapters. |
| PIP: policy information point | NetKingdom/key-cape OIDC claims, directory group resolution, object labels, backend metadata, workflow context, and environment attributes. |
| PAP: policy administration point | Enterprise IAM/policy administration, plus versioned Markitect mapping files for labels, actions, trust zones, and emergency rules. |
This keeps Markitect small and auditable. It enforces decisions where Markdown
knowledge leaves a boundary, but it does not become the enterprise directory,
SSO provider, or policy administration system.
## Local Infrastructure Fit
The local canon already points the right way:
- NetKingdom SSO is the reference identity provider.
- Keycloak is the reference OIDC provider, with privacyIDEA-backed MFA.
- key-cape is the lightweight OIDC/profile-enforcement path for local,
sandbox, and bootstrap scenarios.
- Services should trust OIDC tokens, validate issuer/audience/signature/expiry,
and authorize from explicit roles/scopes.
Markitect should therefore consume the NetKingdom IAM profile rather than
create its own identity standard.
## Enterprise Reference Architecture
```mermaid
flowchart LR
AD["AD / LDAP / HRIS"] --> SCIM["SCIM / Directory Sync<br/>(PIP)"]
SCIM --> IdP["NetKingdom SSO<br/>Keycloak / key-cape-compatible OIDC"]
IdP --> Token["OIDC Access Token<br/>roles, scopes, groups, org, assurance"]
Token --> Mapper["Identity Claim Mapper"]
Mapper --> Subject["PolicySubject"]
Source["Markdown objects<br/>labels, paths, trust zones"] --> Object["PolicyObject"]
Subject --> Gateway["Markitect AccessPolicyGateway<br/>(PEP)"]
Object --> Gateway
Gateway --> PDP["Policy Decision Point<br/>local / OpenFGA / OPA / Cedar"]
PDP --> Decision["PolicyDecision + audit metadata"]
Decision --> Boundary["Filtered query/search/context results"]
```
### Identity Plane
OIDC should be the default authentication path for users and services. SAML may
remain relevant for enterprise federation, but Markitect should normalize both
into the same subject shape.
The canonical accepted claims should follow the NetKingdom IAM profile:
- `iss`
- `sub`
- `aud`
- `exp`
- `iat`
- `scope` or `scp`
- `preferred_username`
- `roles` or `realm_access.roles`
- recommended `groups`, `azp`, `email`, `name`
For humans, Authorization Code + PKCE is the right login flow. For services,
client credentials or workload identity should produce short-lived service
tokens. OAuth token exchange can support hub-to-hub delegation where a service
acts on behalf of a user.
### Directory And Group Plane
Enterprise directories remain authoritative for group membership. Provisioning
should use a standard such as SCIM where possible; AD/LDAP synchronization into
Keycloak is also reasonable when NetKingdom owns the identity plane.
Important design rule:
```text
directory groups -> canonical roles/scopes/trust labels -> Markitect subject
```
Avoid:
```text
raw AD group name -> direct Markitect privilege
```
Reasons:
- AD group names change and often encode organizational accidents.
- Token group claims can be too large for large organizations.
- Privilege should be expressed as app roles/scopes or an explicit mapping file.
- Group membership freshness must be visible in the decision trail.
For Microsoft Entra-style group claims, large tenants may hit token group
overage. Markitect should therefore support a group-resolution adapter rather
than assuming all groups are always present in the token.
### Policy Plane
The existing Markitect interfaces already provide the main policy boundary:
```text
AccessPolicyGateway.authorize(subject, action, object_id, context)
AccessPolicyGateway.filter_results(subject, action, results, context)
AccessPolicyGateway.explain_decision(decision_id)
```
The existing data models also fit enterprise needs:
- `PolicySubject`: identity, roles, groups/labels, allowed actions, attributes.
- `PolicyObject`: path, labels, trust zone, attributes.
- `PolicyDecision`: stable decision id, effect, reason, labels, trust zone,
metadata.
- `PolicyFilterResult`: filtered results, decisions, diagnostics, summary.
The adapter seams are also correct:
- `RelationshipPolicyAdapter` for OpenFGA/SpiceDB/Zanzibar-style checks.
- `RulePolicyAdapter` for OPA/Rego, Cedar, or other ABAC engines.
This follow-up adds the missing interface layer:
```text
OIDC token or SAML assertion -> verified EnterpriseIdentity -> PolicySubject
```
Concrete adapters must validate issuer, audience, expiry, signature, and
assurance metadata before any authorization decision is made. The core package
now exposes protocol/data boundaries for this without taking a dependency on
Keycloak, Entra, LDAP, SCIM, OpenFGA, OPA, or Cedar client libraries.
## Canonical Subject Mapping
Recommended normalized shape:
```yaml
subject:
id: "oidc:<issuer>#<sub>"
display_name: "Ada Lovelace"
principal_type: human | service
issuer: "https://sso.example.org/realms/netkingdom"
audience: ["markitect-tool"]
authorized_party: "markitect-cli"
roles: [viewer, operator]
scopes: [openid, profile, hub:read]
groups:
- /markitect/readers
- /platform/architecture
allowed_labels: [public, internal]
trust_zones: [public, internal]
assurance:
mfa: true
acr: "..."
amr: ["pwd", "otp"]
directory:
source: keycloak | entra | ldap | scim
refreshed_at: "2026-05-04T10:00:00Z"
```
The mapping file should translate enterprise groups and app roles to Markitect
labels and actions:
```yaml
id: markitect-enterprise-policy-map
issuer: https://sso.example.org/realms/netkingdom
audiences: [markitect-tool]
groups:
/markitect/readers:
allowed_labels: [public, internal]
actions: [query, search, read]
/markitect/stewards:
allowed_labels: [public, internal, restricted]
actions: [query, search, read, package, export]
roles:
admin:
allowed_labels: [public, internal, restricted]
actions: [query, search, read, package, export, policy-admin]
scopes:
markitect:read:
actions: [query, search, read]
trust_zones:
internal:
required_groups: [/markitect/readers]
```
## Data/Object Mapping
Markdown remains the source-friendly object labeling layer:
```yaml
---
policy:
labels: [internal]
trust_zone: internal
owner: team:platform-architecture
---
```
For enterprise environments, object metadata should eventually include:
- content labels/classification
- repository/path
- owning team or project
- business domain
- tenancy/org
- retention or export constraints
- provenance of label assignment
Path rules remain useful as a safety net, but document labels and backend
metadata should become authoritative for cached/context-package retrieval.
## Enforcement Points
Markitect should enforce policy at every point where knowledge leaves a
boundary:
- `mkt cache query`
- `mkt search`
- context package creation and activation
- workflow outputs
- assisted/LLM prompt assembly
- export/render steps
- backend APIs or future MCP resources
The highest-risk point is context assembly for agents. Before WP-0008 turns
context caches into agent memory, policy must be able to answer:
- who is activating the context package?
- which token or service account is acting?
- which labels/trust zones are included?
- was anything denied or redacted?
- can this package be reactivated later under the same policy assumptions?
## Interface Confirmation
The WP-0009 infrastructure is a good foundation. It already has:
- policy gateway protocol
- local label gateway
- explainable decisions
- filter-before-return behavior
- query/search integration
- relationship and rule adapter boundaries
This follow-up adds these provider-neutral interfaces in
`markitect_tool.policy.adapters`:
1. `IdentityClaimsAdapter`
- validates OIDC/JWT/SAML assertions
- normalizes NetKingdom/key-cape-compatible claims into
`EnterpriseIdentity`
2. `DirectoryGroupResolver`
- resolves group overage or stale claims
- supports SCIM/Graph/LDAP/Keycloak admin APIs behind adapters
- records freshness and source provenance
3. `EnterprisePolicyMapper`
- maps canonical groups, roles, scopes, and tenants to Markitect labels,
trust zones, actions, and object constraints
4. `DecisionLogStore`
- persists policy decisions for query/context/workflow runs
- records token hash, subject id, action, object id, policy version, result,
reason, and redaction status
5. workflow/runtime policy injection
- `subject_from_token`
- `policy_map`
- `required_assurance`
- `emergency_justification`
Concrete implementations remain future work. This is deliberate: key-cape and
NetKingdom should own identity issuance and profile compliance, while
Markitect owns normalization, policy envelopes, diagnostics, and enforcement at
knowledge boundaries.
## Recommended Direction
Do not make AD/LDAP/Entra groups a Markitect core dependency.
Instead:
1. Accept NetKingdom/key-cape-compatible OIDC tokens.
2. Normalize claims into `PolicySubject`.
3. Map enterprise groups/roles/scopes to Markitect labels/trust zones/actions.
4. Use the existing `AccessPolicyGateway` as the enforcement point.
5. Let OpenFGA/SpiceDB/OPA/Cedar attach through adapter protocols where a
deployment needs stronger central policy.
6. Persist decisions before using this for production agent memory or exports.
## Sources
- OpenID Connect Core 1.0: https://openid.net/specs/openid-connect-core-1_0.html
- OAuth 2.0 Token Exchange, RFC 8693: https://www.rfc-editor.org/rfc/rfc8693
- SCIM Protocol, RFC 7644: https://datatracker.ietf.org/doc/rfc7644
- NIST SP 800-162 ABAC guide: https://csrc.nist.gov/pubs/sp/800/162/upd2/final
- NIST glossary, Policy Enforcement Point:
https://csrc.nist.gov/glossary/term/policy_enforcement_point
- NIST glossary, Policy Decision Point:
https://csrc.nist.gov/glossary/term/policy_decision_point
- NIST glossary, Policy Information Point:
https://csrc.nist.gov/glossary/term/policy_information_point
- Keycloak Server Administration Guide: https://www.keycloak.org/docs/latest/server_admin/
- Microsoft Entra group claims: https://learn.microsoft.com/en-us/security/zero-trust/develop/configure-tokens-group-claims-app-roles
- OpenFGA concepts: https://openfga.dev/docs/concepts
- Open Policy Agent policy language: https://www.openpolicyagent.org/docs/policy-language
- Cedar policy language: https://docs.cedarpolicy.com/
- Local canon: `/home/worsch/the-custodian/canon/standards/iam-profile_v0.1.md`

View File

@@ -38,6 +38,7 @@ and descriptions mirror the operational view.
| `MKTT-WP-0005` | complete | done | `MKTT-WP-0003`, `MKTT-WP-0004` | Runtime context, form state, dynamic rules, workflow integration, and provider-neutral assessment boundary are complete. |
| `MKTT-WP-0011` | complete | done | `MKTT-WP-0003`; task-level triggers: `MKTT-WP-0010-T001`, `MKTT-WP-0010-T005` | Markdown dataflow workflow layer is complete: workflow standard, source collectors, binding model, deterministic steps, assisted boundary, safe outputs, CLI, docs, and examples. |
| `MKTT-WP-0009` | complete | done | `MKTT-WP-0006` | Access-controlled knowledge gateway is complete: local labels, trust zones, path rules, policy-aware cache query/search, decisions, diagnostics, and external adapter boundaries. |
| `MKTT-WP-0014` | P2 | todo | `MKTT-WP-0009` | Enterprise IAM access-control integration: NetKingdom/key-cape-compatible identity claims, directory group resolution, policy maps, durable decision logs, and external PDP examples. |
| `MKTT-WP-0012` | P3 | todo | `MKTT-WP-0004`, `MKTT-WP-0010`, `MKTT-WP-0011` | Future Quarkdown-inspired document function layer: reusable Markdown-native function calls over processors, references, contracts, workflows, and later assisted steps. |
| `MKTT-WP-0008` | P3 | todo | `MKTT-WP-0006`, `MKTT-WP-0007`, `MKTT-WP-0009` | Agent working-memory cache after backend and policy floor are available. |
@@ -74,6 +75,12 @@ operations deserve author-facing function syntax. It should remain optional and
capability-gated, especially before assisted, external, file, or network
functions are allowed.
`MKTT-WP-0014` captures enterprise IAM integration for the access-control
gateway. It should follow `MKTT-WP-0009` and can run before or alongside
security-sensitive context memory work. It does not block local `MKTT-WP-0008`
research, but it should gate production deployment of reactivatable agent
context packages in enterprise environments.
## State Hub Mirror
Native State Hub dependency edges should mirror the whole-workstream
@@ -100,6 +107,7 @@ dependencies:
- `MKTT-WP-0012 -> MKTT-WP-0004`
- `MKTT-WP-0012 -> MKTT-WP-0010`
- `MKTT-WP-0012 -> MKTT-WP-0011`
- `MKTT-WP-0014 -> MKTT-WP-0009`
- `MKTT-WP-0008 -> MKTT-WP-0006`
- `MKTT-WP-0008 -> MKTT-WP-0007`
- `MKTT-WP-0008 -> MKTT-WP-0009`