The standard was accepted at v0.7 on 2026-08-29. Four of flex-auth's review findings are in the accepted text: 9.3's two-owner split, 6.4.2 scoped to the decision's own binding with our canonical request digest as its mechanical test, 9.7.2 split by role, and 17 moving the decision-record schema to access-engine. INTENT.md - Machine-readable layer declaration in frontmatter (layer: Engine, role: PDP), which section 11 requires and we did not have. audit-core noted our declaration was legible only by following the decision trail. - PDP failure semantics stated: our outage is consumer residue, not input degradation; fail-open is not expressible by a PDP at all. - Four owned obligations added: the decision-record schema as our contract, the request digest as the published replay test, a lifetime on every allow, and visibility deadlines per input class. - A Layer Conformance section stating the state honestly: conforming with one declared gap, no Tooling client, not PEP-shaped. - Vocabulary correction: earlier text dropped "control plane" as Staff vocabulary. Section 8 binds it to the Engine layer, which is why kings-guard was asked to release it. The term is ours; we prefer "decision engine" for precision, not boundary. SCOPE.md - Layer and role in the one-liner; the four obligations In Scope; five boundaries established in review but never written down Out of Scope. - Three capability blocks marked planned for workplans completed in May are now current; two blocks added. - Superseded ADR-0006 citation corrected to ADR-0009, which retires the global flag outright rather than deferring it. history/2026-08-29-layer-model-v0.7-alignment-review.md checks each obligation against the code and finds six gaps. FLEX-WP-0019 closes them, with T02 before T04 because a visibility deadline for registry-borne facts is unfalsifiable until provenance can identify the snapshot a decision read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012sgN4GH5ZYT8pJVkCR6dcP Assistant: claude-code Assistant-Model: opus Assistant-Process: 4014348@bnt-lap001 Assistant-Session: a993abda-65a0-4ea8-8ccd-0fcd78c92ac0
16 KiB
| layer | role | framework | standard_version | declared_by | declared_at | pep_stance | tooling_contacts |
|---|---|---|---|---|---|---|---|
| Engine | PDP | netkingdom-security-layer-model | 0.7 | decisions/decisions.md FLEX-DEC-2026-001, FLEX-DEC-2026-002, FLEX-DEC-2026-003 | 2026-08-29 | null |
Flex-Auth Intent
Layer declaration. flex-auth is Engine / PDP under the NetKingdom Security Layer Model (
net-kingdom/canon/standards/security-layer-model_v0.7.md, accepted 2026-08-29). It is the only policy decision point in NetKingdom (§6): no other repository, in any layer, renders or caches an authorization decision. The frontmatter above is the machine-readable form §11 requires; this paragraph is the declaration in flex-auth's own voice.The layer rule that binds every repository: Staff never touches Tooling directly. It acts only through Engine APIs. flex-auth is one of those APIs.
What PDP means here, and what it does not. As the estate's only PDP, flex-auth's outage is consumer residue, not input degradation (§9.3): when flex-auth is unreachable there is no evaluator in the path, so what happens next is the consumer's declared stance and never flex-auth's to express. Fail-open is not expressible by a PDP at all. When flex-auth is reachable but cannot reach its own inputs, the fallback is flex-auth's, deterministic, and fails to reduced authority. The PIP engines — user, tenant, zone, approval, maturity — supply facts flex-auth consumes as claims;
audit-corerecords;secrets-engineholds credential lifecycle downstream of a decision.flex-auth reached this position by review rather than assertion, and holds three records:
FLEX-DEC-2026-001(Engine framing, theaccess-enginename, the authoring/evaluation split),FLEX-DEC-2026-002(§9.3 contested and upheld), andFLEX-DEC-2026-003(v0.6 review; §6.4.2, §9.7.2 and §17 as adopted in v0.7).One item remains open: the ruled rename to
access-engine. It is a separate governed migration — it touchesFLEX-WPprefix ownership, State Hub identifiers, ops-warden's routing tables, zone-engine's boundary text, and secrets-engine integrations — and carries two conditions fromFLEX-DEC-2026-001: repository identity and runtime identity rename in separate revertible steps, repository first, because the enforcing ops-warden pin binds tokens to the protected-system name; andFLEX-WPprefix ownership stays with the repository.
This file captures why this repository exists, the direction it is moving toward, and the kind of system it is meant to become. It is intentionally aspirational and stable, not a description of current implementation.
Intent
Flex-auth is a policy-as-code authorization registry and decision engine for organizations that want to grow from simple access rules into enterprise-grade authorization without giving up clear ownership, local development ergonomics, or inspectable policy decisions.
It is an Engine, role PDP, in the NetKingdom security layer model
(net-kingdom/canon/standards/security-layer-model_v0.7.md): a deterministic
API for a modeled concept, where the same authoritative input state yields the
same result.
Within NetKingdom it is the only policy decision point (standard §6). No other repository, in any layer, may render or cache an authorization decision. Engine typing (§3.3) makes the corollary explicit: a new engine is a PIP unless the standard is amended, so "we need an engine for X" can never become "X now decides".
A note on vocabulary, corrected here. Earlier versions of this file dropped "control plane" on the grounds that it was Staff-layer vocabulary. That reason was wrong on the standard's own terms — §8 binds control plane to the Engine layer, which is why kings-guard was asked to release it. The term is flex-auth's to use. This file prefers decision engine anyway, because it names what flex-auth does rather than where it sits, but the preference is style, not a boundary.
It is the authorization layer in the path from verified identity to protected resources:
verified identity claims
-> flex-auth policy-as-code and authorization registry
-> protected systems and their resources
Flex-auth should run usefully on its own, and should also be able to delegate to or coordinate established authorization engines — relationship/graph engines, rule and attribute policy engines, and directory systems — without binding its own model to any one of them.
Why This Exists
Most organizations start with coarse roles, groups, and application-specific conditionals. Over time they need richer policy:
- resource hierarchies and inherited access
- project/team/tenant boundaries
- relationship-based authorization
- attribute and context based rules
- emergency/break-glass controls
- policy tests and reviewable changes
- durable decision logs and explainability
- integration with identity, MFA, service accounts, and directory groups
Flex-auth should give those organizations a path that starts small and grows cleanly instead of forcing an early leap into a large IAM platform or letting authorization logic sprawl across applications.
Responsibility Boundary
Flex-auth consumes verified identity claims as normative input and never re-defines them. Identity proves who an actor is and how they were authenticated; flex-auth decides what that actor is allowed to do.
The Identity Layer Owns Identity
- Authentication, login, MFA, and token issuance and lifecycle.
- The canonical identity claim contract and required claims.
- Coarse roles, scopes, and assurance claims.
Flex-Auth Owns the Decision
- Evaluation — exclusively. Rendering the decision, in-path, deterministically.
- Protected-system registration.
- Resource namespaces and resource hierarchy.
- Canonical action vocabulary.
- The policy-as-code mechanism: package format, tests, versions, and rollout.
- Mapping enterprise groups, app roles, scopes, tenants, and assurance claims into resource-specific authorization.
- Relationship facts and inherited access.
- PDP adapter coordination.
- Decision logging, explanations, and audit export.
- The decision-record schema, published as flex-auth's own contract (§17). A decision record is the PDP's output artifact — the one thing in the estate only flex-auth produces — so §2 keeps its schema here rather than in Taxonomy. flex-auth argued this against its own interest and took the work on.
- The canonical request digest over normalized subject, action, resource, and context. It is the mechanical test for §6.4.2: a consumer may replay a verdict iff the digest matches and the decision's lifetime holds.
- A stated lifetime on every allow (§9.7.1) — a TTL, or a binding to a session or obligation that ends. An allow with no stated end is a standing grant.
- A revocation visibility deadline per input class (§9.7.2) — approval-claim freshness, registry snapshot cadence, policy package activation, directory ETag. A single number at a PDP is either a fiction or the worst case.
Gate House Owns the Doctrine the Decision Serves
Authoring and governing security doctrine is Staff work. gate-house owns the
invariants policy must satisfy, the authority ceilings, the assistant and
autonomous operating modes, and the authority context — principal, actor,
runtime identity, tenant, mandate, operating mode — which flex-auth consumes as
input claims alongside verified identity claims.
The division is between authoring the rules of the game and rendering a result: gate-house designs the approval contract and the invariants; flex-auth validates approvals and renders decisions at request time. Neither can do the other's half. Policy content for a given protected system remains authored by that system's owner, within flex-auth's mechanism and gate-house's doctrine.
Gate House holds no runtime position and never renders a decision. A deterministic authority boundary inside a non-deterministic layer would violate the invariant the estate is built on.
One condition follows from that, drawn by flex-auth on review (FLEX-DEC-2026-001): an authority ceiling that determines an outcome must reach the decision either as an input claim on the request or as a rule in the versioned policy package, so that its application is reconstructable from the decision record. A ceiling that resolves an outcome before evaluation runs has decided early. This is not a limit on gate-house's authorship — it is what keeps that authorship auditable at decision time, and it is the same test flex-auth applied to zone-engine's zone stance and, in the note above, to its own registry.
Protected Systems Own Enforcement
Applications remain policy enforcement points. They extract resource metadata, call flex-auth for decisions, enforce allow/deny/redact results, and emit local diagnostics. They do not own central policy administration.
Access Lanes Are Not Access Rules
The estate uses "access" for two different things, and the demarcation is normative (standard §8):
- ops-warden and ops-mason own access lanes — how a worker reaches a host: routes, tunnels, SSH certificates, credential lanes.
- flex-auth owns access rules — whether an actor may act at all.
A lane delivers someone to the door. This repository decides whether the door opens. Neither substitutes for the other, and neither owns the other's word.
Design Principles
- Policy is code: versioned, reviewed, tested, and explainable.
- Identity is not authorization: identity claims are inputs, not final decisions.
- Start standalone, scale outward: a local flex-auth deployment should be useful before any external policy engine integration is available.
- Backend-neutral core: flex-auth has its own resource, action, request, decision, and audit vocabulary.
- Pluggable PDPs: relationship, rule, and directory engines are adapters, not hard dependencies.
- Fail visibly: denied, redacted, stale, partial, and uncertain decisions must produce useful diagnostics.
- Grow into enterprise: the same model should support local dev, small teams, and larger enterprise environments.
First-Class Concepts
- Subject: human, service account, group, team, tenant, emergency principal.
- Resource: protected object registered by a system.
- Namespace: resource type and ownership boundary.
- Action: operation requested on a resource.
- Context: request, environment, assurance, workflow, or runtime attributes.
- Policy package: versioned policy-as-code bundle with tests and metadata.
- Relationship fact: subject-resource or resource-resource relation.
- Decision: allow, deny, redact, audit-only, or not-applicable with reason.
- Audit event: durable decision record with policy version and provenance.
Initial API Shape
register_system(system_manifest)
register_resource(resource_manifest)
sync_relationships(relationship_manifest)
check(subject, action, resource, context) -> decision
batch_check(subject, action, resources, context) -> decisions
list_allowed(subject, action, resource_type, filters, context) -> resources
explain(decision_id) -> explanation
publish_policy_package(package)
test_policy_package(package, fixtures)
activate_policy_version(policy_id, version)
record_decision(decision)
Standalone Mode
Standalone flex-auth should provide:
- local resource registry
- local subject/group/team registry
- local relationship facts
- policy package validation
- deterministic check and batch-check APIs
- local decision log
- CLI and service mode
- test fixtures for representative identity claims
Standalone mode should be enough for development, smaller deployments, and integration tests.
Delegated Mode
Delegated mode should let flex-auth coordinate established systems without adopting their models as its own:
- relationship/graph engines for relationship-heavy authorization
- rule and attribute policy engines for attribute/rule policies
- directory systems for group resolution
- a local directory plus policy-evaluation engine for self-contained delegated setups
Flex-auth remains the stable decision point even when the backend changes.
Consumer Patterns
Two consumer shapes drive flex-auth, and the first one to ship deliberately is not a document pipeline — proving the decision engine stays generic.
First shipped consumer — an action gate (ops-warden SSH signing). A protected system asks flex-auth a single "may this actor perform this action now?" question before doing irreversible work:
- it registers a protected system, a resource type (
ssh-certificate), and an action (sign) - it sends one policy check per request, passing subject, resource, and context (actor type, principals, TTL, key fingerprint)
- it enforces the allow/deny decision and records the decision id for audit
- flex-auth owns the policy and durable decision log; the protected system keeps custody of its own keys and secrets
This first consumer validated that flex-auth's resource/action/context model,
POST /v1/check contract, and decision envelope work for a non-document,
high-stakes gate without any consumer-specific routes.
First knowledge-pipeline consumer (planned) — a document and knowledge pipeline (Markitect):
- it registers knowledge bases, repositories, documents, sections, context packages, workflow artifacts, and exports
- it sends policy checks before returning query/search/context results
- it can redact or drop results based on decisions
- flex-auth owns central policy administration and durable audit
Together these shape flex-auth around real authorization needs — both point-in-time action gates and result-filtering pipelines — without making the policy service consumer-specific.
Layer Conformance
flex-auth's conformance state under §11 is conforming with one declared gap. It holds no Tooling client, so the §5 shapes do not apply to it, and it is not PEP-shaped, so it owes no stance map under §6.4.
The declared gap — registry-snapshot digest in decision provenance (§13).
DecisionProvenance carries the evaluator, mode, policy package, policy version,
directory ETag, and decision time, but no digest of the registry snapshot that
supplied resource, subject, and relationship facts. A decision that turned on
registry content cannot be replayed from its own provenance.
v0.7 §9.7.2 promotes this from housekeeping to a conformance prerequisite, on flex-auth's own argument: a stated visibility deadline for a fact carried by a registry snapshot is unfalsifiable while provenance holds no snapshot digest, because nobody can determine afterwards which snapshot a decision read. The deadline and the digest are one gap seen from two sides.
Until it closes, one rule holds and flex-auth applies it to everyone equally, including itself: outcome-determining content belongs in the versioned policy package, not in registry content — for zone stance, for gate-house's authority ceilings, for maturity levels, and for flex-auth's own facts. Registry content carries membership and identity; the policy package carries effect.
Non-Goals
- Flex-auth is not an identity provider.
- Flex-auth is not a replacement for an identity or SSO system.
- Flex-auth is not a mandatory dependency for every local development use case.
- Flex-auth should not force one PDP backend.
- Flex-auth should not hide policy complexity behind opaque admin toggles.
Early Work
- Define the resource/action/decision model.
- Define policy package structure and test fixtures.
- Implement standalone registry and check API.
- Add a first protected-system resource manifest and policy adapter.
- Evaluate a delegated directory-plus-policy backend.
- Add relationship-engine and rule-engine adapter spikes.
- Add identity and enterprise-directory integration examples.