✍ Posted by Immersive Builder Seong
IRSA(IAM Role for Service Account)
파드 내 어플리케이션 컨테이너가 IAM 역할을 사용할 수 있게 해주는 기능입니다.
파드가 특정 IAM 역할로 Assume할 때 토큰을 AWS에 전송하고, AWS는 토큰과 EKS IdP를 통해 해당 IAM 역할을 사용할 수 있는지 검증합니다.
파드(어플리케이션)에 Service Account를 할당하고 IAM Role을 RoleBinding하여 구현합니다.
파드에 Access Key ID를 하드코딩하지 않아 보안상 바람직하고, 노드의 인스턴스 프로파일을 공유하지 않으므로 최소 권한 원칙을 만족합니다.
* Service Account Token Volume Projection
- 서비스 계정 토큰의 시크릿 기반 볼륨 대신 projected volume을 사용합니다.
- 서비스 계정 토큰에서 지원하지 않는 대상(audience), 유효기간(expiration) 등 토큰의 속성을 지정할 수 있습니다.
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /var/run/secrets/tokens
name: vault-token
serviceAccountName: build-robot
volumes:
- name: vault-token
projected:
sources:
- serviceAccountToken:
path: vault-token
expirationSeconds: 7200
audience: vault
* Bound Service Account Token Volume
- Service Account Admission Controller는 토큰 컨트롤러에서 생성한 만료되지 않은 Service Account Token에 시크릿 기반 볼륨 대신 다음과 같은 projected volume을 추가합니다.
- serviceAccountToken: 기본 1시간 후 또는 파드가 삭제될 때 만료됩니다. 이 토큰은 파드에 연결되며 kube-apiserver를 위해 존재합니다.
- configMap: kube-apiserver에 대한 연결을 확인하는 데 사용되는 CA 번들을 포함합니다.
- downwardAPI: 파드의 네임스페이스를 참조합니다.
- name: kube-api-access-<random-suffix>
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
* Configure a Pod to Use a Projected Volume for Storage
- secret, configMap, downwardAPI, serviceAccountToken의 볼륨 마운트를 하나의 디렉터리에 통합하는 기능입니다.
apiVersion: v1
kind: Pod
metadata:
name: test-projected-volume
spec:
containers:
- name: test-projected-volume
image: busybox:1.28
args:
- sleep
- "86400"
volumeMounts:
- name: all-in-one
mountPath: "/projected-volume"
readOnly: true
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: user
- secret:
name: pass
# Create the Secrets:
## Create files containing the username and password:
$ echo -n "admin" > ./username.txt
$ echo -n "1f2d1e2e67df" > ./password.txt
## Package these files into secrets:
$ kubectl create secret generic user --from-file=./username.txt
secret/user created
$ kubectl create secret generic pass --from-file=./password.txt
secret/pass created
# 파드 생성
$ kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml
pod/test-projected-volume created
# 파드 확인
$ kubectl get pod test-projected-volume -o yaml | kubectl neat | yh
```
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: user
- secret:
name: pass
- name: kube-api-access-slltd
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
fieldPath: metadata.namespace
path: namespace
```
# 시크릿 확인
$ kubectl exec -it test-projected-volume -- ls /projected-volume/
password.txt username.txt
$ kubectl exec -it test-projected-volume -- cat /projected-volume/username.txt ;echo
admin
$ kubectl exec -it test-projected-volume -- cat /projected-volume/password.txt ;echo
1f2d1e2e67df
# 삭제
$ kubectl delete pod test-projected-volume && kubectl delete secret user pass
pod "test-projected-volume" deleted
IRSA 실습
1. ServiceAccountToken을 생성하지 않고 파드를 배포해봅니다. (automountServiceAccountToken: false)
로그를 통해 S3 연동에 실패하였음을 확인합니다.
# Test Pod 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
pod/eks-iam-test1 created
# 배포 확인
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
eks-iam-test1 1/1 Running 0 13s
$ kubectl describe pod
```
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 24s default-scheduler Successfully assigned default/eks-iam-test1 to ip-192-168-3-166.ap-northeast-2.compute.internal
Normal Pulling 24s kubelet Pulling image "amazon/aws-cli:latest"
Normal Pulled 12s kubelet Successfully pulled image "amazon/aws-cli:latest" in 11.717s (11.717s including waiting)
Normal Created 12s kubelet Created container my-aws-cli
Normal Started 12s kubelet Started container my-aws-cli
```
# 로그 확인
$ kubectl logs eks-iam-test1
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
# Test Pod 1 삭제
$ kubectl delete pod eks-iam-test1
pod "eks-iam-test1" deleted
2. ServiceAccountToken을 생성하여 파드를 배포해봅니다.
Service Account가 생성될 때 JWT Token이 자동으로 생성됩니다.
결과는 여전히 S3 연동에 실패하는 모습입니다.
# Test Pod 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
pod/eks-iam-test2 created
# 배포 확인
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
eks-iam-test2 1/1 Running 0 28s
$ kubectl describe pod
```
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 41s default-scheduler Successfully assigned default/eks-iam-test2 to ip-192-168-2-115.ap-northeast-2.compute.internal
Normal Pulling 40s kubelet Pulling image "amazon/aws-cli:latest"
Normal Pulled 28s kubelet Successfully pulled image "amazon/aws-cli:latest" in 12.034s (12.034s including waiting)
Normal Created 28s kubelet Created container my-aws-cli
Normal Started 28s kubelet Started container my-aws-cli
```
$ kubectl get pod eks-iam-test2 -o yaml | kubectl neat | yh
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test2
namespace: default
spec:
containers:
- command:
- sleep
- "36000"
image: amazon/aws-cli:latest
name: my-aws-cli
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-vv7g6
readOnly: true
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Never
serviceAccountName: default
terminationGracePeriodSeconds: 0
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: kube-api-access-vv7g6
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
fieldPath: metadata.namespace
path: namespace
$ kubectl exec -it eks-iam-test2 -- ls /var/run/secrets/kubernetes.io/serviceaccount
ca.crt namespace token
# aws 서비스 사용 시도
$ kubectl exec -it eks-iam-test2 -- aws s3 ls
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
# 서비스 어카운트 토큰 확인
$ SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN
eyJhbGciO*****.eyJhdWQ*****.Y45aSLmcn*****
# Test Pod 2 삭제
$ kubectl delete pod eks-iam-test2
3. 쿠버네티스 Service Account(my-sa)를 생성하고 특정 IAM Role을 바인딩합니다.
# Create an iamserviceaccount - AWS IAM role bound to a Kubernetes service account
$ 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)
2024-04-14 03:47:56 [ℹ] 1 existing iamserviceaccount(s) (kube-system/aws-load-balancer-controller) will be excluded
2024-04-14 03:47:56 [ℹ] 1 iamserviceaccount (default/my-sa) was included (based on the include/exclude rules)
2024-04-14 03:47:56 [!] serviceaccounts that exist in Kubernetes will be excluded, use --override-existing-serviceaccounts to override
2024-04-14 03:47:56 [ℹ] 1 task: {
2 sequential sub-tasks: {
create IAM role for serviceaccount "default/my-sa",
create serviceaccount "default/my-sa",
} }2024-04-14 03:47:56 [ℹ] building iamserviceaccount stack "eksctl-myeks-addon-iamserviceaccount-default-my-sa"
2024-04-14 03:47:56 [ℹ] deploying stack "eksctl-myeks-addon-iamserviceaccount-default-my-sa"
2024-04-14 03:47:56 [ℹ] waiting for CloudFormation stack "eksctl-myeks-addon-iamserviceaccount-default-my-sa"
2024-04-14 03:48:26 [ℹ] waiting for CloudFormation stack "eksctl-myeks-addon-iamserviceaccount-default-my-sa"
2024-04-14 03:48:26 [ℹ] created serviceaccount "default/my-sa"
$ eksctl get iamserviceaccount --cluster $CLUSTER_NAME
default my-sa arn:aws:iam::732659419746:role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99
kube-system aws-load-balancer-controller arn:aws:iam::732659419746:role/eksctl-myeks-addon-iamserviceaccount-kube-sys-Role1-9jS2AOMjb6eu
# 확인
$ kubectl get sa
NAME SECRETS AGE
default 0 8h
my-sa 0 33s
$ 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::732659419746:role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
MutatingWebhook에 의해 Environment와 Volume이 추가되고, S3 목록을 불러오는데 성공한 모습입니다.
S3 ReadOnlyAccess 권한을 부여하였기 때문에 노드 또는 VPC에 대한 정보는 조회에 실패합니다.
# Test Pod 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
pod/eks-iam-test3 created
# 해당 SA를 파드가 사용 시 mutatingwebhook으로 Env,Volume 추가함
$ kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml | kubectl neat | yh
# Pod Identity Webhook은 mutatingwebhook을 통해 아래 Env 내용과 1개의 볼륨을 추가함
$ kubectl get pod eks-iam-test3 -o yaml | kubectl neat | yh
apiVersion: v1
kind: Pod
metadata:
name: eks-iam-test3
namespace: default
spec:
containers:
- command:
- sleep
- "36000"
env:
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
- name: AWS_DEFAULT_REGION
value: ap-northeast-2
- name: AWS_REGION
value: ap-northeast-2
- name: AWS_ROLE_ARN
value: arn:aws:iam::732659419746:role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99
- name: AWS_WEB_IDENTITY_TOKEN_FILE
value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
image: amazon/aws-cli:latest
name: my-aws-cli
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-gcs46
readOnly: true
- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
name: aws-iam-token
readOnly: true
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Never
serviceAccountName: my-sa
terminationGracePeriodSeconds: 0
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: aws-iam-token
projected:
sources:
- serviceAccountToken:
audience: sts.amazonaws.com
expirationSeconds: 86400
path: token
- name: kube-api-access-gcs46
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
fieldPath: metadata.namespace
path: namespace
$ kubectl exec -it eks-iam-test3 -- ls /var/run/secrets/eks.amazonaws.com/serviceaccount
token
$ kubectl exec -it eks-iam-test3 -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token ; echo
eyJhb*****.eyJhdWQ*****.RPOun4*****
$ 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::732659419746:role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99
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)
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-gcs46 (ro)
```
Volumes:
aws-iam-token:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 86400
kube-api-access-gcs46:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
```
# 파드에서 aws cli 사용 확인
$ eksctl get iamserviceaccount --cluster $CLUSTER_NAME
NAMESPACE NAME ROLE ARN
default my-sa arn:aws:iam::732659419746:role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99
kube-system aws-load-balancer-controller arn:aws:iam::732659419746:role/eksctl-myeks-addon-iamserviceaccount-kube-sys-Role1-9jS2AOMjb6eu
$ kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
"arn:aws:sts::732659419746:assumed-role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99/botocore-session-1713035603"
# S3 권한에 따른 성공/실패
$ kubectl exec -it eks-iam-test3 -- aws s3 ls
2020-05-31 04:22:17 audio-for-wordpress-11009175126ac46ab1b3674d4bdb43b43bf07212
2020-06-09 17:24:11 bucket-for-aws-translate
2020-06-02 04:36:39 bucket-for-bootstrap
2021-03-10 01:38:35 bucket-for-php-source-code
2021-03-10 08:29:34 cf-templates-11i7zst5zyo80-ap-northeast-2
2021-03-10 20:50:51 hn-input-bucket
2021-03-11 02:01:02 hn-output-bucket
2021-03-13 13:06:10 input-bucket-for-vod
2021-03-10 01:40:25 okms1017
2021-03-15 16:05:03 output-bucket-for-vod
2021-02-22 15:55:35 temporary-web-site
2021-03-10 16:11:55 vod-destination920a3c57-ure3yz5sjtah
2021-03-10 16:11:58 vod-logs6819bb44-q11yuh9ktkmi
2021-03-10 16:12:38 vod-source71e471f1-5r8rnv2ptxxv
$ kubectl exec -it eks-iam-test3 -- aws ec2 describe-instances --region ap-northeast-2
An error occurred (UnauthorizedOperation) when calling the DescribeInstances operation: You are not authorized to perform this operation. User: arn:aws:sts::732659419746:assumed-role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99/botocore-session-1713035603 is not authorized to perform: ec2:DescribeInstances because no identity-based policy allows the ec2:DescribeInstances action
$ kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2
An error occurred (UnauthorizedOperation) when calling the DescribeVpcs operation: You are not authorized to perform this operation. User: arn:aws:sts::732659419746:assumed-role/eksctl-myeks-addon-iamserviceaccount-default--Role1-hZuZABdTBP99/botocore-session-1713035603 is not authorized to perform: ec2:DescribeVpcs because no identity-based policy allows the ec2:DescribeVpcs action
Public OpenID Provider 정보를 조회할 수도 있습니다.
$ IDP=$(aws eks describe-cluster --name myeks --query cluster.identity.oidc.issuer --output text)
$ curl -s $IDP/.well-known/openid-configuration | jq -r '.'
{
"issuer": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/8D687B71EBE1B368120C1A1450DD3178",
"jwks_uri": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/8D687B71EBE1B368120C1A1450DD3178/keys",
"authorization_endpoint": "urn:kubernetes:programmatic_authorization",
"response_types_supported": [
"id_token"
],
"subject_types_supported": [
"public"
],
"claims_supported": [
"sub",
"iss"
],
"id_token_signing_alg_values_supported": [
"RS256"
]
}
* IRSA 취약점
- AWS는 JWT 토큰의 유효성만 확인할 뿐 토큰과 Service Account에 지정된 IAM Role 간에 일관성을 보장하지 않습니다.
- IAM Role의 Condition을 *.* 등으로 잘못 설정한 경우, 토큰과 IAM Role ARN만 있다면 동일 토큰으로 다른 IAM Role을 맡을 수 있습니다.
- EKS OIDC는 외부에서 접근가능한 Public Endpoint입니다.
EKS Pod Identity
- .IRSA의 보안 취약점을 개선하기 위해 신규 출시된 기능입니다.
- 신규 버전의 클러스터 구성 시, OIDC Provider 재생성에 따른 마이그레이션이 불가피합니다.
- Amazon EKS Pod Identity Agent add-on만 추가하면 됩니다.
- Tag 값에 의한 ABAC을 지원합니다.
- CloudTrail과 통합되어 Audit Log를 남길 수 있습니다.
eks-pod-identity-agent를 add-on으로 설치합니다.
# eks pod identity agent add=on 설치
$ ADDON=eks-pod-identity-agent
$ aws eks describe-addon-versions \
--addon-name $ADDON \
--kubernetes-version 1.28 \
--query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
--output text
v1.2.0-eksbuild.1
True
v1.1.0-eksbuild.1
False
v1.0.0-eksbuild.1
False
$ aws eks create-addon --cluster-name $CLUSTER_NAME --addon-name eks-pod-identity-agent
{
"addon": {
"addonName": "eks-pod-identity-agent",
"clusterName": "myeks",
"status": "CREATING",
"addonVersion": "v1.2.0-eksbuild.1",
"health": {
"issues": []
},
"addonArn": "arn:aws:eks:ap-northeast-2:732659419746:addon/myeks/eks-pod-identity-agent/2ac76c89-6b88-a40f-10af-19e517110c20",
"createdAt": "2024-04-14T05:07:54.699000+09:00",
"modifiedAt": "2024-04-14T05:07:54.716000+09:00",
"tags": {}
}
}
# 설치 확인
$ eksctl get addon --cluster $CLUSTER_NAME
NAME VERSION STATUS ISSUES IAMROLE
eks-pod-identity-agent v1.2.0-eksbuild.1 ACTIVE 0
$ 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 3 3 3 3 3 <none> 2m2s
$ kubectl -n kube-system get pods -l app.kubernetes.io/name=eks-pod-identity-agent
NAME READY STATUS RESTARTS AGE
eks-pod-identity-agent-drgdp 1/1 Running 0 2m40s
eks-pod-identity-agent-gdxcc 1/1 Running 0 2m40s
eks-pod-identity-agent-mlgtd 1/1 Running 0 2m40s
$ kubectl get ds -n kube-system eks-pod-identity-agent -o yaml | kubectl neat | yh
```
containers:
- args:
- --port
- "80"
- --cluster-name
- myeks
- --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
```
# 네트워크 정보 확인
$ for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ss -tnlp | grep eks-pod-identit; echo "-----";done
LISTEN 0 4096 127.0.0.1:2703 0.0.0.0:* users:(("eks-pod-identit",pid=183201,fd=8))
LISTEN 0 4096 169.254.170.23:80 0.0.0.0:* users:(("eks-pod-identit",pid=183201,fd=7))
LISTEN 0 4096 [fd00:ec2::23]:80 [::]:* users:(("eks-pod-identit",pid=183201,fd=6))
-----
LISTEN 0 4096 127.0.0.1:2703 0.0.0.0:* users:(("eks-pod-identit",pid=184451,fd=8))
LISTEN 0 4096 169.254.170.23:80 0.0.0.0:* users:(("eks-pod-identit",pid=184451,fd=7))
LISTEN 0 4096 [fd00:ec2::23]:80 [::]:* users:(("eks-pod-identit",pid=184451,fd=6))
-----
LISTEN 0 4096 127.0.0.1:2703 0.0.0.0:* users:(("eks-pod-identit",pid=182539,fd=8))
LISTEN 0 4096 169.254.170.23:80 0.0.0.0:* users:(("eks-pod-identit",pid=182539,fd=3))
LISTEN 0 4096 [fd00:ec2::23]:80 [::]:* users:(("eks-pod-identit",pid=182539,fd=4))
$ for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c route; done
default via 192.168.1.1 dev eth0
169.254.169.254 dev eth0
169.254.170.23 dev pod-id-link0
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.162
192.168.1.42 dev eni4563f7471f4 scope link
192.168.1.59 dev enicc4a85187de scope link
192.168.1.75 dev eni4befcb4bd4e scope link
192.168.1.119 dev eni6600d0d73f2 scope link
192.168.1.191 dev eni0731788645b scope link
192.168.1.217 dev eni875cf18273c scope link
default via 192.168.2.1 dev eth0
169.254.169.254 dev eth0
169.254.170.23 dev pod-id-link0
192.168.2.0/24 dev eth0 proto kernel scope link src 192.168.2.115
192.168.2.124 dev eni97a288408de scope link
192.168.2.135 dev enicc8eb113c61 scope link
192.168.2.149 dev eni137bf751a9d scope link
192.168.2.151 dev eni22db331a2dd scope link
192.168.2.177 dev eni807bbc2abe0 scope link
default via 192.168.3.1 dev eth0
169.254.169.254 dev eth0
169.254.170.23 dev pod-id-link0
192.168.3.0/24 dev eth0 proto kernel scope link src 192.168.3.166
192.168.3.103 dev enib793c0192f2 scope link
192.168.3.151 dev enic14dc1120c4 scope link
192.168.3.171 dev enic12b321181e scope link
192.168.3.234 dev eni28080bf06fb scope link
192.168.3.245 dev enie56f4c00502 scope link
$ for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c -br -4 addr; done
lo UNKNOWN 127.0.0.1/8
eth0 UP 192.168.1.162/24
eth1 UP 192.168.1.14/24
eth2 UP 192.168.1.185/24
pod-id-link0 UNKNOWN 169.254.170.23/32
lo UNKNOWN 127.0.0.1/8
eth0 UP 192.168.2.115/24
eth1 UP 192.168.2.202/24
pod-id-link0 UNKNOWN 169.254.170.23/32
lo UNKNOWN 127.0.0.1/8
eth0 UP 192.168.3.166/24
eth1 UP 192.168.3.76/24
pod-id-link0 UNKNOWN 169.254.170.23/32
$ for node in $N1 $N2 $N3; do ssh ec2-user@$node sudo ip -c addr; done
```
14: pod-id-link0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
link/ether 96:f7:03:87:29:7e brd ff:ff:ff:ff:ff:ff
inet 169.254.170.23/32 scope global pod-id-link0
valid_lft forever preferred_lft forever
inet6 fd00:ec2::23/128 scope global
valid_lft forever preferred_lft forever
inet6 fe80::94f7:3ff:fe87:297e/64 scope link
valid_lft forever preferred_lft forever
```
podidentityassociation을 설정합니다.
$ 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 $AWS_REGION
# 확인
$ eksctl get podidentityassociation --cluster $CLUSTER_NAME
ASSOCIATION ARN NAMESPACE SERVICE ACCOUNT NAME IAM ROLE ARN
arn:aws:eks:ap-northeast-2:732659419746:podidentityassociation/myeks/a-sru7xlkuw3uzavtp5 default s3-sa arn:aws:iam::732659419746:role/s3-eks-pod-identity-role
$ aws eks list-pod-identity-associations --cluster-name $CLUSTER_NAME | jq
{
"associations": [
{
"clusterName": "myeks",
"namespace": "default",
"serviceAccount": "s3-sa",
"associationArn": "arn:aws:eks:ap-northeast-2:732659419746:podidentityassociation/myeks/a-sru7xlkuw3uzavtp5",
"associationId": "a-sru7xlkuw3uzavtp5"
}
]
}
# ABAC - sts:Tagsession 추가
$ 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"
]
}
]
}
Service Accout와 파드를 생성하여 동작을 확인합니다.
# 서비스어카운트, 파드 생성
$ kubectl create sa s3-sa
serviceaccount/s3-sa created
$ 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
pod/eks-pod-identity created
$ kubectl get pod eks-pod-identity -o yaml | kubectl neat| yh
apiVersion: v1
kind: Pod
metadata:
name: eks-pod-identity
namespace: default
spec:
containers:
- command:
- sleep
- "36000"
env:
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
- name: AWS_DEFAULT_REGION
value: ap-northeast-2
- name: AWS_REGION
value: ap-northeast-2
- name: AWS_CONTAINER_CREDENTIALS_FULL_URI
value: http://169.254.170.23/v1/credentials
- name: AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
value: /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
image: amazon/aws-cli:latest
name: my-aws-cli
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-grvtd
readOnly: true
- mountPath: /var/run/secrets/pods.eks.amazonaws.com/serviceaccount
name: eks-pod-identity-token
readOnly: true
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Never
serviceAccountName: s3-sa
terminationGracePeriodSeconds: 0
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes:
- name: eks-pod-identity-token
projected:
sources:
- serviceAccountToken:
audience: pods.eks.amazonaws.com
expirationSeconds: 86400
path: eks-pod-identity-token
- name: kube-api-access-grvtd
projected:
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
fieldPath: metadata.namespace
path: namespace
$ kubectl exec -it eks-pod-identity -- aws sts get-caller-identity --query Arn
"arn:aws:sts::732659419746:assumed-role/s3-eks-pod-identity-role/eks-myeks-eks-pod-id-957ea121-9c25-492e-b6c1-7e83fe2152fa"
$ kubectl exec -it eks-pod-identity -- aws s3 ls
2020-05-31 04:22:17 audio-for-wordpress-11009175126ac46ab1b3674d4bdb43b43bf07212
2020-06-09 17:24:11 bucket-for-aws-translate
2020-06-02 04:36:39 bucket-for-bootstrap
2021-03-10 01:38:35 bucket-for-php-source-code
2021-03-10 08:29:34 cf-templates-11i7zst5zyo80-ap-northeast-2
2021-03-10 20:50:51 hn-input-bucket
2021-03-11 02:01:02 hn-output-bucket
2021-03-13 13:06:10 input-bucket-for-vod
2021-03-10 01:40:25 okms1017
2021-03-15 16:05:03 output-bucket-for-vod
2021-02-22 15:55:35 temporary-web-site
2021-03-10 16:11:55 vod-destination920a3c57-ure3yz5sjtah
2021-03-10 16:11:58 vod-logs6819bb44-q11yuh9ktkmi
2021-03-10 16:12:38 vod-source71e471f1-5r8rnv2ptxxv
$ 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_STS_REGIONAL_ENDPOINTS=regional
AWS_DEFAULT_REGION=ap-northeast-2
AWS_REGION=ap-northeast-2
AWS_CONTAINER_CREDENTIALS_FULL_URI=http://169.254.170.23/v1/credentials
# 토큰 정보 확인
$ kubectl exec -it eks-pod-identity -- ls /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/
eks-pod-identity-token
$ kubectl exec -it eks-pod-identity -- cat /var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token
eyJhbGc*****.eyJhdWQ*****.ksNQHgN*****
[출처]
1) CloudNet@, AEWS 실습 스터디
2) AWS Summit Korea 2022 - Amazon EKS 마이그레이션 요점정리, 강인호 Solution Architect
5) https://kubernetes.io/docs/tasks/configure-pod-container/configure-projected-volume-storage/
6) https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/
'AWS > EKS' 카테고리의 다른 글
[AEWS2] 6-5. Kyverno (0) | 2024.04.13 |
---|---|
[AEWS2] 6-4. OWASP Kubernetes Top 10 (0) | 2024.04.13 |
[AEWS2] 6-2. EKS Authentication & Authorization (0) | 2024.04.13 |
[AEWS2] 6-1. JWT 란? (0) | 2024.04.13 |
[AEWS2] 5-2. Karpenter (1) | 2024.04.07 |