Kubernetes imagePullSecrets Not Working - Fix Private Pulls
You created an imagePullSecret, yet pods still fail to pull. The secret is in the wrong namespace, malformed, or never actually referenced - so the kubelet still pulls anonymously.
What this error means
Pulls keep failing with auth errors even though a pull secret exists. The pod spec or ServiceAccount is not using it, or the Secret is not where the pod runs.
# secret exists in 'default', pod runs in 'prod'
$ kubectl -n prod describe pod api-... | grep -i secret
# (no imagePullSecrets listed → still pulling anonymously → 401)Common causes
Secret in the wrong namespace
imagePullSecrets are namespace-scoped. A secret in default is invisible to a pod in prod; each namespace needs its own copy.
Not referenced by pod or ServiceAccount
Creating the secret does nothing on its own - the pod spec or the pod’s ServiceAccount must list it under imagePullSecrets.
Malformed .dockerconfigjson
A secret of the wrong type, or with a bad/HTML-escaped .dockerconfigjson, is silently ignored by the kubelet.
How to fix it
Create the secret in the pod’s namespace and attach it
kubectl -n prod create secret docker-registry regcred \
--docker-server=registry.example.com \
--docker-username="$REG_USER" --docker-password="$REG_TOKEN"
kubectl -n prod patch serviceaccount default \
-p '{"imagePullSecrets":[{"name":"regcred"}]}'Verify the secret is well-formed and referenced
- Confirm
type: kubernetes.io/dockerconfigjsonwithkubectl get secret regcred -o yaml. - Decode
.dockerconfigjsonand check the auth entry matches the registry host. - Confirm the pod lists the secret:
kubectl get pod <pod> -o jsonpath='{.spec.imagePullSecrets}'.
How to prevent it
- Provision the pull secret into every namespace that runs private images.
- Attach it via the ServiceAccount so new pods inherit it automatically.
- Generate the secret with
kubectl create secret docker-registryrather than hand-editing JSON.