Diagnosing ImagePullBackOff for Private ECR Images on AWS EKS with IRSA

Tech Note: Always backup your configuration files before applying any changes to production environments.

Diagnosing ImagePullBackOff for Private ECR Images on AWS EKS with IRSA

Encountering ImagePullBackOff errors in a Kubernetes environment often signals a problem with accessing container images. When running AWS Elastic Kubernetes Service (EKS) and pulling private images from Elastic Container Registry (ECR) using IAM Roles for Service Accounts (IRSA), this error can point to a nuanced set of misconfigurations. This comprehensive guide provides a detailed breakdown of the common causes and a step-by-step troubleshooting manual to resolve ImagePullBackOff specifically in EKS/ECR/IRSA setups.

Understanding ImagePullBackOff and IRSA on EKS

The ImagePullBackOff status indicates that a Kubernetes pod is unable to pull its specified container image. While generic, in an EKS context leveraging IRSA for private ECR access, this typically means a breakdown in the authentication and authorization chain. IRSA allows Kubernetes service accounts to assume IAM roles, providing granular AWS permissions to pods without distributing AWS credentials. For ECR, this means the pod's service account (via its linked IAM role) needs permission to authenticate with ECR and pull images.

The process involves several components:

  • EKS OIDC Provider: An OpenID Connect (OIDC) identity provider for your EKS cluster that allows IAM to trust identities from your cluster.
  • Kubernetes Service Account: A Kubernetes object that pods use to identify themselves to the cluster.
  • IAM Role: An AWS identity with specific permissions, which is assumed by the Kubernetes service account.
  • ECR Repository: The private AWS container registry where your images are stored.

Symptom Analysis & Root Causes

Symptom: ImagePullBackOff

The primary symptom is a pod stuck in a Pending or CrashLoopBackOff state, with the STATUS column eventually showing ImagePullBackOff. You can confirm this with the following commands:

kubectl get pods -n your-namespace

Look for output similar to:

NAME READY STATUS RESTARTS AGE my-app-pod 0/1 ImagePullBackOff 0 5m

Further investigation into the pod's events will provide more details:

kubectl describe pod my-app-pod -n your-namespace

In the "Events" section, you might see errors like: Failed to pull image "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-private-repo:latest": rpc error: code = Unknown desc = Error response from daemon: Get "https://123456789012.dkr.ecr.us-east-1.amazonaws.com/v2/": no basic auth credentials or Failed to pull image "my-image": rpc error: code = NotFound desc = pull access denied for 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-private-repo, repository does not exist or may require 'docker login'.

Common Root Causes

Here are the most frequent reasons for ImagePullBackOff with private ECR images and IRSA on EKS:

  • Incorrect IAM Role for Service Account (IRSA) Configuration: The Kubernetes Service Account (SA) either doesn't have the correct eks.amazonaws.com/role-arn annotation, or the specified IAM role ARN is invalid.
  • Missing ECR Permissions on IAM Role: The IAM role linked to the service account lacks the necessary permissions to pull images from ECR (e.g., ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, ecr:BatchCheckLayerAvailability, ecr:GetAuthorizationToken).
  • Trust Policy Issues for the IAM Role: The IAM role's trust policy does not correctly allow the EKS OIDC provider to assume the role, or the OIDC provider URL/audience in the trust policy is incorrect. The sub condition in the trust policy might also be wrong (e.g., incorrect namespace or service account name).
  • Service Account Not Linked to Pod: The pod's manifest does not specify the serviceAccountName, or it points to a non-existent service account.
  • Network Connectivity Issues to ECR: EKS worker nodes (or the pod itself if using custom networking) cannot reach the ECR endpoint. This could be due to VPC Security Group rules, Network ACLs, or missing VPC Endpoints for ECR.
  • Image Name/Tag Mismatch or Non-Existent Image: The image URI or tag specified in the pod manifest is incorrect, or the image simply doesn't exist in the specified ECR repository.
  • EKS OIDC Provider Not Configured or Invalid: The OIDC provider for the EKS cluster might not be set up correctly in IAM.

Step-by-Step Resolution Guide

Step 1: Verify Pod and Service Account Configuration

Ensure your pod is explicitly using the correct service account, and that the service account is annotated with the IAM Role ARN.

  • Check Pod Manifest: Verify that your pod's YAML includes serviceAccountName: your-service-account-name and that the image path is correct.
    apiVersion: v1 kind: Pod metadata: name: my-app-pod labels: app: my-app spec: serviceAccountName: my-service-account # <-- This must match your SA name containers: - name: my-app-container image: 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-private-repo:latest # <-- Full ECR URI with account ID and region ports: - containerPort: 80
  • Inspect Service Account: Retrieve the YAML for the service account used by your pod and confirm the presence and correctness of the IAM role ARN annotation.
    kubectl get sa my-service-account -n your-namespace -o yaml
    Look for an annotation like:
    annotations: eks.amazonaws.com/role-arn: arn:aws:iam::YOUR_AWS_ACCOUNT_ID:role/YourEKSIRSAIAMRoleName

    The IAM Role ARN must precisely match the role created for IRSA.

Step 2: Inspect the IAM Role Associated with the Service Account

The IAM role needs a specific trust policy that allows the EKS OIDC provider to assume it, and an attached permissions policy that grants ECR pull access.

  • Retrieve IAM Role Details: Use the AWS CLI to get the details of the IAM role identified in Step 1.
    aws iam get-role --role-name YourEKSIRSAIAMRoleName

    From the output, extract the AssumeRolePolicyDocument (Trust Policy) and check the attached managed/inline policies.

  • Verify Trust Policy: The trust policy must permit the OIDC provider of your EKS cluster to assume the role. Pay close attention to the Federated principal, Action, and especially the Condition block.
    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::YOUR_AWS_ACCOUNT_ID:oidc-provider/oidc.eks.YOUR_AWS_REGION.amazonaws.com/id/YOUR_EKS_OIDC_ID" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.YOUR_AWS_REGION.amazonaws.com/id/YOUR_EKS_OIDC_ID:sub": "system:serviceaccount:your-namespace:my-service-account", "oidc.eks.YOUR_AWS_REGION.amazonaws.com/id/YOUR_EKS_OIDC_ID:aud": "sts.amazonaws.com" } } } ] }

    Ensure:

    • YOUR_AWS_ACCOUNT_ID matches your AWS account ID.
    • YOUR_AWS_REGION matches your EKS cluster's region.
    • YOUR_EKS_OIDC_ID is the correct OIDC ID for your cluster (usually found in the EKS cluster details).
    • your-namespace and my-service-account exactly match the Kubernetes namespace and service account name.
    • The aud condition is set to sts.amazonaws.com.

  • Verify Permissions Policy: The IAM role needs permissions to interact with ECR. A common policy for pulling images looks like this:
    { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecr:GetDownloadUrlForLayer", "ecr:BatchGetImage", "ecr:BatchCheckLayerAvailability", "ecr:GetAuthorizationToken" ], "Resource": "*" } ] }

    While "Resource": "*" is often used for simplicity, it is a best practice to restrict the resource to specific ECR repositories if possible (e.g., "arn:aws:ecr:YOUR_AWS_REGION:YOUR_AWS_ACCOUNT_ID:repository/my-private-repo" for the first three actions, and "*" or specific registries for GetAuthorizationToken if cross-account pull is needed).

Step 3: Verify EKS OIDC Provider

Ensure your EKS cluster has an associated OIDC identity provider in IAM, and its URL matches the one used in the IAM role's trust policy.

  • Get OIDC Issuer URL for your EKS Cluster:
    aws eks describe-cluster --name YOUR_EKS_CLUSTER_NAME --query "cluster.identity.oidc.issuer" --output text

    The output (e.g., https://oidc.eks.YOUR_AWS_REGION.amazonaws.com/id/YOUR_EKS_OIDC_ID) should exactly match the Federated principal in your IAM role's trust policy (excluding the arn:aws:iam::ACCOUNT_ID:oidc-provider/ prefix).

  • List IAM OIDC Providers:
    aws iam list-open-id-connect-providers

    Confirm that an OIDC provider with your EKS cluster's issuer URL exists and is properly configured. If not, you may need to create one (e.g., using eksctl utils associate-iam-oidc-provider --cluster YOUR_EKS_CLUSTER_NAME --approve).

Step 4: Network Connectivity Checks

Even with correct IAM permissions, if your EKS worker nodes or pods cannot reach ECR, image pulls will fail.

  • Security Groups & Network ACLs: Ensure the Security Groups attached to your EKS worker nodes (or Fargate profiles) allow outbound HTTPS (port 443) traffic to ECR endpoints. If ECR VPC Endpoints are used, ensure connectivity to those endpoints.
  • VPC Endpoints for ECR: For private subnets, ensure you have VPC endpoints for ECR (com.amazonaws.YOUR_REGION.ecr.api and com.amazonaws.YOUR_REGION.ecr.dkr) and S3 (com.amazonaws.YOUR_REGION.s3) configured. S3 is required for pulling certain image layers.
  • Test Connectivity from a Debug Pod: Launch a simple pod on your cluster (preferably in the same namespace and with the same service account if possible) to test network reachability.
    kubectl run -it --rm --restart=Never debug-pod --image=alpine -- sh # Inside the debug pod: apk add curl curl -v https://123456789012.dkr.ecr.us-east-1.amazonaws.com/v2/

    You should expect to see an HTTP 401 Unauthorized response, which indicates network reachability. If you see connection timeouts or failures, your network configuration is the problem.

Step 5: Image Name and Tag Verification

A simple typo can cause this error. Double-check the image URI in your pod definition against the actual image in ECR.

  • List ECR Images:
    aws ecr describe-images --repository-name my-private-repo --region us-east-1

    Ensure the image name and tag specified in your pod manifest exist in the ECR repository and match exactly.

Best Practices for Prevention & Performance Optimization

  • Principle of Least Privilege: Always grant the minimum necessary permissions to your IAM roles. For ECR image pulling, this means only the ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, ecr:BatchCheckLayerAvailability, and ecr:GetAuthorizationToken actions. Specify resource ARNs for specific repositories when possible instead of "*".
  • Automated IRSA Provisioning: Utilize tools like eksctl, AWS CDK, or Terraform to provision your EKS clusters, OIDC providers, IAM roles, and Kubernetes service accounts. This reduces manual errors and ensures consistency.
  • VPC Endpoints for ECR & S3: For optimal security and performance, especially in private subnets, configure VPC interface endpoints for ECR API, ECR DKR, and a gateway endpoint for S3. This keeps image pulls within the AWS network, reducing latency and avoiding NAT Gateway costs.
  • Consistent Image Tagging Strategy: Implement a clear and consistent image tagging strategy (e.g., semantic versioning, git commit SHAs). Avoid using :latest in production to prevent unexpected image changes.
  • Proactive Monitoring and Alerting: Set up Amazon CloudWatch alarms for EKS-related metrics, ECR pull failures, and Kubernetes event monitoring to quickly detect and respond to ImagePullBackOff events.
  • Regular Audits: Periodically review your IAM roles, service account configurations, and network policies to ensure they align with security best practices and operational requirements.

Frequently Asked Questions (FAQs)

Q1: Can I use imagePullSecrets with IRSA?

While technically possible, it's generally not recommended to use imagePullSecrets (which typically store static ECR login credentials or Docker config.json) when IRSA is available. IRSA provides a more secure and robust way to grant temporary, rotating credentials to pods, eliminating the need to manage sensitive credentials within Kubernetes secrets. Stick to IRSA for ECR access on EKS for better security posture and simplified credential management.

Q2: How do I ensure my ECR images are highly available for pulling?

ECR itself is a highly available service by design, replicating images across multiple Availability Zones within a region. To optimize pull performance and reliability:

  • Use ECR in the same AWS region as your EKS cluster.
  • Implement VPC Endpoints for ECR and S3 to keep traffic within the AWS network.
  • Ensure your worker nodes have sufficient network bandwidth.
  • Consider ECR Pull Through Cache rules for upstream public registries like Docker Hub to locally cache frequently pulled images within your private ECR.

Q3: What if I have multiple ECR repositories in different AWS accounts?

To pull images from ECR repositories in different AWS accounts, the IAM role associated with your EKS service account needs permissions to access those cross-account repositories. This involves two main steps:

  1. Source Account (where ECR repo resides): Grant the ECR repository policy permission to allow your EKS account's IAM role to perform ECR actions (ecr:GetDownloadUrlForLayer, ecr:BatchGetImage, ecr:BatchCheckLayerAvailability).
  2. Target Account (where EKS cluster runs): Ensure the IAM role linked to your EKS service account has the necessary ECR permissions, possibly with resource ARNs pointing to the cross-account repositories, and definitely ecr:GetAuthorizationToken for the cross-account registry.
This allows a cross-account authorization flow, where your EKS pod obtains an auth token for the target account's ECR, which then has a repository policy granting access.

Popular posts from this blog

Debugging ImagePullBackOff in Kubernetes EKS with AWS ECR authentication issues

Fixing EKS Pod CrashLoopBackOff Due to Readiness Probe Failures

Resolve Nginx `upstream prematurely closed connection` with SSL termination for Docker containers