본 블로그 글은 CloudNet@ 가시다님이 진행하는 스터디, AEWS3기에서 참고하였습니다.
AWS 의 보안 모델은 고객 공동 책임 모델로 AWS는 클라우드의 보안을, 고객은 클라우드에서의 보안 을 담당합니다.
공동 책임 모델에 따라 고객은 클라우드에서의 보안을 관리해야 합니다.
아래 EKS에서의 보안 영역을 참고하면 EKS 노드의 보안은 고객의 영역으로 애플리케이션과 접근을 위한 권한에 대해 보안 관리가 필요합니다.


EKS 보안을 이해하기 위해 쿠버네티스의 접근 제어 과정을 확인하겠습니다.
먼저, 쿠버네티스는 API를 통해 클러스터 내 모든 리소스의 상태를 관리합니다.
kubectl api-resources -v 6
I0316 01:11:45.942538 9369 loader.go:402] Config loaded from file: /Users/hanseungho/.kube/config
I0316 01:11:45.944526 9369 envvar.go:172] "Feature gate default state" feature="ClientsAllowCBOR" enabled=false
I0316 01:11:45.944537 9369 envvar.go:172] "Feature gate default state" feature="ClientsPreferCBOR" enabled=false
I0316 01:11:45.944540 9369 envvar.go:172] "Feature gate default state" feature="InformerResourceVersion" enabled=false
I0316 01:11:45.944542 9369 envvar.go:172] "Feature gate default state" feature="WatchListClient" enabled=false
I0316 01:11:46.678071 9369 round_trippers.go:560] GET https://412E75B86CFB737FB6FC350828183F99.gr7.ap-northeast-2.eks.amazonaws.com/api?timeout=32s 200 OK in 732 milliseconds
I0316 01:11:46.719881 9369 round_trippers.go:560] GET https://412E75B86CFB737FB6FC350828183F99.gr7.ap-northeast-2.eks.amazonaws.com/apis?timeout=32s 200 OK in 38 milliseconds
NAME SHORTNAMES APIVERSION NAMESPACED KIND
bindings v1 true Binding
componentstatuses cs v1 false ComponentStatus
configmaps cm v1 true ConfigMap
endpoints ep v1 true Endpoints
events ev v1 true Event
limitranges limits v1 true LimitRange
namespaces ns v1 false Namespace
nodes no v1 false Node
persistentvolumeclaims pvc v1 true PersistentVolumeClaim
persistentvolumes pv v1 false PersistentVolume
..
..
# api 조회
kubectl get --raw /api
{"kind":"APIVersions","versions":["v1"],"serverAddressByClientCIDRs":[{"clientCIDR":"0.0.0.0/0","serverAddress":"ip-172-16-98-9.ap-northeast-2.compute.internal:443"}]}
# 조회
kubectl get --raw /api/v1/namespaces | jq
{
"kind": "NamespaceList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "111807"
},
"items": [
{
"metadata": {
"name": "amazon-cloudwatch",
"uid": "65294f2e-e971-403b-99cd-b4243ea37184",
"resourceVersion": "1633",
"creationTimestamp": "2025-03-15T09:47:12Z",
"labels": {
"kubernetes.io/metadata.name": "amazon-cloudwatch",
"name": "amazon-cloudwatch"
},
...

쿠버네티스 API 서버(Kube-API Server) 를 호출하는 과정에서 접근 제어(Controlling Access to the Kubernetes API) 가 수행됩니다.

위 kubectl 의 결과들은 ~/.kube/config 에 저장된 정보를 토대로 API 서버를 다음 과정으로 호출합니다.
- certificate-authority-data 는 API 서버의 CA (Certificate Authority) 인증서를 Base64 인코딩한 값으로 API 서버 신뢰된 서버인지 검증합니다.(추가 TLS 서명을 제공하여 서명된 TLS 인증서가 일치하는 지비교)
- aws-iam-authenticator 를 통해 STS를 거쳐 AWS IAM과 연동하여 인증을 수행합니다
sudo vi ~/.kube/config
----
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tL../horang1
server: https://85CC1C62E40F411FBCA3C0A3C98A0F85.gr7.ap-northeast-2.eks.amazonaws.com
name: arn:aws:eks:ap-northeast-2:17..:cluster/horang1
..
contexts:
- context:
cluster: cluster-1.ap-northeast-2.eksctl.io
user: admin@cluster-1.ap-northeast-2.eksctl.io
name: admin@cluster-1.ap-northeast-2.eksctl.io
current-context: arn:aws:eks:ap-northeast-2:170698194833:cluster/hsh-eks
kind: Config
preferences: {}
...
- name: hsh@hsh-kubeflow-cluster2.ap-northeast-2.eksctl.io
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
args:
- token
- -i
- hsh-kubeflow-cluster2
command: aws-iam-authenticator
env:
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
- name: AWS_DEFAULT_REGION
value: ap-northeast-2
- name: AWS_PROFILE
value: hsh
interactiveMode: IfAvailable
provideClusterInfo: false
EKS Security
보안 구성 방식에 따라 다음의 표로 분류됩니다.
구분
|
설명
|
예시
|
aws-auth
|
IAM 사용자·역할과 EKS 클러스터 접근 권한을 연결하는 방식.
|
IAM 사용자나 역할의 클러스터 접근 시 권한 부여
|
Cluster Access Management
|
클러스터 접근 권한 관리(보통 aws-auth 통해 구현).
|
특정 사용자 또는 역할만 EKS 클러스터 접근 가능하도록 설정
|
IRSA
|
Kubernetes의 Pod가 IAM 역할을 통해 AWS 리소스 접근하는 방식.
|
Pod에서 AWS 리소스(S3, DynamoDB 등)에 접근할 때 서비스 계정에 IAM 역할 연결
|
Pod Identity
|
IRSA의 업그레이드 버전으로 Pod에 더 세밀하게 IAM 권한 부여 가능.
|
서비스 계정과 IAM 역할을 연결하고 Pod에 직접 지정하여 세부적 권한 관리 가능
|
Aws-auth ConfigMap (Deprecated 예정)
인증을 AWS IAM, 인가를 k8s RBAC를 통해 진행하여 사용자 또는 역할(Role)의 클러스터 접근 권한을 세부적으로 관리하는 방식입니다.
기본적으로 EKS에서 사용되는 인증/인가였지만 후술할 단점으로 Deprecated 예정인 방식입니다.

aws-auth 방식은 aws-auth configmap을 통해 aws iam 과 k8s을 매핑하여 관리합니다.
- EC2 노드 그룹은 k8s의 "system:bootstrappers", "system:nodes" 권한을 가집니다.
- 클러스터를 구성한 IAM은 aws-auth 와 상관없이 kubernetes-admin Username으로 system:masters 그룹에 권한을 가집니다.
kubectl describe cm aws-auth -n kube-system
Name: aws-auth
Namespace: kube-system
Labels: <none>
Annotations: <none>
Data
====
mapAccounts:
----
[]
mapRoles:
----
- "groups":
- "system:bootstrappers"
- "system:nodes"
"rolearn": "arn:aws:iam::1..:role/core-node-group-eks-node-group-20250315093607877900000004"
"username": "system:node:{{EC2PrivateDNSName}}"
각 권한을 확인하기 위해 krew 툴을 설치합니다.
kubectl krew install access-matrix rbac-tool rbac-view rolesum whoami
위 권한을 확인하면 다음과 같습니다.
# 현재 Context의 보안 정보 확인
kubectl rbac-tool whoami
{Username: "kubernetes-admin",
UID: "aws-iam-authenticator:170698194833:AIDASPPTHX6I4EKOHX7EH",
Groups: ["system:masters",
"system:authenticated"],
Extra: {accessKeyId: ["AKIASPPTHX6I3KJYKZCN"],
arn: ["arn:aws:iam::17,,:user/hsh@.."],
canonicalArn: ["arn:aws:iam::17..:user/hsh@..],
principalId: [".."],
sessionName: [""],
sigs.k8s.io/aws-iam-authenticator/principalId: [".."]}}
# system:masters 권한 확인
kubectl rbac-tool lookup system:masters
SUBJECT | SUBJECT TYPE | SCOPE | NAMESPACE | ROLE | BINDING
-----------------+--------------+-------------+-----------+---------------+----------------
system:masters | Group | ClusterRole | | cluster-admin | cluster-admin
# 노드 그룹 권한 확인
kubectl rbac-tool lookup system:bootstrappers
SUBJECT | SUBJECT TYPE | SCOPE | NAMESPACE | ROLE | BINDING
-----------------------+--------------+-------------+-----------+-----------------------+------------------------
system:bootstrappers | Group | ClusterRole | | eks:node-bootstrapper | eks:node-bootstrapper
# 노드 그룹 권한 확인
kubectl rbac-tool lookup system:nodes
SUBJECT | SUBJECT TYPE | SCOPE | NAMESPACE | ROLE | BINDING
---------------+--------------+-------------+-----------+-----------------------+------------------------
system:nodes | Group | ClusterRole | | eks:node-bootstrapper | eks:node-bootstrapper
위 aws-auth 매핑 정보는 eksctl을 통해 매핑이 가능합니다.
# auth 매핑 예제
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username csi-user01 --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/csi-user01
# 매핑 확인
kubectl describe cm aws-auth -n kube-system
----
...
mapUsers:
----
- groups:
- system:masters
userarn: arn:aws:iam::17...:user/csi-user01
username: csi-user01
이 방식은 IAM, K8s RBAC 둘 다 세팅해야 하는 복잡함과 aws-auth 컨피그맵을 잘못 수정 시 발생할 수 있는 장애가 있어 Deprecated 예정입니다.

Cluster Access
AWS IAM의 역할(Role/User)을 EKS 클러스터 내 Access Entry와 Access Policy라는 Kubernetes 네이티브 객체로 별도 관리하는 방식입니다.
기존 aws-auth ConfigMap 직접 편집이 필요 없으며 Kubernetes API로 관리됩니다.

구성 변경은 AWS 콘솔을 통해 변경이 가능합니다.

EKS API 및 configmap 옵션을 선택하면 업데이트 후 변경이 완료됩니다.

- 액세스 정책은 공식 문서에서 참고
이전 testuser 를 마이그레이션하고자 한다면 Access Entry 생성과 Access Policy 연결이 필요합니다.
aws eks create-access-entry \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::17...:user/csi-user01 \
--type STANDARD
aws eks associate-access-policy \
--cluster-name $CLUSTER_NAME \
--principal-arn arn:aws:iam::17..:user/csi-user01 \
--policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy \
--access-scope type=cluster
# csi-user01 로 변경
aws configure
aws eks update-kubeonfig --name $CLUSTER_NAME
# 권한 확인
kubectl get pods -A

IRSA (IAM Roles for Service Account)
Kubernetes의 Pod가 IAM 역할을 얻어 AWS 서비스를 관리하는 방식입니다.
EKS 파드가 S3 객체를 접근할 때의 보안 접근 방식을 예로 들면 다음과 같이 접근할 수 있습니다.

- IAM 역할 검증 : AWS STS가 JWT 토큰을 검증하고, 해당 Pod가 IAM 역할을 사용할 수 있는지 확인 요청
- OIDC 신뢰 검증 : AWS IAM이 OIDC Provider의 공개키를 가져와 JWT 서명을 검증하여 신뢰 관계 확인
- IAM 권한 체크 완료 : IAM이 STS에게 Pod가 해당 역할을 사용할 권한이 있음을 알림
- 임시 자격 발급 : STS는 Pod에게 사용할 수 있는 임시 자격증명(Temporary Credentials)을 발급
- AWS 리소스 접근 : Pod는 발급받은 임시 자격증명을 사용해 AWS 서비스(S3 등)에 접근
위 S3 접근을 위한 IRSA을 설정하고 과정을 확인하겠습니다.
# ServiceAccount에 IAM Policy 연결
eksctl create iamserviceaccount \
--name my-sa \
--namespace default \
--cluster $CLUSTER_NAME \
--approve \
--attach-policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`AmazonS3ReadOnlyAccess`].Arn' --output text)
# 구성 연결 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
NAMESPACE NAME ROLE ARN
default my-sa arn:aws:iam::17..:role/eksctl-hsh-eks-addon-iamserviceaccount-defaul-Role1-kXIxehnWIfsV
# SA Annotation 확인, Role 정보
kubectl describe sa my-sa
Name: my-sa
Namespace: default
Labels: app.kubernetes.io/managed-by=eksctl
Annotations: eks.amazonaws.com/role-arn: arn:aws:iam::17..:role/eksctl-hsh-eks-addon-iamserviceaccount-defaul-Role1-kXIxehnWIfsV
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
생성한 IAM Role을 확인하면 S3 READ 정책을 확인할 수 있고 신뢰 관계는 구성한 EKS 에 설정된 것을 확인할 수 있습니다.

설정한 SA 를 통해 신규 파드를 생성하여 세부 정보를 확인하겠습니다.
핵심은 파드 생성시 볼륨이 추가되는 것이며 볼륨안 토큰이 AWS STS를 통해 IAM 인증하는 단계입니다. (위 과정 2번)
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
# 해당 SA를 파드가 사용 시 mutatingwebhook으로 Env,Volume 추가함 : AWS IAM 역할을 Pod에 자동으로 주입
kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml
...
matchPolicy: Equivalent
name: iam-for-pods.amazonaws.com
namespaceSelector: {}
objectSelector:
matchExpressions:
- key: eks.amazonaws.com/skip-pod-identity-webhook
operator: DoesNotExist
reinvocationPolicy: IfNeeded
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
resources:
- pods
scope: '*'
sideEffects: None
# Pod yaml 확인시 볼륨이 추가됨 (이 볼륨이 AWS STS를 통해 IAM 인증)
kubectl get pod eks-iam-test3 -o yaml
..
volumes:
- name: aws-iam-token
projected:
defaultMode: 420
sources:
- serviceAccountToken:
audience: sts.amazonaws.com
expirationSeconds: 86400
path: token
# 발급 토큰 확인
kubectl describe pod eks-iam-test3
...
Environment:
AWS_STS_REGIONAL_ENDPOINTS: regional
AWS_DEFAULT_REGION: ap-northeast-2
AWS_REGION: ap-northeast-2
AWS_ROLE_ARN: arn:aws:iam::17..:role/eksctl-hsh-eks-addon-iamserviceaccount-defaul-Role1-kXIxehnWIfsV
AWS_WEB_IDENTITY_TOKEN_FILE: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
# 권한 확인
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
"arn:aws:sts::17...:assumed-role/eksctl-hsh-eks-addon-iamserviceaccount-defaul-Role1-kXIxehnWIfsV/botocore-session-1742047747"
# S3 접근 확인
kubectl exec -it eks-iam-test3 -- aws s3 ls
2024-11-09 08:44:58 cf-template..
또한, IRSA는 EKS addon 사용으로 AWS 서비스를 관리할때 사용합니다.
AWS 로드밸런서 컨트롤러나 EBS CSI 드라이버를 사용한다면 명령어와 AWS 콘솔을 통해 확인할 수 있습니다.
kubectl describe sa aws-load-balancer-controller-sa -n kube-system


다만 IRSA 도 단점이 있습니다.
- 사용자에 따라 권한 (*)를 부여하여 전체 접근이 가능 할 수 있음
- Eleavated Permissions : IAM 관리자가 Identity Provider (IdP) 및 IAM 역할 구성을 직접 설정해야 함
- Cluster scoped : 클러스터 단위 관리 필요, EKS 신규 구성시 기존 Role에 신규 신뢰관계 추가 필요
- Bounded : IAM 역할 신뢰 정책(Trust Policy)의 크기 제한이 존재함

위 단점을 보안한 것이 아래 EKS Pod Identity 입니다.
실습 전 생성한 자원을 삭제합니다.
# 실습 확인 후 파드 삭제 및 IRSA 제거
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 sa
EKS Pod Identity
보완된 점은 신뢰 관계를 OIDC가 아닌 addon(EKS Pod Identity)에서 처리한다는 것입니다.
EKS Pod Identity 가 파드 내 AWS SDK 호출을 인증을 대신하여 AWS 인증 및 검증을 수행합니다.

- IAM 역할 생성 : AWS IAM에서 EKS Pod Identity용 IAM 역할을 생성
- PodIdentityAssociation 생성 : Pod Identity API를 통해 Pod과 IAM 역할을 연결
- Pod Webhook 적용 : Webhook이 Pod 생성 요청을 감지하고 IAM 역할을 주입
- Pod AWS 요청 처리 : Pod 내부 AWS SDK 요청을 EKS Pod Identity Agent가 인증 4a. IAM 역할 인증 : EKS Auth API가 AWS AssumeRoleForPodIdentity 호출 4b. IAM 역할 검증 : Pod Identity API가 IAM 역할 연결을 검증
- AWS 리소스 접근 : Pod가 EKS Pod Identity Agent를 통해 AWS 서비스 사용
eks-pod-identity-agent 을 구성하여 실습하겠습니다.
# 호환 버전 확인
ADDON=eks-pod-identity-agent
aws eks describe-addon-versions \
--addon-name $ADDON \
--kubernetes-version 1.31 \
--query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
--output text
v1.3.5-eksbuild.2
False
v1.3.4-eksbuild.1
True
v1.3.2-eksbuild.2
False
# 설치
eksctl create addon --cluster $CLUSTER_NAME --name eks-pod-identity-agent --version 1.3.4
# 구성 확인
kubectl -n kube-system get daemonset eks-pod-identity-agent
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
eks-pod-identity-agent 2 2 2 2 2 <none> 89s
kubectl get ds -n kube-system eks-pod-identity-agent -o yaml
...
containers:
- args:
- --port
- "80"
- --cluster-name
- hsh-eks
- --probe-port
- "2703"
command:
- /go-runner
- /eks-pod-identity-agent
- server
....
ports:
- containerPort: 80
name: proxy
protocol: TCP
- containerPort: 2703
name: probes-port
protocol: TCP
...
securityContext:
capabilities:
add:
- CAP_NET_BIND_SERVICE
...
hostNetwork: true
...
# 노드 내 접근하여 포트 확인
kubectl node-shell <node-1>
ss -tnlp | grep eks-pod-identit; echo "-----";
ip -c route
ip -c -br - 4 addr

- CAP_NET_BIND_SERVICE : Pod 내부 컨테이너가 80번(HTTP)이나 443번(HTTPS) 같은 낮은 포트(Privileged Port)를 사용할 수 있도록 설정되어 있습니다.
- 169.254.170.23는 AWS IMDS (Instance Metadata Service) 및 EKS Pod Identity에서 IAM 역할을 관리하는 로컬 주소입니다. 이는 AWS STS (Security Token Service)와 연동하여 IAM 역할을 Pod에 제공하는 데 사용됩니다.
- 노드 EC2 Profile에 2023년 기능 출시 이후 Policy에 AssumeRoleForPodIdentity 권한이 업데이트되어 호출이 가능합니다.
IRSA 예제와 같이 파드에서 S3 접근을 위한 예제를 구성하겠습니다.
콘솔에서 확인하면 신뢰 관계에 OIDC 의존성은 사라진 것을 확인할 수 있습니다.
eksctl create podidentityassociation \
--cluster $CLUSTER_NAME \
--namespace default \
--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
ASSOCIATION ARN NAMESPACE SERVICE ACCOUNT NAME IAM ROLE ARN OWNER ARN
arn:aws:eks:ap-northeast-2:17..:podidentityassociation/hsh-eks/a-5nnty2k2s6abbzblo default s3-sa arn:aws:iam::17..:role/s3-eks-pod-identity-role

예제 파드를 배포하여 기능 동작을 확인하겠습니다.
# sa 생성
kubectl create sa s3-sa
# 파드 배포
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
# 접근 확인
kubectl exec -it eks-pod-identity -- aws sts get-caller-identity --query Arn
kubectl exec -it eks-pod-identity -- aws s3 ls
2024-11-09 08:44:58 cf-template..
# 접근 토큰 확인
kubectl exec -it eks-pod-identity -- cat /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
실습 데이터는 다음과 같이 삭제합니다.
eksctl delete podidentityassociation --cluster $CLUSTER_NAME --namespace default --service-account-name s3-sa
kubectl delete pod eks-pod-identity
kubectl delete sa s3-sa
'Cloud' 카테고리의 다른 글
EKS Version Upgrade (0) | 2025.04.02 |
---|---|
EKS Fargate & AutoMode (0) | 2025.03.23 |
EKS Karpenter (0) | 2025.03.09 |
EKS Autoscaling (0) | 2025.03.09 |
Grafana Observability구성 (0) | 2025.03.01 |