K8s imagePullSecrets: Private Registry Auth
Configure imagePullSecrets for pulling container images from private registries. Create docker-registry secrets, attach to pods and ServiceAccounts.
π‘ Quick Answer: Create a docker-registry secret with
kubectl create secret docker-registry myregistry --docker-server=registry.example.com --docker-username=user --docker-password=pass, then reference it in your pod spec withimagePullSecrets: [{name: myregistry}]. For cluster-wide access, attach the secret to thedefaultServiceAccount in each namespace.
The Problem
Pulling images from private registries (Docker Hub paid, ECR, GCR, Quay, Harbor, Artifactory) requires authentication. Without imagePullSecrets, Kubernetes returns ImagePullBackOff or ErrImagePull. You need to create registry credentials as a Secret and tell pods or ServiceAccounts to use them.
flowchart LR
POD["Pod<br/>(imagePullSecrets)"] -->|"Auth credentials"| KUBELET["Kubelet"]
KUBELET -->|"docker login"| REG["Private Registry<br/>(registry.example.com)"]
REG -->|"Pull image"| KUBELET
KUBELET -->|"Start container"| PODThe Solution
Create Registry Secret
# Method 1: kubectl create (most common)
kubectl create secret docker-registry myregistry \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=user@example.com \
--namespace=my-app
# Method 2: From existing Docker config
kubectl create secret generic myregistry \
--from-file=.dockerconfigjson=$HOME/.docker/config.json \
--type=kubernetes.io/dockerconfigjson \
--namespace=my-app
# Method 3: YAML manifest
cat << 'EOF' | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
name: myregistry
namespace: my-app
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: eyJhdXRocyI6... # base64-encoded docker config
EOF
# Verify
kubectl get secret myregistry -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | jq .Use in Pod Spec
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: registry.example.com/my-app:v1.0
imagePullSecrets:
- name: myregistry
---
# Deployment with imagePullSecrets
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: registry.example.com/my-app:v1.0
imagePullSecrets:
- name: myregistryAttach to ServiceAccount (Cluster-Wide)
# Attach to default ServiceAccount β all pods in namespace get it
kubectl patch serviceaccount default \
-n my-app \
-p '{"imagePullSecrets": [{"name": "myregistry"}]}'
# Verify
kubectl get serviceaccount default -n my-app -o yaml
# Automate for all namespaces
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
kubectl create secret docker-registry myregistry \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
-n "$ns" --dry-run=client -o yaml | kubectl apply -f -
kubectl patch serviceaccount default -n "$ns" \
-p '{"imagePullSecrets": [{"name": "myregistry"}]}'
doneMultiple Registries
# Pod pulling from multiple private registries
apiVersion: v1
kind: Pod
metadata:
name: multi-registry
spec:
containers:
- name: app
image: registry.example.com/app:v1
- name: sidecar
image: quay.io/myorg/sidecar:v2
imagePullSecrets:
- name: example-registry # registry.example.com
- name: quay-registry # quay.ioCloud Provider Registries
# AWS ECR
TOKEN=$(aws ecr get-login-password --region us-east-1)
kubectl create secret docker-registry ecr-secret \
--docker-server=123456789.dkr.ecr.us-east-1.amazonaws.com \
--docker-username=AWS \
--docker-password="$TOKEN"
# β οΈ ECR tokens expire in 12h β use ECR credential helper or CronJob to refresh
# GCR / Artifact Registry
kubectl create secret docker-registry gcr-secret \
--docker-server=us-docker.pkg.dev \
--docker-username=_json_key \
--docker-password="$(cat service-account-key.json)"
# Azure ACR
kubectl create secret docker-registry acr-secret \
--docker-server=myregistry.azurecr.io \
--docker-username=myregistry \
--docker-password="$(az acr credential show -n myregistry --query passwords[0].value -o tsv)"Using βdocker-password-stdin
# Pipe password from file or command (avoids password in shell history)
kubectl create secret docker-registry myregistry \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password="$(cat /path/to/password-file)"
# Or from environment variable
kubectl create secret docker-registry myregistry \
--docker-server=registry.example.com \
--docker-username=myuser \
--docker-password="$REGISTRY_PASSWORD"Common Issues
| Issue | Cause | Fix |
|---|---|---|
ImagePullBackOff | Missing or wrong imagePullSecrets | Verify secret exists in same namespace as pod |
unauthorized: authentication required | Wrong credentials | Recreate secret with correct password |
Secret not found | Secret in different namespace | Create secret in podβs namespace |
| ECR auth expired | Token valid only 12h | Use CronJob to refresh or credential helper |
no basic auth credentials | docker-server URL mismatch | Ensure server URL matches image prefix exactly |
| Works in default SA, not in custom | Custom SA missing secret | Patch the specific ServiceAccount |
Best Practices
- Attach to ServiceAccount β avoid repeating
imagePullSecretsin every pod spec - Use External Secrets Operator β sync registry creds from Vault/AWS Secrets Manager
- Rotate credentials regularly β update secrets without redeploying pods
- Never hardcode passwords in YAML β use
kubectl createor sealed secrets - One secret per registry β easier to rotate and audit
- ECR: automate token refresh β CronJob every 10h to recreate the secret
Key Takeaways
imagePullSecretsprovides registry authentication for private container images- Create with
kubectl create secret docker-registryβ fastest method - Attach to ServiceAccount for namespace-wide access without per-pod config
- Cloud registries (ECR, GCR, ACR) have provider-specific credential patterns
- Always create the secret in the same namespace as the pods that need it
ImagePullBackOffis almost always a missing or misconfigured imagePullSecrets

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
