Kubernetes ImagePullBackOff: Resolving Private Registry Authentication on CentOS Stream / Rocky Linux
Troubleshoot Kubernetes ImagePullBackOff due to private registry authentication failures on CentOS Stream and Rocky Linux. Fix secret issues quickly.
Troubleshoot Kubernetes ImagePullBackOff due to private registry authentication failures on CentOS Stream and Rocky Linux. Fix secret issues quickly.
Introduction
The ImagePullBackOff error in Kubernetes is a common symptom indicating that a Pod cannot start because it's unable to pull its specified container image from a registry. While this error can stem from various causes like incorrect image names, network issues, or registry downtime, one of the most frequent and frustrating culprits, especially in production environments, is private registry authentication failure.
This guide specifically addresses ImagePullBackOff errors occurring when your Kubernetes cluster, running on CentOS Stream or Rocky Linux nodes, fails to authenticate with a private container image registry (e.g., Docker Hub Private Repos, AWS ECR, Azure Container Registry, Google Container Registry, Harbor, etc.). You'll learn how to diagnose the underlying authentication problem and implement robust solutions.
Symptom & Error Signature
When a Pod experiences ImagePullBackOff due to authentication issues, you'll typically observe the following:
Pod status: Your Pod will repeatedly show
ImagePullBackOfforErrImagePullin its status, often cycling throughPendingorCrashLoopBackOffif previous attempts failed.kubectl get pods -n my-app-namespaceNAME READY STATUS RESTARTS AGE my-app-deployment-78f9xxxx 0/1 ImagePullBackOff 0 2m another-pod-xxxxxxxx 1/1 Running 0 10mPod Events: Detailed events for the problematic Pod will clearly indicate authentication failures. This is the most crucial diagnostic output.
kubectl describe pod my-app-deployment-78f9xxxx -n my-app-namespace... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m default-scheduler Successfully assigned my-app-deployment-78f9xxxx to worker-node-01.example.com Normal Pulled 1m (x2 over 2m) kubelet Container image "my-private-registry/my-image:latest" already present on machine Warning Failed 1m (x2 over 2m) kubelet Failed to pull image "my-private-registry/my-image:latest": rpc error: code = Unknown desc = Error response from daemon: Get "https://my-private-registry/v2/": unauthorized: authentication required Warning Failed 1m (x2 over 2m) kubelet Error: ErrImagePull Normal BackOff 40s (x3 over 2m) kubelet Back-off pulling image "my-private-registry/my-image:latest" Warning Failed 40s (x3 over 2m) kubelet Error: ImagePullBackOffLook specifically for messages like "unauthorized: authentication required" or "401 Unauthorized".
Root Cause Analysis
The ImagePullBackOff error, when specifically related to "unauthorized: authentication required," indicates that the Kubernetes node's container runtime (e.g., containerd or cri-o) cannot successfully log in to the specified private image registry using the provided credentials. This can be attributed to several underlying issues:
Missing or Incorrect
imagePullSecrets:- The
PodorDeploymentmanifest may not specifyimagePullSecrets. - The
imagePullSecretsspecified may refer to aSecretthat does not exist in the same namespace. - The
imagePullSecretsvalue might be misspelled or reference an incorrectSecretname.
- The
Invalid or Malformed Kubernetes
Secret:- The Kubernetes
Secretof typekubernetes.io/dockerconfigjsoncontains incorrect, expired, or malformed registry credentials. - The
dockerconfigjsoncontent within theSecretis not a valid base64 encoded JSON string, or its structure is incorrect. - The
authtoken orpasswordin theSecrethas expired, been revoked, or is simply wrong.
- The Kubernetes
Incorrect Namespace for the
Secret:- Kubernetes
Secretsare namespace-scoped. If theSecretproviding the registry credentials is not in the same namespace as the Pod attempting to pull the image, authentication will fail.
- Kubernetes
Network Connectivity or DNS Issues to the Registry:
- While less common for authentication-specific errors (which imply a successful initial connection), network path issues or incorrect DNS resolution for the registry hostname can prevent the authentication handshake from completing. This can sometimes manifest ambiguously.
Container Runtime Configuration Issues (Less Common for Authentication):
- For
containerdorcri-oon CentOS Stream/Rocky Linux, if there's a misconfiguration inconfig.tomlorregistries.conf.dthat overrides or interferes with howimagePullSecretsare handled, it could cause issues. This is rare whenimagePullSecretsare correctly defined.
- For
Step-by-Step Resolution
Follow these steps to systematically diagnose and resolve the ImagePullBackOff authentication error.
1. Verify Pod Status and Events
Start by confirming the exact error messages as described in the "Symptom & Error Signature" section.
kubectl get pods -n my-app-namespace
kubectl describe pod my-app-deployment-78f9xxxx -n my-app-namespace
Carefully review the Events section for "unauthorized: authentication required" or similar messages indicating a credential problem.
2. Inspect the imagePullSecrets Configuration in Your Deployment
Ensure your Pod, Deployment, or StatefulSet manifest correctly references the imagePullSecrets.
kubectl get deployment my-app-deployment -n my-app-namespace -o yaml
Look for the imagePullSecrets field under spec.template.spec:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
namespace: my-app-namespace
spec:
# ... other deployment spec ...
template:
spec:
containers:
- name: my-app
image: my-private-registry/my-image:latest
# ... container config ...
imagePullSecrets:
- name: my-registry-secret # <--- This is the secret name to verify
Make a note of the imagePullSecrets name (e.g., my-registry-secret) and the namespace (e.g., my-app-namespace).
3. Validate the Kubernetes Secret
This is the most critical step. You need to ensure the referenced Secret exists, is in the correct namespace, and contains valid credentials.
a. Check if the Secret Exists
kubectl get secret my-registry-secret -n my-app-namespace
If the output says Error from server (NotFound): secrets "my-registry-secret" not found, then the secret is missing, or you're looking in the wrong namespace. Proceed to create or recreate it.
b. Inspect the Secret Content
Kubernetes Secrets store credentials as base64 encoded strings. When decoding, be extremely cautious not to expose sensitive information in public logs or outputs. Use this step for diagnostic purposes only.
Inspect the Secret's content to verify the dockerconfigjson.
kubectl get secret my-registry-secret -n my-app-namespace -o yaml
You'll see a data field with config.json or .dockerconfigjson (depending on how it was created) which is base64 encoded. Decode it:
kubectl get secret my-registry-secret -n my-app-namespace -o jsonpath='{.data..dockerconfigjson}' | base64 --decode
The output should look similar to this (formatted for readability; it will be a single line in actual output):
{
"auths": {
"my-private-registry": {
"username": "your-username",
"password": "your-password-or-token",
"email": "[email protected]",
"auth": "base64-encoded-username:password"
}
}
}
Verify the following:
- The registry URL (
my-private-registry) precisely matches the one used in your image name (my-private-registry/my-image:latest). Trailing slashes or port differences matter.- The
usernameandpassword(orauthtoken) are correct and have not expired.- The entire JSON structure is valid.
c. Recreate the Secret if Necessary
If the secret is missing, incorrect, or you suspect the credentials are bad, recreate it.
First, delete the old secret (if it exists):
kubectl delete secret my-registry-secret -n my-app-namespace
Then, create a new one using your actual registry credentials.
kubectl create secret docker-registry my-registry-secret
--docker-server=my-private-registry
--docker-username=YOUR_REGISTRY_USERNAME
--docker-password='YOUR_REGISTRY_PASSWORD_OR_TOKEN'
[email protected]
-n my-app-namespace
Replace my-private-registry, YOUR_REGISTRY_USERNAME, YOUR_REGISTRY_PASSWORD_OR_TOKEN, [email protected], and my-app-namespace with your actual values.
When using
docker-password, enclose it in single quotes if it contains special characters. Some registries use long access tokens for passwords.
Alternatively, using an existing ~/.docker/config.json:
If you have successfully logged in via podman login or docker login on a workstation, you can generate the secret directly from your ~/.docker/config.json file.
# On your workstation where podman/docker login works:
# First, ensure you have a valid ~/.docker/config.json with the registry credentials
podman login my-private-registry
# Then, create the secret in Kubernetes
kubectl create secret generic my-registry-secret
--from-file=.dockerconfigjson=$HOME/.docker/config.json
-n my-app-namespace
4. Ensure Correct Namespace
As mentioned, Secrets are namespace-scoped. Always double-check that the Secret lives in the exact same namespace as the Pod trying to pull the image. If not, delete and recreate it in the correct namespace.
5. Test Registry Credentials Independently on a Node (CentOS Stream / Rocky Linux Specific)
To definitively rule out credential issues versus Kubernetes configuration, try to log in and pull the image directly from one of your Kubernetes worker nodes. This step is crucial for isolating the problem.
a. SSH into a Kubernetes Worker Node
ssh [email protected]
b. Log in to the Private Registry using podman or docker
On CentOS Stream / Rocky Linux, podman is the default container runtime tool. docker-ce can also be installed. Use the one your cluster is configured to interact with, or just podman for testing.
# If using podman (recommended on RHEL-based systems)
podman login my-private-registry
# Enter YOUR_REGISTRY_USERNAME and YOUR_REGISTRY_PASSWORD_OR_TOKEN when prompted.
# If using docker-ce (if installed)
docker login my-private-registry
# Enter YOUR_REGISTRY_USERNAME and YOUR_REGISTRY_PASSWORD_OR_TOKEN when prompted.
If podman login (or docker login) fails with "unauthorized" or similar errors, your credentials are definitively incorrect or expired. You must fix them with your registry provider.
c. Attempt to Pull the Image
If podman login was successful, try to pull the image:
podman pull my-private-registry/my-image:latest
If this succeeds, then the credentials themselves are fine, and the problem likely lies within the Kubernetes Secret or its association with the Pod. If it fails, your credentials are still the primary issue.
6. Check Node Container Runtime Configuration (Advanced/Less Common)
On CentOS Stream / Rocky Linux, Kubernetes typically uses containerd as its Container Runtime Interface (CRI). While imagePullSecrets should handle authentication, a misconfigured containerd could sometimes interfere.
a. Access Containerd Configuration
grep -r "registry" /etc/containerd/config.toml
Look for any [plugins."io.containerd.grpc.v1.cri".registry.configs."my-private-registry".auth] sections. These are generally used for hardcoding credentials or specific registry behaviors, which should not interfere with imagePullSecrets. However, ensure there are no conflicting or incorrect entries.
b. Check for Registry Mirrors or Insecure Registries
Also, check for [plugins."io.containerd.grpc.v1.cri".registry.mirrors] or insecure_skip_verify_v2 under [plugins."io.containerd.grpc.v1.cri".registry]. If you have a private registry that uses self-signed certificates and is not properly configured for trusted CAs, you might also see related errors, though they usually manifest differently than "unauthorized."
If you made changes to config.toml, restart containerd:
sudo systemctl restart containerd
7. Address Potential DNS/Network Issues
Although authentication errors usually imply a successful handshake, it's good practice to quickly rule out DNS or basic network connectivity to the registry if other steps fail.
a. Check DNS Resolution on Nodes
# On a worker node:
dig my-private-registry
nslookup my-private-registry
Ensure these commands resolve to the correct IP address for your registry. Check /etc/resolv.conf on the node if DNS lookups fail or are incorrect.
b. Test Network Connectivity
# On a worker node:
curl -I https://my-private-registry/v2/
You should see an HTTP 401 Unauthorized response (which is good, it means the registry was reached and demanded authentication). If you get connection refused, timeout, or DNS errors, then network connectivity is the root cause.
8. Redeploy the Pod
After making any changes to the Kubernetes Secret or your Deployment manifest, you need to force Kubernetes to re-pull the image. Simply deleting the problematic Pod will achieve this.
kubectl delete pod my-app-deployment-78f9xxxx -n my-app-namespace
Kubernetes will create a new Pod (via the Deployment controller), which will attempt to pull the image using the updated Secret. Monitor its status:
kubectl get pods -n my-app-namespace -w
You should now see the new Pod transition to ContainerCreating and then Running. If it still fails, repeat the troubleshooting steps, carefully reviewing each detail.