From d9de62dccdb0954f3d17c8ab52adacf2d0947d82 Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:05:39 -0300 Subject: [PATCH 1/2] fix(k8s): let scope-configurations override the image pull secrets The values.yaml default (ENABLED: true, SECRETS: [ecr-secret]) reaches build_context as the IMAGE_PULL_SECRETS env var, because the workflow includes that file. The env branch ran before the provider branch, so security.image_pull_secrets in scope-configurations was never read and every deployment carried ecr-secret whether the cluster had it or not. Read the provider first and fall back to the included value, the same priority every other setting uses. An empty secret list now disables the block, so naming no secrets stops rendering an imagePullSecrets entry the kubelet cannot resolve. Co-Authored-By: Claude Opus 5 (1M context) --- k8s/deployment/build_context | 39 +++++++++------- k8s/deployment/tests/build_context.bats | 59 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 17 deletions(-) diff --git a/k8s/deployment/build_context b/k8s/deployment/build_context index c0340487..ba548659 100755 --- a/k8s/deployment/build_context +++ b/k8s/deployment/build_context @@ -118,23 +118,28 @@ fi if [[ -n "$PULL_SECRETS" ]]; then IMAGE_PULL_SECRETS=$PULL_SECRETS else - if [ -n "${IMAGE_PULL_SECRETS:-}" ]; then - IMAGE_PULL_SECRETS=$(echo "$IMAGE_PULL_SECRETS" | jq .) - else - PULL_SECRETS_ENABLED=$(get_config_value \ - --provider '.providers["scope-configurations"].security.image_pull_secrets_enabled' \ - --default "false" - ) - PULL_SECRETS_LIST=$(get_config_value \ - --provider '.providers["scope-configurations"].security.image_pull_secrets | @json' \ - --default "[]" - ) - - IMAGE_PULL_SECRETS=$(jq -n \ - --argjson enabled "$PULL_SECRETS_ENABLED" \ - --argjson secrets "$PULL_SECRETS_LIST" \ - '{ENABLED: $enabled, SECRETS: $secrets}') - fi + # Providers win over IMAGE_PULL_SECRETS, which is how values.yaml reaches + # this script (the workflow includes it), so an installation can turn the + # secrets off or replace them from scope-configurations like every other + # setting. Without a provider the included value still applies. + ENV_PULL_SECRETS=${IMAGE_PULL_SECRETS:-'{}'} + + PULL_SECRETS_ENABLED=$(get_config_value \ + --provider '.providers["scope-configurations"].security.image_pull_secrets_enabled' \ + --default "$(echo "$ENV_PULL_SECRETS" | jq -r '.ENABLED // false')" + ) + PULL_SECRETS_LIST=$(get_config_value \ + --provider '.providers["scope-configurations"].security.image_pull_secrets | @json' \ + --default "$(echo "$ENV_PULL_SECRETS" | jq -c '.SECRETS // []')" + ) + + # An empty list means nothing to pull with: rendering `imagePullSecrets` with + # no entries, or naming a secret the cluster does not have, only makes the + # kubelet warn on every pod. + IMAGE_PULL_SECRETS=$(jq -n \ + --argjson enabled "$PULL_SECRETS_ENABLED" \ + --argjson secrets "$PULL_SECRETS_LIST" \ + '{ENABLED: ($enabled and ($secrets | length > 0)), SECRETS: $secrets}') fi SCOPE_TRAFFIC_PROTOCOL=$(echo "$CONTEXT" | jq -r .scope.capabilities.protocol) diff --git a/k8s/deployment/tests/build_context.bats b/k8s/deployment/tests/build_context.bats index 72f95cc6..38a7efff 100644 --- a/k8s/deployment/tests/build_context.bats +++ b/k8s/deployment/tests/build_context.bats @@ -273,6 +273,65 @@ resolve_traffic_container_version() { assert_equal "$IMAGE_PULL_SECRETS" '["secret1"]' } +# The resolution below mirrors build_context: the provider wins, then the +# IMAGE_PULL_SECRETS env (which is how values.yaml reaches the script), and an +# empty secret list always disables the block. +resolve_pull_secrets() { + local env_value=${IMAGE_PULL_SECRETS:-'{}'} + local enabled secrets + enabled=$(get_config_value \ + --provider '.providers["scope-configurations"].security.image_pull_secrets_enabled' \ + --default "$(echo "$env_value" | jq -r '.ENABLED // false')" + ) + secrets=$(get_config_value \ + --provider '.providers["scope-configurations"].security.image_pull_secrets | @json' \ + --default "$(echo "$env_value" | jq -c '.SECRETS // []')" + ) + jq -n --argjson enabled "$enabled" --argjson secrets "$secrets" \ + '{ENABLED: ($enabled and ($secrets | length > 0)), SECRETS: $secrets}' +} + +@test "image pull secrets: the values.yaml default applies when no provider sets it" { + export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}' + + result=$(resolve_pull_secrets) + + assert_equal "$(echo "$result" | jq -r '.ENABLED')" "true" + assert_contains "$result" "ecr-secret" +} + +@test "image pull secrets: the provider overrides the values.yaml default" { + export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}' + export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = { + "security": { "image_pull_secrets": ["registry-creds"] } + }') + + result=$(resolve_pull_secrets) + + assert_contains "$result" "registry-creds" + assert_equal "$(echo "$result" | jq -r '.SECRETS | index("ecr-secret") // "absent"')" "absent" +} + +@test "image pull secrets: an empty provider list turns the block off" { + export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}' + export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = { + "security": { "image_pull_secrets": [] } + }') + + result=$(resolve_pull_secrets) + + assert_equal "$(echo "$result" | jq -r '.ENABLED')" "false" + assert_equal "$(echo "$result" | jq -c '.SECRETS')" "[]" +} + +@test "image pull secrets: nothing configured anywhere leaves it off" { + unset IMAGE_PULL_SECRETS + + result=$(resolve_pull_secrets) + + assert_equal "$(echo "$result" | jq -r '.ENABLED')" "false" +} + # ============================================================================= # get_config_value Tests - DEPLOY_STRATEGY # ============================================================================= From ed2aff35e30c087c74765592edba3cd7e5551fa5 Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Fri, 11 Sep 2026 12:16:41 -0300 Subject: [PATCH 2/2] fix(k8s)!: stop defaulting image pull secrets to ecr-secret The k8s values shipped ENABLED: true with ecr-secret, a secret the scope names but never creates, so any cluster without it got a kubelet warning on every pod for a secret it was never going to have. azure and azure-aro already ship ENABLED: false; this aligns k8s with them. BREAKING CHANGE: a cluster that has ecr-secret and relied on the default to inject it must now declare it in the scope-configurations provider under security.image_pull_secrets. Co-Authored-By: Claude Opus 5 (1M context) --- k8s/deployment/tests/build_context.bats | 23 ++++++++++++++++++++++- k8s/values.yaml | 9 ++++++--- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/k8s/deployment/tests/build_context.bats b/k8s/deployment/tests/build_context.bats index 38a7efff..cd97e0d0 100644 --- a/k8s/deployment/tests/build_context.bats +++ b/k8s/deployment/tests/build_context.bats @@ -291,7 +291,16 @@ resolve_pull_secrets() { '{ENABLED: ($enabled and ($secrets | length > 0)), SECRETS: $secrets}' } -@test "image pull secrets: the values.yaml default applies when no provider sets it" { +@test "image pull secrets: the values.yaml default leaves the block off" { + # What k8s/values.yaml now ships. + export IMAGE_PULL_SECRETS='{"ENABLED":false,"SECRETS":[]}' + + result=$(resolve_pull_secrets) + + assert_equal "$(echo "$result" | jq -r '.ENABLED')" "false" +} + +@test "image pull secrets: an included value with secrets still applies when no provider sets it" { export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}' result=$(resolve_pull_secrets) @@ -300,6 +309,18 @@ resolve_pull_secrets() { assert_contains "$result" "ecr-secret" } +@test "image pull secrets: the provider turns them on over an off default" { + export IMAGE_PULL_SECRETS='{"ENABLED":false,"SECRETS":[]}' + export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = { + "security": { "image_pull_secrets_enabled": true, "image_pull_secrets": ["registry-creds"] } + }') + + result=$(resolve_pull_secrets) + + assert_equal "$(echo "$result" | jq -r '.ENABLED')" "true" + assert_contains "$result" "registry-creds" +} + @test "image pull secrets: the provider overrides the values.yaml default" { export IMAGE_PULL_SECRETS='{"ENABLED":true,"SECRETS":["ecr-secret"]}' export CONTEXT=$(echo "$CONTEXT" | jq '.providers["scope-configurations"] = { diff --git a/k8s/values.yaml b/k8s/values.yaml index 4f43e079..6fe7faf4 100644 --- a/k8s/values.yaml +++ b/k8s/values.yaml @@ -49,10 +49,13 @@ configuration: # port for pod-to-pod traffic BEFORE setting this — with VPC CNI custom # networking that is the security group in the ENIConfig CRD, not the node's. # MAIN_TRAFFIC_MANAGER_PORT: 10080 + # Off by default, like azure and azure-aro: the scope names pull secrets but + # never creates them, so a default pointing at one leaves every pod asking + # the kubelet for a secret the cluster does not have. Clusters that need one + # set security.image_pull_secrets in the scope-configurations provider. IMAGE_PULL_SECRETS: - ENABLED: true - SECRETS: - - ecr-secret + ENABLED: false + SECRETS: [] # VAULT_ADDR: "http://localhost:8200" # VAULT_TOKEN: "myroot" IAM: