EKS Pod Identity vs IRSA, 2년 굴려보고 우리 팀이 정리한 것
Pod Identity가 정식으로 나온 지 이제 2년 반쯤 됐다. 그동안 우리 팀에서는 IRSA로 굴러가는 클러스터 4개, Pod Identity로 새로 띄운 클러스터 3개를 운영해봤다. 솔직히 처음에는 "OIDC 트러스트 한 줄 더 박는 게 그렇게 귀찮은 일인가?" 싶었는데, 클러스터가 늘어나면서 생각이 좀 바뀌었다.
최근 6월 기준으로 Medium에 다시 비교 글이 올라오길래(이게 또 새로 입사하는 친구들이 가장 많이 찾는 주제다) 우리 팀 내부 결정 기록을 정리해서 공유한다. 결론부터 적으면, 새 워크로드는 Pod Identity, 단 Fargate에 띄울 거면 IRSA. 그리고 둘은 같은 클러스터에서 공존시켜도 별 문제 없다.
트러스트 정책의 무게
IRSA의 진짜 비용은 IAM role 자체가 아니라 트러스트 정책이다. 우리 팀이 클러스터를 prod-a, prod-b, stage, dev 이렇게 4개 굴리는데, 같은 워크로드(예: external-dns)가 4개 클러스터에 다 깔린다. IRSA 시절에는 external-dns용 IAM role 하나에 트러스트 정책 statement가 4개 박혀 있었다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::1234:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/PROD_A_ID" },
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": { "StringEquals": { "...PROD_A_ID:sub": "system:serviceaccount:kube-system:external-dns" } }
},
{ /* prod-b */ },
{ /* stage */ },
{ /* dev */ }
]
}
새 클러스터를 띄울 때마다 OIDC provider를 IAM에 등록하고, 각 role의 트러스트 정책에 statement를 추가해야 했다. 자동화는 했지만 IAM 권한이 필요한 작업이라 클러스터 만드는 팀과 IAM 관리하는 팀이 분리된 조직이면 매번 티켓 한 번씩 돌려야 한다.
Pod Identity는 이 부분을 그냥 통째로 들어낸다. IAM role 트러스트 정책은 EKS 서비스 프린시플(pods.eks.amazonaws.com) 하나만 신뢰하면 되고, "어떤 클러스터의 어떤 SA가 이 role을 쓸 수 있는가"는 EKS API의 pod identity association으로 따로 관리된다.
aws eks create-pod-identity-association \
--cluster-name prod-a \
--namespace kube-system \
--service-account external-dns \
--role-arn arn:aws:iam::1234:role/external-dns
클러스터 추가될 때마다 IAM 건드릴 필요가 없다. 이게 우리 팀에서 가장 크게 와닿은 차이다.
그래서 IRSA가 끝났느냐, 그건 아니다
Pod Identity가 못 하는 게 몇 가지 있다.
첫 번째는 Fargate. Pod Identity Agent는 노드에 DaemonSet으로 뜨는데, Fargate에는 DaemonSet이 안 뜬다. 사이드카로 끼워넣어도 privileged mode가 필요해서 또 안 된다. 우리 팀은 일부 배치 워크로드를 Fargate에 돌리는데, 이 부분은 그대로 IRSA로 유지 중이다. AWS containers-roadmap의 Fargate 지원 이슈는 2년째 열려 있고 아직 별 진척이 없다.
두 번째는 EKS Anywhere / 자체 운영 K8s. Pod Identity는 EKS 클라우드 전용이다. 자체 운영하는 클러스터에서 AWS 리소스에 접근해야 한다면 그냥 OIDC 페더레이션(=IRSA 방식)을 쓰는 게 맞다.
세 번째는 세션 태그를 SA 어노테이션으로 동적으로 넣어야 하는 케이스. IRSA는 토큰에 박힌 클레임을 그대로 세션 태그로 옮길 수 있는데(ABAC 만들 때 유용), Pod Identity는 association에 정적으로 매핑되는 구조다. 6월에 ABAC 강화 업데이트가 좀 들어오긴 했지만 IRSA만큼 자유롭지는 않다.
마이그레이션 — 우리 팀이 한 방식
처음에는 "한 번에 다 갈아엎자" 얘기가 나왔는데, 막상 해보니 멱등성이 깨지는 구간이 있어서 점진 이관으로 바꿨다.
1. Pod Identity Agent를 add-on으로 설치한다. 이건 기존 IRSA에 아무 영향 없다.
2. 마이그레이션 대상 워크로드를 정한다. 우리 팀은 상태 없는 컨트롤러부터 손댔다. external-dns, cluster-autoscaler(이미 Karpenter로 갈아탔지만), aws-load-balancer-controller 같은 것들.
3. 새 IAM role을 만든다. 기존 IRSA role 재활용 안 하고 신규로 판다. 이유는 단순한데, IRSA role에 박힌 트러스트 정책을 갑자기 EKS 서비스 프린시플로 바꾸면 잠깐 권한이 깨지는 윈도우가 생긴다.
4. create-pod-identity-association으로 SA에 묶는다.
5. SA에서 eks.amazonaws.com/role-arn 어노테이션을 제거한다 (선택). 이게 핵심인데, 어노테이션이 남아 있으면 IRSA가 우선이다. Pod Identity로 갈아탔다고 생각했는데 실제로는 여전히 IRSA를 타는 황당한 상황을 한 번 겪었다.
6. 파드 재시작 후 STS Get-Caller-Identity 로그로 어느 경로로 인증됐는지 확인한다.
kubectl exec -n kube-system deploy/external-dns -- \
aws sts get-caller-identity --query 'Arn' --output text
응답에 assumed-role 뒤에 붙는 세션 이름을 보면 어느 쪽인지 보인다. Pod Identity는 eks-<cluster>-<ns>-<sa>-<rand>, IRSA는 botocore-session-<ts> 형태가 자주 잡힌다.
성능 차이는 거의 없다
처음에 신경 쓰였던 게 Pod Identity Agent의 오버헤드였다. 노드마다 DaemonSet으로 뜨고, 모든 AWS SDK 호출이 169.254.170.23(에이전트의 link-local) 거쳐서 나간다. 우리 팀 노드 90대 클러스터에서 일주일 모니터링한 결과 에이전트 컨테이너의 CPU는 거의 노이즈 수준(평균 5m 미만), 메모리는 30~40MiB 정도였다. STS AssumeRole 호출 지연도 IRSA(웹 아이덴티티 페더레이션)와 측정상 유의미한 차이는 없었다.
다만 에이전트가 죽으면 그 노드의 모든 Pod Identity 워크로드가 인증 실패한다. 우리는 에이전트에 PriorityClass system-node-critical 박고, livenessProbe 좀 더 보수적으로 잡아두는 식으로 대응했다. IRSA는 kube-apiserver가 토큰 발급해주는 구조라 이런 단일 실패점이 없다 — 이게 보안팀이 IRSA를 더 좋아하는 한 가지 이유이기도 하다.
정리
| 항목 | IRSA | Pod Identity |
|---|---|---|
| 트러스트 정책 관리 | 클러스터별로 statement 추가 | 서비스 프린시플 하나 |
| Fargate | 지원 | 미지원 |
| EKS Anywhere/자체 운영 | 지원 | 미지원 |
| 단일 실패점 | 없음 (apiserver) | 노드별 에이전트 |
| 권장 시기 | Fargate, 자체 운영 | 새 EC2 워크로드 |
우리 팀의 결정은 "새로 만드는 워크로드는 무조건 Pod Identity, 기존 IRSA는 굳이 마이그레이션 안 함"으로 정리됐다. 트러스트 정책에 statement 4개 박혀 있는 IRSA role을 굳이 갈아엎을 이유가 없다. 잘 돌아가고 있으면 그대로 둔다. 새로 띄울 게 있으면 Pod Identity로 만든다.
그리고 솔직히 이건 AWS 측에서 좀 정리해줬으면 하는데, Fargate 지원이 들어오기 전까지는 "Pod Identity가 미래"라고 말하기가 좀 애매하다. 우리 팀처럼 Fargate를 쓰는 곳이 많은 조직이면 IRSA를 한참 더 쓰게 될 거다.
혹시 다른 팀에서 한꺼번에 마이그레이션해본 경험 있으면 어떻게 했는지 궁금하다.
추가 리소스: