- Published on
EKS OIDC Provider 삭제로 IRSA 전부 실패했을 때 복구
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서로 다른 팀/파이프라인이 같은 EKS 클러스터를 쓰는 환경에서 IAM OIDC Provider를 삭제해버리면, 그 순간부터 IRSA(IAM Roles for Service Accounts) 기반의 모든 Pod가 AWS API 호출에 실패하기 시작합니다. 증상은 대개 "어제까지 되던 S3/STS 호출이 갑자기 전부 AccessDenied"처럼 보이지만, 실제로는 OIDC 연동 자체가 끊겨 STS가 웹 아이덴티티 토큰을 신뢰하지 못하는 상태가 됩니다.
이 글은 “OIDC Provider 삭제 → IRSA 전부 실패” 상황에서 정확히 무엇이 망가졌는지를 빠르게 확인하고, OIDC Provider를 재생성한 뒤, 각 IAM Role의 Trust Policy와 Kubernetes ServiceAccount 설정을 복구해서 정상화하는 절차를 단계별로 다룹니다.
관련해서 IRSA에서 STS AccessDenied를 더 넓은 관점으로 점검하는 체크리스트는 아래 글도 함께 보면 좋습니다.
1) 장애 시그널: 어떤 에러가 뜨나
OIDC Provider가 사라지면 IRSA는 다음 패턴으로 터집니다.
- 앱 로그/SDK 에러
AccessDenied/InvalidIdentityTokenNo OpenIDConnect provider found in your account for https://oidc.eks.<region>.amazonaws.com/id/<CLUSTER_ID>AssumeRoleWithWebIdentity호출 실패
- Kubernetes 이벤트는 대체로 조용합니다(컨테이너는 뜨지만 AWS 호출이 실패).
즉, Pod는 Running인데 AWS API만 실패하는 형태가 흔합니다.
2) 왜 전부 실패하나: IRSA 동작 원리에서의 “끊긴 고리”
IRSA는 요약하면 다음 흐름입니다.
- Pod 안에서
AWS_WEB_IDENTITY_TOKEN_FILE(서비스어카운트 토큰)을 읽음 - SDK가
sts:AssumeRoleWithWebIdentity호출 - STS는 토큰의
iss(issuer)가 가리키는 IAM OIDC Provider를 찾아 신뢰 여부 확인 - IAM Role의 Trust Policy(Condition의
sub,aud)가 토큰 클레임과 일치하면 임시 자격증명 발급
여기서 3번의 OIDC Provider가 삭제되면 STS가 issuer를 검증할 수 없어서, 클러스터 내 모든 IRSA가 동시에 무너집니다.
3) 10분 내 원인 확정: OIDC Provider 존재 여부 확인
3.1 클러스터 OIDC Issuer 확인
aws eks describe-cluster \
--name <cluster-name> \
--region <region> \
--query "cluster.identity.oidc.issuer" \
--output text
출력 예:
https://oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B716D3041E
3.2 IAM에 OIDC Provider가 남아있는지 확인
aws iam list-open-id-connect-providers --query "OpenIDConnectProviderList[].Arn" --output text
각 Provider의 URL은 아래로 확인합니다.
aws iam get-open-id-connect-provider \
--open-id-connect-provider-arn <provider-arn>
Url 목록에 위에서 확인한 oidc.eks.../id/<ID>가 없다면, 삭제된 것이 확정입니다.
4) 복구 핵심: OIDC Provider를 “클러스터 Issuer와 동일하게” 재생성
OIDC Provider는 EKS 클러스터의 issuer URL과 thumbprint, 그리고 **client ID(aud)**가 정확해야 합니다. EKS IRSA의 client ID는 일반적으로 sts.amazonaws.com입니다.
가장 안전한 방법은 eksctl로 재연결(재생성)하는 것입니다.
4.1 eksctl로 OIDC Provider 재생성
eksctl utils associate-iam-oidc-provider \
--cluster <cluster-name> \
--region <region> \
--approve
성공하면 IAM에 OIDC Provider가 다시 생성됩니다.
> 운영 환경에서는 이 단계가 가장 중요합니다. OIDC Provider를 콘솔에서 수동 생성할 수도 있지만, thumbprint/URL 오타로 시간이 크게 늘어납니다.
4.2 (검증) 생성 후 issuer가 매칭되는지 확인
ISSUER=$(aws eks describe-cluster --name <cluster-name> --region <region> \
--query "cluster.identity.oidc.issuer" --output text)
aws iam list-open-id-connect-providers --query "OpenIDConnectProviderList[].Arn" --output text | \
tr '\t' '\n' | while read -r arn; do
url=$(aws iam get-open-id-connect-provider --open-id-connect-provider-arn "$arn" --query Url --output text)
if [ "https://$url" = "$ISSUER" ]; then
echo "MATCH: $arn -> $url"
fi
done
MATCH가 찍히면 “OIDC Provider 복구”는 완료입니다.
5) 두 번째 복구 포인트: IAM Role Trust Policy가 여전히 올바른가
OIDC Provider를 다시 만들었는데도 일부 워크로드가 계속 실패한다면, 다음을 의심해야 합니다.
- Role의 Trust Policy가 이전 OIDC Provider ARN을 Principal로 잡고 있었고, 재생성 후 ARN이 달라짐
Condition의sub(serviceaccount) 또는aud가 실제 토큰과 불일치
5.1 Trust Policy에서 가장 흔히 망가지는 부분
IRSA Trust Policy 예시는 아래와 같습니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::<ACCOUNT_ID>:oidc-provider/oidc.eks.<region>.amazonaws.com/id/<CLUSTER_ID>"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.<region>.amazonaws.com/id/<CLUSTER_ID>:aud": "sts.amazonaws.com",
"oidc.eks.<region>.amazonaws.com/id/<CLUSTER_ID>:sub": "system:serviceaccount:<namespace>:<serviceaccount>"
}
}
}
]
}
여기서 Federated ARN이 현재 계정에 존재하는 OIDC Provider ARN과 일치해야 합니다.
5.2 OIDC Provider ARN을 기준으로 Trust Policy 일괄 점검
- 현재 클러스터 issuer에 해당하는 OIDC Provider ARN 찾기
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=<region>
CLUSTER_ID=<cluster-id-from-issuer>
OIDC_ARN=$(aws iam list-open-id-connect-providers --query "OpenIDConnectProviderList[].Arn" --output text | \
tr '\t' '\n' | grep "oidc-provider/oidc.eks.${REGION}.amazonaws.com/id/${CLUSTER_ID}" | head -n 1)
echo "$OIDC_ARN"
- 특정 Role의 trust policy 확인
aws iam get-role --role-name <role-name> --query "Role.AssumeRolePolicyDocument" --output json
Federated가 위 OIDC_ARN과 다르면, 정상적으로 STS가 신뢰하지 않습니다.
5.3 Trust Policy 수정(예: aws cli)
cat > trust.json <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "REPLACE_WITH_OIDC_ARN"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"REPLACE_WITH_ISSUER_HOSTPATH:aud": "sts.amazonaws.com",
"REPLACE_WITH_ISSUER_HOSTPATH:sub": "system:serviceaccount:default:my-sa"
}
}
}
]
}
JSON
# 편의상 sed로 치환(환경에 맞게 수정)
OIDC_ARN='<oidc-provider-arn>'
ISSUER_HOSTPATH='oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLE...'
sed -i.bak "s|REPLACE_WITH_OIDC_ARN|$OIDC_ARN|g" trust.json
sed -i.bak "s|REPLACE_WITH_ISSUER_HOSTPATH|$ISSUER_HOSTPATH|g" trust.json
aws iam update-assume-role-policy --role-name <role-name> --policy-document file://trust.json
> ISSUER_HOSTPATH는 https://를 뺀 host/path 형태로 들어갑니다. (Trust policy key는 oidc.eks...:sub 형태)
6) 세 번째 복구 포인트: Kubernetes ServiceAccount annotation 확인
IRSA는 ServiceAccount에 아래 annotation이 있어야 합니다.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-sa
namespace: default
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::<ACCOUNT_ID>:role/<role-name>
확인:
kubectl get sa my-sa -n default -o yaml
annotation이 없다면, 해당 Pod는 IRSA를 쓰지 못하고(또는 노드 IAM으로 떨어져) 다른 형태의 실패를 유발할 수 있습니다.
7) 실제로 “복구됐는지” 확인하는 가장 빠른 방법
7.1 Pod 안에서 현재 자격증명 확인
AWS CLI가 들어있는 디버그 Pod로 확인하는 게 빠릅니다.
kubectl run -n default irsa-debug \
--rm -it --restart=Never \
--image public.ecr.aws/aws-cli/aws-cli:2.15.0 \
--serviceaccount my-sa \
--command -- sh
Pod 내부에서:
aws sts get-caller-identity
- 기대 결과:
Arn이assumed-role/<role-name>/...형태로 나와야 합니다. - 실패한다면 에러 메시지에
No OpenIDConnect provider found/InvalidIdentityToken/AccessDenied가 섞여 나옵니다.
7.2 토큰 클레임(sub/aud) 확인(필요 시)
cat $AWS_WEB_IDENTITY_TOKEN_FILE | awk -F. '{print $2}' | base64 -d 2>/dev/null | jq
여기서 aud, sub, iss를 보고 Trust Policy의 Condition과 정확히 맞는지 확인합니다.
8) 운영에서 자주 겪는 함정 4가지
8.1 OIDC Provider를 재생성하면 ARN이 바뀔 수 있다
OIDC Provider는 “URL이 같아도” 리소스 ARN은 새로 만들어질 수 있습니다. Trust Policy의 Principal.Federated가 옛 ARN을 가리키면 계속 실패합니다.
8.2 Trust Policy의 Condition key 오타
oidc.eks.<region>.amazonaws.com/id/<CLUSTER_ID>:sub에서 <CLUSTER_ID>가 틀리거나, region이 다르면 무조건 실패합니다.
8.3 ServiceAccount 교체/롤링이 안 되어 토큰이 갱신되지 않는다고 착각
대부분은 OIDC/Trust 문제지만, 워크로드가 오래 살아있고 토큰/환경변수 상태가 애매하면 Deployment 롤링 재시작으로 증상이 정리되는 경우가 있습니다.
kubectl rollout restart deploy/<deploy-name> -n <namespace>
8.4 IRSA와 노드 IAM 권한이 섞여 “일부만” 되는 것처럼 보임
어떤 Pod는 노드 IAM으로도 동작(예: 읽기 권한은 노드에 있음)하고, 어떤 Pod는 IRSA 전용 권한이 필요해 실패하면서 장애가 더 헷갈립니다. sts get-caller-identity로 “누구로 호출하는지”부터 고정하세요.
9) 재발 방지: 삭제 사고를 막는 실전 가드레일
- IAM OIDC Provider 삭제 권한 제한
- 최소한
iam:DeleteOpenIDConnectProvider는 운영 계정에서 강하게 제한
- Terraform/CloudFormation으로 OIDC Provider를 코드로 관리
- 수동 생성/삭제를 줄이고, drift를 감지
- IRSA 핵심 Role에 대한 자동 점검
- 정기적으로
assume role with web identity성공 여부를 canary job으로 확인
- 변경 작업 전 체크리스트화
- “클러스터 OIDC issuer 확인 → IAM OIDC Provider 존재 확인 → 주요 Role trust principal 일치 확인”을 릴리즈 체크에 포함
10) 복구 요약(런북 형태)
- (A) 클러스터 issuer 확인:
aws eks describe-cluster ... identity.oidc.issuer - (B) IAM OIDC Provider 존재 확인:
aws iam list-open-id-connect-providers - (C) 없으면 재생성:
eksctl utils associate-iam-oidc-provider --approve - (D) 주요 Role trust policy의
Principal.Federated가 새 OIDC Provider ARN인지 확인/수정 - (E) ServiceAccount annotation 확인:
eks.amazonaws.com/role-arn - (F) 디버그 Pod로
aws sts get-caller-identity확인
이 순서대로 하면 “OIDC Provider 삭제로 IRSA 전부 실패” 상황은 대개 30~60분 내에 안정적으로 복구됩니다. 핵심은 OIDC Provider 복구만으로 끝나지 않고, Trust Policy의 Federated ARN/Condition까지 함께 맞춰야 한다는 점입니다.