- Published on
Terraform로 EKS 업그레이드 후 aws-auth 꼬임으로 노드 Join 실패 해결
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
Terraform로 EKS를 운영하다 보면, 클러스터 버전 업그레이드(또는 모듈 업그레이드) 이후 갑자기 노드가 Ready로 올라오지 않고 NodeGroup이 계속 NotReady/Unhealthy로 남는 상황을 만날 수 있습니다. 이때 원인이 네트워크나 AMI가 아니라 kube-system/aws-auth ConfigMap 꼬임인 경우가 매우 흔합니다.
특히 다음 조건이 겹치면 재현 확률이 높습니다.
- Terraform EKS 모듈 버전 변경과 함께 EKS 버전을 업그레이드
- Managed Node Group/자체 ASG 혼재
- IRSA, access entry, aws-auth 관리 방식이 과거/현재가 섞임
aws-auth를 Terraform이 관리하지만, 중간에 수동 수정이 들어감
이 글에서는 “왜 Join이 실패하는지”를 로그/이벤트로 빠르게 확인하고, 꼬인 aws-auth를 안전하게 복구한 뒤, Terraform에서 재발 방지까지 하는 실전 절차를 다룹니다.
증상: 노드는 뜨는데 클러스터에 안 붙는다
대표적으로 아래 현상이 함께 나타납니다.
- EC2 인스턴스(노드)는 정상 기동, EKS 콘솔에서도 NodeGroup 인스턴스는 생성됨
- Kubernetes에서는 노드가 보이지 않거나, 잠깐 보였다가 사라짐
- NodeGroup 상태가
CREATE_FAILED또는NodeCreationFailure
확인 포인트:
kubectl get nodes
kubectl -n kube-system get cm aws-auth -o yaml
kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -n 50
노드 Join 실패는 결국 “노드가 API 서버에 인증/인가를 못 받는다”로 귀결되는 경우가 많고, 그 핵심이 aws-auth의 mapRoles/mapUsers 매핑입니다.
원인: aws-auth ConfigMap이 왜 꼬이나?
EKS에서 워커 노드(kubelet)는 노드 IAM Role을 통해 AWS IAM 인증을 받고, Kubernetes RBAC으로 매핑되어야 노드로 승인됩니다. 이 매핑을 전통적으로 담당하던 것이 kube-system/aws-auth ConfigMap입니다.
Terraform 업그레이드 이후 꼬임이 발생하는 대표 패턴은 다음과 같습니다.
1) mapRoles에서 노드 Role이 누락/덮어쓰기
Terraform이 aws-auth를 “전체 리소스”로 관리하는데, 중간에 다른 경로(예: eksctl, 콘솔, 수동 kubectl edit)로 수정되면 다음 apply에서 덮어쓰기가 발생합니다.
- 기존 노드 Role 매핑이 사라짐
- 새로운 노드그룹 Role이 추가되지 않음
system:bootstrappers,system:nodes그룹이 빠짐
2) rolearn 문자열이 미세하게 바뀜(리네이밍/재생성)
모듈 업그레이드로 IAM Role 이름/경로가 바뀌거나, Launch Template/NodeGroup 재생성 과정에서 Role을 교체하면 aws-auth의 rolearn이 이전 값을 가리키게 됩니다.
3) EKS Access Entry(새 권한 모델)와 혼용
최근 EKS는 Access Entry 기반 권한 부여가 확장되었지만, 노드 Join은 여전히 aws-auth에 의존하는 구성들이 많습니다(특히 기존 클러스터). 팀 내에서 “이제 aws-auth 안 써도 된다”는 오해로 관리가 느슨해지면, 업그레이드 타이밍에 문제가 터집니다.
진단: 진짜 aws-auth 문제인지 빠르게 판별하기
1) NodeGroup 이벤트/상태 확인
aws eks describe-nodegroup \
--cluster-name <CLUSTER> \
--nodegroup-name <NG> \
--query 'nodegroup.health.issues'
Unauthorized/AccessDenied류가 보이거나, 노드가 계속 교체되는데 Join이 안 되면 aws-auth 가능성이 큽니다.
2) kubelet 부트스트랩 로그(EC2) 확인
노드 인스턴스에서(SSM 또는 SSH):
sudo journalctl -u kubelet -n 200 --no-pager
sudo cat /var/log/cloud-init-output.log | tail -n 200
다음 유형의 메시지가 힌트가 됩니다.
- API 서버 연결은 되는데 인증/인가 실패
node "ip-..." is forbidden류
3) aws-auth에 노드 Role이 있는지 확인
kubectl -n kube-system get cm aws-auth -o jsonpath='{.data.mapRoles}'
노드 Role이 있어야 하는 최소 형태는 대개 아래처럼 생깁니다.
system:bootstrapperssystem:nodes- username 패턴:
system:node:{{EC2PrivateDNSName}}
해결: aws-auth를 올바른 상태로 복구하기
1) 현재 aws-auth 백업
kubectl -n kube-system get cm aws-auth -o yaml > aws-auth.backup.yaml
2) 노드 Role ARN 식별
Managed Node Group의 노드 Role:
aws eks describe-nodegroup \
--cluster-name <CLUSTER> \
--nodegroup-name <NG> \
--query 'nodegroup.nodeRole' \
--output text
여러 NodeGroup이면 각각 확인합니다.
3) aws-auth에 mapRoles 추가/수정
아래는 가장 흔한 정상 예시입니다. rolearn만 본인 값으로 바꿉니다.
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- rolearn: arn:aws:iam::<ACCOUNT_ID>:role/<NODE_INSTANCE_ROLE>
username: system:node:{{EC2PrivateDNSName}}
groups:
- system:bootstrappers
- system:nodes
적용:
kubectl apply -f aws-auth.fixed.yaml
여기서 중요한 점:
mapRoles는 YAML “문자열 블록” 안에 또 YAML 리스트가 들어가는 구조라 인덴트가 조금만 틀려도 깨집니다.- 여러 Role을 넣을 경우
- rolearn:항목을 같은 레벨로 나열해야 합니다.
4) 노드 재기동(또는 NodeGroup 롤링)
aws-auth를 고쳐도 이미 실패 상태인 노드가 계속 재시도하다가 꼬일 수 있어, 다음 중 하나를 권장합니다.
- NodeGroup 인스턴스 수를 0으로 내렸다가 다시 올리기(가능하면)
- ASG 인스턴스 교체(terminate)
- Managed Node Group 업데이트로 롤링
정상화 확인:
kubectl get nodes -o wide
kubectl -n kube-system get pods -o wide
이후 CoreDNS 등 필수 파드가 연쇄적으로 문제를 일으키는 경우도 있는데, 그건 별도 트러블슈팅이 필요합니다. (참고: AWS EKS CoreDNS CrashLoopBackOff와 DNS 타임아웃 해결)
Terraform에서 재발 방지: aws-auth를 “한 군데서만” 관리하기
가장 위험한 운영 패턴은 aws-auth를 Terraform이 관리하면서도, 운영자가 급할 때 kubectl edit로 고치는 것입니다. 업그레이드/배포 타이밍에 누군가의 변경이 덮어써지며 장애가 재발합니다.
선택지 A) Terraform로 aws-auth를 일관되게 관리
terraform-aws-modules/eks를 쓴다면(버전에 따라 다르지만) 보통 아래처럼 aws_auth_roles 또는 manage_aws_auth_configmap 계열 옵션을 사용합니다.
예시(개념 코드):
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = var.cluster_name
cluster_version = var.cluster_version
manage_aws_auth_configmap = true
aws_auth_roles = [
{
rolearn = aws_iam_role.node_role.arn
username = "system:node:{{EC2PrivateDNSName}}"
groups = ["system:bootstrappers", "system:nodes"]
}
]
}
핵심 원칙:
- 노드 Role(모든 NodeGroup/ASG)의 ARN이 항상 aws_auth_roles에 포함되게 만들기
- 수동 수정 금지(필요하면 Terraform 변수/코드로 반영)
선택지 B) Terraform은 aws-auth를 건드리지 않고, 별도 GitOps로 관리
클러스터 내부 리소스는 Argo CD/Flux 같은 GitOps로 관리하고, Terraform은 인프라까지만 책임지는 방식도 좋습니다. 단, 이 경우에도 “단일 소스 오브 트루스” 원칙을 지켜야 합니다.
업그레이드 시 체크리스트(장애 예방)
1) 업그레이드 전 aws-auth 스냅샷
kubectl -n kube-system get cm aws-auth -o yaml > aws-auth.pre-upgrade.yaml
2) NodeGroup별 nodeRole 목록화
aws eks list-nodegroups --cluster-name <CLUSTER> --output text
# 각 노드그룹에 대해
aws eks describe-nodegroup --cluster-name <CLUSTER> --nodegroup-name <NG> --query 'nodegroup.nodeRole' --output text
3) 업그레이드 직후 “노드 Join”을 가장 먼저 확인
kubectl get nodes
kubectl -n kube-system get pods
노드가 안 붙으면 애플리케이션 증상(CrashLoopBackOff, ImagePullBackOff 등)만 보고 헤매기 쉽습니다. 예를 들어 노드가 붙지 않아 CNI/코어 파드가 불안정하면, 이미지 풀도 연쇄적으로 실패할 수 있습니다. 이미지 인증/IRSA 이슈와 구분이 필요합니다. (참고: Kubernetes ImagePullBackOff 401 - ECR·IRSA·imagePullSecrets)
실전 팁: aws-auth YAML 사고를 줄이는 방법
kubectl edit대신 파일 기반으로kubectl apply를 사용해 변경 이력을 남기기mapRoles블록을 수정할 때는 YAML lint 또는 최소한kubectl apply --dry-run=client -f ...로 문법 검증
kubectl apply --dry-run=client -f aws-auth.fixed.yaml
- Terraform을 쓴다면
plan에서aws-auth변경(diff)을 항상 리뷰하고, 노드 Role 항목이 사라지는지 체크
결론
Terraform로 EKS 업그레이드 후 노드 Join이 실패한다면, 네트워크/CNI/AMI를 의심하기 전에 kube-system/aws-auth부터 확인하는 것이 시간 대비 효율이 가장 좋습니다. 대부분의 케이스는 노드 IAM Role 매핑 누락 또는 덮어쓰기로 설명되며, mapRoles에 올바른 rolearn, username, system:bootstrappers/system:nodes 그룹을 복구하면 빠르게 정상화됩니다.
마지막으로, aws-auth는 “누가 최종적으로 관리하는지”를 팀 차원에서 합의하고(Terraform 또는 GitOps), 업그레이드 전후로 스냅샷/검증 절차를 넣으면 같은 장애를 반복하지 않을 수 있습니다.