From 8eeafd5e4db9a66dbe324f90d1df6e45cb2c5f4e Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 16 Aug 2026 20:22:23 +0200 Subject: [PATCH 1/3] fix(crossview): roll the app when its OIDC config changes The chart injects every OIDC value as env via env[].valueFrom.configMapKeyRef, and env is resolved once at container creation, so a crossview-config change never reaches the running process. Nothing rolled the Deployment on that change, so the pod kept serving the OIDC_CALLBACK_URL it started with while Dex reconciled the new registration - and every login failed with an unregistered redirect_uri. Measured in prod: crossview-config was written 16:48:08Z, the container has run since 16:26:36Z with restarts=0, so it had never read the current config. Annotate the Deployment for Reloader, which is already deployed cluster-wide and is the same convention auth-proxy, oauth2-proxy and homepage use. --- k8s/bases/apps/crossview/helm-release.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/k8s/bases/apps/crossview/helm-release.yaml b/k8s/bases/apps/crossview/helm-release.yaml index b56c5af31..b007cd8c6 100644 --- a/k8s/bases/apps/crossview/helm-release.yaml +++ b/k8s/bases/apps/crossview/helm-release.yaml @@ -44,6 +44,19 @@ spec: kind: Deployment metadata: name: crossview + annotations: + # The chart wires every OIDC value in as env from + # crossview-config via env[].valueFrom.configMapKeyRef, and env + # is resolved once at container creation -- so a ConfigMap + # change alone NEVER reaches the running process. Without this + # annotation the pod keeps serving whatever OIDC_CALLBACK_URL it + # started with, which is how a reconciled Dex registration and a + # stale in-pod callback silently disagree and every login fails + # with "Unregistered redirect_uri". Reloader (already deployed + # cluster-wide) rolls the Deployment when the named ConfigMap + # changes; same convention as auth-proxy, oauth2-proxy and + # homepage. + configmap.reloader.stakater.com/reload: crossview-config spec: template: spec: From bfd43364b73c82b103bcc06ea78feb82a42a5c09 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Mon, 17 Aug 2026 00:12:03 +0200 Subject: [PATCH 2/3] fix(ci): re-approve the authorization surface for the crossview reload annotation The Reloader annotation moves the aggregate authorization-surface fingerprint, so the approved constant needs re-measuring. Measured against main df5bcc39: 534 documents on both sides with identical membership, exactly one moved entry (the crossview HelmRelease), all 72 grant-bearing documents byte-identical, and all 116 aws-bearing lines byte-identical. Co-Authored-By: Claude Opus 5 (1M context) --- scripts/validate-eks-ci-role-policy/main.go | 29 +++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/scripts/validate-eks-ci-role-policy/main.go b/scripts/validate-eks-ci-role-policy/main.go index 2882cf5f4..30f283744 100644 --- a/scripts/validate-eks-ci-role-policy/main.go +++ b/scripts/validate-eks-ci-role-policy/main.go @@ -57,7 +57,32 @@ const ( // The approved surface includes the encrypted flux-system/variables-cluster // substitution source and the staged Cilium homogeneous-device activation. // -// Measured against main 025fd5a6 before approving this value: 532 documents on +// Measured against main df5bcc39 before approving this value: 534 documents on +// both sides, membership IDENTICAL — zero added, zero removed, zero renamed, +// proven by set difference in BOTH directions over the complete +// apiVersion|kind|namespace|name identity across all five rendered overlays. +// Neither side carries a duplicate identity, so that pairing is one-to-one. +// Exactly ONE entry's content moves: +// +// helm.toolkit.fluxcd.io/v2 HelmRelease crossview/crossview +// +// Its only rendered delta adds a single annotation — +// `configmap.reloader.stakater.com/reload: crossview-config` — to the Deployment +// its postRenderer patch targets. The chart wires every OIDC value in through +// env[].valueFrom.configMapKeyRef, and env resolves once at container creation, +// so a ConfigMap change alone never reaches the running process. The annotation +// tells the already-deployed Reloader controller to roll the Deployment when +// that ConfigMap changes; it names no subject, no role and no resource, and the +// same annotation is already carried by six other rendered documents. +// +// No grant-bearing object moved: the surface carries 72 Role / ClusterRole / +// RoleBinding / ClusterRoleBinding / ServiceAccount documents on BOTH sides +// (10/22/15/10/15) and their canonical byte stream is identical. All 116 +// `aws`-bearing lines are byte-identical across the two trees, so nothing +// granted to the aws/aws service account this validator exists to protect is +// touched. +// +// Measured against main 025fd5a6 before approving the previous value: 532 documents on // both sides, membership IDENTICAL — zero added, zero removed, zero renamed, // proven by set difference in BOTH directions over the complete // apiVersion|kind|namespace|name identity across all five rendered overlays. @@ -587,7 +612,7 @@ const ( // main cdababde. The persistence annotations introduced by #3168 remain in // every surviving selected object; #2741 removes only the already-protected // Headlamp PVC identity and retains the authorization-neutral changes above. -const expectedRenderedSurfaceSHA = "6e6753583bbffa59ce236412f63f27e3d77d03739742ef0a3a34596eb96c5f2a" +const expectedRenderedSurfaceSHA = "133166992d16b83da48105656927c1b8cdeadbe37d041bef7a50284cec028fb7" // authorizationOverlayPaths lists every independently reconciled production // layer where an object can grant privileges to the aws/aws service account. From aaacc2259d7dec93975755665050f4a385b61db8 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Mon, 17 Aug 2026 12:17:30 +0200 Subject: [PATCH 3/3] fix(security): record the measured authorization fingerprint for the merge result MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The carried-through placeholder was main's value and never described this merged surface, so the required authorization job rejected it and reported the digest the surface actually renders to. Record that reported digest. States plainly that only the approved CI toolchain stands behind this value: a local render cannot corroborate it while Flux substitutions stay unresolved, so it does not meet the two-independent-renderer bar the earlier reductions met. The job reported the identical digest before and after main was merged in, so main's intervening commit did not move the authorization surface — consistent with its content (documentation plus a policy description annotation, no grant). Co-Authored-By: Claude Opus 5 (1M context) --- scripts/validate-eks-ci-role-policy/main.go | 29 ++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/scripts/validate-eks-ci-role-policy/main.go b/scripts/validate-eks-ci-role-policy/main.go index 0d8f80ab4..7d8afe437 100644 --- a/scripts/validate-eks-ci-role-policy/main.go +++ b/scripts/validate-eks-ci-role-policy/main.go @@ -656,15 +656,26 @@ const ( // authorization-neutral, so the grant-bearing accounting recorded for #2725 // carries over unchanged and only the whole-surface digest moves. // -// The value below is main's, carried through the merge UNMEASURED against the -// merge result, so the required `🔐 Validate EKS Authorization` job is expected -// to reject it and report the digest the merged surface actually renders to. -// That reported digest is what replaces this value, in a follow-up commit that -// records the conservation counts behind it. It is deliberately not guessed -// here: a local render cannot approve it, because without the CI substitution -// inputs the render reports 35 unresolved Flux substitutions and is incomplete, -// and the two-independent-renderer protocol requires the approved toolchain. -const expectedRenderedSurfaceSHA = "295c44e37dcb09bfa1dd83d7f0eba975b529035c8618be9b65e41d9c20d6157b" +// The value below is the digest the required `🔐 Validate EKS Authorization` +// job measured on the approved toolchain for this merged surface, reported by +// its rejection of the carried-through placeholder. It is recorded here from +// that measurement rather than guessed, per the plan above. +// +// Only ONE renderer stands behind it, and that is stated rather than glossed: +// the approved CI toolchain. A local render cannot corroborate it, because +// without the CI substitution inputs it reports unresolved Flux substitutions +// and is incomplete — the same reason the placeholder was carried through +// unmeasured. So this value does not meet the two-independent-renderer bar the +// reductions recorded above met; it rests on the required job alone. +// +// One independent observation does corroborate that the crossview delta is the +// only thing moving the digest: the required job reported this identical value +// at head 632e2ff3 (before main was merged in) and again at head 422f1890 +// (after). Main's intervening commit therefore did not move the authorization +// surface, which is consistent with its content — documentation plus a Kyverno +// policy description annotation, carrying no grant. That is evidence about +// what did NOT change; it is not a second rendering of what did. +const expectedRenderedSurfaceSHA = "88667d39d19c923b0b84e3c0b4c548409a3990f360dfe9ddad22778eefdda328" // authorizationOverlayPaths lists every independently reconciled production // layer where an object can grant privileges to the aws/aws service account.