From 352af96ff2601b72d861ec377354ad604d9beef9 Mon Sep 17 00:00:00 2001 From: Ryan Cook Date: Wed, 4 Mar 2026 09:53:26 -0500 Subject: [PATCH 1/3] resolve #822 changing cm to secret Signed-off-by: Ryan Cook --- .../example_deployment.yaml | 24 +++++++---- .../example_deployment_spiffe.yaml | 24 +++++++---- .../demos/webhook/k8s/configmaps-webhook.yaml | 14 +++++-- CLAUDE.md | 13 +++--- .../templates/clusterrole.yaml | 3 ++ kagenti-webhook/CLAUDE.md | 11 +++-- kagenti-webhook/config/rbac/role.yaml | 3 ++ .../webhook/injector/container_builder.go | 8 ++-- .../injector/container_builder_test.go | 42 +++++++++++++++++++ 9 files changed, 112 insertions(+), 30 deletions(-) diff --git a/AuthBridge/client-registration/example_deployment.yaml b/AuthBridge/client-registration/example_deployment.yaml index fbbf4bf24..c2dfa742a 100644 --- a/AuthBridge/client-registration/example_deployment.yaml +++ b/AuthBridge/client-registration/example_deployment.yaml @@ -10,14 +10,24 @@ metadata: namespace: my-agent data: SPIRE_ENABLED: "false" - # Replace these placeholder values with real endpoints/credentials + # Replace these placeholder values with real endpoints KEYCLOAK_URL: "http://keycloak.keycloak.svc:8080" KEYCLOAK_REALM: "master" - KEYCLOAK_ADMIN_USERNAME: "admin" - KEYCLOAK_ADMIN_PASSWORD: "admin" KEYCLOAK_TOKEN_EXCHANGE_ENABLED: "true" KEYCLOAK_CLIENT_REGISTRATION_ENABLED: "true" --- +# keycloak-admin-secret - Keycloak admin credentials for client registration +# Replace the placeholder values with your actual admin credentials. +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-admin-secret + namespace: my-agent +type: Opaque +stringData: + KEYCLOAK_ADMIN_USERNAME: "admin" + KEYCLOAK_ADMIN_PASSWORD: "changeme" +--- apiVersion: v1 kind: ServiceAccount metadata: @@ -77,13 +87,13 @@ spec: key: KEYCLOAK_REALM - name: KEYCLOAK_ADMIN_USERNAME valueFrom: - configMapKeyRef: - name: environments + secretKeyRef: + name: keycloak-admin-secret key: KEYCLOAK_ADMIN_USERNAME - name: KEYCLOAK_ADMIN_PASSWORD valueFrom: - configMapKeyRef: - name: environments + secretKeyRef: + name: keycloak-admin-secret key: KEYCLOAK_ADMIN_PASSWORD - name: CLIENT_NAME value: my-app diff --git a/AuthBridge/client-registration/example_deployment_spiffe.yaml b/AuthBridge/client-registration/example_deployment_spiffe.yaml index 327838a94..e1327b747 100644 --- a/AuthBridge/client-registration/example_deployment_spiffe.yaml +++ b/AuthBridge/client-registration/example_deployment_spiffe.yaml @@ -10,14 +10,24 @@ metadata: namespace: my-agent data: SPIRE_ENABLED: "true" - # Replace these placeholder values with real endpoints/credentials + # Replace these placeholder values with real endpoints KEYCLOAK_URL: "http://keycloak.keycloak.svc:8080" KEYCLOAK_REALM: "master" - KEYCLOAK_ADMIN_USERNAME: "admin" - KEYCLOAK_ADMIN_PASSWORD: "admin" KEYCLOAK_TOKEN_EXCHANGE_ENABLED: "true" KEYCLOAK_CLIENT_REGISTRATION_ENABLED: "true" --- +# keycloak-admin-secret - Keycloak admin credentials for client registration +# Replace the placeholder values with your actual admin credentials. +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-admin-secret + namespace: my-agent +type: Opaque +stringData: + KEYCLOAK_ADMIN_USERNAME: "admin" + KEYCLOAK_ADMIN_PASSWORD: "changeme" +--- apiVersion: v1 kind: ServiceAccount metadata: @@ -91,13 +101,13 @@ spec: key: KEYCLOAK_REALM - name: KEYCLOAK_ADMIN_USERNAME valueFrom: - configMapKeyRef: - name: environments + secretKeyRef: + name: keycloak-admin-secret key: KEYCLOAK_ADMIN_USERNAME - name: KEYCLOAK_ADMIN_PASSWORD valueFrom: - configMapKeyRef: - name: environments + secretKeyRef: + name: keycloak-admin-secret key: KEYCLOAK_ADMIN_PASSWORD - name: CLIENT_NAME value: my-app diff --git a/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml b/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml index 6cb6f6b33..3591cd429 100644 --- a/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml +++ b/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml @@ -17,9 +17,17 @@ data: SPIRE_ENABLED: "true" KEYCLOAK_URL: "http://keycloak-service.keycloak.svc:8080" KEYCLOAK_REALM: "demo" - # Demo/development only: do NOT use hardcoded admin credentials in production. - # For production deployments, supply these via a Kubernetes Secret and reference - # them from your Pod/Deployment using env.valueFrom.secretKeyRef instead of this ConfigMap. + +--- +# keycloak-admin-secret - Keycloak admin credentials for client registration +# Replace the placeholder values with your actual admin credentials. +apiVersion: v1 +kind: Secret +metadata: + name: keycloak-admin-secret + namespace: team1 +type: Opaque +stringData: KEYCLOAK_ADMIN_USERNAME: "admin" KEYCLOAK_ADMIN_PASSWORD: "admin" # Comma-separated list of Keycloak client IDs that should receive the agent's diff --git a/CLAUDE.md b/CLAUDE.md index ce27fc46a..2e9cfdc6e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -196,12 +196,13 @@ Hooks: When the webhook injects sidecars, the target namespace needs these ConfigMaps: -| ConfigMap | Used by | Keys | -|-----------|---------|------| -| `environments` | client-registration | `KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_ADMIN_USERNAME`, `KEYCLOAK_ADMIN_PASSWORD` | -| `authbridge-config` | envoy-proxy (ext-proc) | `TOKEN_URL`, `ISSUER`, `TARGET_AUDIENCE`, `TARGET_SCOPES` | -| `spiffe-helper-config` | spiffe-helper | SPIFFE helper configuration file | -| `envoy-config` | envoy-proxy | Envoy YAML configuration | +| Resource | Kind | Used by | Keys | +|----------|------|---------|------| +| `environments` | ConfigMap | client-registration | `KEYCLOAK_URL`, `KEYCLOAK_REALM` | +| `keycloak-admin-secret` | Secret | client-registration | `KEYCLOAK_ADMIN_USERNAME`, `KEYCLOAK_ADMIN_PASSWORD` | +| `authbridge-config` | ConfigMap | envoy-proxy (ext-proc) | `TOKEN_URL`, `ISSUER`, `TARGET_AUDIENCE`, `TARGET_SCOPES` | +| `spiffe-helper-config` | ConfigMap | spiffe-helper | SPIFFE helper configuration file | +| `envoy-config` | ConfigMap | envoy-proxy | Envoy YAML configuration | ## Common Development Tasks diff --git a/charts/kagenti-webhook/templates/clusterrole.yaml b/charts/kagenti-webhook/templates/clusterrole.yaml index 780ee2705..6056c0401 100644 --- a/charts/kagenti-webhook/templates/clusterrole.yaml +++ b/charts/kagenti-webhook/templates/clusterrole.yaml @@ -15,6 +15,9 @@ rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["get", "create", "update"] diff --git a/kagenti-webhook/CLAUDE.md b/kagenti-webhook/CLAUDE.md index 6ee4a72f2..fd7f3770b 100644 --- a/kagenti-webhook/CLAUDE.md +++ b/kagenti-webhook/CLAUDE.md @@ -149,13 +149,18 @@ make generate - **Container existence checks**: `containerExists()` and `volumeExists()` helpers prevent duplicate injection. - **Kubebuilder markers**: Webhook path markers (e.g., `+kubebuilder:webhook:path=...`) in Go comments generate the webhook manifests. Do not change these without running `make manifests`. -### ConfigMap Dependencies at Runtime -Injected sidecars expect these ConfigMaps to exist in the target namespace: -- `environments` -- `KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_ADMIN_USERNAME`, `KEYCLOAK_ADMIN_PASSWORD` +### Runtime Dependencies +Injected sidecars expect these resources to exist in the target namespace: + +ConfigMaps: +- `environments` -- `KEYCLOAK_URL`, `KEYCLOAK_REALM` - `authbridge-config` -- `TOKEN_URL`, `ISSUER`, `TARGET_AUDIENCE`, `TARGET_SCOPES` - `spiffe-helper-config` -- SPIFFE helper configuration (when SPIRE is enabled) - `envoy-config` -- Envoy proxy configuration +Secrets: +- `keycloak-admin-secret` -- `KEYCLOAK_ADMIN_USERNAME`, `KEYCLOAK_ADMIN_PASSWORD` + ### Security Model - `proxy-init` runs as an init container with a short lifetime (iptables setup). - `envoy-proxy` runs as UID 1337. diff --git a/kagenti-webhook/config/rbac/role.yaml b/kagenti-webhook/config/rbac/role.yaml index 36af9f0a5..77114f2d2 100644 --- a/kagenti-webhook/config/rbac/role.yaml +++ b/kagenti-webhook/config/rbac/role.yaml @@ -15,6 +15,9 @@ rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get", "list", "watch"] +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["serviceaccounts"] verbs: ["get", "create", "update"] diff --git a/kagenti-webhook/internal/webhook/injector/container_builder.go b/kagenti-webhook/internal/webhook/injector/container_builder.go index 5e08d8544..c5a79a014 100644 --- a/kagenti-webhook/internal/webhook/injector/container_builder.go +++ b/kagenti-webhook/internal/webhook/injector/container_builder.go @@ -135,9 +135,9 @@ func (b *ContainerBuilder) BuildClientRegistrationContainerWithSpireOption(name, { Name: "KEYCLOAK_ADMIN_USERNAME", ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "environments", + Name: "keycloak-admin-secret", }, Key: "KEYCLOAK_ADMIN_USERNAME", }, @@ -146,9 +146,9 @@ func (b *ContainerBuilder) BuildClientRegistrationContainerWithSpireOption(name, { Name: "KEYCLOAK_ADMIN_PASSWORD", ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + SecretKeyRef: &corev1.SecretKeySelector{ LocalObjectReference: corev1.LocalObjectReference{ - Name: "environments", + Name: "keycloak-admin-secret", }, Key: "KEYCLOAK_ADMIN_PASSWORD", }, diff --git a/kagenti-webhook/internal/webhook/injector/container_builder_test.go b/kagenti-webhook/internal/webhook/injector/container_builder_test.go index 6a06f1cf0..97244cb95 100644 --- a/kagenti-webhook/internal/webhook/injector/container_builder_test.go +++ b/kagenti-webhook/internal/webhook/injector/container_builder_test.go @@ -134,3 +134,45 @@ func TestBuildClientRegistrationContainer_HasPlatformClientIDsEnv(t *testing.T) t.Error("client-registration container missing PLATFORM_CLIENT_IDS env var") } } + +func TestBuildClientRegistrationContainer_AdminCredentialsFromSecret(t *testing.T) { + builder := NewContainerBuilder(config.CompiledDefaults()) + container := builder.BuildClientRegistrationContainerWithSpireOption("my-app", "my-ns", true) + + sensitiveKeys := []string{"KEYCLOAK_ADMIN_USERNAME", "KEYCLOAK_ADMIN_PASSWORD"} + for _, key := range sensitiveKeys { + for _, env := range container.Env { + if env.Name != key { + continue + } + if env.ValueFrom == nil || env.ValueFrom.SecretKeyRef == nil { + t.Errorf("env %q must use SecretKeyRef, got ConfigMapKeyRef or literal", key) + continue + } + if env.ValueFrom.SecretKeyRef.Name != "keycloak-admin-secret" { + t.Errorf("env %q SecretKeyRef.Name = %q, want %q", key, env.ValueFrom.SecretKeyRef.Name, "keycloak-admin-secret") + } + } + } +} + +func TestBuildClientRegistrationContainer_NonSensitiveKeysFromConfigMap(t *testing.T) { + builder := NewContainerBuilder(config.CompiledDefaults()) + container := builder.BuildClientRegistrationContainerWithSpireOption("my-app", "my-ns", true) + + nonSensitiveKeys := []string{"KEYCLOAK_URL", "KEYCLOAK_REALM"} + for _, key := range nonSensitiveKeys { + for _, env := range container.Env { + if env.Name != key { + continue + } + if env.ValueFrom == nil || env.ValueFrom.ConfigMapKeyRef == nil { + t.Errorf("env %q must use ConfigMapKeyRef", key) + continue + } + if env.ValueFrom.ConfigMapKeyRef.Name != "environments" { + t.Errorf("env %q ConfigMapKeyRef.Name = %q, want %q", key, env.ValueFrom.ConfigMapKeyRef.Name, "environments") + } + } + } +} From 907456a62b62933fbab40f566edd84134e4d064e Mon Sep 17 00:00:00 2001 From: Mariusz Sabath Date: Fri, 6 Mar 2026 18:31:53 -0500 Subject: [PATCH 2/3] docs: add keycloak-admin-secret creation step to demo guides Update demo-ui.md and demo-manual.md to document the new keycloak-admin-secret Secret that client-registration reads admin credentials from (instead of the environments ConfigMap). Assisted-By: Claude (Anthropic AI) Signed-off-by: Mariusz Sabath --- AuthBridge/demos/github-issue/demo-manual.md | 32 ++++++++++++++----- AuthBridge/demos/github-issue/demo-ui.md | 33 ++++++++++++++------ 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/AuthBridge/demos/github-issue/demo-manual.md b/AuthBridge/demos/github-issue/demo-manual.md index 40bbde8d0..b67459718 100644 --- a/AuthBridge/demos/github-issue/demo-manual.md +++ b/AuthBridge/demos/github-issue/demo-manual.md @@ -282,13 +282,26 @@ This creates: --- -## Step 3: Apply Demo ConfigMaps +## Step 3: Create Keycloak Admin Secret and Apply Demo ConfigMaps The Kagenti installer creates default ConfigMaps (`environments`, `spiffe-helper-config`, `envoy-config`, `authbridge-config`) with the correct -`kagenti` realm settings and 300s Envoy timeouts. This step overrides only -`authbridge-config` with demo-specific values — the token exchange target -audience (`github-tool`), scopes, and the agent's SPIFFE ID for inbound +`kagenti` realm settings and 300s Envoy timeouts. + +The client-registration sidecar needs Keycloak admin credentials to register +agents as OAuth clients. These are stored in a Kubernetes Secret (not a +ConfigMap) to follow security best practices. Create the secret **before** +deploying the agent: + +```bash +kubectl create secret generic keycloak-admin-secret -n team1 \ + --from-literal=KEYCLOAK_ADMIN_USERNAME=admin \ + --from-literal=KEYCLOAK_ADMIN_PASSWORD=admin \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +Then apply the demo-specific `authbridge-config` override — the token exchange +target audience (`github-tool`), scopes, and the agent's SPIFFE ID for inbound audience validation. Apply this **before** deploying the agent. ```bash @@ -806,17 +819,20 @@ kubectl delete pod test-client -n team1 --ignore-not-found **Symptom:** `{"error":"invalid_client","error_description":"Invalid client or Invalid client credentials"}` -**Cause:** The agent pod's `environments` ConfigMap was missing or incorrect at startup, -so the client-registration sidecar registered the client with wrong settings. +**Cause:** The `keycloak-admin-secret` Secret or `environments` ConfigMap was missing +or incorrect at startup, so the client-registration sidecar couldn't register the client. **Fix:** ```bash -# 1. Verify the installer's environments ConfigMap has the correct realm +# 1. Verify the keycloak-admin-secret exists +kubectl get secret keycloak-admin-secret -n team1 + +# 2. Verify the installer's environments ConfigMap has the correct realm kubectl get configmap environments -n team1 -o jsonpath='{.data.KEYCLOAK_REALM}' # Should show: kagenti -# 2. Re-apply the demo ConfigMap and restart +# 3. Re-apply the demo ConfigMap and restart kubectl apply -f demos/github-issue/k8s/configmaps.yaml kubectl rollout restart deployment/git-issue-agent -n team1 ``` diff --git a/AuthBridge/demos/github-issue/demo-ui.md b/AuthBridge/demos/github-issue/demo-ui.md index 0485b6b15..b4b0d5e86 100644 --- a/AuthBridge/demos/github-issue/demo-ui.md +++ b/AuthBridge/demos/github-issue/demo-ui.md @@ -173,14 +173,26 @@ This creates: --- -## Step 2: Apply Demo ConfigMaps +## Step 2: Create Keycloak Admin Secret and Apply Demo ConfigMaps The Kagenti installer creates default ConfigMaps (`environments`, `spiffe-helper-config`, `envoy-config`, `authbridge-config`) with the correct -`kagenti` realm settings and 300s Envoy timeouts. This step overrides only -`authbridge-config` with demo-specific values — the token exchange target -audience (`github-tool`), scopes, and the agent's SPIFFE ID for inbound -audience validation. +`kagenti` realm settings and 300s Envoy timeouts. + +The client-registration sidecar needs Keycloak admin credentials to register +agents as OAuth clients. These are stored in a Kubernetes Secret (not a +ConfigMap) to follow security best practices: + +```bash +kubectl create secret generic keycloak-admin-secret -n team1 \ + --from-literal=KEYCLOAK_ADMIN_USERNAME=admin \ + --from-literal=KEYCLOAK_ADMIN_PASSWORD=admin \ + --dry-run=client -o yaml | kubectl apply -f - +``` + +Then apply the demo-specific `authbridge-config` override — the token exchange +target audience (`github-tool`), scopes, and the agent's SPIFFE ID for inbound +audience validation: ```bash cd AuthBridge @@ -682,17 +694,20 @@ kubectl rollout status deployment/git-issue-agent -n team1 --timeout=180s **Symptom:** `{"error":"invalid_client","error_description":"Invalid client or Invalid client credentials"}` -**Cause:** The agent pod's `environments` ConfigMap was missing or incorrect at startup, -so the client-registration sidecar registered the client with wrong settings. +**Cause:** The `keycloak-admin-secret` Secret or `environments` ConfigMap was missing +or incorrect at startup, so the client-registration sidecar couldn't register the client. **Fix:** ```bash -# 1. Verify the installer's environments ConfigMap has the correct realm +# 1. Verify the keycloak-admin-secret exists +kubectl get secret keycloak-admin-secret -n team1 + +# 2. Verify the installer's environments ConfigMap has the correct realm kubectl get configmap environments -n team1 -o jsonpath='{.data.KEYCLOAK_REALM}' # Should show: kagenti -# 2. Re-apply the demo ConfigMap and restart +# 3. Re-apply the demo ConfigMap and restart kubectl apply -f demos/github-issue/k8s/configmaps.yaml kubectl rollout restart deployment/git-issue-agent -n team1 ``` From 128ae718efd5d6a54140a4795b79364c7cefa3a6 Mon Sep 17 00:00:00 2001 From: Mariusz Sabath Date: Mon, 9 Mar 2026 11:07:07 -0400 Subject: [PATCH 3/3] fix: address PR #179 review feedback - Move PLATFORM_CLIENT_IDS comment block from Secret stringData back to the environments ConfigMap data section where it belongs - Add 'found' checks to AdminCredentialsFromSecret test so it fails if KEYCLOAK_ADMIN_USERNAME/PASSWORD env vars are absent entirely - Add 'found' checks to NonSensitiveKeysFromConfigMap test so it fails if KEYCLOAK_URL/KEYCLOAK_REALM env vars are absent entirely Assisted-By: Claude (Anthropic AI) Signed-off-by: Mariusz Sabath --- AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml | 10 +++++----- .../webhook/injector/container_builder_test.go | 10 ++++++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml b/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml index 3591cd429..d72f3c566 100644 --- a/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml +++ b/AuthBridge/demos/webhook/k8s/configmaps-webhook.yaml @@ -17,6 +17,11 @@ data: SPIRE_ENABLED: "true" KEYCLOAK_URL: "http://keycloak-service.keycloak.svc:8080" KEYCLOAK_REALM: "demo" + # Comma-separated list of Keycloak client IDs that should receive the agent's + # audience scope. This allows existing clients (like the UI) to include the + # agent's audience in their tokens without manual Keycloak configuration. + # Default: "kagenti" (the platform UI client) + # PLATFORM_CLIENT_IDS: "kagenti" --- # keycloak-admin-secret - Keycloak admin credentials for client registration @@ -30,11 +35,6 @@ type: Opaque stringData: KEYCLOAK_ADMIN_USERNAME: "admin" KEYCLOAK_ADMIN_PASSWORD: "admin" - # Comma-separated list of Keycloak client IDs that should receive the agent's - # audience scope. This allows existing clients (like the UI) to include the - # agent's audience in their tokens without manual Keycloak configuration. - # Default: "kagenti" (the platform UI client) - # PLATFORM_CLIENT_IDS: "kagenti" --- # authbridge-config ConfigMap - Used by envoy-proxy for token exchange and inbound validation diff --git a/kagenti-webhook/internal/webhook/injector/container_builder_test.go b/kagenti-webhook/internal/webhook/injector/container_builder_test.go index 97244cb95..72efa94fc 100644 --- a/kagenti-webhook/internal/webhook/injector/container_builder_test.go +++ b/kagenti-webhook/internal/webhook/injector/container_builder_test.go @@ -141,10 +141,12 @@ func TestBuildClientRegistrationContainer_AdminCredentialsFromSecret(t *testing. sensitiveKeys := []string{"KEYCLOAK_ADMIN_USERNAME", "KEYCLOAK_ADMIN_PASSWORD"} for _, key := range sensitiveKeys { + found := false for _, env := range container.Env { if env.Name != key { continue } + found = true if env.ValueFrom == nil || env.ValueFrom.SecretKeyRef == nil { t.Errorf("env %q must use SecretKeyRef, got ConfigMapKeyRef or literal", key) continue @@ -153,6 +155,9 @@ func TestBuildClientRegistrationContainer_AdminCredentialsFromSecret(t *testing. t.Errorf("env %q SecretKeyRef.Name = %q, want %q", key, env.ValueFrom.SecretKeyRef.Name, "keycloak-admin-secret") } } + if !found { + t.Errorf("client-registration container missing env var %q", key) + } } } @@ -162,10 +167,12 @@ func TestBuildClientRegistrationContainer_NonSensitiveKeysFromConfigMap(t *testi nonSensitiveKeys := []string{"KEYCLOAK_URL", "KEYCLOAK_REALM"} for _, key := range nonSensitiveKeys { + found := false for _, env := range container.Env { if env.Name != key { continue } + found = true if env.ValueFrom == nil || env.ValueFrom.ConfigMapKeyRef == nil { t.Errorf("env %q must use ConfigMapKeyRef", key) continue @@ -174,5 +181,8 @@ func TestBuildClientRegistrationContainer_NonSensitiveKeysFromConfigMap(t *testi t.Errorf("env %q ConfigMapKeyRef.Name = %q, want %q", key, env.ValueFrom.ConfigMapKeyRef.Name, "environments") } } + if !found { + t.Errorf("client-registration container missing env var %q", key) + } } }