1. Pod에서 AWS API를 호출하면 무슨 일이 생기나
컨테이너 안에 AWS Access Key를 넣는 건 위험하다. 이미지가 유출되면 키도 같이 나간다. 그렇다고 노드의 IAM Role을 그대로 쓰면 모든 Pod가 동일한 권한을 갖게 된다. 개발팀이 원하는 건 "런타임에서 자격증명이 자동으로 주입되면서도 Pod 단위로 최소 권한이 적용되는 것"이다.
1.1 노드 IAM Role 공유의 문제
서비스 어카운트를 마운트하지 않은 Pod를 하나 만들어 보자.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test1
spec:
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
args: ['s3', 'ls']
restartPolicy: Never
automountServiceAccountToken: false
terminationGracePeriodSeconds: 0
EOF
로그를 확인하면 AccessDenied가 뜬다.
kubectl logs eks-iam-test1
# An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
이 Pod는 SA 토큰이 없으므로 IMDS(Instance Metadata Service)를 타고 노드의 IAM Role을 사용한다. 노드 IAM Role에 S3 권한이 없으니 실패하는 것이다.
여기서 진짜 문제가 드러난다. 만약 노드 IAM Role에 S3 권한을 추가하면? 이 노드 위의 모든 Pod가 S3에 접근할 수 있게 된다. 특정 Pod에만 S3 권한을 주고 싶어도 방법이 없다. "Pod 단위로 권한을 나눌 수 없다."
CloudTrail에서 ListBuckets 이벤트를 보면 userIdentity에 노드의 IAM Role ARN(eksctl-myeks-nodegroup-ng-NodeInstanceRole-xxxx)이 찍힌다. 어떤 Pod가 호출했는지 구분이 불가능하다.
kubectl delete pod eks-iam-test1
1.2 기본 SA 토큰은 AWS용이 아니다
이번에는 기본 SA가 자동 마운트되는 Pod를 만들어 본다.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test2
spec:
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
command: ['sleep', '36000']
restartPolicy: Never
terminationGracePeriodSeconds: 0
EOF
Pod에 마운트된 SA 토큰을 디코딩해 보자.
# 토큰 확인
kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token ; echo
# jwt decode
SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
jwt decode $SA_TOKEN --json --iso8601
페이로드를 보면 이렇다.
{
"aud": ["https://kubernetes.default.svc"],
"exp": 1716619848,
"iat": 1685083848,
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX",
"kubernetes.io": {
"namespace": "default",
"pod": { "name": "eks-iam-test2" },
"serviceaccount": { "name": "default" }
},
"sub": "system:serviceaccount:default:default"
}
aud가 https://kubernetes.default.svc다. Kubernetes API 서버의 ClusterIP 서비스 도메인으로, 이 토큰의 수신자가 K8s API 서버라는 뜻이다. AWS STS는 이 토큰을 받아주지 않는다. STS가 처리하려면 aud가 sts.amazonaws.com이어야 한다.
Kubernetes 1.12부터 도입된 ProjectedServiceAccountToken 기능으로 이 토큰에는 aud와 exp(만료 시간)가 설정되어 있다. OIDC 규격을 따르는 JWT이므로 원칙적으로 외부 서비스 인증에도 쓸 수 있다. 하지만 aud가 K8s API용이기 때문에 AWS 인증에는 별도 토큰이 필요하다.
정리하면 상황은 이렇다.
- 노드 IAM Role을 공유하면 Pod 단위 권한 분리가 안 된다
- 기본 SA 토큰은 K8s API용이라 AWS 인증에 쓸 수 없다
IRSA는 이 두 문제를 OIDC로 풀었다.
kubectl delete pod eks-iam-test2
2. IRSA - OIDC로 Pod에 AWS 권한 부여하기
IRSA(IAM Roles for Service Accounts)는 Kubernetes가 발급한 JWT 토큰을 AWS가 OIDC Provider로 검증한 뒤 IAM Role을 부여하는 구조다. EKS 1.14부터 지원한다.
2.1 OIDC 인증 흐름

Pod가 생성되면 MutatingWebhook이 JWT 토큰과 IAM Role ARN 정보를 Pod Spec에 주입한다. 이후 Pod 안의 Application SDK가 AWS 리소스를 사용하려 할 때 인증 흐름이 시작된다.
- Pod의 SDK가 자신의 JWT와 IAM Role ARN을 STS에 보내 임시 키를 요청한다 (
AssumeRoleWithWebIdentity) - STS는 토큰과 Role ARN을 IAM에 전달하여 승인을 요청한다
- IAM은 토큰의
iss(발급자)가 등록된 OIDC Provider와 일치하는지,sub(주체)가 Trust Policy의 조건과 맞는지,aud가sts.amazonaws.com인지,exp가 만료되지 않았는지 확인한다 - IAM이 OIDC Provider의 JWKS(JSON Web Key Set) URL에서 공개키를 가져와 토큰 서명을 검증한다
- 검증을 통과하면 STS가 임시 자격증명을 발급한다
- Pod의 SDK가 발급받은 임시 키로 S3 같은 AWS 서비스를 호출한다

처음 접하면 단계가 많아 보이지만 실제로는 SDK가 대부분 자동으로 처리한다. 개발자가 코드에서 별도의 인증 객체를 만들 필요 없이 Default Credential Provider를 쓰면 된다.
# IRSA가 설정된 Pod에서는 이렇게만 해도 된다
import boto3
s3 = boto3.client('s3') # SDK가 환경변수의 WebIdentityToken을 자동으로 읽음
response = s3.list_buckets()
OIDC Discovery endpoint로 이 구조를 직접 확인할 수 있다.
# 클러스터의 OIDC issuer URL 확인
IDP=$(aws eks describe-cluster --name myeks --query cluster.identity.oidc.issuer --output text)
# Discovery endpoint 호출 - OIDC Provider의 메타데이터
curl -s $IDP/.well-known/openid-configuration | jq .
{
"issuer": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX",
"jwks_uri": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX/keys",
"authorization_endpoint": "urn:kubernetes:programmatic_authorization",
"response_types_supported": ["id_token"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"]
}
jwks_uri로 공개키를 가져올 수 있고 IAM은 이 키로 Pod가 보낸 JWT 서명이 변조되지 않았는지 확인한다.
# 공개키 세트(JWKS) 확인
curl -s $IDP/keys | jq .
2.2 MutatingWebhook이 Pod Spec에 끼워넣는 것
IRSA가 설정된 SA를 사용하는 Pod가 생성되면 pod-identity-webhook이 작동한다.
kubectl get MutatingWebhookConfiguration
# NAME WEBHOOKS AGE
# pod-identity-webhook 1 4h38m
# ...
이 webhook의 이름은 iam-for-pods.amazonaws.com이다. Pod 생성 요청을 가로채서 아래 항목을 주입한다.
환경변수
AWS_ROLE_ARN: assume할 IAM Role의 ARNAWS_WEB_IDENTITY_TOKEN_FILE: JWT 토큰 파일 경로 (/var/run/secrets/eks.amazonaws.com/serviceaccount/token)
Projected Volume
- 마운트 경로:
/var/run/secrets/eks.amazonaws.com/serviceaccount/token audience: sts.amazonaws.com, 만료 86400초(24시간)로 자동 갱신
Deployment YAML에는 이 항목이 없다. kubectl get deploy -o yaml과 kubectl describe pod를 비교해 보면 차이가 보인다. Deployment 명세에는 정의하지 않았는데 Pod에는 들어 있는 Env와 Volume이 바로 webhook이 끼워넣은 것이다.
2.3 실습: AWS LBC를 IRSA로 설치하고 주입 결과 확인하기
AWS Load Balancer Controller(LBC)를 IRSA로 설치하면서 위에서 설명한 구조를 직접 확인해 보자. 현재 Node IAM Role에는 ELB 관련 권한이 없는 상태다.
OIDC Provider 등록 확인
EKS 클러스터에는 전용 OIDC Provider가 있다. IAM에 등록되어 있는지 확인한다.
oidc_id=$(aws eks describe-cluster --name myeks \
--query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
echo $oidc_id
aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4
OIDC ID가 출력되면 등록된 상태다. 출력이 없으면 eksctl utils associate-iam-oidc-provider로 등록해야 한다.
IAM Policy 생성
LBC가 ALB/NLB를 제어하려면 관련 IAM 권한이 필요하다.
curl -o aws_lb_controller_policy.json \
https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/refs/heads/main/docs/install/iam_policy.json
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://aws_lb_controller_policy.json
IRSA 생성 (iamserviceaccount)
eksctl create iamserviceaccount는 CloudFormation을 통해 Kubernetes SA와 IAM Role을 한 번에 만들고 Trust Policy로 연결한다.
CLUSTER_NAME=myeks
eksctl create iamserviceaccount \
--cluster=$CLUSTER_NAME \
--namespace=kube-system \
--name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
--override-existing-serviceaccounts \
--approve
생성 결과를 확인한다.
# IRSA 목록 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
# SA에 IAM Role ARN annotation 확인
kubectl get sa -n kube-system aws-load-balancer-controller -o yaml
# annotations:
# eks.amazonaws.com/role-arn: arn:aws:iam::XXXX:role/eksctl-myeks-addon-iamserviceaccount-...
Trust Policy 구조 확인
IAM 콘솔에서 생성된 Role의 Trust Policy를 보면 이런 구조다.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::XXXX:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks....:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller",
"oidc.eks....:aud": "sts.amazonaws.com"
}
}
}]
}
Principal이 EKS 클러스터의 OIDC Provider다. Condition에서 sub(SA 이름)와 aud(sts.amazonaws.com)를 확인한다. "이 OIDC Provider가 발급한 토큰 중에서 kube-system 네임스페이스의 aws-load-balancer-controller SA가 가진 토큰만 이 Role을 assume할 수 있다"는 뜻이다.
Helm으로 LBC 설치 및 주입 확인
SA는 이미 만들었으므로 serviceAccount.create=false로 설치한다.
helm repo add eks https://aws.github.io/eks-charts
helm repo update
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system --version 3.1.0 \
--set clusterName=$CLUSTER_NAME \
--set serviceAccount.name=aws-load-balancer-controller \
--set serviceAccount.create=false \
--set enableCertManager=true
LBC Pod를 describe해서 webhook이 주입한 항목을 확인한다.
kubectl describe pod -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
Environment:
AWS_STS_REGIONAL_ENDPOINTS: regional
AWS_DEFAULT_REGION: ap-northeast-2
AWS_REGION: ap-northeast-2
AWS_ROLE_ARN: arn:aws:iam::XXXX:role/eksctl-myeks-addon-...
AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
Mounts:
/var/run/secrets/eks.amazonaws.com/serviceaccount from aws-iam-token (ro)
Volumes:
aws-iam-token:
Type: Projected
TokenExpirationSeconds: 86400
Deployment YAML에는 AWS_ROLE_ARN이나 aws-iam-token 볼륨이 정의되어 있지 않다. 비교해 보면 webhook 주입을 눈으로 확인할 수 있다.
kubectl get deploy -n kube-system aws-load-balancer-controller -o yaml | grep -c AWS_ROLE_ARN
# 0 (Deployment에는 없음)
두 번째 토큰의 audience도 확인해 보자.
kubectl get pod -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller \
-o yaml | grep -A3 'serviceAccountToken'
# audience: sts.amazonaws.com
# expirationSeconds: 86400
# path: token
섹션 1.2에서 본 기본 SA 토큰은 aud: https://kubernetes.default.svc였다. IRSA가 주입한 두 번째 토큰은 aud: sts.amazonaws.com이다. 같은 Pod에 토큰이 두 개 마운트되는 셈이다. 하나는 K8s API용이고 다른 하나는 AWS STS용이다.
2.4 실습: S3 ReadOnly IRSA로 권한 경계 확인하기
이번에는 S3 읽기 전용 권한만 가진 IRSA를 직접 만들어서 권한 경계가 어떻게 동작하는지 확인해 보자.
eksctl create iamserviceaccount \
--name my-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--approve \
--role-name eksctl-myeks-pod-irsa-s3-readonly-role \
--attach-policy-arn $(aws iam list-policies \
--query 'Policies[?PolicyName==`AmazonS3ReadOnlyAccess`].Arn' --output text)
이 SA를 사용하는 Pod를 생성한다.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test3
spec:
serviceAccountName: my-sa
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
command: ['sleep', '36000']
restartPolicy: Never
terminationGracePeriodSeconds: 0
EOF
주입된 IRSA 토큰을 디코딩해 본다.
SA_TOKEN=$(kubectl exec -it eks-iam-test3 -- \
cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token)
jwt decode $SA_TOKEN --json --iso8601
{
"aud": ["sts.amazonaws.com"],
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX",
"kubernetes.io": {
"namespace": "default",
"pod": { "name": "eks-iam-test3" },
"serviceaccount": { "name": "my-sa" }
},
"sub": "system:serviceaccount:default:my-sa"
}
aud가 sts.amazonaws.com이고 sub가 system:serviceaccount:default:my-sa다. Trust Policy의 Condition에 적힌 값과 정확히 대응된다. 이 조합이 맞아야 STS가 임시 자격증명을 발급한다.
권한 경계를 확인해 보자.
# 어떤 Role로 인증되었는지 확인
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
# "arn:aws:sts::XXXX:assumed-role/eksctl-myeks-pod-irsa-s3-readonly-role/botocore-session-..."
# S3는 된다
kubectl exec -it eks-iam-test3 -- aws s3 ls
# EC2는 안 된다
kubectl exec -it eks-iam-test3 -- aws ec2 describe-instances --region ap-northeast-2
# An error occurred (UnauthorizedOperation)
# VPC도 안 된다
kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2
# An error occurred (UnauthorizedOperation)
S3ReadOnlyAccess 정책만 붙었으므로 S3만 접근 가능하고 나머지는 전부 거부된다. 섹션 1.1에서 노드 IAM Role로는 불가능했던 Pod 단위 최소 권한이 동작하는 것이다.
CloudTrail에서 AssumeRoleWithWebIdentity 이벤트도 확인할 수 있다.
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleWithWebIdentity \
--max-items=1 | jq '.Events[] | (.CloudTrailEvent | fromjson) | {eventName, eventSource, userIdentity}'
userIdentity.type이 WebIdentityUser이고 identityProvider에 EKS OIDC Provider ARN이 찍혀 있다. 섹션 1.1에서 노드 IAM Role만 보이던 것과 비교하면 누가 호출했는지 추적이 가능해진 것이다.
# 리소스 정리
kubectl delete pod eks-iam-test3
eksctl delete iamserviceaccount --cluster $CLUSTER_NAME --name my-sa --namespace default
3. Pod Identity - OIDC 없이 더 단순하게
EKS Pod Identity는 2023년에 나온 인증 방식이다. IRSA처럼 Pod 단위 IAM 권한을 부여하지만 OIDC Provider 등록이 필요 없다. EKS 1.24 이상에서 사용할 수 있다.
3.1 Pod Identity Agent가 동작하는 방식

IRSA에서는 Pod 안의 SDK가 직접 STS를 호출했다. Pod Identity는 각 노드에 설치된 Agent가 인증을 대행하는 구조다.
eks-pod-identity-agent는 EKS addon으로 설치되는 DaemonSet이다. hostNetwork: true로 노드 네트워크를 직접 사용하며 link-local 주소 169.254.170.23의 port 80에서 요청을 수신한다.
# DaemonSet 확인
kubectl -n kube-system get daemonset eks-pod-identity-agent
kubectl get ds -n kube-system eks-pod-identity-agent -o yaml | grep -A2 hostNetwork
# hostNetwork: true
노드에 SSH로 접속해서 네트워크 상태를 직접 확인해 보면 구조가 보인다.
# Agent가 리스닝하는 포트 확인
sudo ss -tnlp | grep eks-pod-identit
# LISTEN 169.254.170.23:80 users:(("eks-pod-identit",...))
# LISTEN 127.0.0.1:2703 users:(("eks-pod-identit",...))
# link-local 인터페이스 확인
sudo ip -c addr show pod-id-link0
# inet 169.254.170.23/32 scope global pod-id-link0
pod-id-link0이라는 가상 인터페이스에 169.254.170.23 주소가 할당되어 있다. Pod가 이 주소로 자격증명을 요청하면 Agent가 EKS Auth API(AssumeRoleForPodIdentity)를 호출하여 임시 자격증명을 받아 돌려준다.
link-local 주소를 사용하는 건 AWS 메타데이터 서비스(IMDS, 169.254.169.254)와 같은 패턴이다. Pod에서 별도 설정 없이 고정된 주소로 접근할 수 있어서 편리하다. CAP_NET_BIND_SERVICE capability로 권한이 부여된 80 포트를 사용한다.
3.2 실습: podidentityassociation으로 S3 접근 설정하기
IRSA에서는 eksctl create iamserviceaccount를 썼다. Pod Identity에서는 eksctl create podidentityassociation을 쓴다.
eksctl create podidentityassociation \
--cluster $CLUSTER_NAME \
--namespace default \
--create-service-account \
--service-account-name s3-sa \
--role-name s3-eks-pod-identity-role \
--permission-policy-arns arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
--region ap-northeast-2
생성된 연결을 확인한다.
eksctl get podidentityassociation --cluster $CLUSTER_NAME
# NAMESPACE SERVICE ACCOUNT NAME IAM ROLE ARN
# default s3-sa arn:aws:iam::XXXX:role/s3-eks-pod-identity-role
aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME | jq
Trust Policy 비교
생성된 IAM Role의 Trust Policy를 확인하면 IRSA와 확연히 다르다.
aws iam get-role --query 'Role.AssumeRolePolicyDocument' \
--role-name s3-eks-pod-identity-role | jq .
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}]
}
IRSA의 Trust Policy에는 OIDC Provider ARN과 SA 이름까지 Condition에 들어갔다. Pod Identity는 pods.eks.amazonaws.com 서비스만 Principal로 지정하면 끝이다. OIDC Provider URL도 없고 SA를 명시하는 Condition도 없다. sts:TagSession은 세션 태그 기능(ABAC)을 위한 것이다.
Pod 생성 및 환경변수 확인
이 SA를 사용하는 Pod를 생성한다.
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: eks-pod-identity
spec:
serviceAccountName: s3-sa
containers:
- name: my-aws-cli
image: amazon/aws-cli:latest
command: ['sleep', '36000']
restartPolicy: Never
terminationGracePeriodSeconds: 0
EOF
환경변수를 확인하면 IRSA와 다른 변수가 주입되어 있다.
kubectl exec -it eks-pod-identity -- env | grep AWS
# AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
# AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials
# AWS_STS_REGIONAL_ENDPOINTS=regional
# AWS_DEFAULT_REGION=ap-northeast-2
# AWS_REGION=ap-northeast-2
IRSA는 AWS_ROLE_ARN과 AWS_WEB_IDENTITY_TOKEN_FILE을 주입했다. Pod Identity는 AWS_CONTAINER_CREDENTIALS_FULL_URI로 link-local Agent 주소를 넣어준다. SDK가 이 URL로 자격증명을 요청하는 방식이다.
토큰 디코딩
kubectl exec -it eks-pod-identity -- \
cat /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
{
"aud": ["pods.eks.amazonaws.com"],
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/XXXX",
"kubernetes.io": {
"namespace": "default",
"pod": { "name": "eks-pod-identity" },
"serviceaccount": { "name": "s3-sa" }
},
"sub": "system:serviceaccount:default:s3-sa"
}
aud가 pods.eks.amazonaws.com이다. IRSA는 sts.amazonaws.com, 기본 SA는 kubernetes.default.svc였다. 토큰의 aud 값만 비교해도 세 방식이 구분된다.
link-local 직접 호출
Pod 안에서 Agent의 link-local 주소로 직접 자격증명을 요청해 볼 수 있다.
kubectl exec -it eks-pod-identity -- bash
# Pod 내부에서 실행
EKS_POD_IDENTITY_TOKEN=$(cat $AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE)
curl -s 169.254.170.23/v1/credentials \
-H "Authorization: $EKS_POD_IDENTITY_TOKEN" | jq
{
"AccessKeyId": "ASIA...",
"SecretAccessKey": "NGY/...",
"Token": "IQoJb3...",
"Expiration": "2026-04-02T16:14:05Z"
}
Agent가 EKS Auth API를 대신 호출해서 받아온 임시 자격증명이 그대로 돌아온다. SDK는 내부적으로 이 과정을 자동으로 처리하는 것이다. AWS 자격증명의 3요소(AccessKeyId, SecretAccessKey, Token)가 모두 들어 있다.
S3 접근 및 CloudTrail 확인
kubectl exec -it eks-pod-identity -- aws sts get-caller-identity --query Arn
# "arn:aws:sts::XXXX:assumed-role/s3-eks-pod-identity-role/..."
kubectl exec -it eks-pod-identity -- aws s3 ls
# (버킷 목록 출력)
CloudTrail에서는 AssumeRoleForPodIdentity 이벤트로 기록된다. IRSA의 AssumeRoleWithWebIdentity와 이벤트 이름부터 다르다.
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRoleForPodIdentity \
--max-items=1 | jq '.Events[] | (.CloudTrailEvent | fromjson) | {eventName, eventSource}'
eventSource가 eks-auth.amazonaws.com인 것을 확인할 수 있다. IRSA는 sts.amazonaws.com이었다. 인증 경로 자체가 다르기 때문이다.
# 리소스 정리
kubectl delete pod eks-pod-identity
eksctl delete podidentityassociation \
--cluster $CLUSTER_NAME --namespace default --service-account-name s3-sa
kubectl delete sa s3-sa
3.3 IRSA에서 뭐가 달라졌나
두 방식을 직접 실습하면서 확인한 차이를 정리한다.
| 항목 | IRSA | Pod Identity |
|---|---|---|
| Trust Policy | OIDC Provider를 Federated Principal로 지정 + Condition에 sub, aud 명시 | pods.eks.amazonaws.com 서비스 주체만 지정 |
| 토큰 audience | sts.amazonaws.com |
pods.eks.amazonaws.com |
| 인증 경로 | Pod SDK가 STS를 직접 호출 | Pod가 link-local Agent에 요청, Agent가 EKS Auth API 호출 |
| 클러스터 확장 | 새 클러스터마다 OIDC 등록 필요, Trust Policy에 추가해야 함 | 동일 Role 재사용 가능, Trust Policy 수정 불필요 |
| 세션 태그 | 미지원 | 클러스터명, 네임스페이스, SA명이 세션 태그로 붙어 ABAC 가능 |
| CloudTrail 이벤트 | AssumeRoleWithWebIdentity (sts.amazonaws.com) |
AssumeRoleForPodIdentity (eks-auth.amazonaws.com) |
클러스터 확장 시 차이가 실무에서 체감이 크다. IRSA는 EKS 클러스터를 새로 만들 때마다 OIDC Provider를 등록하고 기존 IAM Role의 Trust Policy에 새 OIDC Provider를 추가해야 한다. Trust Policy 크기 제한 때문에 하나의 Role에 최대 8개 클러스터까지만 연결할 수 있다. Pod Identity는 클러스터가 늘어나도 같은 Role에 podidentityassociation만 추가하면 된다.
'AWS > EKS' 카테고리의 다른 글
| EKS Multi-tenant SaaS GitOps 워크샵(Flux v2 + Argo Workflows) (0) | 2026.04.27 |
|---|---|
| [AEWS4] EKS IRSA 트러블슈팅 가이드 (0) | 2026.04.19 |
| EKS 컴퓨팅과 오토스케일링 - AEWS4 3주차 (0) | 2026.04.03 |
| [ AEWS4 ] EKS 네트워킹 살펴보기 (0) | 2026.03.25 |
| [AEWS4] EKS가 만들어주는 AWS 리소스 들여다보기 (0) | 2026.03.19 |