Skip to content

fix(k8s): let scope-configurations override the image pull secrets - #256

Open
agustincelentano wants to merge 2 commits into
mainfrom
fix/image-pull-secrets-provider-precedence
Open

fix(k8s): let scope-configurations override the image pull secrets#256
agustincelentano wants to merge 2 commits into
mainfrom
fix/image-pull-secrets-provider-precedence

Conversation

@agustincelentano

@agustincelentano agustincelentano commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

El problema

Todo deployment que crea el scope k8s sale con este bloque, exista o no el secret en el cluster:

spec:
  imagePullSecrets:
    - name: ecr-secret

En una instalación EKS donde ese secret no existe (la imagen se baja con el rol del nodo), el kubelet emite el aviso en cada pod, para siempre:

Warning  FailedToRetrieveImagePullSecret  pod/d-367602183-1963913225-766559468d-bd9q4
Unable to retrieve some image pull secrets (ecr-secret); attempting to pull the image may not succeed.

Los pods andan, así que no rompe nada: ensucia los eventos de todos los namespaces y manda a investigar un problema que no existe. Lo peor es que no hay forma de desactivarlo: la instalación tiene security.image_pull_secrets: [] en su provider scope-configurations y no pasa nada.

Por qué el provider no se lee

k8s/values.yaml trae el default:

IMAGE_PULL_SECRETS:
  ENABLED: true
  SECRETS:
    - ecr-secret

Los workflows lo cargan con include: "$SERVICE_PATH/values.yaml", así que llega a build_context como variable de entorno. Y ahí la resolución estaba escrita al revés:

if [[ -n "$PULL_SECRETS" ]]; then
  IMAGE_PULL_SECRETS=$PULL_SECRETS
else
  if [ -n "${IMAGE_PULL_SECRETS:-}" ]; then   # ← el include siempre la deja seteada
    IMAGE_PULL_SECRETS=$(echo "$IMAGE_PULL_SECRETS" | jq .)
  else
    ... get_config_value --provider '...security.image_pull_secrets_enabled' ...  # inalcanzable
  fi
fi

La rama del env siempre matchea, así que la del provider es código muerto. Es la única variable del script resuelta así: el resto usa get_config_value --provider ... --env ... --default ..., con prioridad providers → env → default.

Qué cambia

Se consulta el provider primero y el valor incluido pasa a ser el default:

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 // []')")

Y una lista vacía apaga el bloque:

'{ENABLED: ($enabled and ($secrets | length > 0)), SECRETS: $secrets}'

Sin eso, image_pull_secrets: [] con enabled heredado en true rendericaría un imagePullSecrets: sin entradas. Un secret que no se nombra no se puede usar.

PULL_SECRETS sigue ganando sobre todo, sin cambios.

Y el default deja de nombrar un secret que el scope no crea

Con lo de arriba solo, una instalación que no configura el provider sigue igual: el default de values.yaml manda y el warning sigue. Así que el default también cambia:

IMAGE_PULL_SECRETS:
  ENABLED: false
  SECRETS: []

No es una decisión nueva del repo: azure/values.yaml y azure-aro/values.yaml ya vienen con ENABLED: false. El overlay k8s era el único que quedaba nombrando ecr-secret, un secret de ECR que el scope no crea y que en GKE, en AKS o en un EKS que usa el rol del nodo no significa nada.

Esto es breaking para un caso concreto: un cluster que tiene ecr-secret creado y depende de que el scope lo inyecte sin haberlo configurado en ningún lado. Esa instalación tiene que declararlo ahora en el provider:

security:
  image_pull_secrets: ["ecr-secret"]
  image_pull_secrets_enabled: true

Que es justamente lo que antes no funcionaba.

Compatibilidad

  • Instalación sin provider de scope-configurations: el default ahora es "sin secrets", así que deja de pedir ecr-secret. Es el cambio breaking de arriba.
  • Instalación con el provider configurado: ahora se respeta. Antes se ignoraba, así que el único cambio de comportamiento es que la configuración empieza a funcionar.
  • Instalación con image_pull_secrets: []: deja de emitir el bloque, que es exactamente lo que pedía.

Tests

Siete casos en build_context.bats: el nuevo default deja el bloque apagado; un valor incluido con secrets sigue aplicando sin provider; el provider los enciende sobre un default apagado; el provider reemplaza la lista incluida; una lista vacía en el provider apaga el bloque; sin nada configurado queda apagado. La suite queda en 80/82 — los dos rojos (replica calculation) ya fallan en main y no los toca este cambio.

🤖 Generated with Claude Code

agustincelentano and others added 2 commits September 11, 2026 12:05
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) <noreply@anthropic.com>
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) <noreply@anthropic.com>
@agustincelentano

Copy link
Copy Markdown
Collaborator Author

Sumé el segundo commit: el default de k8s/values.yaml pasa a ENABLED: false / SECRETS: [].

Con solo el cambio de precedencia, una instalación que no configura el provider seguía igual: el default mandaba y el warning seguía. Y el default nombraba ecr-secret, un secret que el scope no crea. azure/values.yaml y azure-aro/values.yaml ya vienen con ENABLED: false; k8s era el único que quedaba.

Es breaking para un cluster que tenga ese secret y dependa del default para inyectarlo: ahora lo declara en security.image_pull_secrets, que es justamente lo que el primer commit hace funcionar. Tests 7 casos, suite 82 (los 2 rojos de replica calculation ya fallan en main).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant