Send a caller identity to flex-auth so policy.enabled can flip
flex-auth's flex-auth-ops-warden pin (FLEX-WP-0016) TokenReviews the caller and binds resource.system: ops-warden to system:serviceaccount:ops-warden:ops-warden. policy.py posted /v1/check with no Authorization header, so the pin logs "caller authentication warning" and can only run callerAuth.mode: warn — which, under ADHOC-2026-08-17-T01, is exactly what blocks policy.enabled: true. - policy.caller_auth (none | file | env | command) + src/warden/caller_identity.py: token resolved per call, never cached, written, or logged (ADR-0002) - both check_sign_policy and check_fetch_policy attach the bearer header; an unobtainable token fails closed rather than retrying anonymously - scripts/check_policy_caller_identity.py: read-only gate, prints length and a truncated fingerprint only, distinguishes 401 (audience/binding) from 403 - example config: caller_auth block, and flex_auth_url corrected — it pointed at flex-auth.flex-auth.svc, a Service that does not exist - WARDEN-WP-0031, PolicyGatedSigning caller-identity section and flip sequence Default stays mode: none, so behaviour is unchanged until an operator opts in. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
35aff380a3
commit
0a331413a2
9 changed files with 728 additions and 12 deletions
133
workplans/WARDEN-WP-0031-policy-caller-identity.md
Normal file
133
workplans/WARDEN-WP-0031-policy-caller-identity.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
id: WARDEN-WP-0031
|
||||
type: workplan
|
||||
title: "Calling-side identity for flex-auth, so policy.enabled can flip"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
owner: ops-warden
|
||||
topic_slug: netkingdom
|
||||
planning_priority: P1
|
||||
depends_on_workplans:
|
||||
- WARDEN-WP-0007
|
||||
related_workplans:
|
||||
- WARDEN-WP-0009
|
||||
created: "2026-08-19"
|
||||
updated: "2026-08-19"
|
||||
---
|
||||
|
||||
# WARDEN-WP-0031 — Calling-side identity for flex-auth
|
||||
|
||||
flex-auth shipped `flex-auth-ops-warden` (FLEX-WP-0016 T01/T02): an
|
||||
independently rollable in-cluster pin carrying ops-warden's production registry
|
||||
and policy package, on digest `sha256:138aa347…`, at
|
||||
`flex-auth-ops-warden.flex-auth.svc.cluster.local:8080`.
|
||||
|
||||
It runs `callerAuth.mode: warn`, and it says why in its own logs:
|
||||
|
||||
```
|
||||
caller authentication warning: caller is not authenticated
|
||||
```
|
||||
|
||||
`src/warden/policy.py` posted `/v1/check` with **no `Authorization` header**.
|
||||
flex-auth authenticates the caller with a Kubernetes TokenReview and binds
|
||||
`resource.system: ops-warden` to `system:serviceaccount:ops-warden:ops-warden`;
|
||||
an unauthenticated caller can only be served in `warn`. So the pin cannot
|
||||
enforce, and per ADHOC-2026-08-17-T01 — `policy.enabled` must not flip anywhere
|
||||
while `/v1/check` still answers unauthenticated callers — `policy.enabled` stays
|
||||
false. The gap is ours, not flex-auth's, and this workplan closes it.
|
||||
|
||||
Warn is also not A2 evidence: a request that succeeds because failures are
|
||||
downgraded proves nothing about the enforcing path.
|
||||
|
||||
## Ownership
|
||||
|
||||
| Concern | Owner |
|
||||
| --- | --- |
|
||||
| The pin, its digest, `callerAuth.mode` | flex-auth |
|
||||
| Sending a caller identity on `/v1/check` | **ops-warden** (this workplan) |
|
||||
| Choosing the token source on a given host | ops-warden operator |
|
||||
| `policy.enabled: true` in `warden.yaml` | ops-warden operator |
|
||||
|
||||
## Design note — fail closed on identity too
|
||||
|
||||
When a caller token is configured but cannot be obtained, `check_sign_policy`
|
||||
raises under `fail_closed` rather than retrying unauthenticated. Falling back to
|
||||
an anonymous call is precisely the behaviour that keeps the pin in `warn`; a
|
||||
gate that silently degrades to the ungated path is not a gate (ADR-0004's choke
|
||||
point argument, applied to ops-warden as a caller).
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Caller identity on the outbound policy call.** `policy.caller_auth` in
|
||||
`warden.yaml` (`mode: none | file | env | command`, `token_path`, `token_env`,
|
||||
`command`, `audience`); `src/warden/caller_identity.py` resolves the token at
|
||||
call time and never caches, logs, or echoes it (ADR-0002); both
|
||||
`check_sign_policy` and `check_fetch_policy` attach `Authorization: Bearer …`.
|
||||
Whitespace-bearing and empty tokens are rejected before the call, because
|
||||
flex-auth rejects them outright.
|
||||
|
||||
Done 2026-08-19. `mode: none` remains the default, so behaviour is unchanged
|
||||
until an operator opts in. Tests in `tests/test_policy.py`.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T02
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Readiness gate.** `scripts/check_policy_caller_identity.py` — read-only:
|
||||
config loads, mode is not `none`, a token is actually obtainable, and with
|
||||
`--url` a live `/v1/check` against a port-forward of the warn pin. Prints the
|
||||
token's length and a truncated SHA-256 fingerprint only, so its output is safe
|
||||
to paste into a handoff. Exit 0 ready / 1 not ready / 2 bad input. Distinguishes
|
||||
401 (token not accepted — audience or binding) from 403 (authenticated but not
|
||||
allowed to represent `system: ops-warden`).
|
||||
|
||||
Done 2026-08-19.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T03
|
||||
status: done
|
||||
priority: medium
|
||||
```
|
||||
|
||||
**Docs.** `examples/warden.production.example.yaml` gains the `caller_auth`
|
||||
block with both realistic sources, and its `flex_auth_url` is corrected — the
|
||||
example pointed at `flex-auth.flex-auth.svc.cluster.local`, a Service that does
|
||||
not exist. `wiki/PolicyGatedSigning.md` gains the caller-identity section and
|
||||
the flip sequence.
|
||||
|
||||
Done 2026-08-19.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T04
|
||||
status: wait
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Pick the token source and prove it against the warn pin.** Operator work on
|
||||
the real host: `kubectl create token` (workstation) or a projected token
|
||||
(in-cluster PEP), then
|
||||
`python scripts/check_policy_caller_identity.py --url http://127.0.0.1:19090`
|
||||
against a port-forward. Expect `effect=allow` for `agt-state-hub-bridge` while
|
||||
the warn log stops printing `caller authentication warning` — the absence of
|
||||
that line, not the allow, is the evidence.
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0031-T05
|
||||
status: wait
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Sequence the flip.** Only after T04: tell flex-auth to set
|
||||
`callerAuth.mode: enforce` on `flex-auth-ops-warden` (their FLEX-WP-0016 T03),
|
||||
re-run the gate against the enforcing pin, and only then set
|
||||
`policy.enabled: true` with `fail_closed: true`. Flipping before enforce buys
|
||||
nothing; flipping before T04 401s every `warden sign`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue