- Published on
EKS Pod ImagePullBackOff - ECR 인증·IRSA 점검법
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
EKS에서 배포는 성공했는데 Pod 상태가 ImagePullBackOff 또는 ErrImagePull로 멈추는 순간이 있습니다. 이 문제는 겉으로는 “이미지를 못 받는다”로 보이지만, 실제 원인은 크게 두 갈래로 갈립니다.
- 노드가 ECR에 인증하지 못한다: 노드 IAM, 네트워크, ECR 정책, 리전 불일치
- IRSA로 풀려고 했는데 잘못 이해했다: 기본적으로 이미지 풀은 노드가 하고, IRSA는 애플리케이션 컨테이너의 AWS API 권한을 위한 것
이 글은 ECR 인증과 IRSA를 축으로, ImagePullBackOff를 빠르게 진단하는 체크리스트를 제공합니다.
1) 먼저 이벤트로 “왜 못 받는지”를 문자열로 확인
가장 먼저 해야 할 일은 Pod 이벤트를 보는 것입니다. ImagePullBackOff는 결과일 뿐이고, 이벤트에 원인 메시지가 들어 있습니다.
kubectl describe pod -n <namespace> <pod-name>
# 또는 이벤트만 보기
kubectl get events -n <namespace> --sort-by=.lastTimestamp | tail -n 50
자주 보는 메시지 패턴은 다음과 같습니다.
no basic auth credentials: ECR 로그인 토큰을 못 얻음, 또는 imagePullSecret 미설정denied: User ... is not authorized to perform: ecr:BatchGetImage: IAM 권한 부족dial tcp ... i/o timeout: 네트워크 경로 문제 (NAT, VPC 엔드포인트, 라우팅)manifest unknown: 태그/레포 이름/리전 불일치
이 단계에서 메시지가 i/o timeout 계열이면 네트워크 점검이 우선입니다. VPC 라우팅이나 NAT, 보안그룹 문제는 다른 증상(예: RDS 타임아웃)과 결이 비슷하니, 네트워크 진단 흐름은 이 글도 함께 참고하면 좋습니다.
2) 핵심 오해 정리: 이미지 풀은 “대부분 노드 IAM”이 담당
EKS에서 kubelet이 컨테이너 런타임을 통해 이미지를 pull 할 때, 기본적으로는 “노드(EC2)의 IAM Role”이 ECR 권한을 가져야 합니다.
- IRSA는 Pod 내부 애플리케이션이 S3, DynamoDB, SQS 같은 AWS API를 호출할 때 쓰는 권한 위임 방식입니다.
- 이미지 pull 권한을 IRSA로 주고 싶어 하는 경우가 많은데, 일반적인 EKS 구성에서는 IRSA만으로는 해결되지 않습니다.
예외적으로, 별도의 이미지 크리덴셜 제공 방식(imagePullSecrets)을 쓰거나, 다른 런타임/구성에서 webhook으로 credential을 주입하는 패턴이 있지만, “기본 EKS”에서는 먼저 노드 IAM을 의심하는 게 맞습니다.
3) 노드 IAM Role에 ECR 권한이 있는지 확인
3-1) 노드 Role 찾기
Managed Node Group이면 다음으로 확인할 수 있습니다.
aws eks describe-nodegroup \
--cluster-name <cluster> \
--nodegroup-name <nodegroup> \
--query 'nodegroup.nodeRole' \
--output text
Karpenter나 직접 구성한 노드라면 EC2 인스턴스 프로파일에서 Role을 확인해야 합니다.
3-2) 최소 필요 권한
ECR에서 이미지를 pull 하려면 대개 아래 권한이 필요합니다.
ecr:GetAuthorizationTokenecr:BatchGetImageecr:GetDownloadUrlForLayerecr:BatchCheckLayerAvailability
AWS 관리 정책으로는 보통 AmazonEC2ContainerRegistryReadOnly를 노드 Role에 붙이면 해결됩니다.
aws iam attach-role-policy \
--role-name <node-role-name> \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
만약 조직에서 권한을 세분화한다면, 노드 Role에 위 액션들이 허용되어 있는지 IAM Policy Simulator로 검증하는 게 빠릅니다. 권한 추적 자체가 필요하면 다음 글의 “권한 추적 루틴”이 도움이 됩니다.
4) ECR 리전, 레포, 태그 불일치 점검
의외로 많습니다. 특히 멀티 리전 환경에서 account.dkr.ecr.ap-northeast-2.amazonaws.com와 ap-southeast-1이 섞이면 pull이 실패합니다.
# 이미지 URI 예
# <account-id>.dkr.ecr.<region>.amazonaws.com/<repo>:<tag>
aws ecr describe-images \
--region <region> \
--repository-name <repo> \
--image-ids imageTag=<tag>
manifest unknown이면 태그가 없거나 다른 레포를 보고 있을 확률이 큽니다.repository does not exist면 레포 이름 오타 또는 리전 불일치 가능성이 큽니다.
5) 프라이빗 서브넷 노드라면 네트워크 경로가 첫 번째 변수
노드가 프라이빗 서브넷에 있고 NAT Gateway 또는 VPC 엔드포인트가 없다면, ECR에 접근하지 못해 i/o timeout이나 context deadline exceeded가 뜹니다.
ECR pull은 크게 두 엔드포인트가 관여합니다.
- ECR API:
ecr.api(토큰/메타데이터) - ECR DKR:
ecr.dkr(이미지 레이어)
프라이빗 환경에서 NAT 없이 가려면 보통 아래 VPC 엔드포인트가 필요합니다.
- Interface Endpoint:
com.amazonaws.<region>.ecr.api - Interface Endpoint:
com.amazonaws.<region>.ecr.dkr - Gateway Endpoint:
com.amazonaws.<region>.s3(ECR 레이어 전송이 S3를 경유하는 경우가 많음)
점검 포인트:
- 엔드포인트가 노드 서브넷 라우팅 테이블에 연결되어 있는가
- 엔드포인트 SG가 노드 SG에서 443을 허용하는가
- 프라이빗 DNS가 활성화되어 있는가
6) ECR 레포 정책(Resource Policy)로 막히는 케이스
노드 Role에 권한이 있어도, 레포 정책에서 특정 principal만 허용하면 거절됩니다.
aws ecr get-repository-policy \
--region <region> \
--repository-name <repo>
여기서 Principal 제한, aws:PrincipalArn 조건, 조직 ID 조건 등이 걸려 있으면 노드 Role이 해당 조건을 만족하는지 확인해야 합니다.
7) IRSA는 어디를 점검해야 하나: “앱이 AWS API를 호출할 때”
앞서 말했듯 이미지 풀 자체는 보통 노드 IAM 이슈입니다. 그럼에도 IRSA 점검이 필요한 경우는 다음입니다.
- 사용 중인 환경이 이미지 pull credential을 IRSA로 주입하도록 별도 구성되어 있다
initContainer나 사이드카가 시작 직후 AWS API를 호출하는데, 그 실패가 이미지 풀 문제로 오해되고 있다- 애플리케이션이 ECR에서 추가 아티팩트를 받거나(예: Helm chart, private registry 토큰 교환) AWS API 의존이 있다
IRSA 점검은 아래 순서로 진행합니다.
7-1) 클러스터 OIDC 제공자 연결 확인
aws eks describe-cluster \
--name <cluster> \
--query 'cluster.identity.oidc.issuer' \
--output text
OIDC issuer가 있어야 IRSA가 동작합니다. 없다면 eksctl utils associate-iam-oidc-provider 또는 Terraform로 OIDC provider를 연결해야 합니다.
7-2) ServiceAccount에 role annotation이 있는지
kubectl get sa -n <namespace> <serviceaccount> -o yaml
아래 형태가 있어야 합니다.
eks.amazonaws.com/role-arn: arn:aws:iam::<account-id>:role/<role-name>
7-3) IAM Role의 Trust Policy 조건이 정확한지
IRSA Role의 trust policy에서 가장 흔한 실수는 sub 조건이 namespace, serviceaccount와 불일치하는 것입니다.
다음은 전형적인 trust policy 형태입니다. 본문에 부등호 문자가 들어가지 않도록 JSON은 코드 블록으로 제공합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<account-id>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<oidc-id>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<oidc-id>:aud": "sts.amazonaws.com",
"oidc.eks.<region>.amazonaws.com/id/<oidc-id>:sub": "system:serviceaccount:<namespace>:<serviceaccount>"
}
}
}
]
}
여기서 sub가 실제 ServiceAccount와 1글자라도 다르면 Pod는 Role을 Assume하지 못합니다.
7-4) Pod 내부에서 실제로 어떤 자격증명을 쓰는지 확인
Pod에 들어가서 환경 변수를 확인하면 IRSA가 주입되었는지 빠르게 알 수 있습니다.
kubectl exec -n <namespace> -it <pod-name> -- sh -lc 'env | grep -E "AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE|AWS_REGION"'
AWS_WEB_IDENTITY_TOKEN_FILE가 있으면 IRSA 경로로 자격증명을 얻는 구성일 가능성이 큽니다.
8) imagePullSecrets를 쓰는 경우의 점검
ECR이 아닌 외부 프라이빗 레지스트리거나, ECR이라도 조직 정책상 노드 Role을 쓰지 않고 시크릿으로 강제하는 경우가 있습니다.
kubectl get secret -n <namespace>
kubectl describe secret -n <namespace> <secret-name>
kubectl get sa -n <namespace> <serviceaccount> -o yaml
# imagePullSecrets 항목 확인
ECR을 docker-registry 타입 시크릿으로 붙이는 방식은 토큰 만료 이슈가 생길 수 있습니다. 이 경우 자동 갱신 메커니즘이 없으면 시간이 지나며 간헐적으로 ImagePullBackOff가 재발합니다.
9) 빠른 결론을 위한 “10분 체크리스트”
kubectl describe pod이벤트에서 에러 문자열 확보manifest unknown이면 URI, 리전, 태그부터 교정no basic auth credentials면 노드 IAM 또는 imagePullSecrets 전략 확인- 노드 Role에
AmazonEC2ContainerRegistryReadOnly부착 여부 확인 - 프라이빗 서브넷이면 NAT 또는 ECR VPC 엔드포인트(
ecr.api,ecr.dkr,s3) 확인 - ECR 레포 정책에서 principal 제한 여부 확인
- IRSA는 “앱 AWS API 권한” 관점에서 OIDC, SA annotation, trust policy
sub일치 여부 확인
10) 재발 방지 팁: 관측 가능성(Observability)과 표준화
- 노드 그룹 Role에 ECR pull 권한을 표준으로 포함시키고, 변경은 코드(Terraform)로만 관리
- 프라이빗 클러스터는 ECR VPC 엔드포인트 구성을 템플릿화
ImagePullBackOff알림을 이벤트 기반으로 받아 초기에 탐지- 권한 문제는 “누가 무엇을 거부당했는지”를 남기도록 CloudTrail 조회 루틴을 운영
운영에서 중요한 건 한 번 고치는 것보다, 다음에 같은 증상이 나왔을 때 5분 안에 “IAM인지, 네트워크인지, 리전/태그인지”를 갈라내는 것입니다. 위 순서대로 보면 대부분의 ImagePullBackOff는 재현 없이도 원인까지 도달할 수 있습니다.