Skip to content

Phase 2 S12.e: authoritative allowlistRef mode (fail-closed) - #120

Merged
Pal Lakatos-Toth (pallakatos) merged 1 commit into
devfrom
phase2-s12-e-authoritative
Apr 30, 2026
Merged

Pal Lakatos-Toth (pallakatos) merged 1 commit into
devfrom
phase2-s12-e-authoritative

Conversation

@pallakatos

Copy link
Copy Markdown
Collaborator

Promote spec.networkPolicy.allowlistRef from status-only (S12.b) to
authoritative source for NetworkPolicy egress. Lifts the
`AZURECLAW_FEATURE_SIGNED_ALLOWLIST` env gate (always-on).

What changed

  • Resolver (`controller/src/policy_fetcher.rs`):
    `resolve_allowlist[_with_handle]` implements the 4-branch
    decision tree:
    1. no ref + inline → legacy inline (`AllowlistAuthoritative=False/Inline`)
    2. ref + verify ok → artifact endpoints; LKG updated
      (`Verified=True`, `Authoritative=True/Verified`,
      `Drift=…` if inline differs)
    3. ref + verify fails + LKG present → LKG endpoints
      (`Authoritative=False/StaleLKG`)
    4. ref + verify fails + no LKG → fail closed: no user egress,
      pod not deployed, Degraded + requeue
      (`Authoritative=False/FailedClosed`).
  • LKG cache: in-process `HashMap<(ns,name), LkgEntry>` —
    controller restart drops it deliberately so a stale allowlist
    cannot ride across an operator-visible event.
  • Drift detection: set-equal after host-lowercase + default-port-443
    normalization. `InlineCleared` debounce (≤2 reconciles) before
    the condition drops out of status.
  • Transient errors preserve prior conditions and re-use prior LKG.
  • Reconciler: resolution computed once, drives both NP egress
    rules and status patch. `fail_closed_no_lkg` short-circuits pod
    deployment after writing the (no-user-rules) NP and stamping
    Degraded.
  • Helm CRD: new `Allowlist` printer column (priority 1);
    `allowlistRef` description updated.
  • Docs: new audit doc
    `docs/security-audits/2026-04-30-phase2-s12-e-authoritative.md`,
    new "Authoritative mode" section in
    `docs/policy-canonical-format.md`, CHANGELOG entry.

Tests

  • 16 new resolver / LKG / drift tests in
    `controller/src/policy_fetcher.rs` (resolution branches, LKG round
    trip, restart simulation, security property that inline is never a
    silent fallback, drift normalization, malformed signer policy, …).
  • 5 feature-gate-specific tests removed (code path no longer exists).
  • Net: controller 401 → 412 passing. Full workspace
    `cargo fmt --all && cargo clippy --all-targets -- -D warnings && cargo test --all`
    green. `helm lint deploy/helm/azureclaw` green.

Migration

None. There is no installed base; the prior gate defaulted off, so no
production cluster relied on the old behavior. Operators who set
`allowlistRef` will now see verify run on the next reconcile —
either publish a SignerPolicy (S12.d) or unset the ref to keep using
inline endpoints.

Threat model

See `docs/security-audits/2026-04-30-phase2-s12-e-authoritative.md`.
Key properties:

  • inline is never a silent fallback when `allowlistRef` is set
  • LKG is in-process only; restart drops it
  • `fail_closed_no_lkg` writes only baseline NP rules and refuses to
    deploy the pod
  • transient errors do not collapse a working sandbox

🤖 Generated with the assistance of GitHub Copilot.

Promote spec.networkPolicy.allowlistRef from status-only to authoritative
source for NetworkPolicy egress.

* Lift AZURECLAW_FEATURE_SIGNED_ALLOWLIST env gate (always-on).
* Add resolve_allowlist[_with_handle] in controller/src/policy_fetcher.rs
  implementing the four-branch decision tree:
  (1) no ref + inline → legacy inline path
  (2) ref + verify ok → artifact endpoints (LKG updated)
  (3) ref + verify fails + LKG present → LKG endpoints
  (4) ref + verify fails + no LKG → fail-closed (no user egress, no pod)
* Add in-process per-(ns,name) last-known-good cache. Controller restart
  drops the LKG deliberately so the first post-restart reconcile of a
  verify-failing sandbox cannot ride a stale allowlist across an
  operator-visible event.
* Surface three status conditions: AllowlistVerified (existing),
  AllowlistAuthoritative (new), AllowlistDrift (new) with
  2-reconcile InlineCleared debounce.
* Reconciler computes resolution once, drives both NP egress and
  status. fail_closed_no_lkg short-circuits pod deployment.
* Helm CRD: new Allowlist printer column (priority 1); allowlistRef
  description updated.
* CHANGELOG, audit doc, policy-canonical-format.md updated.
* Tests: 401 → 412 controller (16 new − 5 removed feature-gate);
  full workspace cargo fmt/clippy/test green; helm lint green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pallakatos
Pal Lakatos-Toth (pallakatos) merged commit 8e1721e into dev Apr 30, 2026
16 checks passed
Pal Lakatos-Toth (pallakatos) added a commit that referenced this pull request May 12, 2026
Promote spec.networkPolicy.allowlistRef from status-only to authoritative
source for NetworkPolicy egress.

* Lift AZURECLAW_FEATURE_SIGNED_ALLOWLIST env gate (always-on).
* Add resolve_allowlist[_with_handle] in controller/src/policy_fetcher.rs
  implementing the four-branch decision tree:
  (1) no ref + inline → legacy inline path
  (2) ref + verify ok → artifact endpoints (LKG updated)
  (3) ref + verify fails + LKG present → LKG endpoints
  (4) ref + verify fails + no LKG → fail-closed (no user egress, no pod)
* Add in-process per-(ns,name) last-known-good cache. Controller restart
  drops the LKG deliberately so the first post-restart reconcile of a
  verify-failing sandbox cannot ride a stale allowlist across an
  operator-visible event.
* Surface three status conditions: AllowlistVerified (existing),
  AllowlistAuthoritative (new), AllowlistDrift (new) with
  2-reconcile InlineCleared debounce.
* Reconciler computes resolution once, drives both NP egress and
  status. fail_closed_no_lkg short-circuits pod deployment.
* Helm CRD: new Allowlist printer column (priority 1); allowlistRef
  description updated.
* CHANGELOG, audit doc, policy-canonical-format.md updated.
* Tests: 401 → 412 controller (16 new − 5 removed feature-gate);
  full workspace cargo fmt/clippy/test green; helm lint green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pallakatos
Pal Lakatos-Toth (pallakatos) deleted the phase2-s12-e-authoritative branch June 1, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant