Pin caller-auth digest in warn on independently rollable overlay pins
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

The sanctioned Helm chart could not promote ADR 0004 at all, and the
emergency manifests selected enforce. That made a FLEX-WP-0011 apply
either a no-op or a global 401. First production pin is now warn, per
consumer, on CI digest sha256:138aa347… . Enforce stays a later
per-consumer flip so USER-WP-0023-T03 can close without waiting on
tenant-engine.
This commit is contained in:
tegwick 2026-08-19 12:31:08 +02:00
parent 3de72fe6f5
commit fa278674c1
22 changed files with 268 additions and 55 deletions

View file

@ -2,5 +2,5 @@ apiVersion: v2
name: flex-auth name: flex-auth
description: Independently rollable flex-auth policy-decision Deployment (one consumer per release). description: Independently rollable flex-auth policy-decision Deployment (one consumer per release).
type: application type: application
version: 0.1.0 version: 0.2.0
appVersion: "0.1.0" appVersion: "0.1.0"

View file

@ -18,3 +18,18 @@ app.kubernetes.io/name: {{ include "flex-auth.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: flex-auth app.kubernetes.io/part-of: flex-auth
{{- end -}} {{- end -}}
{{- define "flex-auth.callerAuth.mode" -}}
{{- $mode := "disabled" -}}
{{- if and (hasKey .Values "callerAuth") .Values.callerAuth (hasKey .Values.callerAuth "mode") .Values.callerAuth.mode -}}
{{- $mode = .Values.callerAuth.mode -}}
{{- end -}}
{{- if not (has $mode (list "disabled" "warn" "enforce")) -}}
{{- fail (printf "callerAuth.mode must be disabled, warn, or enforce; got %q" $mode) -}}
{{- end -}}
{{- $mode -}}
{{- end -}}
{{- define "flex-auth.callerAuth.enabled" -}}
{{- if has (include "flex-auth.callerAuth.mode" .) (list "warn" "enforce") -}}true{{- else -}}false{{- end -}}
{{- end -}}

View file

@ -15,6 +15,9 @@ spec:
{{- include "flex-auth.labels" . | nindent 8 }} {{- include "flex-auth.labels" . | nindent 8 }}
spec: spec:
automountServiceAccountToken: false automountServiceAccountToken: false
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
serviceAccountName: {{ include "flex-auth.name" . }}
{{- end }}
securityContext: securityContext:
runAsNonRoot: true runAsNonRoot: true
seccompProfile: seccompProfile:
@ -25,6 +28,15 @@ spec:
imagePullPolicy: {{ .Values.image.pullPolicy }} imagePullPolicy: {{ .Values.image.pullPolicy }}
args: args:
{{- toYaml .Values.args | nindent 12 }} {{- toYaml .Values.args | nindent 12 }}
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
{{- $binding := required "callerAuth.binding is required when callerAuth.mode is warn or enforce" .Values.callerAuth.binding }}
- --caller-auth-mode
- {{ include "flex-auth.callerAuth.mode" . | quote }}
- --caller-kubernetes-url
- {{ required "callerAuth.kubernetesURL is required when callerAuth.mode is warn or enforce" .Values.callerAuth.kubernetesURL | quote }}
- --caller-binding
- {{ $binding | quote }}
{{- end }}
ports: ports:
- name: http - name: http
containerPort: {{ .Values.service.port }} containerPort: {{ .Values.service.port }}
@ -46,3 +58,25 @@ spec:
drop: drop:
- ALL - ALL
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
volumeMounts:
- mountPath: {{ .Values.callerAuth.reviewer.mountPath }}
name: flex-auth-reviewer
readOnly: true
{{- end }}
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
volumes:
- name: flex-auth-reviewer
projected:
defaultMode: 0440
sources:
- serviceAccountToken:
audience: {{ .Values.callerAuth.reviewer.audience | quote }}
expirationSeconds: {{ .Values.callerAuth.reviewer.expirationSeconds }}
path: token
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
{{- end }}

View file

@ -11,7 +11,16 @@ spec:
policyTypes: policyTypes:
- Ingress - Ingress
- Egress - Egress
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
egress:
- ports:
- port: 443
protocol: TCP
- port: 6443
protocol: TCP
{{- else }}
egress: [] egress: []
{{- end }}
{{- if .Values.consumer.isolated }} {{- if .Values.consumer.isolated }}
ingress: [] ingress: []
{{- else }} {{- else }}

View file

@ -0,0 +1,30 @@
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "flex-auth.name" . }}-tokenreviewer
labels:
{{- include "flex-auth.labels" . | nindent 4 }}
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "flex-auth.name" . }}-tokenreviewer
labels:
{{- include "flex-auth.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: {{ include "flex-auth.name" . }}-tokenreviewer
subjects:
- kind: ServiceAccount
name: {{ include "flex-auth.name" . }}
namespace: {{ .Release.Namespace }}
{{- end }}

View file

@ -0,0 +1,9 @@
{{- if eq (include "flex-auth.callerAuth.enabled" .) "true" }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "flex-auth.name" . }}
labels:
{{- include "flex-auth.labels" . | nindent 4 }}
automountServiceAccountToken: false
{{- end }}

View file

@ -29,6 +29,18 @@ consumer:
namespace: "" namespace: ""
podName: "" podName: ""
# disabled keeps the image bootable without TokenReview (isolated canary).
# Production pins set warn, then enforce, independently per consumer.
callerAuth:
mode: disabled
audience: flex-auth
kubernetesURL: https://kubernetes.default.svc
binding: ""
reviewer:
mountPath: /var/run/secrets/flex-auth-reviewer
audience: https://kubernetes.default.svc
expirationSeconds: 3600
resources: resources:
requests: requests:
cpu: 25m cpu: 25m

View file

@ -7,6 +7,12 @@ emergency kubectl path recovered on 2026-08-11 from live
`last-applied-configuration`, kept so a rollback does not depend on a `last-applied-configuration`, kept so a rollback does not depend on a
cluster annotation or on Helm history. cluster annotation or on Helm history.
Caller authentication (FLEX-WP-0015-T02) is pinned here in **`warn`**,
matching `values/user-engine.yaml` and `values/tenant-engine.yaml`. Do not
edit these files back to `enforce` and apply them as a shortcut: that is
the hazard. Flip `callerAuth.mode` per consumer in the overlay after that
consumer's warn logs are clean, then re-render or edit only that pin.
Manifests for the two cluster-local flex-auth policy-decision services. Manifests for the two cluster-local flex-auth policy-decision services.
| File | Deployment | Consumer | Service DNS | | File | Deployment | Consumer | Service DNS |
@ -86,10 +92,12 @@ last-known-good digest below.
| Deployment | Last-known-good digest | Policy state | | Deployment | Last-known-good digest | Policy state |
| --- | --- | --- | | --- | --- | --- |
| `flex-auth-tenant-engine` | `sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc` | **live** — nine-action policy (FLEX-WP-0014), CI-built from `f304688` | | `flex-auth-tenant-engine` | `sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b` | **pin, not live** — caller-auth **warn** (FLEX-WP-0015-T02), CI `main-3de72fe` |
| `flex-auth-tenant-engine` *(live until warn promote)* | `sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc` | nine-action policy (FLEX-WP-0014), CI-built from `f304688` |
| `flex-auth-tenant-engine` *(previous)* | `sha256:9320df394a642eff24da8af4a0ee8886a7bb78b0f14d8ee1deeb30ea8eeeaba7` | seven-action policy, FLEX-WP-0013 restore; guardrail actions deny `unknown_action` | | `flex-auth-tenant-engine` *(previous)* | `sha256:9320df394a642eff24da8af4a0ee8886a7bb78b0f14d8ee1deeb30ea8eeeaba7` | seven-action policy, FLEX-WP-0013 restore; guardrail actions deny `unknown_action` |
| `flex-auth-tenant-engine` *(rollback)* | `sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa` | four-action policy; lifecycle actions deny `unknown_action` | | `flex-auth-tenant-engine` *(rollback)* | `sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa` | four-action policy; lifecycle actions deny `unknown_action` |
| `flex-auth-user-engine` | `sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` | **current** — FLEX-WP-0009-T04, nine fixtures (incl. registration-applicant) verified live 2026-08-16 | | `flex-auth-user-engine` | `sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b` | **pin, not live** — caller-auth **warn** (FLEX-WP-0015-T02), CI `main-3de72fe` |
| `flex-auth-user-engine` *(live until warn promote)* | `sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` | FLEX-WP-0009-T04, nine fixtures (incl. registration-applicant) verified live 2026-08-16 |
| `flex-auth-user-engine` *(previous)* | `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` | FLEX-WP-0009-T03, six fixtures verified live 2026-08-10 | | `flex-auth-user-engine` *(previous)* | `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` | FLEX-WP-0009-T03, six fixtures verified live 2026-08-10 |
Rolling back the tenant-engine service to `c25fc34a…` restores fail-closed Rolling back the tenant-engine service to `c25fc34a…` restores fail-closed

View file

@ -25,12 +25,12 @@ spec:
- --policy - --policy
- /opt/flex-auth/examples/tenant-engine/policy_package.md - /opt/flex-auth/examples/tenant-engine/policy_package.md
- --caller-auth-mode - --caller-auth-mode
- enforce - warn
- --caller-kubernetes-url - --caller-kubernetes-url
- https://10.43.0.1 - https://10.43.0.1
- --caller-binding - --caller-binding
- tenant-engine=system:serviceaccount:tenant-engine:tenant-engine - tenant-engine=system:serviceaccount:tenant-engine:tenant-engine
image: forgejo.coulomb.social/coulomb/flex-auth@sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc image: forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /healthz path: /healthz

View file

@ -25,12 +25,12 @@ spec:
- --policy - --policy
- /opt/flex-auth/examples/user-engine/policy_package.md - /opt/flex-auth/examples/user-engine/policy_package.md
- --caller-auth-mode - --caller-auth-mode
- enforce - warn
- --caller-kubernetes-url - --caller-kubernetes-url
- https://10.43.0.1 - https://10.43.0.1
- --caller-binding - --caller-binding
- user-engine=system:serviceaccount:user-engine:user-engine - user-engine=system:serviceaccount:user-engine:user-engine
image: forgejo.coulomb.social/coulomb/flex-auth@sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4 image: forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
livenessProbe: livenessProbe:
httpGet: httpGet:
path: /healthz path: /healthz

View file

@ -38,9 +38,11 @@ cached across rotation.
Three modes support promotion: `disabled`, `warn`, and `enforce`. Warn mode Three modes support promotion: `disabled`, `warn`, and `enforce`. Warn mode
records the same authentication failures without logging credentials. It is a records the same authentication failures without logging credentials. It is a
bounded migration aid, not a conformant steady state. The reviewed desired bounded migration aid, not a conformant steady state. The first production pin
manifests select `enforce`; promotion still follows FLEX-WP-0011 and requires a is `warn` on each independently rollable Deployment; `enforce` is the end
new immutable image digest plus caller rollout evidence. state and is flipped per consumer after that consumer's warn logs are clean.
Promotion follows FLEX-WP-0011. The two production pins must not be flipped
together: user-engine can enforce while tenant-engine stays in warn.
## Rejected alternatives ## Rejected alternatives

View file

@ -271,7 +271,7 @@ volunteer.
| Task | | | Task | |
|---|---| |---|---|
| T01 | Publish the posture vector and this review; reply to `rapp-postgres` | | T01 | Publish the posture vector and this review; reply to `rapp-postgres` |
| T02 | **Close the A0**: TokenReview source/desired state done; immutable promotion pending | | T02 | **Close the A0**: TokenReview source + warn-first overlay pin done; operator promote-then-per-consumer-enforce pending |
| T03 | Deleted the unused tenant-engine live-roles adapter | | T03 | Deleted the unused tenant-engine live-roles adapter |
| T04 | AuthZEN endpoint — `wait`, with a written trigger | | T04 | AuthZEN endpoint — `wait`, with a written trigger |
| T05 | `make verify-posture` guards declaration/source/deployment drift | | T05 | `make verify-posture` guards declaration/source/deployment drift |

View file

@ -45,6 +45,32 @@ $RAILIANCE rollback . --apply --approval-id <state-hub-id> --revision <helm-rev>
The canary Service is `flex-auth-canary.flex-auth.svc.cluster.local:8080`. The canary Service is `flex-auth-canary.flex-auth.svc.cluster.local:8080`.
Production consumers keep calling their own Service names. Production consumers keep calling their own Service names.
## Caller-auth promotion (FLEX-WP-0015-T02)
The two production pins are independently rollable. Do not flip both to
`enforce` in one apply. The first pin of digest
`sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b`
is **warn** on each consumer.
```bash
# Warn pin (safe if a caller still sends no token)
helm upgrade --install flex-auth-user-engine charts/flex-auth \
--namespace flex-auth -f values/user-engine.yaml --wait --timeout 2m
helm upgrade --install flex-auth-tenant-engine charts/flex-auth \
--namespace flex-auth -f values/tenant-engine.yaml --wait --timeout 2m
# Confirm warn logs: "caller authentication warning:" must be absent for a
# migrated caller. user-engine is migrated; tenant-engine live status is
# unconfirmed. Isolated canary keeps callerAuth.mode=disabled.
# Then set values/user-engine.yaml callerAuth.mode: enforce and upgrade only
# that release. USER-WP-0023-T03 runs only after that flip. tenant-engine
# stays warn until its logs are clean.
```
Emergency kubectl path is also warn. Applying it in enforce is the hazard
the warn pin exists to prevent.
## Rolling a production pin ## Rolling a production pin
Policy is baked into the image. Do not build images on a workstation. Policy is baked into the image. Do not build images on a workstation.
@ -76,8 +102,10 @@ or re-apply the last-known-good digest in `deploy/README.md`.
| Deployment | Last-known-good digest | Policy state | | Deployment | Last-known-good digest | Policy state |
| --- | --- | --- | | --- | --- | --- |
| `flex-auth-tenant-engine` | `sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc` | **live** — nine-action policy (FLEX-WP-0014), CI-built from `f304688` | | `flex-auth-tenant-engine` | `sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b` | **pin, not live** — caller-auth warn (FLEX-WP-0015-T02), CI `main-3de72fe` |
| `flex-auth-tenant-engine` *(live until warn promote)* | `sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc` | nine-action policy (FLEX-WP-0014), CI-built from `f304688` |
| `flex-auth-tenant-engine` *(previous)* | `sha256:9320df394a642eff24da8af4a0ee8886a7bb78b0f14d8ee1deeb30ea8eeeaba7` | seven-action policy, FLEX-WP-0013 restore | | `flex-auth-tenant-engine` *(previous)* | `sha256:9320df394a642eff24da8af4a0ee8886a7bb78b0f14d8ee1deeb30ea8eeeaba7` | seven-action policy, FLEX-WP-0013 restore |
| `flex-auth-tenant-engine` *(rollback)* | `sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa` | four-action policy; lifecycle actions deny `unknown_action` | | `flex-auth-tenant-engine` *(rollback)* | `sha256:c25fc34a6cd7e64d955f8723ec70e176a583d5ae71d76280c4e2d89fba0fe0aa` | four-action policy; lifecycle actions deny `unknown_action` |
| `flex-auth-user-engine` | `sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` | FLEX-WP-0009-T04, nine fixtures, live 2026-08-16 | | `flex-auth-user-engine` | `sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b` | **pin, not live** — caller-auth warn (FLEX-WP-0015-T02), CI `main-3de72fe` |
| `flex-auth-user-engine` *(live until warn promote)* | `sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` | FLEX-WP-0009-T04, nine fixtures, live 2026-08-16 |
| `flex-auth-user-engine` *(previous)* | `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` | FLEX-WP-0009-T03, six fixtures | | `flex-auth-user-engine` *(previous)* | `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` | FLEX-WP-0009-T03, six fixtures |

View file

@ -40,10 +40,11 @@ tenancy:
own inputs. Not a defect and not a target for movement. own inputs. Not a defect and not a target for movement.
A: >- A: >-
The running immutable digest still authenticates no caller, so current The running immutable digest still authenticates no caller, so current
remains A0. Source and reviewed desired manifests implement A2 with an remains A0. Source, overlay, and reviewed desired manifests implement
audience-scoped Kubernetes TokenReview choke point and exact A2 with an audience-scoped Kubernetes TokenReview choke point and exact
protected-system-to-ServiceAccount bindings. Promotion and a live protected-system-to-ServiceAccount bindings. The first production pin
unbound-request probe remain under FLEX-WP-0011/FLEX-WP-0015-T02. is warn, independently per consumer, under FLEX-WP-0011/FLEX-WP-0015-T02.
Current moves to A2 only after enforce and a live unbound-request probe.
E: >- E: >-
No tenant data at rest. Tenant scoping in decisions runs through one No tenant data at rest. Tenant scoping in decisions runs through one
choke point (internal/decision/engine.go normalizeRequest and the choke point (internal/decision/engine.go normalizeRequest and the
@ -84,6 +85,7 @@ evidence:
- "internal/callerauth/auth.go" - "internal/callerauth/auth.go"
- "internal/callerauth/auth_test.go" - "internal/callerauth/auth_test.go"
- "cmd/flex-auth/main_test.go" - "cmd/flex-auth/main_test.go"
- "charts/flex-auth/templates/rbac.yaml"
- "deploy/caller-auth-rbac.yaml" - "deploy/caller-auth-rbac.yaml"
- "docs/adr/0004-inbound-caller-authentication.md" - "docs/adr/0004-inbound-caller-authentication.md"
deployment: "deploy/flex-auth-user-engine.yaml, deploy/flex-auth-tenant-engine.yaml" deployment: "values/user-engine.yaml, values/tenant-engine.yaml, deploy/flex-auth-user-engine.yaml, deploy/flex-auth-tenant-engine.yaml"

View file

@ -12,4 +12,21 @@ for values in values/stage1.yaml values/stage2-canary.yaml values/stage3-product
helm template flex-auth charts/flex-auth -f "${values}" --namespace flex-auth >/dev/null helm template flex-auth charts/flex-auth -f "${values}" --namespace flex-auth >/dev/null
done done
user_render="$(helm template flex-auth-user-engine charts/flex-auth -f values/user-engine.yaml --namespace flex-auth)"
echo "$user_render" | grep -q -- '--caller-auth-mode' || { echo "user-engine render omits caller-auth-mode" >&2; exit 1; }
echo "$user_render" | grep -A1 -- '--caller-auth-mode' | grep -q warn || { echo "user-engine first pin must be warn" >&2; exit 1; }
echo "$user_render" | grep -q tokenreviews || { echo "user-engine render omits TokenReview RBAC" >&2; exit 1; }
echo "$user_render" | grep -q flex-auth-reviewer || { echo "user-engine render omits reviewer projection" >&2; exit 1; }
tenant_render="$(helm template flex-auth-tenant-engine charts/flex-auth -f values/tenant-engine.yaml --namespace flex-auth)"
echo "$tenant_render" | grep -A1 -- '--caller-auth-mode' | grep -q warn || { echo "tenant-engine first pin must be warn" >&2; exit 1; }
echo "$tenant_render" | grep -q 'tenant-engine=system:serviceaccount:tenant-engine:tenant-engine' \
|| { echo "tenant-engine render omits its exact binding" >&2; exit 1; }
canary_render="$(helm template flex-auth-canary charts/flex-auth -f values/stage2-canary.yaml --namespace flex-auth)"
if echo "$canary_render" | grep -q tokenreviews; then
echo "isolated canary must not create TokenReview RBAC" >&2
exit 1
fi
echo "stage1 overlay render ok" echo "stage1 overlay render ok"

View file

@ -26,14 +26,36 @@ fail() {
exit 1 exit 1
} }
caller_mode_from_manifest() {
awk '
$0 ~ /--caller-auth-mode/ { getline; gsub(/^[[:space:]-]+/, ""); print; exit }
' "$1"
}
caller_mode_from_values() {
awk '
$1 == "callerAuth:" { in_block=1; next }
in_block && /^[^[:space:]#]/ { exit }
in_block && $1 == "mode:" { print $2; exit }
' "$1"
}
if grep -q 'authenticator.Authorize' "$main"; then if grep -q 'authenticator.Authorize' "$main"; then
[[ "${declared_a:-0}" -ge 2 ]] || fail "caller authentication exists but current/implemented A is below 2" [[ "${declared_a:-0}" -ge 2 ]] || fail "caller authentication exists but current/implemented A is below 2"
for manifest in deploy/flex-auth-user-engine.yaml deploy/flex-auth-tenant-engine.yaml; do for manifest in deploy/flex-auth-user-engine.yaml deploy/flex-auth-tenant-engine.yaml; do
grep -q -- '--caller-auth-mode' "$root/$manifest" || fail "$manifest omits caller auth mode" grep -q -- '--caller-auth-mode' "$root/$manifest" || fail "$manifest omits caller auth mode"
grep -q 'enforce' "$root/$manifest" || fail "$manifest does not select enforce mode" mode="$(caller_mode_from_manifest "$root/$manifest")"
[[ "$mode" == "warn" || "$mode" == "enforce" ]] || fail "$manifest caller-auth-mode is ${mode:-empty}, not warn or enforce"
grep -q -- '--caller-binding' "$root/$manifest" || fail "$manifest omits the exact system binding" grep -q -- '--caller-binding' "$root/$manifest" || fail "$manifest omits the exact system binding"
grep -q 'flex-auth-reviewer' "$root/$manifest" || fail "$manifest omits the reviewer token projection"
done done
[[ -f "$root/deploy/caller-auth-rbac.yaml" ]] || fail "TokenReview RBAC manifest is absent" [[ -f "$root/deploy/caller-auth-rbac.yaml" ]] || fail "TokenReview RBAC manifest is absent"
grep -q 'tokenreviews' "$root/charts/flex-auth/templates/rbac.yaml" || fail "overlay TokenReview RBAC template is absent"
for values in values/user-engine.yaml values/tenant-engine.yaml; do
mode="$(caller_mode_from_values "$root/$values")"
[[ "$mode" == "warn" || "$mode" == "enforce" ]] || fail "$values callerAuth.mode is ${mode:-empty}, not warn or enforce"
grep -q 'binding:' "$root/$values" || fail "$values omits callerAuth.binding"
done
else else
[[ "${declared_a:-0}" -lt 2 ]] || fail "A2 is declared without a caller-authentication choke point" [[ "${declared_a:-0}" -lt 2 ]] || fail "A2 is declared without a caller-authentication choke point"
fi fi

View file

@ -2,7 +2,7 @@
name: flex-auth-local name: flex-auth-local
image: image:
repository: forgejo.coulomb.social/coulomb/flex-auth repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4 digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args: args:
- serve - serve
- --addr - --addr

View file

@ -3,7 +3,7 @@
name: flex-auth-canary name: flex-auth-canary
image: image:
repository: forgejo.coulomb.social/coulomb/flex-auth repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4 digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args: args:
- serve - serve
- --addr - --addr

View file

@ -5,7 +5,7 @@
name: flex-auth-canary name: flex-auth-canary
image: image:
repository: forgejo.coulomb.social/coulomb/flex-auth repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4 digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args: args:
- serve - serve
- --addr - --addr

View file

@ -1,8 +1,10 @@
# Production pin for the tenant-engine policy service. Independently rollable. # Production pin for the tenant-engine policy service. Independently rollable.
# Warn is safe whether or not the live tenant-engine client already sends a
# token. Do not flip this pin to enforce until its warn logs are clean.
name: flex-auth-tenant-engine name: flex-auth-tenant-engine
image: image:
repository: forgejo.coulomb.social/coulomb/flex-auth repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:1bf060e61122693ce98359c167cc5fe8bdafc84e097e090eaa71af94d0f27cbc digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args: args:
- serve - serve
- --addr - --addr
@ -11,6 +13,10 @@ args:
- /opt/flex-auth/examples/tenant-engine/registry_snapshot.json - /opt/flex-auth/examples/tenant-engine/registry_snapshot.json
- --policy - --policy
- /opt/flex-auth/examples/tenant-engine/policy_package.md - /opt/flex-auth/examples/tenant-engine/policy_package.md
callerAuth:
mode: warn
kubernetesURL: https://10.43.0.1
binding: tenant-engine=system:serviceaccount:tenant-engine:tenant-engine
consumer: consumer:
isolated: false isolated: false
namespace: tenant-engine namespace: tenant-engine

View file

@ -1,8 +1,10 @@
# Production pin for the user-engine policy service. Independently rollable. # Production pin for the user-engine policy service. Independently rollable.
# First caller-auth pin is warn (FLEX-WP-0015-T02). Flip mode to enforce only
# after warn logs are clean of unauthenticated callers for this consumer.
name: flex-auth-user-engine name: flex-auth-user-engine
image: image:
repository: forgejo.coulomb.social/coulomb/flex-auth repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4 digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args: args:
- serve - serve
- --addr - --addr
@ -11,6 +13,10 @@ args:
- /opt/flex-auth/examples/user-engine/registry_snapshot.json - /opt/flex-auth/examples/user-engine/registry_snapshot.json
- --policy - --policy
- /opt/flex-auth/examples/user-engine/policy_package.md - /opt/flex-auth/examples/user-engine/policy_package.md
callerAuth:
mode: warn
kubernetesURL: https://10.43.0.1
binding: user-engine=system:serviceaccount:user-engine:user-engine
consumer: consumer:
isolated: false isolated: false
namespace: user-engine namespace: user-engine

View file

@ -14,7 +14,7 @@ related_workplans:
- FLEX-WP-0004 - FLEX-WP-0004
- FLEX-WP-0011 - FLEX-WP-0011
created: "2026-08-17" created: "2026-08-17"
updated: "2026-08-18" updated: "2026-08-19"
state_hub_workstream_id: "31846b19-c2a3-428e-950b-5985bc9146eb" state_hub_workstream_id: "31846b19-c2a3-428e-950b-5985bc9146eb"
--- ---
@ -110,38 +110,50 @@ Ship through the FLEX-WP-0011 staged-promotion path, not by direct apply.
ServiceAccount TokenReview with a separately projected reviewer identity and ServiceAccount TokenReview with a separately projected reviewer identity and
exact `resource.system` → ServiceAccount bindings. Both check endpoints share exact `resource.system` → ServiceAccount bindings. Both check endpoints share
the choke point; missing/mismatched identity fails 401/403 and reviewer outage the choke point; missing/mismatched identity fails 401/403 and reviewer outage
fails 503. Unit and handler tests include the required unbound request. Desired fails 503. Unit and handler tests include the required unbound request. Source
manifests select enforce mode and carry narrow TokenReview RBAC. The running committed as `1e1e077`.
digest is unchanged, so `tenancy.current.A` honestly remains 0 while
`tenancy.implemented.A` is 2. Source committed as `1e1e077`.
**Remaining, in this order — the sequence is a constraint, not a preference.** 2026-08-19 overlay outcome: the sanctioned Helm chart did not render caller
`ops-warden` ruled on rollout (2026-08-17) and `user-engine` asked for the same: auth at all, so a FLEX-WP-0011 pin of the new digest would have stayed
`disabled`. That is now wired. Desired emergency manifests and production
values select **`warn`**, not `enforce` — applying the previous enforce
manifests was the hazard. CI image `sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b`
(`main-3de72fe`, built 2026-08-18T13:25Z) contains the TokenReview flags.
The running cluster digest is still unchanged, so `tenancy.current.A`
remains 0 while `tenancy.implemented.A` is 2.
1. Build and pin a new immutable digest carrying the caller-auth code. **Better path than a global enforce flip.** The two production Deployments
2. Promote it in **`warn` mode**, not `enforce`. The reviewed desired manifests are independently rollable (FLEX-WP-0011). USER-WP-0023-T03 only probes
in `deploy/` select `enforce` because that is the end state — applying them `flex-auth-user-engine`. Serializing that probe on tenant-engine's caller
directly is the hazard. Warn authenticates and logs failures without status would 401 tenant-engine writes if we enforced them together, and
rejecting, so it is safe for an unmigrated caller. would delay user-engine A2 evidence for no safety gain. Sequence:
3. Confirm the warn logs are clean of unauthenticated callers. `user-engine` is
migrated and deployed as of 2026-08-18 (image `sha256:c501aeb2…`, token at
`/var/run/secrets/flex-auth-caller/token`). `tenant-engine`'s caller status
is **unconfirmed — asked 2026-08-18**; promoting `enforce` while their
client sends no token 401s every check and blocks their write paths.
`ops-warden` adopts the calling side on its own schedule.
4. Flip to `enforce`, then capture the live negative probe. `user-engine` has
the three assertions written and ready in their
`docs/flex-auth-caller-identity.md`; they deliberately have not run it,
because against an unenforced digest "no token returns 401" comes back as a
normal decision and would record as false evidence.
5. Only then may `policy.enabled` flip anywhere — `ops-warden` names that the
real deadline, and it is the same gate as FLEX-WP-0007.
**Operator gate.** Steps 14 need cluster credentials this session does not 1. Pin the caller-auth digest in overlay + emergency manifests — **done
2026-08-19**, first mode `warn` on both consumers.
2. Operator: promote each pin in warn via `helm upgrade --install
flex-auth-<consumer> charts/flex-auth --namespace flex-auth -f
values/<consumer>.yaml`. Isolated canary may boot the same digest with
caller-auth disabled. Do not `kubectl apply` an enforce manifest.
3. Confirm warn logs per consumer. `user-engine` is migrated and deployed
as of 2026-08-18 (image `sha256:c501aeb2…`, token at
`/var/run/secrets/flex-auth-caller/token`). `tenant-engine` source and
desired manifests already project that token and send it; live digest
is still unconfirmed. Warn is safe either way. `ops-warden` adopts the
calling side on its own schedule.
4. Flip **user-engine only** to `enforce` (`callerAuth.mode: enforce` in
`values/user-engine.yaml`, same digest). Then capture the live negative
probe from a user-engine pod. The three assertions are already written
in user-engine `docs/flex-auth-caller-identity.md`; they must not run
against warn, because "no token returns 401" would still be a decision.
5. Flip tenant-engine to enforce only after its warn logs are clean.
6. Only then may `policy.enabled` flip anywhere — `ops-warden` names that
the real deadline, and it is the same gate as FLEX-WP-0007.
**Operator gate.** Steps 25 need cluster credentials this session does not
have: `kubectl` returns `Unauthorized` and the context is `default`, which have: `kubectl` returns `Unauthorized` and the context is `default`, which
`tenant-engine` documented on 2026-08-16 as indistinguishable from a `tenant-engine` documented on 2026-08-16 as indistinguishable from a
wrong-cluster KUBECONFIG. Promotion follows FLEX-WP-0011 staged promotion and wrong-cluster KUBECONFIG. Promotion follows FLEX-WP-0011 and the CI image,
the CI image build, not a hand-built image. not a hand-built image.
`RISK-F-0001` (risk-nexus) tracks this A0 externally. Their NetworkPolicy `RISK-F-0001` (risk-nexus) tracks this A0 externally. Their NetworkPolicy
question was answered 2026-08-18: both Deployments carry an ingress policy question was answered 2026-08-18: both Deployments carry an ingress policy
@ -218,6 +230,7 @@ correct-looking responses, exactly like the two silent pin rollbacks the
estate has already been bitten by. estate has already been bitten by.
Completed 2026-08-18. `make verify-posture` checks the current/implemented Completed 2026-08-18. `make verify-posture` checks the current/implemented
distinction, both authenticated handlers, enforce-mode desired manifests, distinction, both authenticated handlers, warn-or-enforce desired manifests
TokenReview RBAC, absence of a latent tenant-engine caller, and the stateless and overlay pins, TokenReview RBAC, absence of a latent tenant-engine caller,
deployment assumptions behind `R: n/a`. and the stateless deployment assumptions behind `R: n/a`. First production
pin is warn; enforce is the end state, flipped per consumer.