aws-auth → K8S 오브젝트 (ConfigMap) 로 관리
Access Entry → AWS API 로 관리
관리 주체에 따라 모든 차이가 파생됩니다 !
그래서 즉, aws-auth의 보안 취약한 단점과 락아웃되는 단점들을 보완하여
관리 주체가 AWS API인 Access Entry로 Migration 하는 추세이며, 가독성이 좋게 표로 정리하겠습니다.
항목
aws-auth
Access Entry
관리 위치
kube-system ConfigMap
EKS API / 콘솔
수정 권한
kubectl 권한자
IAM 권한자
락아웃 위험
있음 ⚠️
없음 ✅
CloudTrail 감사
안 됨
됨 ✅
노드 그룹 등록
수동
type 지정으로 자동 ✅
AWS 관리형 정책
없음
있음 ✅
마이그레이션
-
API_AND_CONFIG_MAP 모드로 병행 가능
02. Authorization (인가)
운영자가 "kubectl" 명령을 쳤을 때 인증을 받고나면 인가 부분에서 EKS 표준인 RBAC에 아래와 같이 물어봅니다.
1. 인증 완료
→ username: "devuser"
→ groups: ["dev-group"]
이 두 가지가 확정됨
2. API Server가 RBAC에 물어봄
→ "devuser가 default 네임스페이스에서
pods를 get 할 수 있어?"
3. RBAC가 RoleBinding 뒤짐
→ dev-group이 pod-reader Role에 묶여있네
→ pod-reader는 pods get 허용하네
→ 허용
"dev 팀은 월~금 09:00~18:00에만 배포 가능"
"production NS에는 image tag가 latest인 Pod 배포 금지"
"특정 레이블 없는 리소스는 생성 불가"
이런 시간, 레이블, 비즈니스 규칙 기반 정책은 RBAC verb/resource 체계로 표현 불가능합니다.
그래서 이 방식은 Webhook으로 외부 정책 엔진에 위임하는 방식입니다.
그래서 결론적으로 RBAC + Node vs Webhook 뭘 사용해야 할까요?
RBAC → "누가 어떤 리소스에 어떤 동작을" 제어
Webhook → "어떤 조건일 때" 제어 (시간, 레이블, 비즈니스 규칙 등)
둘 관계는 베타적이지 않습니다.
귀사의 내부 정책이나, 비즈니스 요구사항에 맞춰서 협의하여 운영하시면 되겠습니다.
03. Admission Control
전체 흐름을 한줄 요약하자면, 인증/인가에 통과한 요청에 대해서
변조 확인, 정책 검사, 외부 검사를 통해 최종적으로 허용/거부를 해주는 녀석입니다.
위 다이어그램으로 단계별로 설명드리도록 하겠습니다.
1) User → API Server → Authentication + Authorization
사용자가 "Pod 만들어줘" 요청
→ 인증 (너 누구야)
→ 인가 (이 작업 해도 돼)
이 부분은 위에서 설명드렸던 인증 / 인가 관련된 부분입니다.
2) Mutating Webhook(s)
"For all Validating Policies" 부분이 등록된 Mutating Webhook이 여러개면 순서대로 하나씩 돌아요 (Loop)
그렇다면, Mutating이 하는 일을 예시로 들어본다면,
- resource limit 없는 Pod → 기본값 자동 주입
- 레이블 없는 Pod → 레이블 자동 추가
- Istio sidecar 자동 삽입
여기서 중요한 점은 거부도 가능합니다. Modify or reject 라고 적혀있는 것이
수정도 가능하고 거부도 가능하다는 의미입니다.
3) Validating Admission Policies (정책 위반 검사)
여기서도 마찬가지로 Webhook이 여러개면 순서대로 하나씩 돌아요 (Loop)
Validating이 하는 일을 예시로 들어본다면,
- image tag가 latest면 거부
- resource limit 없으면 거부
- 특정 레이블 없으면 거부
즉, Mutating과 차이는 거부만 가능하다는 점이겠네요 (Validating은 오브젝트 수정X)
4) Validating Webhook(s)
위 두 가지 Mutating과 Validating은 Loop 였지만 이 녀석은 par 입니다.
즉, 루프 도는 녀석이 아닌 병렬적으로 전부 동시에 처리합니다.
그렇다면, 왜 얘만 병렬로 처리할까요?
Mutating은 순서가 중요합니다.
→ A가 수정한 결과를 B가 봐야 하니까 직렬
Validating Webhook은 순서가 상관이 없어요.
→ 그냥 "이 오브젝트 괜찮아?" 물어보는 거라
→ 동시에 다 물어보고 하나라도 reject 하면 거부
→ 병렬로 처리해서 빠르게
그래서 결론적으론 아래와 같이 동작합니다.
Mutating Webhooks 루프(직렬) - 수정 가능
↓
Validating Policies 루프(직렬) - 거부만
↓
Validating Webhooks 병렬 - 거부만
↓
전부 통과 → etcd 저장
04. 실제 인증 상세 흐름도
복잡한 구조여서 인증-인가-Admission Control 단계를 지나 다시 흐름을 복습하고자 해당 챕터를 마련했습니다.
1) 토큰 생성 (Client Side)
사용자가 'kubectl' 명령을 치기 전에 먼저 "내가 누구인지 증명할 토큰"이 필요합니다.
일반 K8S는 인증서나 static token을 쓰지만 EKS는 IAM 자격증명으로 Pre-signed URL을 만들어서 토큰으로 사용해요.
'aws eks get-token' 명령을 치면 AWS CLI가 로컬에 저장된 IAM 자격증명으로
STS GetCallerIdentity URL에 서명을 해서 반환해줍니다.
핵심은 이 URL 자체가 토큰이라는 거에요 ! 실제 API 호출은 아직 안 했고, "나중에 이 URL로 호출하면 내가 누구인지 증명할 수 있어" 라는 서명된 약속을 만든 것뿐입니다. 추가적으로, X-Amz-Expires가 60초로 되어있는데 토큰 만료 시간입니다. (탈취당해도 60초만 유효함)
2) API Server에 요청
토큰이 생겼으면 이제 kubectl이 실제 요청을 보냅니다.
Bearer Token으로 이 Pre-signed URL을 담아서 API Server에 전달하겠죠 ?
여기서 포인트는, API Server는 이 토큰을 직접 검증할 수 없습니다.
왜냐하면 이건 AWS STS 서명이라서 K8S가 AWS IAM을 모르기 때문입니다.
그래서 API Server는 Webhook Token Authentication 방식으로 aws-iam-authenticator server에
검증을 위임합니다. 이게 K8S의 확장 포인트에요.
3) Token Review
API Server가 토큰 검증을 외부에 위임하는 방식이 바로 TokenReview입니다.
TokenReview는 K8S 표준 오브젝트 입니다.
API Server가 aws-iam-authenticator server에 아래와 같은 요청을 보냅니다.
"이 Bearer Token, 유효한 거야?
유효하면 이게 어떤 사용자야?"
aws-iam-authenticator server는 이걸 받아서 다음 단계인 STS 검증으로 넘어가겠죠.
4) STS 검증 및 IAM ARN 반환
aws-iam-authenticator server가 토큰(Pre-signed URL)을 실제로 실행해서 진짜 신원을 확인하는 단계.
aws-iam-authenticator server가 Pre-signed URL을 가지고 STS GetCallerIdentity를 실제로 호출합니다.
① 관리자가 kubectl 명령
② AWS-IAM-Authenticator Client가 Pre-signed URL 생성 (토큰 발급)
③ kubectl이 API Server에 Action + Token 전달
④ API Server가 Id Token 확인
⑤ AWS-IAM-Authenticator Server가 STS에 GetCallerIdentity 호출
⑥ STS가 성공 응답 (IAM ARN 반환)
⑦ aws-auth ConfigMap에서 K8S User 확인 (ARN → username/group 매핑)
⑧ K8S RBAC에서 RoleBinding 확인
⑨ 허용/차단 결과 반환
결국 EKS 인증의 핵심은 IAM이라는 외부 신원 체계를 K8S가 이해할 수 있는 username, group으로
번역해주는 것이고, 그 번역 사전 역할을 하는 것이 aws-auth ConfigMap 또는 Access Entry 입니다.
05. Managing Service Accounts
ServiceAccount 토큰이 실제로 어떻게 동작할까?에 대해 다뤄보는 챕터입니다.
토큰 발급 방식
Pod가 뜰 때 자동으로 아래 경로에 토큰이 마운트 됩니다.
/var/run/secrets/kubernetes.io/serviceaccount/
├── token ← JWT 토큰
├── ca.crt ← API Server 인증서 검증용
└── namespace ← 현재 네임스페이스
예전 방식은 Static JWT 였어요 (토큰의 만료 기간이 없었고, Secret Object로 저장됨)
토큰의 만료 기간이 없다면 토큰이 영구적으로 유효하게 되고, 탈취당하면 답이 없어집니다.
그래서 지금은 Bound Service Account Token 방식으로 바뀌었습니다.
만료시간 있음 (기본 1시간)
audience 포함 (어떤 서비스용 토큰인지)
Pod 삭제되면 자동 무효화
kubelet이 만료 전에 자동 갱신
Static JWT 방식 vs Bound Service Account Token 방식을 JWT로 디코딩해서 비교해보면
이게 위에서 설명드렸던 Node Authorizer가 처리하는 system:node:<nodeName> 형식입니다.
📌API Server → kubelet 인증 (인바운드)
반대로 API Server가 kubelet에 요청을 보낼 때도 있습니다.
kubectl logs → API Server가 kubelet에 로그 요청
kubectl exec → API Server가 kubelet에 exec 요청
kubectl port-forward
이때 kubelet은 두 가지 방식으로 인증 / 인가를 처리합니다.
# 인증 2가지
Anonymous → 인증 없이 접근 허용 (기본값, 위험 ⚠️)
Webhook → API Server에 "이 요청자 인증됐어?" 물어봄 (권장)
#인가 2가지
AlwaysAllow → 전부 허용 (위험 ⚠️)
Webhook → API Server RBAC에 위임 (권장)