# 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
(PIP)"] SCIM --> IdP["NetKingdom SSO
Keycloak / key-cape-compatible OIDC"] IdP --> Token["OIDC Access Token
roles, scopes, groups, org, assurance"] Token --> Mapper["Identity Claim Mapper"] Mapper --> Subject["PolicySubject"] Source["Markdown objects
labels, paths, trust zones"] --> Object["PolicyObject"] Subject --> Gateway["Markitect AccessPolicyGateway
(PEP)"] Object --> Gateway Gateway --> PDP["Policy Decision Point
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. The current Markitect-side implementation provides deterministic local building blocks: - `NetKingdomIdentityClaimsAdapter` validates required IAM-profile claims, issuer, audience, token timestamps, roles/scopes, and production rejection of local development issuers for already trusted claims or explicit JWT fixtures. - `EnterprisePolicyMap` and `LocalEnterprisePolicyMapper` map groups, roles, and scopes into `PolicySubject` labels, trust zones, actions, and diagnostic attributes. - `StaticDirectoryGroupResolver` models group freshness and overage without a live directory dependency. - `FlexAuthResourceManifest` describes Markitect knowledge resources for future flex-auth registration. - `LocalDecisionLogStore` provides a JSONL development/test sink for decision records. Live OIDC discovery, JWKS signature verification, directory synchronization, central policy administration, and durable enterprise audit should be provided by flex-auth/key-cape-facing adapters rather than Markitect core. ## Canonical Subject Mapping Recommended normalized shape: ```yaml subject: id: "oidc:#" 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] ``` Command-line subject mapping: ```text mkt policy subject examples/policy/netkingdom-claims.yaml \ --policy-map examples/policy/enterprise-policy-map.yaml ``` ## Data/Object Mapping Markdown remains the source-friendly object labeling layer: ```yaml --- policy: labels: [internal] trust_zone: internal owner: team:platform-architecture --- ``` A Markitect knowledge base can publish an explicit flex-auth resource manifest: ```yaml id: markitect-example-knowledge-base system: markitect-tool actions: [read, query, search, package, export] resources: - id: knowledge-base:markitect-example type: knowledge_base - id: document:internal-note type: document parent: knowledge-base:markitect-example path: examples/policy/private/internal-note.md labels: [internal] trust_zone: internal ``` 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. ## flex-auth Boundary The preferred long-term shape is a separate `flex-auth` service/repo under the NetKingdom authorization umbrella. In that model, Markitect remains a resource consumer and policy enforcement point. flex-auth owns the central resource registry, enterprise group/role/scope mapping, external PDP adapters, and durable decision logs. The product survey, Keycloak/Entra analysis, and boundary recommendation now live in the sibling `flex-auth` repo: `flex-auth/docs/flex-auth-authorization-registry-research.md`. Implementation follow-up is tracked there: - `FLEX-WP-0002`: standalone policy-as-code core and check APIs. - `FLEX-WP-0003`: flex-auth service-side Markitect consumer integration. - `FLEX-WP-0004`: delegated PDP and directory adapters. Markitect should not implement a live flex-auth service client until `FLEX-WP-0003` stabilizes the resource-registration and check/batch_check API. ## 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`