πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Configuration intermediate ⏱ 15 minutes K8s 1.28+

K8s imagePullSecrets: Private Registry Auth

Configure imagePullSecrets for pulling container images from private registries. Create docker-registry secrets, attach to pods and ServiceAccounts.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ 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 with imagePullSecrets: [{name: myregistry}]. For cluster-wide access, attach the secret to the default ServiceAccount 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"| POD

The 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: myregistry

Attach 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"}]}'
done

Multiple 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.io

Cloud 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

IssueCauseFix
ImagePullBackOffMissing or wrong imagePullSecretsVerify secret exists in same namespace as pod
unauthorized: authentication requiredWrong credentialsRecreate secret with correct password
Secret not foundSecret in different namespaceCreate secret in pod’s namespace
ECR auth expiredToken valid only 12hUse CronJob to refresh or credential helper
no basic auth credentialsdocker-server URL mismatchEnsure server URL matches image prefix exactly
Works in default SA, not in customCustom SA missing secretPatch the specific ServiceAccount

Best Practices

  • Attach to ServiceAccount β€” avoid repeating imagePullSecrets in 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 create or sealed secrets
  • One secret per registry β€” easier to rotate and audit
  • ECR: automate token refresh β€” CronJob every 10h to recreate the secret

Key Takeaways

  • imagePullSecrets provides 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
  • ImagePullBackOff is almost always a missing or misconfigured imagePullSecrets
#imagepullsecrets #private-registry #docker-registry #authentication #container-images
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens