brunch

You can make anything
by writing

C.S.Lewis

by Master Seo May 30. 2023

EKS 8탄-14. EKS 보안3 -IRSA

EKS 8탄 - 6주 차

본 내용은 CloudNet 주말 스터디 내용을 참고로 작성되었습니다.

https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9 dfa44 a27 ff431 dafdd2 edacc8 a1863  

계속 테스트하며  내용과 설명이 업데이트됩니다.



목표

IRSA이해



<1> IRSA 동작  이해

<2> 실습 0

<3> 실습 1

<4> 실습 2

<4> 실습 3 - IRSA 세팅 후 확인



<1> IRSA 동작  이해


IRSA 는 ?

k8s 파드가  AWS 서비스 사용 시 필요하다.



1

EC2 Instance Profile은 사용하기 편하지만, 최소 권한 제공원칙에 위배된다.

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를 사용하게 하자.




<2> 실습 0


1

watch -d kubectl get pods,svc


2

링크

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 는 ?

k8s 파드가  AWS 서비스 사용 시 필요하다.

AWS STS/IAM ↔ IAM OIDC Identity Provider(EKS IdP) 인증/인가를 처리한다.

IRSA는 인증/인가 구현도 전혀 다르다~



3

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






<3> 실습 1


서비스 어카운트 토큰 기능을 끄고 사용해 보자.


서비스 어카운트의 자동으로 토큰이 발급되는 것을 끄는것이다.


# 파드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





<4>  실습 2


Kubernetes Pods are given an identity through a Kubernetes concept called a 

Kubernetes Service Account


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






<4> 실습 3 - IRSA 세팅 후 확인


1

IRSA는  Pod가 AWS서비스 어카운트를 사용하려 할 때 쓴다.


iamserviceaccount로 입력하는 것은  IRSA이다.

해당 Pod만 동작한다.

애버테이션에 들어간 롤 확인


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



감사합니다.



매거진의 이전글 EKS 8탄-13. EKS 보안2-취약점 점검
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari