EKS 8탄 - 6주 차
IRSA이해
IRSA 는 ?
EC2가 탈취 당하면 모든 Pod가 권한을 가지게 되어 취약하게 된다.
따라서 IRSA를 사용하라~
# 설정 예시 1 : eksctl 사용 시
eksctl create cluster --name $CLUSTER_NAME ... --external-dns-access --full-ecr-access --asg-access
# 설정 예시 2 : eksctl로 yaml 파일로 노드 생성 시
cat myeks.yaml | yh
...
managedNodeGroups:
- amiFamily: AmazonLinux2
iam:
withAddonPolicies:
albIngress: false
appMesh: false
appMeshPreview: false
autoScaler: true
awsLoadBalancerController: false
certManager: true
cloudWatch: true
ebs: false
efs: false
externalDNS: true
fsx: false
imageBuilder: true
xRay: false
#콘솔에서 확인
노드 > 보안 > IAM 역할 > 정책으로 모두 추가 된다.
해당 정책을 사용할수 있게 된다는 것이다.
IMDS를 사용하는 모든 컨테이너, 탈취된 컨테이너도 모두 권한을 사용할수 있게 된다.
그래서, IRSA를 사용하게 하자.
1
watch -d kubectl get pods,svc
https://aws.amazon.com/ko/blogs/containers/diving-into-iam-roles-for-service-accounts/
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
// projected: 볼륨을 쓰면, 만료 기간과 대상을 지정할수 있다.
3
시크릿을 projected: 볼륨을 쓴다.
# Create the Secrets:
## Create files containing the username and password:
echo -n "admin" > ./username.txt
echo -n "1f2d1e2e67df" > ./password.txt
4
## Package these files into secrets:
kubectl create secret generic user --from-file=./username.txt
kubectl create secret generic pass --from-file=./password.txt
5
# 파드 생성
kubectl apply -f https://k8s.io/examples/pods/storage/projected.yaml
6
# 파드 확인
볼륨 확인
kubectl get pod test-projected-volume -o yaml | kubectl neat | yh
...
volumes:
- name: all-in-one
projected:
defaultMode: 420
sources:
- secret:
name: user
- secret:
name: pass
- name: kube-api-access-n6n9v
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
7
# 시크릿 확인
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
8
결론
projected: 볼륨을 쓰면, 만료 기간과 대상을 지정할수 있다.
기본 토큰은 위 기능을 제공 하지 않는다.
9
# 삭제
kubectl delete pod test-projected-volume && kubectl delete secret user pass
2
IRSA 는 ?
IRSA는 인증/인가 구현도 전혀 다르다~
POD별로 권한을 할당하는 IRSA
서로다른 롤을 POD가 사용가능하도록 하는 IRSA
파드가 특정 IAM 역할로 Assume 할때 토큰을 AWS에 전송하고, AWS는 토큰과 EKS IdP를 통해 해당 IAM 역할을 사용할 수 있는지 검증
AWS IAM이 쿠버네티스를 통해 인증을 처리한다.
pod는 iam이 받아서 eks쪽 oidc통해 인증 반는다.
절차?
OIDC IDP등록
동영상 보세요
AWS 신은수님 동영상
https://youtu.be/wgH9xL_48vM?t=1163
서비스 어카운트 토큰 기능을 끄고 사용해 보자.
서비스 어카운트의 자동으로 토큰이 발급되는 것을 끄는것이다.
# 파드1 생성
S3 조회하는 파드 사용해보자.
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
EOF
# 확인
kubectl get pod
파드도 에러로 나온다.
kubectl describe pod
# 로그 확인
kubectl logs eks-iam-test1
# 파드1 삭제
kubectl delete pod eks-iam-test1
Kubernetes Pods are given an identity through a Kubernetes concept called a
When a Service Account is created, a JWT token is automatically created as a Kubernetes Secret.
This Secret can then be mounted into Pods and used by that Service Account to authenticate to the Kubernetes API Server.
# 파드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
EOF
# 확인
kubectl get pod
kubectl describe pod
볼륨이 생긴다.
# aws 서비스 사용 시도
kubectl exec -it eks-iam-test2 -- aws s3 ls
파드에서 S3 조회 테스트를 하는 것이다.
# 서비스 어카운트 토큰 확인
토큰은 확인 가능하다.
SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo $SA_TOKEN
# jwt 혹은 아래 JWT 웹 사이트 이용
어떤 토큰인지 확인 할수 있다.
jwt decode $SA_TOKEN --json --iso8601
...
#헤더
{
"alg": "RS256",
"kid": "1a8fcaee12b3a8f191327b5e9b997487ae93baab"
}
# 페이로드 : OAuth2에서 쓰이는 aud, exp 속성 확인! > projectedServiceAccountToken 기능으로 토큰에 audience,exp 항목을 덧붙힘
## iss 속성 : EKS OpenID Connect Provider(EKS IdP) 주소 > 이 EKS IdP를 통해 쿠버네티스가 발급한 토큰이 유요한지 검증
{
"aud": [
"https://kubernetes.default.svc" # 해당 주소는 k8s api의 ClusterIP 서비스 주소 도메인명, kubectl get svc kubernetes
],
"exp": 1716619848,
"iat": 1685083848,
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/F6A7523462E8E6CDADEE5D41DF2E71F6",
"kubernetes.io": {
"namespace": "default",
"pod": {
"name": "eks-iam-test2",
"uid": "10dcccc8-a16c-4fc7-9663-13c9448e107a"
},
"serviceaccount": {
"name": "default",
"uid": "acb6c60d-0c5f-4583-b83b-1b629b0bdd87"
},
"warnafter": 1685087455
},
"nbf": 1685083848,
"sub": "system:serviceaccount:default:default"
}
# 파드2 삭제
kubectl delete pod eks-iam-test2
2
파드가 AWS 서비스를 사용할때 IRSA 세팅을 한다.
# 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)
(2분 걸림)
뭐가 되나?
1) 서비스 어카운트가 생긴다.
2) IAM role이 만들어진다.
3) IAM Role 을 쓸수 있게 트러스트 정책이 추가 된다.(신뢰관계 OIDC 페더레이션도 해준다. 다른 인증기관, 쿠버네티스와 연계 해주는것이다. 오픈ID 커넥터 주소이다.)
3
# 확인 >> 웹 관리 콘솔에서 CloudFormation Stack >> IAM Role 확인
# aws-load-balancer-controller IRSA는 어떤 동작을 수행할 것 인지 생각해보자!
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
(testuser:default) [root@myeks-bastion ~]# eksctl get iamserviceaccount --cluster $CLUSTER_NAME
NAMESPACE NAME ROLE ARN
default my-sa arn:aws:iam::451032684083:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1DD0I6JONR0OE
kube-system aws-load-balancer-controller arn:aws:iam::451032684083:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-1F5FZJEUNH5L8
# Inspecting the newly created Kubernetes Service Account, we can see the role we want it to assume in our pod.
kubectl get sa
.
(testuser:default) [root@myeks-bastion ~]# kubectl get sa
NAME SECRETS AGE
default 0 55m
my-sa 0 37s
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::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1MJUYW59O6QGH
Image pull secrets: <none>
Mountable secrets: <none>
Tokens: <none>
Events: <none>
4
# 파드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
EOF
5
# 해당 SA를 파드가 사용 시 mutatingwebhook으로 Env,Volume 추가함
중간에 환경내용이 자동으로 들어가는 것이다.!!
kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml | kubectl neat | yh
# 파드 생성 yaml에 없던 내용이 추가됨!!!!!
# Pod Identity Webhook은 mutating webhook을 통해 아래 Env 내용과 1개의 볼륨을 추가함
kubectl get pod eks-iam-test3
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::911283464785:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-GE2DZKJYWCEN
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-69rh8 (ro)
...
Volumes:
aws-iam-token:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 86400
kube-api-access-sn467:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
...
6
# 파드에서 aws cli 사용 확인
eksctl get iamserviceaccount --cluster $CLUSTER_NAME
최종적으로 확인!!!
kubectl exec -it eks-iam-test3 -- aws sts get-caller-identity --query Arn
"arn:aws:sts::476286675138:assumed-role/eksctl-myeks-addon-iamserviceaccount-default-Role1-1CN89GMW4W0O5/botocore-session-1686493217"
7
확인 ?
# 되는 것고 안되는 것은 왜그런가?
kubectl exec -it eks-iam-test3 -- aws s3 ls
(testuser:default) [root@myeks-bastion ~]# kubectl exec -it eks-iam-test3 -- aws s3 ls
2023-03-13 08:34:39 cf-templates-18pmd1tc8r6q0-ap-northeast-2
2023-03-21 05:50:14 cf-templates-18pmd1tc8r6q0-us-east-2
2023-04-27 08:48:51 master-seo-bk11
2023-04-27 08:19:29 master-seo-bk9
파드가 할수 잇다.
8
kubectl exec -it eks-iam-test3 -- aws ec2 describe-instances --region ap-northeast-2
ec2는 안된다!!
왜?
롤의 권한이 없다.
kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2
(admin@myeks:default) [root@myeks-bastion ~]# 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 per form this operation.
command terminated with exit code 254
(admin@myeks:default) [root@myeks-bastion ~]# 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.
command terminated with exit code 254
9
삭제
dvwa 인그레스 삭제
kubectl delete ingress ingress-dvwa
핼름 삭제
helm uninstall -n monitoring kube-prometheus-stack
클러스터 삭제
eksctl delete cluster --name $CLUSTER_NAME && aws cloudformation delete-stack --stack-name $CLUSTER_NAME
(10분 걸림)
삭제를 콘솔에서 확인
IAM testuser 계정
EC2 서버 없는지 확인
EC2 > 로드 밸런서에서 로드밸런서 없는지 확인
VPC 삭제
https://brunch.co.kr/@topasvga/3307
전체 보기
https://brunch.co.kr/@topasvga/3217