블로그 불러오는 중...
문의 보내기
남겨주면 블로그 주인에게 바로 전달돼요.
오늘은 kubectl get pods 등 쿠버네티스 명령어를 쳤을 때 어떻게 인증이 되어 결과를 보여주는 지에 대해서 실습을 한다.
# 코드 다운로드, 작업 디렉터리 이동
git clone https://github.com/gasida/aews.git
cd aews/4w
# 배포 : 12분 소요
terraform init
terraform plan
nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
tail -f create.log
# EKS 자격증명 설정
$(terraform output -raw configure_kubectl)
kubectl config rename-context $(cat ~/.kube/config | grep current-context | awk '{print $2}') myeks
export CLUSTER_NAME=myeks
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
# 기본 정보 확인
kubectl get ds,pod -n kube-system -l app.kubernetes.io/instance=eks-pod-identity-agent
kubectl describe deploy -n external-dns external-dns | grep Args: -A10
kubectl get all -n cert-manager
kubectl get crd | grep cert-manager
# SSM 관리 대상 인스턴스 목록 조회
aws ssm describe-instance-information \
--query "InstanceInformationList[*].{InstanceId:InstanceId, Status:PingStatus, OS:PlatformName}" \
--output text # table
# session-manager-plugin 을 통한 인스턴스 접속
export NODE2=i-049e533d99344c0ad
export NODE2=i-049e533d99344c0ad
aws ssm start-session --target $NODE1
aws ssm start-session --target $NODE2
krew 란 kubectl 플러그인 패키지 매니저이다. 해당 명령어로 krew 를 설치하고, 추후에 패키지를 받아서 권한 등을 조금 더 쉽게 테스트 해 본다.
(
set -x; cd "$(mktemp -d)" &&
OS="$(uname | tr '[:upper:]' '[:lower:]')" &&
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')" &&
KREW="krew-${OS}_${ARCH}" &&
curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/latest/download/${KREW}.tar.gz" &&
tar zxvf "${KREW}.tar.gz" &&
./"${KREW}" install krew
)
export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
source ~/.bashrckrew 를 설치하고 여러가지 플러그인을 테스트 해 본다.
# 설치
kubectl krew install access-matrix rbac-tool rolesum whoami rbac-view
# k8s 인증된 주체 확인
kubectl whoami
# Show an RBAC access matrix for server resources
kubectl access-matrix -h
kubectl access-matrix # Review access to cluster-scoped resources
kubectl access-matrix --namespace default # Review access to namespaced resources in 'default'
# RBAC Lookup by subject (user/group/serviceaccount) name
kubectl rbac-tool -h
kubectl rbac-tool lookup
kubectl rbac-tool lookup system:masters
kubectl rbac-tool lookup system:nodes # eks:node-bootstrapper
kubectl rbac-tool lookup system:bootstrappers # eks:node-bootstrapper
kubectl describe ClusterRole eks:node-bootstrapper
# RBAC List Policy Rules For subject (user/group/serviceaccount) name
kubectl rbac-tool policy-rules
kubectl rbac-tool policy-rules -e '^system:.*'
kubectl rbac-tool policy-rules -e '^system:authenticated'
# Generate ClusterRole with all available permissions from the target cluster
kubectl rbac-tool show
# Shows the subject for the current context with which one authenticates with the cluster
kubectl rbac-tool whoami
# Summarize RBAC roles for subjects : ServiceAccount(default), User, Group
kubectl rolesum -h
kubectl rolesum aws-node -n kube-system # sa
kubectl rolesum -k User system:kube-proxy # user
kubectl rolesum -k Group system:masters # group
kubectl rolesum -k Group system:nodes
kubectl rolesum -k Group system:authenticated
# [운영서버1 EC2 : 터미널1] A tool to visualize your RBAC permissions
kubectl rbac-view
INFO[0000] Getting K8s client
INFO[0000] serving RBAC View and http://localhost:8800
## 이후 해당 운영서버1 EC2 공인 IP:8800 웹 접속 : 최초 접속 후 정보 가져오는데 다시 시간 걸림 (2~3분 정도 후 화면 출력됨)
echo -e "RBAC View Web http://$(curl -s ipinfo.io/ip):8800"
위와 같이, 시각적으로 잘 정리해 주는 유용한 플러그인으로 보인다.
아래는 kubectl 로 명령어를 실행했을 때 AWS 내에서 권한을 검증하는 워크플로우를 정리했다.

1단계: 클라이언트 사이드
kubectl get pods와 같은 명령어를 입력합니다.kubectl은 설정된 aws-iam-authenticator(또는 AWS CLI)를 호출합니다. 이때 AWS STS를 향하는 Pre-signed URL을 생성하여 이를 토큰으로 사용합니다.2단계: API 서버로 요청 (인증 시도)
3단계: AWS STS를 통한 신원 검증 (AuthN)
4단계: IAM 계정과 K8S 유저 매핑
aws-auth ConfigMap(또는 최신 EKS의 Access Entry)을 참조합니다. AWS에서 확인된 IAM 계정이 쿠버네티스 내부의 어떤 유저/그룹에 매핑되어 있는지 확인합니다.5단계: RBAC을 통한 권한 확인 (AuthZ)
6단계: 최종 결과 반환
우리는 해당 내용을 실습을 진행하면서 배워 본다.
# sts caller id의 ARN 확인
aws sts get-caller-identity --query Arn
cat ~/.kube/config
export CLUSTER_NAME=myeks
aws eks get-token --cluster-name $CLUSTER_NAME | jq
aws eks get-token --cluster-name $CLUSTER_NAME | jq -r '.status.token'
aws eks get-token --cluster-name $CLUSTER_NAME --debug | jq
# EKS 인증 토큰 가져오기
## 각 토큰은 k8s-aws-v1로 시작하여 base64 인코딩 문자열로 이어집니다.
TOKEN_DATA=$(aws eks get-token --cluster-name myeks | jq -r '.status.token')
echo $TOKEN_DATA
IFS='.' read header payload signature <<< "$TOKEN_DATA"
echo "$payload"
# sts 에 서명해 보내는 Presigned URL
TOKEN_BODY=$(echo "$payload" | sed 's/^k8s-aws-v1.//')
echo "$TOKEN_BODY" | tr -- '-_' '+/' | base64 --decode 2>/dev/null위의 부분에서, cat ~/.kube/config 명령어를 확인해 보면
kind: Config
users:
- name: arn:aws:eks:ap-northeast-2:975372933996:cluster/eks-private
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- --region
- ap-northeast-2
- eks
- get-token
- --cluster-name
- eks-private
- --output
- json
command: aws
env: null
interactiveMode: IfAvailable
provideClusterInfo: false이 부분을 보면, 토큰을 가져오는 것을 볼 수 있다.
kubectl의 Client-Go 라이브러리는 Pre-Signed URL을 Bearer Token으로 k8s action 과 함께 EKS API Cluster Endpoint로 요청을 보낸다. 그래서 우리는 따로 presigned url 을 설정 할 필요가 없다.
kubectl get node -v=10
TOKEN_DATA=$(aws eks get-token --cluster-name myeks | jq -r '.status.token')
echo $TOKEN_DATA
curl -k -v -XGET \
-H "Authorization: Bearer $TOKEN_DATA" \
-H "Accept: application/json" \
'https://79D2998210A4065B12A8C534D7802477.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500'직접 cURL 로 요청을 보냈을 때 답변이 온다. 이것을 kubectl 은 내장으로 해당 작업을 해 주는 것이다.
아래와 같은 형태로, 실제 응답이 오는 것을 확인 할 수 있다.

만약에 키를 이상한 것을 보낼 경우 권한이 없음을 보여 준다.

k8s 는 다양한 인증 방식을 적용한다 링크

이 중에서, EKS는 Webhook Token authentication 을 사용한다.
# tokenreviews api 리소스 확인
kubectl api-resources | grep authentication
# TokenReview는 사용자에 대한 토큰 인증을 시도(확인)합니다.
kubectl explain tokenreviews.spec
kubectl explain tokenreviews.status
kubectl explain tokenreviews.status.user
kubectl explain tokenreviewsGROUP: authentication.k8s.io KIND: TokenReview VERSION: v1
DESCRIPTION: TokenReview attempts to authenticate a token to a known user. Note: TokenReview requests may be cached by the webhook token authenticator plugin in the kube-apiserver.
토큰 리뷰의 경우, 사용자에 대한 인증을 시도하는 역할을 한다. 직접 Token Review 를 직접 요청해 본다.
# 직접 TokenReview 요청 해보기!
TOKEN_DATA=$(aws eks get-token --cluster-name myeks | jq -r '.status.token')
cat > token-review.yaml << EOF
apiVersion: authentication.k8s.io/v1
kind: TokenReview
metadata:
name: mytoken
spec:
token: ${TOKEN_DATA}
EOF
cat token-review.yaml
# AWS 인증 확인 후 응답 시 : 유저, K8S Subject(group) 등
## => Amazon EKS 클러스터를 생성할 경우, 클러스터를 생성하는 IAM 보안 주체에게는 Amazon EKS 제어 영역의 클러스터 역할 기반 액세스 제어(RBAC) 구성에 system:masters 권한이 자동으로 부여됩니다.
## => 이 보안 주체는 표시되는 구성에 나타나지 않음!
## groups=[system:authenticated] => 즉, system:masters 가 생략되어 있다고 보면 됨!
kubectl create -f token-review.yaml -v=9해당 Token Review 의 결과를 보면 아래와 같다.
{"kind":"TokenReview","apiVersion":"authentication.k8s.io/v1","metadata":{"name":"mytoken","managedFields":[{"manager":"kubectl-create","operation":"Update","apiVersion":"authentication.k8s.io/v1","time":"2026-04-12T11:57:19Z","fieldsType":"FieldsV1","fieldsV1":{"f:spec":{"f:token":{}}}}]},"spec":{"token":"k8s-aws-v1.aHR0cHM6Ly9zdHMuYXAtbm9ydGhlYXN0LTIuYW1hem9uYXdzLmNvbS8_QWN0aW9uPUdldENhbGxlcklkZW50aXR5JlZlcnNpb24..."},"status":{"authenticated":true,"user":{"username":"arn:aws:iam::975372933996:root","uid":"aws-iam-authenticator:975372933996:975372933996","groups":["system:authenticated"],"extra":{"accessKeyId":["AKIA6GGGB3NWLPJQBP6Z"],"arn":["arn:aws:iam::975372933996:root"],"canonicalArn":["arn:aws:iam::975372933996:root"],"principalId":["975372933996"],"sessionName":[""],"sigs.k8s.io/aws-iam-authenticator/principalId":["975372933996"]}},"audiences":["https://kubernetes.default.svc"]}}이제는 인증은 지나오고, 인가 부분이다.

ConfigMap 으로 처리하는 방식은 이제 deprecated 된다. 그리고 여러 문제점이 있어, EKS API 방식으로 사용해야 한다.
인가 관련 SubjectAccessReview 와 관련 정보를 확인 해 본다.
aws eks list-access-entries --cluster-name myeks | jq
# api 리소스 확인
kubectl api-resources | grep subject
# Shows the subject for the current context with which one authenticates with the cluster
kubectl rbac-tool -h
kubectl rbac-tool whoami
# 직접 SubjectAccessReviews 요청 확인 해보기
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
cat > sar-request.yaml << EOF
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
user: "arn:aws:iam::${ACCOUNT_ID}:user/admin" # 확인하고 싶은 IAM ARN 또는 K8s User
groups:
- system:masters
resourceAttributes:
namespace: "kube-system"
verb: "get"
resource: "pods"
EOF
cat sar-request.yaml
위 실습의 결과 값 마지막 즈음에 JSON 내 "status":{"allowed":true}} 부분을 보면 인가에 성공한 것을 알 수 있다.
EKS API 의 경우 확인 해 보자
export ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/root | jq # Linux
aws eks list-access-policies
aws eks list-access-policies --output table# 노드에서 실행
aws ssm start-session --target $NODE1
--------------------------------------
sudo su -
# EC2 에서 별도 aws configure 없이 sts 실행 확인 : IAM Role!
aws sts get-caller-identity --query Arn
aws s3 ls
aws ec2 describe-vpcs --no-cli-pager
# 임시 보안 자격 증명(토큰)을 요청
export CLUSTER_NAME=myeks
aws eks get-token --cluster-name $CLUSTER_NAME | jq
aws eks get-token --cluster-name $CLUSTER_NAME | jq -r '.status.token'
aws eks get-token --cluster-name $CLUSTER_NAME --debug | jq자격증명을 가지고 s3는 조회가 안 되는데, vpc 같은 경우는 조회가 된다. 해당 노드에 권한 들어 있어 조회가 된다.
해당 노드도 자격증명 토큰 발급이 가능한 것을 볼 수 있다.
해당 노드에 kubectl 을 설치하고 노드를 조회할 수 있는지 보자
# kubectl 설치
# https://docs.aws.amazon.com/eks/latest/userguide/install-kubectl.html
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.35.2/2026-02-27/bin/linux/amd64/kubectl
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version
kubectl get pod -A
kubectl get node
워커 노드 권한 기준으로 권한이 조회 되는 것을 볼 수 있다.
RBAC Tool 을 이용해 노드의 권한을 확인 해 본다.
curl https://raw.githubusercontent.com/alcideio/rbac-tool/master/download.sh | bash
rbac-tool -h Groups: ["system:nodes", "system:authenticated"] system:nodes 로 나오는 것을 볼 수 있다.
신규 유저를 생성하고, 정책을 추가한다.
aws iam create-user --user-name testuser
# 사용자에게 프로그래밍 방식 액세스 권한 부여
aws iam create-access-key --user-name testuser
# testuser 사용자에 정책을 추가
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser
# get-caller-identity 확인
aws sts get-caller-identity --query Arn신규 유저의 자격증명 테스트를 위해 도커 컨테이너를 한개 만들어서 그 안에서 테스트를 진행한다.
docker run -it --name aws-cli --entrypoint /bin/sh amazon/aws-cli
-------------------------------------------------
# aws cli 명령 시도
aws s3 ls
aws configure
aws sts get-caller-identity --query Arn
처음의 caller 와 두번째 docker 내의 caller 차이가 있다.
kubectl 등 쿠버네티스 권한이 있는지 테스트 한다
CLUSTER_NAME=myeks
aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser
Added new context testuser to /root/.kube/config
# kubeconfig 확인
cat ~/.kube/config
curl -O https://s3.us-west-2.amazonaws.com/amazon-eks/1.35.2/2026-02-27/bin/linux/amd64/kubectl # windows (WSL2)
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
kubectl version --client=true
kubectl get node -v6
# rbac-tool 설치 : https://github.com/alcideio/rbac-tool
yum install tar gzip -y
curl https://raw.githubusercontent.com/alcideio/rbac-tool/master/download.sh | bash
# Shows the subject for the current context with which one authenticates with the cluster
./bin/rbac-tool whoamiAWS Access 권한이 있으나, EKS 권한은 없기 때문에 권한이 없다고 나온다.
# testuser 의 access entry 생성
export CLUSTER_NAME=myeks
export ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]
# testuser에 AmazonEKSAdminPolicy 연동
aws eks associate-access-policy --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy --access-scope type=cluster
# 확인
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq아래와 같이 새로운 액세스 엔트리가 생성 된 것을 볼 수 있다.

그 이후에 명령어를 치면, 조회가 되는 것을 확인 할 수 있다.

이제 Access Entry 를 삭제한다.
aws eks delete-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]
이제 실행 환경에서, 나는 WSL로 다시 돌아와 하기 명령어로 ClusterRole 생성한다.
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-viewer-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list", "get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pod-admin-role
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["*"]
EOF
kubectl get clusterrole | grep ^pod
# ClusterRoleBinding 생성
kubectl create clusterrolebinding viewer-role-binding --clusterrole=pod-viewer-role --group=pod-viewer
kubectl create clusterrolebinding admin-role-binding --clusterrole=pod-admin-role --group=pod-admin
kubectl get clusterrolebinding | grep -E 'admin-role|viewer-role'
# 확인
kubectl rbac-tool lookup pod-viewer
kubectl rbac-tool lookup pod-admin
kubectl rolesum -k Group pod-viewer
kubectl rolesum -k Group pod-admin 아래와 같은 형태로 권한 형태를 확인 해 볼 수 있다.

아래는 커스텀 롤들을 적용해 본다.
docker run -it --name aws-cli --entrypoint /bin/sh amazon/aws-cli
-----------------------------------------------------------------
# Access Entry 설정 : 먼저 k8s group pod-viewer
aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-viewer
aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser
aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq
# kubectl 시도
kubectl get node -A
kubectl get pod -A
kubectl auth can-i get pods --all-namespaces
kubectl auth can-i delete pods --all-namespaces
aws eks update-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-admin | jq -r .accessEntry
kubectl get node -A
kubectl get pod -A
kubectl auth can-i get pods --all-namespaces
kubectl auth can-i delete pods --all-namespaces그룹도 업데이트 되어 있는 것을 볼 수 있다.

해당 실습이 끝났으면 docker 컨테이너 삭제와 testuser 계정을 삭제한다.
docker rm -f aws-cli, 그리고 콘솔에서 유저 삭제 한다.
애플리케이션에서, S3 라던지 AWS 서비스를 이용하려면 AWS 자격증명을 해야 한다.
| 항목 | IRSA (기존) | EKS Pod Identity (신규) |
|---|---|---|
| 인증 메커니즘 | OIDC 기반 (ID 공급자 필요) | EKS 인증 웹훅 by Pod Identity Agent (직접 연동) |
| 설정 복잡도 | 높음 (OIDC 생성, Trust Policy 복잡) | 낮음 (단순 매핑) |
| 신뢰 관계 (Trust) | oidc-eks.amazonaws.com 참조 | pods.eks.amazonaws.com 서비스 참조 |
| 확장성 | 클러스터별로 OIDC 설정 필요 | 여러 클러스터에서 동일 역할 재사용 용이 |
| SDK 지원 | 대부분 지원 | 최신 버전 SDK 필요 |
# 파드1 생성
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
# 확인
kubectl get pod
kubectl describe pod
# 로그 확인
kubectl logs eks-iam-test1
# 파드1 삭제
kubectl delete pod eks-iam-test1AWS 자원을 사용하지 않는 파드의 경우 automountServiceAccountToken: false 를 주어 Pod Spec에 토큰을 전달하지 않도록 설정할 수 있다.
# 파드2 생성
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
# 확인
kubectl get pod
kubectl describe pod
kubectl get pod eks-iam-test2 -o yaml
kubectl get pod eks-iam-test2 -o yaml | grep serviceAccount
kubectl get sa default
kubectl exec -it eks-iam-test2 -- ls -al /var/run/secrets/kubernetes.io/serviceaccount
kubectl exec -it eks-iam-test2 -- ls -al /var/run/secrets/kubernetes.io/serviceaccount/..data
kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token ;echo
kubectl exec -it eks-iam-test2 -- aws s3 ls
# 서비스 어카운트 토큰 확인
SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN토큰의 경우 jwt.io 사이트에서 안에 내용을 확인 해 볼 수 있다. aud, iss 등 정보를 확인 할 수 있다.
# 클러스터에 기존 IAM OIDC 공급자가 있는지 확인합니다. 클러스터의 OIDC 공급자 ID를 검색하여 변수에 저장합니다.
oidc_id=$(aws eks describe-cluster --name myeks --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)
echo $oidc_id
# 클러스터 ID를 가진 IAM OIDC 공급자가 계정에 이미 있는지 확인합니다.
# aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4
aws iam list-open-id-connect-providers | grep $oidc_id | cut -d "/" -f4
IDP=$(aws eks describe-cluster --name myeks --query cluster.identity.oidc.issuer --output text)
curl -s $IDP/.well-known/openid-configuration | jq -r '.'
curl -s $IDP/keys | jq -r '.'
curl -s https://oidc.eks.ap-northeast-2.amazonaws.com/id/D101CFA79EB3A774D39A52E2425B034F/.well-known/openid-configuration | jq .
# Discovery 엔드포인트 호출 (.well-known) : OIDC issuer 주소 뒤에 /.well-known/openid-configuration을 붙이면 됩
curl -s https://oidc.eks.ap-northeast-2.amazonaws.com/id/032357E88E266F4AE7C2E8CF6F5EFEB0/.well-known/openid-configuration | jq .
iam policy 생성해 본다. 나는 2주차 실습으로 인해 이미 있었다.
# IAM Policy json 파일 다운로드 : Download an IAM policy for the AWS Load Balancer Controller that allows it to make calls to AWS APIs on your behalf.
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
cat aws_lb_controller_policy.json | jq
# AWSLoadBalancerControllerIAMPolicy 생성 : Create an IAM policy using the policy downloaded in the previous step.
aws iam create-policy \
--policy-name AWSLoadBalancerControllerIAMPolicy \
--policy-document file://aws_lb_controller_policy.json
# 확인
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)
aws iam get-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy | jq# IRSA 생성 : cloudforamtion 를 통해 IAM Role 생성
CLUSTER_NAME=myeks
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl get serviceaccounts -n kube-system aws-load-balancer-controller
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
# 확인 : 아래 출력되는 Role ARN을 관리콘솔에서 확인!
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
# NAMESPACE NAME ROLE ARN
# kube-system aws-load-balancer-controller arn:aws:iam::975372933996:role/eksctl-myeks-addon-iamserviceaccount-kube-sys-Role1-DAkDX62o4YOt
# k8s 에 SA 확인
# Inspecting the newly created Kubernetes Service Account, we can see the role we want it to assume in our pod.
kubectl get serviceaccounts -n kube-system aws-load-balancer-controller -o yaml아래와 같이 Role 이 만들어 져 있는 것을 볼 수 있다.

설정한 권한 테스트를 위해 ALB Controller 를 설치한다.
# Helm Chart Repository 추가
helm repo add eks https://aws.github.io/eks-charts
helm repo update
# Helm Chart - AWS Load Balancer Controller 설치
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
# 확인
helm list -n kube-system
kubectl get pod -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
kubectl logs -n kube-system deployment/aws-load-balancer-controller -f
# 인증서 관련 정보 확인
## LBC는 단순히 AWS ALB/NLB를 만들기만 하는 것이 아니라, 사용자가 작성한 Ingress나 Service 설정이 올바른지 검토하고 수정하는 역할도 수행
## 이를 위해 API 서버는 LBC의 9443 포트로 HTTPS 요청을 보내는데, 이 통신을 위해 aws-load-balancer-tls 인증서가 필요함.
## 이때 해당 인증서의 만료 전 Cert-manager 이 자동 갱신 처리해줌
## 발급된 인증서 데이터를 aws-load-balancer-tls라는 이름의 Secret에 저장
kubectl get certificaterequests,issuers,certificates -n kube-system
kubectl get secret -n kube-system
kubectl get secret aws-load-balancer-tls -n kube-system -o yaml
# cert-manager 류의 인증서 자동 갱신 미사용 시?
## LBC의 웹훅 인증서는 보통 유효기간이 짧습니다. cert-manager가 없으면 인증서가 만료되는 순간 ,
# kubectl apply 명령이 모두 에러(Internal error: failed calling webhook...)가 나며 클러스터 관리가 불가능해집니다.
# AWS Load Balancer Controller 확인
kubectl get serviceaccounts -n kube-system aws-load-balancer-controller -o yaml
kubectl rolesum -n kube-system aws-load-balancer-controller
kubectl get deployment -n kube-system aws-load-balancer-controller
kubectl describe deploy -n kube-system aws-load-balancer-controller
kubectl describe deploy -n kube-system aws-load-balancer-controller | grep 'Service Account'
확인 해본다.
# 아래 ENV 와 두번쨰 볼륨은 어떻게 pod spec 에 설정이 주입되었을까요?
k get deploy -n kube-system aws-load-balancer-controller -o yaml # 비교해보자!
kubectl describe pod -n kube-system -l app.kubernetes.io/name=aws-load-balancer-controller
이런 식으로 데이터가 들어가 있는데, 이것은 Mutating admission webhook 이 처리한다고 한다.
Mutating Webhook은 쿠버네티스 API 요청이 들어왔을 때, 해당 오브젝트를 "사용자가 보낸 그대로 두지 않고, 중간에 가로채서 내용을 강제로 수정(Mutate)하는 기능" 이다.
아래의 결과로 mutatingwebhook 을 확인해 볼 수 있다.
kubectl get MutatingWebhookConfiguration
kubectl describe MutatingWebhookConfiguration pod-identity-webhook
kubectl get MutatingWebhookConfiguration pod-identity-webhook -o yamlkubeopsview 로 ALB Controller 가 잘 사용되는지 확인 해 본다.
# kube-ops-view : NodePort 나 LoadBalancer Type 필요 없음!
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/
helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set service.main.type=ClusterIP --set env.TZ="Asia/Seoul" --namespace kube-system
# 확인
kubectl get deploy,pod,svc,ep -n kube-system -l app.kubernetes.io/instance=kube-ops-view
# 사용 리전의 인증서 ARN 변수 지정 : 정상 상태 확인(만료 상태면 에러 발생!)
CERT_ARN=$(aws acm list-certificates --query 'CertificateSummaryList[].CertificateArn[]' --output text)
echo $CERT_ARN
MyDomain=devchanki.com
echo $MyDomain
# kubeopsview 용 Ingress 설정 : group 설정으로 1대의 ALB를 여러개의 ingress 에서 공용 사용
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/certificate-arn: $CERT_ARN
alb.ingress.kubernetes.io/group.name: study
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
alb.ingress.kubernetes.io/load-balancer-name: myeks-ingress-alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/success-codes: 200-399
alb.ingress.kubernetes.io/target-type: ip
labels:
app.kubernetes.io/name: kubeopsview
name: kubeopsview
namespace: kube-system
spec:
ingressClassName: alb
rules:
- host: kubeopsview.$MyDomain
http:
paths:
- backend:
service:
name: kube-ops-view
port:
number: 8080
path: /
pathType: Prefix
EOF
# service, ep, ingress 확인
kubectl get ingress,svc,ep -n kube-system
# Kube Ops View 접속 정보 확인
echo -e "Kube Ops View URL = https://kubeopsview.$MyDomain/#scale=1.5"ALB 가 생성된 것을 확인 할 수 있다.

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)
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl get sa
kubectl describe sa my-sa
# 파드 3번 생성
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
# 파드에서 aws cli 사용 확인
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
# "arn:aws:sts::975372933996:assumed-role/eksctl-myeks-pod-irsa-s3-readonly-role/botocore-session-1776002192"
get-caller-identity 호출 시 아까 확인한 role 이 적용되어 있는 것을 볼 수 있다.
그리고 s3 목록을 가져오는 것도 볼 수 있다.
아래 사진은 Role 이 생성된 것을 console 을 통해 볼 수 있다.

생성된 파드에서도, ServiceAccountToken 이 주입된 것을 볼 수 있다.

파드 내에서 s3 를 사용할 수 있는 권한이 바인딩 된 것을 볼 수 있다.

kubectl delete pod eks-iam-test3
eksctl delete iamserviceaccount --cluster $CLUSTER_NAME --name my-sa --namespace default
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
kubectl get saEKS Pod Identity는 "포드(Pod)가 AWS 서비스(S3, DynamoDB 등)에 접근할 수 있도록 IAM 권한을 부여하는 가장 최신이자 가장 단순한 방식"입니다.
기존에 사용하던 **IRSA(IAM Roles for Service Accounts)**의 복잡함을 해결하기 위해 작년(2023년 말)에 출시된 기능입니다. 블로그에 정리하시기 좋게 핵심 위주로 요약해 드릴게요.
이 기능도 내부적으로는 Mutating Webhook과 Agent를 사용하여 동작합니다.
AWS_CONTAINER_CREDENTIALS_FULL_URI (로컬 에이전트 주소)eks-pod-identity-agent가 Pod의 요청을 받습니다.이 표를 블로그에 넣으시면 독자들이 차이점을 한눈에 이해하기 좋습니다.
| 구분 | IRSA (기존) | EKS Pod Identity (신규) |
|---|---|---|
| 설정 복잡도 | 높음 (OIDC 공급자, 복잡한 Trust Policy) | 낮음 (단순 매핑 설정) |
| IAM 역할 재사용 | 클러스터마다 Trust Policy 수정 필요 | 쉬움 (여러 클러스터에서 동일 역할 사용 가능) |
| 네트워크 | Pod이 직접 AWS STS와 통신 | 노드의 에이전트를 통해 통신 |
| 지원 환경 | EKS 전체 (Fargate 포함) | EC2 기반 EKS 전용 (현재 Fargate 미지원) |
| 확장성 | OIDC 제한 등으로 대규모 시 병목 발생 가능 | 매우 높음 (태그 기반 권한 관리 최적화) |
pods.eks.amazonaws.com 서비스가 지정됩니다.)eks-pod-identity-agent 애드온을 설치합니다.
# 확인
eksctl get addon --cluster $CLUSTER_NAME
kubectl -n kube-system get daemonset eks-pod-identity-agent
kubectl -n kube-system get pods -l app.kubernetes.io/name=eks-pod-identity-agent
kubectl get ds -n kube-system eks-pod-identity-agent -o yamleksctl 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
# 확인
kubectl get sa
kubectl get sa s3-sa -oyaml
eksctl get podidentityassociation --cluster $CLUSTER_NAME
aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME | jq
# IAM Role 확인 : ABAC 지원을 위해 sts:Tagsession 추가
aws iam get-role --query 'Role.AssumeRolePolicyDocument' --role-name s3-eks-pod-identity-role | jq .파드를 생성한다.
# 파드 생성
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
## Amazon EKS가 EKS Pod Identity 연결이 있는 서비스 계정을 사용하는 새 Pod를 시작하면 EKS Pod Identity 웹훅이 실행됩니다
## 두 개의 환경 변수를 추가하여 pod 사양을 변경 합니다 : AWS_CONTAINER_CREDENTIALS_FULL_URI , AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
kubectl get pod eks-pod-identity -o yaml
kubectl exec -it eks-pod-identity -- aws sts get-caller-identity --query Arn
kubectl exec -it eks-pod-identity -- aws s3 ls
kubectl exec -it eks-pod-identity -- env | grep AWS
kubectl exec -it eks-pod-identity -- ls /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/
kubectl exec -it eks-pod-identity -- cat /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
토큰을 jwt.io 에서 확인해 보니, 조금 달랐다.
pod identity 는 다음과 같고, 권한이 없을 땐 kubernetes, 그리고 irsa 는 sts.aws 였다.

eks-pod-identity-agent (DaemonSet) 를 통해 통신합니다. 하지만 Fargate는 사용자가 노드 서버를 관리하지 않으며, 데몬셋을 띄울 수 없는 구조입니다.AWS_CONTAINER_CREDENTIALS_FULL_URI)와 토큰 방식을 사용합니다. 아주 오래된 버전의 AWS SDK는 이 경로를 인식하지 못하고 예전 방식만 찾다가 권한 오류가 발생합니다.| 상황 | 추천 방식 |
|---|---|
| EC2 기반 EKS 워커 노드 | EKS Pod Identity (설정이 훨씬 편함) |
| AWS Fargate | IRSA (OIDC) (유일한 선택지) |
| 오래된 레거시 앱 (SDK 업데이트 불가) | IRSA (OIDC) (호환성 때문) |
| 여러 클러스터에서 같은 Role 재사용 | EKS Pod Identity (Trust Policy 관리가 쉬움) |
# kube-ops-view Ingress 삭제 (ALB 제거)
kubectl delete ingress -n kube-system kubeopsview
kubectl get ingress -n kube-system
# IRSA 설정 삭제
CLUSTER_NAME=myeks
eksctl delete iamserviceaccount --cluster=$CLUSTER_NAME --namespace=kube-system --name=aws-load-balancer-controller
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
# 테라폼으로 생성된 리소스 삭제
terraform destroy -auto-approve
rm -rf ~/.kube/config오늘은 실습 자체는 이해하면 실습에 한정해서 어려운 내용은 없었다. AWS 는 사용하나 회사에서 쿠버네티스를 사용하지 않다보니, 해당 내용이 이해가 잘 되지 않아 여러번 학습 하였다. 중간 실습에서 실무 같은 느낌의 devops 를 만들어 보면서 조금 더 배운 것 같다.