Prepare renamed Access Engine runtime twins with exact reviewer scope
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 1m2s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
tegwick 2026-10-11 22:53:54 +02:00
parent 0bc15925e9
commit dd15d8cf3f
26 changed files with 1480 additions and 26 deletions

View file

@ -0,0 +1,6 @@
apiVersion: v2
name: access-engine
description: Independently rollable access-engine policy-decision Deployment (one consumer per release).
type: application
version: 0.2.0
appVersion: "0.1.0"

View file

@ -0,0 +1,35 @@
{{- define "access-engine.image" -}}
{{- if not .Values.image.digest }}
{{- fail "image.digest is required (digest_policy=required); do not deploy by tag" }}
{{- end }}
{{- printf "%s@%s" .Values.image.repository .Values.image.digest -}}
{{- end -}}
{{- define "access-engine.name" -}}
{{- required "name is required" .Values.name -}}
{{- end -}}
{{- define "access-engine.selectorLabels" -}}
app.kubernetes.io/name: {{ include "access-engine.name" . }}
{{- end -}}
{{- define "access-engine.labels" -}}
{{ include "access-engine.selectorLabels" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/part-of: access-engine
{{- end -}}
{{- define "access-engine.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 "access-engine.callerAuth.enabled" -}}
{{- if has (include "access-engine.callerAuth.mode" .) (list "warn" "enforce") -}}true{{- else -}}false{{- end -}}
{{- end -}}

View file

@ -0,0 +1,167 @@
{{- if .Values.auditDelivery.enabled }}
{{- if ne (first .Values.args) "serve" }}
{{- fail "auditDelivery currently supports serve decision pins only" }}
{{- end }}
{{- if not .Values.outbox.enabled }}
{{- fail "auditDelivery requires enabled durable outbox" }}
{{- end }}
{{- if not (regexMatch "^https?://[^/?#@]+/v1/events$" .Values.auditDelivery.url) }}
{{- fail "auditDelivery.url must be an explicit http(s) /v1/events endpoint" }}
{{- end }}
{{- if or (not (hasPrefix "/" .Values.auditDelivery.mountPath)) (contains ".." .Values.auditDelivery.mountPath) }}
{{- fail "auditDelivery.mountPath must be an absolute normalized directory" }}
{{- end }}
{{- end }}
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: {{ .Release.Namespace }}
name: {{ include "access-engine.name" . }}
labels:
{{- include "access-engine.labels" . | nindent 4 }}
spec:
{{- if .Values.outbox.enabled }}
{{- if ne (int .Values.replicaCount) 1 }}
{{- fail "outbox requires replicaCount=1: one writer per source and PVC" }}
{{- end }}
strategy:
type: Recreate
{{- end }}
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "access-engine.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "access-engine.labels" . | nindent 8 }}
spec:
automountServiceAccountToken: false
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
serviceAccountName: {{ include "access-engine.name" . }}
{{- end }}
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
containers:
- name: access-engine
image: {{ include "access-engine.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
{{- toYaml .Values.args | nindent 12 }}
{{- if .Values.outbox.enabled }}
- --outbox-dir
- {{ .Values.outbox.mountPath | quote }}
- --emission-source
- {{ required "outbox.source is required when outbox.enabled=true" .Values.outbox.source | quote }}
{{- end }}
{{- if .Values.auditDelivery.enabled }}
- --audit-url
- {{ .Values.auditDelivery.url | quote }}
- --audit-token-file
- {{ printf "%s/token" .Values.auditDelivery.mountPath | quote }}
{{- end }}
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
{{- $binding := "" }}
{{- if not (and .Values.readback .Values.readback.enabled) }}
{{- $binding = required "callerAuth.binding is required when callerAuth.mode is warn or enforce" .Values.callerAuth.binding }}
{{- end }}
- --caller-audience
- {{ required "callerAuth.audience is required" .Values.callerAuth.audience | quote }}
- --caller-reviewer-token-file
- {{ printf "%s/token" .Values.callerAuth.reviewer.mountPath | quote }}
- --caller-ca-file
- {{ printf "%s/ca.crt" .Values.callerAuth.reviewer.mountPath | quote }}
- --caller-auth-mode
- {{ include "access-engine.callerAuth.mode" . | quote }}
- --caller-kubernetes-url
- {{ required "callerAuth.kubernetesURL is required when callerAuth.mode is warn or enforce" .Values.callerAuth.kubernetesURL | quote }}
{{- if and .Values.readback .Values.readback.enabled }}
{{- /* serve-readback admits one readback caller and no /v1/check binding (FLEX-DEC-2026-019). */}}
- --readback-caller
- {{ required "readback.caller is required when readback.enabled=true" .Values.readback.caller | quote }}
{{- else }}
- --caller-binding
- {{ $binding | quote }}
{{- range .Values.callerAuth.extraBindings }}
- --caller-binding
- {{ . | quote }}
{{- end }}
{{- end }}
{{- end }}
ports:
- name: http
containerPort: {{ .Values.service.port }}
livenessProbe:
httpGet:
path: {{ .Values.health.path }}
port: http
periodSeconds: 20
readinessProbe:
httpGet:
path: {{ .Values.health.path }}
port: http
periodSeconds: 5
resources:
{{- toYaml .Values.resources | nindent 12 }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
{{- if or .Values.outbox.enabled .Values.auditDelivery.enabled (eq (include "access-engine.callerAuth.enabled" .) "true") }}
volumeMounts:
{{- if .Values.auditDelivery.enabled }}
- mountPath: {{ .Values.auditDelivery.mountPath | quote }}
name: access-engine-audit
readOnly: true
{{- end }}
{{- if .Values.outbox.enabled }}
- mountPath: {{ .Values.outbox.mountPath | quote }}
name: access-engine-outbox
{{- end }}
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
- mountPath: {{ .Values.callerAuth.reviewer.mountPath }}
name: access-engine-reviewer
readOnly: true
{{- end }}
{{- end }}
{{- if or .Values.outbox.enabled .Values.auditDelivery.enabled (eq (include "access-engine.callerAuth.enabled" .) "true") }}
volumes:
{{- if .Values.auditDelivery.enabled }}
- name: access-engine-audit
secret:
secretName: {{ required "auditDelivery.secretName must name an admitted existing Secret" .Values.auditDelivery.secretName | quote }}
defaultMode: 0440
items:
- key: {{ required "auditDelivery.secretKey is required" .Values.auditDelivery.secretKey | quote }}
path: token
{{- end }}
{{- if .Values.outbox.enabled }}
- name: access-engine-outbox
persistentVolumeClaim:
claimName: {{ default (printf "%s-outbox" (include "access-engine.name" .)) .Values.outbox.existingClaim | quote }}
{{- end }}
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
- name: access-engine-reviewer
projected:
defaultMode: 0440
sources:
- serviceAccountToken:
{{- if .Values.callerAuth.reviewer.audience }}
audience: {{ .Values.callerAuth.reviewer.audience | quote }}
{{- end }}
expirationSeconds: {{ .Values.callerAuth.reviewer.expirationSeconds }}
path: token
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
{{- end }}
{{- end }}

View file

@ -0,0 +1,68 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
namespace: {{ .Release.Namespace }}
name: {{ include "access-engine.name" . }}
labels:
{{- include "access-engine.labels" . | nindent 4 }}
spec:
podSelector:
matchLabels:
{{- include "access-engine.selectorLabels" . | nindent 6 }}
policyTypes:
- Ingress
- Egress
{{- if or .Values.auditDelivery.enabled (eq (include "access-engine.callerAuth.enabled" .) "true") }}
egress:
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
- ports:
- port: 443
protocol: TCP
- port: 6443
protocol: TCP
{{- end }}
{{- if .Values.auditDelivery.enabled }}
{{- if or (not (regexMatch "^[1-9][0-9]*$" (toString .Values.auditDelivery.receiverPort))) (lt (int .Values.auditDelivery.receiverPort) 1) (gt (int .Values.auditDelivery.receiverPort) 65535) }}
{{- fail "auditDelivery.receiverPort must be explicitly set to a valid receiver port" }}
{{- end }}
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: {{ required "auditDelivery.receiverNamespace is required" .Values.auditDelivery.receiverNamespace | quote }}
podSelector:
matchLabels:
app.kubernetes.io/name: {{ required "auditDelivery.receiverPodName is required" .Values.auditDelivery.receiverPodName | quote }}
ports:
- port: {{ .Values.auditDelivery.receiverPort }}
protocol: TCP
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: {{ required "auditDelivery.dnsNamespace is required" .Values.auditDelivery.dnsNamespace | quote }}
podSelector:
matchLabels:
k8s-app: {{ required "auditDelivery.dnsPodLabel is required" .Values.auditDelivery.dnsPodLabel | quote }}
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
{{- end }}
{{- else }}
egress: []
{{- end }}
{{- if .Values.consumer.isolated }}
ingress: []
{{- else }}
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: {{ required "consumer.namespace is required when not isolated" .Values.consumer.namespace }}
podSelector:
matchLabels:
app.kubernetes.io/name: {{ required "consumer.podName is required when not isolated" .Values.consumer.podName }}
ports:
- port: {{ .Values.service.port }}
protocol: TCP
{{- end }}

View file

@ -0,0 +1,20 @@
{{- if and .Values.outbox.enabled (not .Values.outbox.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: {{ .Release.Namespace }}
name: {{ include "access-engine.name" . }}-outbox
annotations:
helm.sh/resource-policy: keep
labels:
{{- include "access-engine.labels" . | nindent 4 }}
spec:
accessModes:
- ReadWriteOnce
{{- if .Values.outbox.storageClassName }}
storageClassName: {{ .Values.outbox.storageClassName | quote }}
{{- end }}
resources:
requests:
storage: {{ .Values.outbox.size | quote }}
{{- end }}

View file

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

View file

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
namespace: {{ .Release.Namespace }}
name: {{ include "access-engine.name" . }}
labels:
{{- include "access-engine.labels" . | nindent 4 }}
spec:
selector:
{{- include "access-engine.selectorLabels" . | nindent 4 }}
ports:
- name: http
port: {{ .Values.service.port }}
targetPort: http

View file

@ -0,0 +1,10 @@
{{- if eq (include "access-engine.callerAuth.enabled" .) "true" }}
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: {{ .Release.Namespace }}
name: {{ include "access-engine.name" . }}
labels:
{{- include "access-engine.labels" . | nindent 4 }}
automountServiceAccountToken: false
{{- end }}

View file

@ -0,0 +1,87 @@
# Default chart values. Real pins live in values/*.yaml — never promote a tag.
name: access-engine
namespace: access-engine
image:
repository: forgejo.coulomb.social/coulomb/access-engine
digest: ""
pullPolicy: IfNotPresent
replicaCount: 1
# Inert until enabled for an approved pin. The outbox is single-writer.
outbox:
enabled: false
source: ""
mountPath: /var/lib/access-engine/outbox
size: 1Gi
storageClassName: ""
existingClaim: ""
# Inert preparation: caller provides reviewed existing Secret and exact receiver.
# The chart never creates/mints sender credentials or registers a sender.
auditDelivery:
enabled: false
url: ""
secretName: ""
secretKey: ""
mountPath: /var/run/secrets/access-engine-audit
receiverNamespace: ""
receiverPodName: ""
receiverPort: 0
dnsNamespace: ""
dnsPodLabel: ""
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/access-engine/examples/tenant-engine/registry_snapshot.json
- --policy
- /opt/access-engine/examples/tenant-engine/policy_package.md
service:
port: 8080
health:
path: /healthz
consumer:
isolated: false
namespace: ""
podName: ""
# disabled keeps the image bootable without TokenReview (isolated canary).
# Production pins set warn, then enforce, independently per consumer.
# serve-readback pins (FLEX-WP-0035) admit one readback caller via
# --readback-caller instead of --caller-binding.
readback:
enabled: false
caller: ""
callerAuth:
mode: disabled
audience: access-engine
kubernetesURL: https://kubernetes.default.svc
binding: ""
# Further resource.system=principal pairs, each rendered as its own
# --caller-binding (e.g. ops-warden-fetch binds every catalog owner system
# to the ops-warden ServiceAccount).
extraBindings: []
reviewer:
mountPath: /var/run/secrets/access-engine-reviewer
# Empty: kubelet mints the API server's default audiences so TokenReview
# authenticates. A custom audience (e.g. https://kubernetes.default.svc)
# 401s on this k3s cluster, whose API audiences are
# https://kubernetes.default.svc.cluster.local and k3s.
audience: ""
expirationSeconds: 3600
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 300m
memory: 192Mi

View file

@ -43,30 +43,35 @@ func argAfter(args []string, flag string) []string {
// package at the same digest its own pin runs. The package is baked into the
// image, so same image digest and same path is the same package digest.
func TestReadbackPinMatchesParticipantPins(t *testing.T) {
readback := loadPinValues(t, "application-readback.yaml")
if len(readback.Args) == 0 || readback.Args[0] != "serve-readback" {
t.Fatal("readback pin must run serve-readback, which mounts no /v1/check")
}
participants := map[string]string{"informed-decision": "informed-decision-lifecycle.yaml"}
packages := argAfter(readback.Args, "--package")
if len(packages) != len(participants) {
t.Fatalf("readback packages %v, want one per participant %v", packages, participants)
}
for _, pkg := range packages {
system, path, _ := strings.Cut(pkg, "=")
file, ok := participants[system]
if !ok {
t.Fatalf("readback package for %q has no participant pin", system)
}
own := loadPinValues(t, file)
if own.Image.Digest != readback.Image.Digest {
t.Errorf("%s: readback image %s, own pin %s", system, readback.Image.Digest, own.Image.Digest)
}
if policies := argAfter(own.Args, "--policy"); len(policies) != 1 || policies[0] != path {
t.Errorf("%s: readback package %s, own pin %v", system, path, policies)
}
if !strings.Contains(strings.Join(argAfter(readback.Args, "--registry"), " "), strings.Join(argAfter(own.Args, "--registry"), " ")) {
t.Errorf("%s: readback pin does not load its registry", system)
}
for _, prefix := range []string{"", "access-engine/"} {
t.Run(prefix, func(t *testing.T) {
readback := loadPinValues(t, prefix+"application-readback.yaml")
if len(readback.Args) == 0 || readback.Args[0] != "serve-readback" {
t.Fatal("readback pin must run serve-readback, which mounts no /v1/check")
}
participants := map[string]string{"informed-decision": "informed-decision-lifecycle.yaml"}
packages := argAfter(readback.Args, "--package")
if len(packages) != len(participants) {
t.Fatalf("readback packages %v, want one per participant %v", packages, participants)
}
for _, pkg := range packages {
system, path, _ := strings.Cut(pkg, "=")
file, ok := participants[system]
if !ok {
t.Fatalf("readback package for %q has no participant pin", system)
}
own := loadPinValues(t, prefix+file)
if own.Image.Digest != readback.Image.Digest {
t.Errorf("%s: readback image %s, own pin %s", system, readback.Image.Digest, own.Image.Digest)
}
if policies := argAfter(own.Args, "--policy"); len(policies) != 1 || policies[0] != path {
t.Errorf("%s: readback package %s, own pin %v", system, path, policies)
}
if !strings.Contains(strings.Join(argAfter(readback.Args, "--registry"), " "), strings.Join(argAfter(own.Args, "--registry"), " ")) {
t.Errorf("%s: readback pin does not load its registry", system)
}
}
})
}
}

View file

@ -0,0 +1,8 @@
# FLEX-WP-0036-T05; creation remains gated on ordered predecessor live proof.
apiVersion: v1
kind: Namespace
metadata:
name: access-engine
labels:
kubernetes.io/metadata.name: access-engine
app.kubernetes.io/part-of: access-engine

View file

@ -0,0 +1,439 @@
{
"schema": "build-mode-prepared-change-v2",
"workplan": "FLEX-WP-0036",
"task": "FLEX-WP-0036-T05",
"status": "PREPARED_SOURCE_ONLY_NATIVE_RED_BATCH_WAIT",
"target": "access-engine namespace and nine side-by-side releases",
"prerequisites": [
"Single daily red batch disposition authorizes exact nine new TokenReview ServiceAccount bindings",
"Ordered preceding critical-path live evidence by coordinator",
"T03 image compatibility rollout verified on existing pins",
"T04 exact artifact availability and same-digest twin provenance verified",
"Old T05 declared external dependency qualified by coordinator; worker did not inspect wait task",
"Actual live pin inventory/digest and CPU headroom reconciled before server dry-run"
],
"expected_result": "Nine renamed releases Ready; /healthz200; anonymous protected routes401; exact twin image/policy and caller/network scope unchanged",
"abort_owner": "Custodian coordinator acting as Access runtime change owner",
"abort_conditions": [
"Any source/live twin digest or package argv mismatch",
"Any unproven preceding critical-path gate",
"Insufficient headroom or rollout stall",
"New pin cannot TokenReview or cannot match old decision behavior",
"Any changed caller principal, ingress/egress grant or shared durable writer state",
"Any missing exact red-batch authorization for new API principals or recovery revocation scope"
],
"verification": [
"Fresh helm template + server dry-run for exact source revision, namespace and pin manifests",
"Reconcile live nine-pin inventory and image digests against source",
"Ready, healthz200 and anonymous401 each new pin",
"Live authenticated owner allow/deny correspondence with old twin; no consumer switch in T05",
"Read back exact nine bound ServiceAccount subjects and TokenReview-only ClusterRole rules; prove no additional subjects/resources/verbs were admitted"
],
"rollback": "Before execution: no native grants exist to revoke. If the exact red batch is authorized and executed, suspend newly introduced GitOps reconciliation and scale only new access-engine Deployments to zero to stop workloads; this does NOT revoke their TokenReview authority. Rollback must additionally revoke exactly the nine new ClusterRoleBindings through the authorized red-batch recovery scope, retaining prior flex-auth bindings and all namespaces/data. Do not claim scale-zero alone revokes credentials or API authority. Destructive namespace/data deletion remains outside this item.",
"scope_limits": [
"No consumer endpoint/egress flip",
"No live mutation executed",
"No dual repository publication or unproven new image paths claimed",
"No durable writer twins generated",
"Nine new Kubernetes API TokenReview caller grants are explicitly proposed in red batch; no new protected-consumer caller mappings, secret grants or native writes executed"
],
"pins": [
{
"name": "access-engine-application-readback",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "user-engine",
"podName": "user-engine"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-lifecycle",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-sitting",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-t03",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:6600c7a62c36dfb4fbb42590722613827d07ff49875b1f0f4b5de63d8351658d",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-ops-warden-fetch",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:419bc37420d0d0a5304a8587448f1fdbf87117fb041fb43081b0449b4a7bb13b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "key-cape=system:serviceaccount:ops-warden:ops-warden",
"extraBindings": [
"railiance-platform=system:serviceaccount:ops-warden:ops-warden"
],
"audience": "access-engine"
},
"consumer": {
"isolated": true
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-ops-warden",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "ops-warden=system:serviceaccount:ops-warden:ops-warden",
"audience": "access-engine"
},
"consumer": {
"isolated": true
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-secrets-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "secrets-engine=system:serviceaccount:secrets-engine:secrets-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "secrets-engine",
"podName": "secrets-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-tenant-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "tenant-engine=system:serviceaccount:tenant-engine:tenant-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "tenant-engine",
"podName": "tenant-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-user-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "user-engine=system:serviceaccount:user-engine:user-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "user-engine",
"podName": "user-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
}
],
"classification": {
"source_preparation": "blue reversible local source work",
"native_namespace_and_pins": "red access-scope expansion: new ServiceAccounts receive Kubernetes TokenReview API create authority",
"reason": "Equality of verb sets does not establish equality of principals; nine new bound subjects can now create tokenreviews.",
"approval_route": "one item in the single daily red batch; no per-item founder request"
},
"supersedes": {
"path": "/tmp/access-runtime-twins-prepared-receipt.json",
"sha256": "ddf0d366afa3330ab753079dc6e4c122559b3bb2b9c6e38faf72d23f8a09127d",
"reason": "First prepared receipt incorrectly classified new TokenReview principals as blue based on role-verb parity."
},
"new_access_scope": [
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-application-readback",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-application-readback"
},
"binding": "access-engine-application-readback-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-application-readback-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-informed-decision-lifecycle",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-informed-decision-lifecycle"
},
"binding": "access-engine-informed-decision-lifecycle-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-informed-decision-lifecycle-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-informed-decision-sitting",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-informed-decision-sitting"
},
"binding": "access-engine-informed-decision-sitting-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-informed-decision-sitting-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-informed-decision-t03",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-informed-decision-t03"
},
"binding": "access-engine-informed-decision-t03-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-informed-decision-t03-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-ops-warden-fetch",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-ops-warden-fetch"
},
"binding": "access-engine-ops-warden-fetch-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-ops-warden-fetch-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-ops-warden",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-ops-warden"
},
"binding": "access-engine-ops-warden-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-ops-warden-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-secrets-engine",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-secrets-engine"
},
"binding": "access-engine-secrets-engine-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-secrets-engine-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-tenant-engine",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-tenant-engine"
},
"binding": "access-engine-tenant-engine-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-tenant-engine-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
},
{
"subject": {
"kind": "ServiceAccount",
"namespace": "access-engine",
"name": "access-engine-user-engine",
"authenticated_username": "system:serviceaccount:access-engine:access-engine-user-engine"
},
"binding": "access-engine-user-engine-tokenreviewer",
"role": {
"kind": "ClusterRole",
"name": "access-engine-user-engine-tokenreviewer"
},
"capability": {
"apiGroups": [
"authentication.k8s.io"
],
"resources": [
"tokenreviews"
],
"verbs": [
"create"
]
},
"scope": "cluster-scoped TokenReview API create; not a secrets-read grant or protected-consumer impersonation grant"
}
],
"daily_red_batch_item": {
"id": "FLEX-WP-0036-T05-tokenreview-twins",
"request": "Authorize exact nine access-engine ServiceAccount TokenReview create bindings, together with exact binding revocation recovery; dependent namespace/pin rollout stays gated on T03/T04 and ordered predecessor evidence.",
"new_subject_count": 9,
"scope_list_field": "new_access_scope",
"execution_state": "not executed",
"scope_limits": "No secrets-read grants, protected-consumer mapping expansion, namespace/data deletion or consumer endpoint change."
}
}

View file

@ -0,0 +1,190 @@
{
"schema": "build-mode-prepared-blue-change-v1",
"workplan": "FLEX-WP-0036",
"task": "FLEX-WP-0036-T05",
"status": "PREPARED_SOURCE_ONLY_NATIVE_WAIT",
"target": "access-engine namespace and nine side-by-side releases",
"prerequisites": [
"Ordered preceding critical-path live evidence by coordinator",
"T03 image compatibility rollout verified on existing pins",
"T04 exact artifact availability and same-digest twin provenance verified",
"Old T05 declared external dependency qualified by coordinator; worker did not inspect wait task",
"Actual live pin inventory/digest and CPU headroom reconciled before server dry-run"
],
"expected_result": "Nine renamed releases Ready; /healthz200; anonymous protected routes401; exact twin image/policy and caller/network scope unchanged",
"abort_owner": "Custodian coordinator acting as Access runtime change owner",
"abort_conditions": [
"Any source/live twin digest or package argv mismatch",
"Any unproven preceding critical-path gate",
"Insufficient headroom or rollout stall",
"New pin cannot TokenReview or cannot match old decision behavior",
"Any changed caller principal, ingress/egress grant or shared durable writer state"
],
"verification": [
"Fresh helm template + server dry-run for exact source revision, namespace and pin manifests",
"Reconcile live nine-pin inventory and image digests against source",
"Ready, healthz200 and anonymous401 each new pin",
"Live authenticated owner allow/deny correspondence with old twin; no consumer switch in T05"
],
"rollback": "Suspend newly introduced GitOps reconciliation and scale only newly created access-engine Deployments to zero. Leave flex-auth releases, namespace, data and caller configuration intact. Do not delete old/new namespaces, RBAC or durable storage in this blue scope; destructive cleanup goes to the red batch.",
"scope_limits": [
"No consumer endpoint/egress flip",
"No live mutation executed",
"No new caller grants or secrets",
"No dual repository publication or unproven new image paths claimed",
"No durable writer twins generated"
],
"pins": [
{
"name": "access-engine-application-readback",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "user-engine",
"podName": "user-engine"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-lifecycle",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-sitting",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-informed-decision-t03",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:6600c7a62c36dfb4fbb42590722613827d07ff49875b1f0f4b5de63d8351658d",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "informed-decision=system:serviceaccount:informed-decision:review",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "informed-decision",
"podName": "informed-decision"
},
"request_cpu": "5m",
"request_memory": "32Mi"
},
{
"name": "access-engine-ops-warden-fetch",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:419bc37420d0d0a5304a8587448f1fdbf87117fb041fb43081b0449b4a7bb13b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "key-cape=system:serviceaccount:ops-warden:ops-warden",
"extraBindings": [
"railiance-platform=system:serviceaccount:ops-warden:ops-warden"
],
"audience": "access-engine"
},
"consumer": {
"isolated": true
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-ops-warden",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "ops-warden=system:serviceaccount:ops-warden:ops-warden",
"audience": "access-engine"
},
"consumer": {
"isolated": true
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-secrets-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "secrets-engine=system:serviceaccount:secrets-engine:secrets-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "secrets-engine",
"podName": "secrets-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-tenant-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "tenant-engine=system:serviceaccount:tenant-engine:tenant-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "tenant-engine",
"podName": "tenant-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
},
{
"name": "access-engine-user-engine",
"image": "forgejo.coulomb.social/coulomb/flex-auth@sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b",
"caller_auth": {
"mode": "enforce",
"kubernetesURL": "https://10.43.0.1",
"binding": "user-engine=system:serviceaccount:user-engine:user-engine",
"audience": "access-engine"
},
"consumer": {
"isolated": false,
"namespace": "user-engine",
"podName": "user-engine"
},
"request_cpu": "25m",
"request_memory": "32Mi"
}
]
}

View file

@ -6,6 +6,8 @@ cd "$(dirname "${BASH_SOURCE[0]}")/.."
python3 tests/validate_app_toml.py
python3 tests/test_outbox_chart.py
python3 tools/gen_runtime_twins.py --check
python3 tests/test_runtime_twins.py
for values in values/stage1.yaml values/stage2-canary.yaml values/stage3-production.yaml \
values/user-engine.yaml values/tenant-engine.yaml values/ops-warden.yaml; do

View file

@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""Source render integration tests; never contacts the cluster."""
import copy
import importlib.util
from pathlib import Path
import subprocess
import unittest
import yaml
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location("twins", ROOT / "tools/gen_runtime_twins.py")
twins = importlib.util.module_from_spec(spec)
spec.loader.exec_module(twins)
def render(chart, values, namespace, name):
output = subprocess.check_output(["helm", "template", name, str(ROOT / "charts" / chart), "-f", str(ROOT / "values" / values), "--namespace", namespace], text=True)
return {obj["kind"]: obj for obj in yaml.safe_load_all(output) if obj}
def after(args, flag):
return [args[i + 1] for i, item in enumerate(args[:-1]) if item == flag]
class RuntimeTwinTests(unittest.TestCase):
def test_actual_nine_twin_render_security_and_content(self):
for pin in twins.PINS:
with self.subTest(pin=pin):
source = yaml.safe_load((ROOT / "values" / (pin + ".yaml")).read_text())
new = yaml.safe_load((ROOT / "values/access-engine" / (pin + ".yaml")).read_text())
self.assertEqual(new, twins.twin(source))
old_objects = render("flex-auth", pin + ".yaml", "flex-auth", source["name"])
objects = render("access-engine", "access-engine/" + pin + ".yaml", "access-engine", new["name"])
self.assertEqual(set(objects), set(old_objects))
for kind in ("Deployment", "Service", "ServiceAccount", "NetworkPolicy"):
self.assertEqual(objects[kind]["metadata"]["namespace"], "access-engine")
deployment = objects["Deployment"]
pod = deployment["spec"]["template"]["spec"]
container = pod["containers"][0]
old_container = old_objects["Deployment"]["spec"]["template"]["spec"]["containers"][0]
self.assertEqual(container["image"], old_container["image"])
self.assertEqual(container["args"][:len(source["args"])], source["args"])
self.assertEqual(after(container["args"], "--caller-audience"), ["access-engine"])
self.assertEqual(after(container["args"], "--caller-binding"), after(old_container["args"], "--caller-binding"))
self.assertEqual(after(container["args"], "--readback-caller"), after(old_container["args"], "--readback-caller"))
self.assertEqual(pod["serviceAccountName"], new["name"])
mount = next(m["mountPath"] for m in container["volumeMounts"] if m["name"] == "access-engine-reviewer")
self.assertEqual(after(container["args"], "--caller-reviewer-token-file"), [mount + "/token"])
self.assertEqual(after(container["args"], "--caller-ca-file"), [mount + "/ca.crt"])
self.assertFalse(pod["automountServiceAccountToken"])
self.assertEqual(objects["ClusterRole"]["rules"], old_objects["ClusterRole"]["rules"])
binding = objects["ClusterRoleBinding"]
self.assertEqual(binding["subjects"], [{"kind": "ServiceAccount", "name": new["name"], "namespace": "access-engine"}])
self.assertEqual(binding["roleRef"]["name"], new["name"] + "-tokenreviewer")
self.assertEqual(objects["NetworkPolicy"]["spec"]["ingress"], old_objects["NetworkPolicy"]["spec"]["ingress"])
self.assertEqual(objects["NetworkPolicy"]["spec"]["egress"], old_objects["NetworkPolicy"]["spec"]["egress"])
self.assertEqual(objects["Service"]["spec"]["selector"], deployment["spec"]["selector"]["matchLabels"])
self.assertEqual(deployment["spec"]["selector"]["matchLabels"], {"app.kubernetes.io/name": new["name"]})
self.assertTrue(container["securityContext"]["readOnlyRootFilesystem"])
self.assertFalse(container["securityContext"]["allowPrivilegeEscalation"])
self.assertEqual(container["livenessProbe"], old_container["livenessProbe"])
self.assertEqual(container["readinessProbe"], old_container["readinessProbe"])
def test_refuse_unpinned_unenforced_and_shared_writer(self):
source = yaml.safe_load((ROOT / "values/user-engine.yaml").read_text())
for field, value in (("image", {"digest": "latest"}), ("callerAuth", {"mode": "disabled"}), ("outbox", {"enabled": True}), ("auditDelivery", {"enabled": True}), ("name", "other-pin")):
with self.subTest(field=field):
bad = copy.deepcopy(source); bad[field] = value
with self.assertRaises(ValueError): twins.twin(bad)
self.assertNotIn("namespace", source)
if __name__ == "__main__": unittest.main()

View file

@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""Prepare exact-content runtime twins. Local files only; never applies to Kubernetes.
Namespace/release/chart/ServiceAccount and caller audience move to access-engine.
Image repository+digest and policy/registry argv remain exact existing-twin values
until publication/path migration is separately proven.
"""
from pathlib import Path
import argparse
import copy
import re
import yaml
ROOT = Path(__file__).resolve().parents[1]
PINS = ("ops-warden", "ops-warden-fetch", "secrets-engine", "user-engine", "tenant-engine", "informed-decision-lifecycle", "informed-decision-sitting", "informed-decision-t03", "application-readback")
def twin(source):
result = copy.deepcopy(source)
if not re.fullmatch(r"sha256:[0-9a-f]{64}", source.get("image", {}).get("digest", "")):
raise ValueError("existing twin must have an immutable SHA256 digest")
name = source.get("name", "")
if not name.startswith("flex-auth-"):
raise ValueError("existing pin must have an exact flex-auth release name")
if source.get("callerAuth", {}).get("mode") != "enforce":
raise ValueError("new twin requires existing enforced caller authentication")
if source.get("outbox", {}).get("enabled") or source.get("auditDelivery", {}).get("enabled"):
raise ValueError("durable outbox/audit twins require independent source/custody; never share writer state")
result["name"] = "access-engine-" + name[len("flex-auth-"):]
result["namespace"] = "access-engine"
result["callerAuth"]["audience"] = "access-engine"
return result
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true")
args = parser.parse_args()
for pin in PINS:
source = yaml.safe_load((ROOT / "values" / (pin + ".yaml")).read_text())
target = ROOT / "values" / "access-engine" / (pin + ".yaml")
result = twin(source)
if args.check:
if not target.exists() or yaml.safe_load(target.read_text()) != result:
raise SystemExit(f"runtime twin drift: {target}")
else:
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text("# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.\n" + yaml.safe_dump(result, sort_keys=False))
if __name__ == "__main__":
main()

View file

@ -0,0 +1,34 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-application-readback
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229
args:
- serve-readback
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/application-readback/registry_snapshot.json
- --registry
- /opt/flex-auth/examples/informed-decision-lifecycle/registry.json
- --package
- informed-decision=/opt/flex-auth/examples/informed-decision-lifecycle/policy.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
audience: access-engine
readback:
enabled: true
caller: system:serviceaccount:user-engine:user-engine
consumer:
isolated: false
namespace: user-engine
podName: user-engine
resources:
requests:
cpu: 5m
memory: 32Mi
limits:
cpu: 300m
memory: 192Mi
namespace: access-engine

View file

@ -0,0 +1,30 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-informed-decision-lifecycle
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:e8c57c18a4a9d5583be099146984f7e9cd881446218b65aeefd7619b18aa9229
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/informed-decision-lifecycle/registry.json
- --policy
- /opt/flex-auth/examples/informed-decision-lifecycle/policy.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: informed-decision=system:serviceaccount:informed-decision:review
audience: access-engine
consumer:
isolated: false
namespace: informed-decision
podName: informed-decision
resources:
requests:
cpu: 5m
memory: 32Mi
limits:
cpu: 300m
memory: 192Mi
namespace: access-engine

View file

@ -0,0 +1,30 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-informed-decision-sitting
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:bdac62bc3f089cba0df7c35eeb8d0d9b3af2d4bae5e4ea4767516c1ed20b1e99
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/informed-decision-lifecycle-review/registry.json
- --policy
- /opt/flex-auth/examples/informed-decision-lifecycle-review/policy.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: informed-decision=system:serviceaccount:informed-decision:review
audience: access-engine
consumer:
isolated: false
namespace: informed-decision
podName: informed-decision
resources:
requests:
cpu: 5m
memory: 32Mi
limits:
cpu: 300m
memory: 192Mi
namespace: access-engine

View file

@ -0,0 +1,30 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-informed-decision-t03
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:6600c7a62c36dfb4fbb42590722613827d07ff49875b1f0f4b5de63d8351658d
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/informed-decision-t03/registry.json
- --policy
- /opt/flex-auth/examples/informed-decision-t03/policy.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: informed-decision=system:serviceaccount:informed-decision:review
audience: access-engine
consumer:
isolated: false
namespace: informed-decision
podName: informed-decision
resources:
requests:
cpu: 5m
memory: 32Mi
limits:
cpu: 300m
memory: 192Mi
namespace: access-engine

View file

@ -0,0 +1,23 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-ops-warden-fetch
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:419bc37420d0d0a5304a8587448f1fdbf87117fb041fb43081b0449b4a7bb13b
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/ops-warden-fetch/registry_snapshot.json
- --policy
- /opt/flex-auth/examples/ops-warden-fetch/policy_package.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: key-cape=system:serviceaccount:ops-warden:ops-warden
extraBindings:
- railiance-platform=system:serviceaccount:ops-warden:ops-warden
audience: access-engine
consumer:
isolated: true
namespace: access-engine

View file

@ -0,0 +1,21 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-ops-warden
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/ops-warden/production_registry_snapshot.json
- --policy
- /opt/flex-auth/examples/ops-warden/policy_package.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: ops-warden=system:serviceaccount:ops-warden:ops-warden
audience: access-engine
consumer:
isolated: true
namespace: access-engine

View file

@ -0,0 +1,23 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-secrets-engine
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/secrets-engine/registry_snapshot.json
- --policy
- /opt/flex-auth/examples/secrets-engine/policy_package.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: secrets-engine=system:serviceaccount:secrets-engine:secrets-engine
audience: access-engine
consumer:
isolated: false
namespace: secrets-engine
podName: secrets-engine
namespace: access-engine

View file

@ -0,0 +1,23 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-tenant-engine
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/tenant-engine/registry_snapshot.json
- --policy
- /opt/flex-auth/examples/tenant-engine/policy_package.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: tenant-engine=system:serviceaccount:tenant-engine:tenant-engine
audience: access-engine
consumer:
isolated: false
namespace: tenant-engine
podName: tenant-engine
namespace: access-engine

View file

@ -0,0 +1,23 @@
# GENERATED by tools/gen_runtime_twins.py; same image/package as existing twin.
name: access-engine-user-engine
image:
repository: forgejo.coulomb.social/coulomb/flex-auth
digest: sha256:138aa3471c46bca6e814691fa1e6520aedda3dffd743e6b09141ab433afdb64b
args:
- serve
- --addr
- 0.0.0.0:8080
- --registry
- /opt/flex-auth/examples/user-engine/registry_snapshot.json
- --policy
- /opt/flex-auth/examples/user-engine/policy_package.md
callerAuth:
mode: enforce
kubernetesURL: https://10.43.0.1
binding: user-engine=system:serviceaccount:user-engine:user-engine
audience: access-engine
consumer:
isolated: false
namespace: user-engine
podName: user-engine
namespace: access-engine

View file

@ -181,7 +181,7 @@ args reference.
```task
id: FLEX-WP-0036-T05
status: todo
status: wait
priority: medium
depends_on: [FLEX-WP-0036-T03, FLEX-WP-0036-T04]
state_hub_task_id: "13b93d7a-8341-5c76-9ae8-0f36b45b10fc"
@ -197,6 +197,24 @@ that each twin pair runs the same digest.
Gate: every new pin Ready, `/healthz` 200, anonymous requests 401; founder go.
Blocked on `FLEX-WP-0020-T11` closing.
2026-10-11: native wait qualified once against existing `depends_on` T03/T04:
coordinator must prove predecessor image rollout on existing pins before any
new namespace/pin creation. No wait-task inspection or new grant was needed.
Actual source preparation adds the renamed chart, exact-content generated twins,
explicit audience/reviewer paths and render/fixture correspondence checks.
Twins retain the exact existing image repository/digest and policy argv; these
are migration compatibility details until an identical digest is published under
the renamed repository and the baked new paths are proven. No namespace or
release has been created by this preparation. Local source preparation is reversible blue work under
`the-custodian/canon/standards/build-mode-change-authorization_v0.1.md`.
Native rollout creates nine new ServiceAccount subjects bound to cluster-scoped
`create` on `authentication.k8s.io/tokenreviews`; matching the prior role's verbs
does not make those new principals an unchanged access scope. It is one red
access-scope-expansion item in the single daily batch, including exact binding
revocation recovery. No per-item founder request is needed. The first prepared
blue receipt is preserved as superseded by the classification correction; no
native action occurred. T03/T04 and ordered predecessor gates remain unchanged.
## Consumers switch over, one at a time
```task