A security orchestrator observes a changing system, selects an intervention, applies it through enforcement points, and watches the result. That makes it a feedback controller. Because its outputs can revoke credentials, isolate workloads, reduce grants, require stronger authentication, or stop new leases, it is also a privileged actor.

Design rule: the controller may propose a security action; it may not bypass the same identity, policy, tenant, freshness, and scope checks imposed on other privileged actors.

Closed-loop model

Observe → decide → authorize → enforce

Fail closed

Rendering diagram…

1. Model the system before automating it

Use a discrete-time model. At step k, let the protected system state be:

Xk=(Rk,Gk,Lk,Hk,Tk)
Rkresources and their security-relevant configuration
Gkactive grants, roles and policy bindings
Lksessions, credentials, tokens and leases
Hkworkload, identity and control-plane health
Tktenant ownership and isolation relationships

The controller rarely sees Xk directly. It receives an observation:

yk=h(Xk)+νk

Here h is the measurement process—logs, identity events, configuration snapshots, traces, posture signals and alerts—and νk represents missing, delayed, duplicated, corrupted or noisy telemetry. Treating observations as perfect state is the first modelling error to avoid.

Symbols and implementation counterparts

SymbolMeaningTypical implementation
XkSecurity-relevant system stateResource graph, IAM bindings, session store, workload inventory
ykObservation available to the controllerNormalized event plus correlated state snapshot
ΠkPolicy and its exact versionSigned policy bundle, revision and rollout metadata
ukCandidate actionTyped command: revoke, quarantine, step-up, deny-new-leases
ωkExternal disturbanceAttacker action, failure, deploy, scaling event, administrator change
dkAuthorization decision recordPermit/deny, scope, reason, policy revision, expiry, evidence

2. Close the loop

Let the information available at step k be the observation history and the current policy:

Ik=(y0,…,yk,Πk)

The controller proposes an action from that information:

uk=𝒞(y0,…,yk,Πk)

The system then evolves under the applied action and the external disturbance:

Xk+1=ℱ(Xk,u~k,ωk)

The tilde matters: uk is only a proposal. The plant receives ũk, the action that survives authorization and enforcement.

3. Put an authorization guard in front of the controller

Define an authorization guard A that evaluates the controller identity, requested operation, target tenant, target resource, policy revision and current preconditions. Here X̂k is the freshest state the authorizer can observe under the declared consistency contract:

ak=A(uk,X^k,Πk)∈{0,1}

The command delivered for enforcement is therefore:

u~k={ukif ak=1u∅if ak=0

u∅ is a safe no-op or a fail-closed transition. It must not silently become “execute anyway and alert later.”

Authorization predicate
Apply(uk)⇒ControllerAuthenticated∧ActionAuthorized(uk)∧TenantScopeValid(uk)∧PreconditionsSatisfied(uk)

What the guard must bind

A permit should bind at least the controller identity, action type, tenant, resource set, permitted effect, policy revision, evidence revision, issue time, expiry time, preconditions and an idempotency key. A valid signature over an under-specified command is not adequate authorization.

{
  "decision_id": "dec_01…",
  "controller": "security-orchestrator/prod",
  "action": "revoke_session_family",
  "tenant_id": "tenant-a",
  "resource_ids": ["user:1842"],
  "policy_revision": 417,
  "evidence_revision": 88031,
  "preconditions": ["session_epoch == 91", "risk_state == confirmed"],
  "not_before": "2026-09-14T10:12:20Z",
  "expires_at": "2026-09-14T10:12:50Z",
  "idempotency_key": "contain:incident-712:user-1842"
}

4. Containment must shrink authority

Let ℛ(X) be the set of protected effects reachable from state X: API calls, data reads, writes, role assumptions, token exchanges, network flows and lease creation. An action explicitly labelled containment must be non-expansive:

ℛafter⊆ℛbefore

A useful containment action usually makes the inclusion strict. The weaker subset form permits an idempotent replay: revoking an already-revoked credential does not further shrink authority, but it also does not restore any.

Check the effect, not the action label. Moving a workload into a “quarantine” network that accidentally gains a new administrative path violates containment even if the command is named isolate.

Restoration is not the inverse edge

Restoration expands reachable effects. It is therefore a new authorization decision at a later time, not an automatic reversal when an anomaly score falls:

Restore(u−1,k′)⇒NewPermit(k′)∧¬ScoreOnly

A falling anomaly score is evidence. It is not authority. Restoration should re-evaluate identity, policy, tenant, current resource state, incident disposition, credential lifecycle and required approvals. Expired or revoked authority stays dead unless a new grant is issued.

Security is a constrained control objective

Blindly minimizing reachable authority can destroy availability. A practical controller minimizes risk, disruption and control churn subject to hard safety and service constraints:

minuk:k+N∑ik+N[αRisk(Xi)+βDisruption(ui)+γChurn(ui)]

Rate limits, dwell times, hysteresis and human approval for high-blast-radius actions are not operational afterthoughts. They are mechanisms that prevent oscillation and unsafe over-correction.

5. Make tenant isolation a transition property

For tenants j ∈ 𝒯, represent the overall state as a product of tenant projections plus explicitly shared infrastructure:

X=(×j∈𝒯X(j))×Xshared

If action u is scoped to tenant t, every unrelated tenant projection should remain observationally equivalent to the no-op transition:

j≠t(u)⇒projj(ℱ(X,u,ω))≃projj(ℱ(X,u∅,ω))

Shared resources require an explicit coupling model. If isolating one tenant can exhaust a shared gateway, rotate a shared key or invalidate a shared cache, that cross-tenant effect belongs in the declared action scope and blast-radius review. It must not remain an invisible side effect.

6. Choose a consistency contract

Authorization is evaluated against distributed state: policy replicas, identity stores, revocation indexes, caches, resource versions and enforcement points. “The controller was authorized” is incomplete unless the system defines which version of that state counted.

Contract A

Strict authorization

With monotonically ordered authorization revisions, at a defined serialization point τ(q), the effect uses a decision based on a revision at least as new as the required revision for request q.

rev(d)≥requiredRev(q,τ(q))

Use this where post-revocation effects are unacceptable and the latency cost is justified.

Contract B

Bounded stale authorization

Permit a decision from a snapshot no older than Δauth, then state the maximum exposure window explicitly.

now−snapshotTime(d)≤Δauth

A conservative revocation bound is W ≤ Δprop + Δcache + Δin-flight. Measure all three terms; do not call the system “eventually consistent” and leave the risk unbounded.

Google’s Zanzibar paper is useful here because it treats authorization consistency as a system property, including causal ordering and externally consistent decisions, rather than as a cache implementation detail. The exact mechanism need not be copied; the discipline should be.

7. Verify the protected effect, not merely the decision

The central safety property connects the request, the decision actually enforced, and the resulting protected effect. Here q is a protected request and t is its effect time:

∀q,t:ProtectedEffectExecuted(q,t)⇒ValidEnforcedPermit(q,t)∧EffectWithinAuthorizedScope(q,t)

This is stronger than “the policy engine returned permit.” It requires proof that the PEP enforced the intended decision, that the decision was valid at the chosen consistency point, and that the observed side effects stayed inside the decision’s scope.

Expanded permit validity predicate
ValidEnforcedPermit(q,t)≜Decision(q)=Permit∧ControllerAuthenticated(q)∧ActionAuthorized(q)∧TenantScopeValid(q)∧PolicyFreshEnough(q,t)∧PreconditionsSatisfied(q,t)∧NotBefore(q)≤t<ExpiresAt(q)∧PEPBoundToDecision(q)∧ReplaySafe(q)

NIST SP 800-207 separates the logical policy engine, which decides; the policy administrator, which establishes or terminates the communication path; and the policy enforcement point, which enables, monitors and terminates the connection. Those roles can be colocated or replicated, but the proof obligations remain distinct.

8. Translate the model into software contracts

A practical implementation can preserve the model without turning every service into a control-theory project. The important move is to make proposals, decisions, commands and effect receipts distinct records.

  1. Normalize observations. Attach tenant, subject, resource, event time, ingestion time, source integrity and evidence revision.
  2. Build a candidate action. Make it typed, deterministic for the same input, bounded in scope and safe to retry.
  3. Authorize at execution time. Evaluate controller identity, action, tenant, resource, policy revision, current preconditions and decision lifetime.
  4. Enforce through a narrow adapter. The PEP accepts only signed or mutually authenticated commands with an explicit schema and allowlist.
  5. Return an effect receipt. Record the actual changed resources, previous and resulting versions, partial failures and enforcement time.
  6. Observe again. Confirm the intended state transition. A successful API response is not proof that the system reached the safe state.
def reconcile(observation, policy_revision):
    candidate = controller.propose(observation, policy_revision)
    decision = authorizer.evaluate(candidate, fresh_state=True)

    if not decision.permit:
        return audit.denied(candidate, decision)

    command = bind(candidate, decision, ttl_seconds=30)
    receipt = enforcement_point.apply(command)

    assert receipt.tenant_id == decision.tenant_id
    assert receipt.effects <= decision.authorized_effects
    return verifier.confirm(receipt)

Separate control planes by capability

ComponentMay doMust not do
DetectorProduce evidence and confidenceDirectly mutate protected state
ControllerPropose a bounded typed actionMint its own authority
Policy engineDecide using identity, policy and contextAssume enforcement occurred
Policy administratorIssue or terminate the authorized command/pathBroaden the decided scope
PEPEnforce and return a receiptAccept ambiguous tenant or resource targets
VerifierCompare intended and observed effectsTreat request acceptance as state convergence

9. Worked example: suspicious workload credentials

Assume a workload identity begins making unusual cross-service calls.

01

Observe. The detector correlates new egress destinations, a token exchange and an anomalous call graph. The observation is scoped to tenant A and workload W.

02

Propose. The controller requests deny_new_leases(W) and revoke_session_family(W). It does not request deletion, role changes or a tenant-wide network shutdown.

03

Authorize. Policy permits this controller to contain workload W in tenant A for 30 seconds, provided the workload generation and identity epoch still match the evidence.

04

Enforce. The identity PEP increments W’s session epoch; the lease PEP denies new grants. Each returns a versioned receipt.

05

Verify. Existing sessions fail revalidation, no new leases appear, unrelated tenant projections are unchanged, and ℛafter ⊂ ℛbefore.

06

Restore deliberately. A later recovery workflow issues fresh workload credentials only after remediation evidence and a new permit. A lower risk score does not re-enable the old epoch.

10. Verification plan

Test the model at three levels.

Properties

State-machine tests

  • No protected effect without a valid permit.
  • Containment never expands reachable effects.
  • Replays are idempotent.
  • Restore always requires a new decision.
Distributed behaviour

Fault injection

  • Delay policy and revocation propagation.
  • Duplicate and reorder commands.
  • Expire a decision during enforcement.
  • Partition the controller from one PEP.
Isolation

Tenant proofs

  • Generate cross-tenant identifiers.
  • Exercise shared-resource coupling.
  • Compare effect receipts with permit scope.
  • Alert on missing tenant attribution.

Trust anchors: identity issuers, policy authorities, signing and encryption keys, clocks, enforcement components and the evidence path used to verify effects. Compromise of one of these components changes what the invariant can guarantee; the threat model must say so explicitly.

Sources and further reading

From model to evidence

Can your automation prove what it changed?

A useful security review should connect controller identity, policy revision, enforcement receipts, tenant scope and post-action evidence—not stop at a diagram or a successful API response.

Get a free Drift Audit →