AEWS STUDY - 6주차 Security

Eljoe·2023년 6월 2일
0

AEWS STUDY

목록 보기
6/7
post-thumbnail

6주차

본 페이지는 AWS EKS Workshop 실습 스터디의 일환으로 매주 실습 결과와 생각을 기록하는 장으로써 작성하였습니다.

실습 전 환경 배포

$curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/eks-oneclick5.yaml
$aws cloudformation deploy --template-file eks-oneclick5.yaml --stack-name myeks --parameter-overrides KeyName=atomy-test-key.pem SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 MyIamUserAccessKeyID=AKIAR5... MyIamUserSecretAccessKey='R1oQ...' ClusterBaseName=myeks --region ap-northeast-2
$ssh -i eljoe-test-key.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)

$kubectl ns default
$NICK=eljoelee
$kubectl ctx
$kubectl config rename-context admin@myeks.ap-northeast-2.eksctl.io $NICK

$MyDomain=eljoe-test.link
$echo "export MyDomain=eljoe-test.link" >> /etc/profile
$MyDnzHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text)

# ExternalDNS
$curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/aews/externaldns.yaml
$MyDomain=$MyDomain MyDnzHostedZoneId=$MyDnzHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -

# LB Controller
$helm repo add eks https://aws.github.io/eks-charts
$helm repo update
$helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=$CLUSTER_NAME \
--set serviceAccount.create=false --set serviceAccount.name=aws-load-balancer-controller

# 노드 IP 변수 지정
$N1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address})
$N2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address})
$N3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address})
$echo "export N1=$N1" >> /etc/profile
$echo "export N2=$N2" >> /etc/profile
$echo "export N3=$N3" >> /etc/profile

# 노드 보안그룹 확인 및 설정
$NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values='*ng1*' --query "SecurityGroups[*].[GroupId]" --output text)
$aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr 192.168.1.0/24

# 노드 접속 확인
$for node in $N1 $N2 $N3; do ssh ec2-user@$node hostname; done

Authentication & Authorization

  • krew 플러그인 설치

    $kubectl krew install access-matrix rbac-tool rbac-view rolesum
    
    # Namespace(default) 리소스 접근 권한 출력
    $kubectl access-matrix --namespace default
    
    # User, Group, ServiceAccount에 연결한 Role/ClusterRole 검색
    $kubectl rbac-tool lookup system:masters
      SUBJECT        | SUBJECT TYPE | SCOPE       | NAMESPACE | ROLE
    +----------------+--------------+-------------+-----------+---------------+
      system:masters | Group        | ClusterRole |           | cluster-admin
  • Flow

    💡 인증은 AWS IAM, 인가는 K8S RBAC에서 처리

    1. EKS Cluster 접근 권한을 부여한 PC에서 kubectl 명령어를 입력한다.

      $kubectl get node
    2. PC의 kubeconfig 내 정의된 eks get-token 명령어를 실행하여 STS(Security Token Service)로 요청을 전달한다.

      $cat ~/.kube/config | yh
      ...
      users:
      - name: eljoe@myeks.ap-northeast-2.eksctl.io
        user:
          exec:
            apiVersion: client.authentication.k8s.io/v1beta1
            args:
            - eks
            - get-token
            - --output
            - json
            - --cluster-name
            - myeks
            - --region
            - ap-northeast-2
            command: aws
            env:
            - name: AWS_STS_REGIONAL_ENDPOINTS
              value: regional
            interactiveMode: IfAvailable
            provideClusterInfo: false
      
      # 하기 명령어를 실행하는 것과 동일하다.
      $aws eks get-token --output json --cluster-name myeks --region ap-northeast-2
    3. STS로부터 Base64로 인코딩된 토큰 값을 응답으로 전달 받는다.

      $aws eks get-token --output json --cluster-name myeks --region ap-northeast-2 | jq
      {
        "kind": "ExecCredential",
        "apiVersion": "client.authentication.k8s.io/v1beta1",
        "spec": {},
        "status": {
          "expirationTimestamp": "2023-05-31T20:49:26Z",
          "token": "k8s-aws-v1.aHR0cHM6..."
        }
      }
      • 토큰 값을 디코딩하면 STS getCallerIdentity API를 호출하는 Pre-Signed URL임을 알 수 있다.

    4. kubectl의 Client-Go 라이브러리가 Pre-Signed URL을 Bearer Token으로 EKS Cluster Endpoint를 통해 API 서버로 요청을 전송한다.

      💡 Client-Go
      K8S 클러스터와 상호작용하기 위한 공식 Go 라이브러리, kubectl은 Client-Go를 내부적으로 사용하여 K8S 클러스터와 상호작용한다.

    5. API 서버는 내부의 token webhook server로 동작하는 aws-iam-authenticator에게 eks get-token 명령어를 통해 생성한 토큰의 Review를 요청한다.

    6. 요청을 전달 받은 aws-iam-authenticator는 Token authentication webhook을 호출하고 토큰을 통해 sts get-caller-identity 명령어를 수행하여 IAM에 요청한다.

      # 호출한 자신의 IAM Entity 반환
      $aws sts get-caller-identity
      {
          "UserId": "AIDAR5GKWUSFIWT65CUO3",
          "Account": "131421611146",
          "Arn": "arn:aws:iam::131421611146:user/eljoe"
      }
      
      # 다음과 같이 x-k8s-aws-id header를 통해 고유한 클러스터 ID를 삽입하여 요청한다.
      $curl -H 'x-k8s-aws-id: myeks' "https://sts.ap-northeast-2.amazonaws.com/?
      Action=GetCallerIdentity&
      Version=2011-06-15&
      X-Amz-Algorithm=AWS4-HMAC-SHA256&
      X-Amz-Credential=AKIAR5GKW...%2F20230601%2Fap-northeast-2%2Fsts%2Faws4_request&
      X-Amz-Date=20230601T015250Z&
      X-Amz-Expires=60&
      X-Amz-SignedHeaders=host%3Bx-k8s-aws-id&
      X-Amz-Signature=97ecd3cd2c64b4180a267f2c76....."
      
      <GetCallerIdentityResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
        <GetCallerIdentityResult>
          <Arn>arn:aws:iam::131421611146:user/eljoe</Arn>
          <UserId>AIDAR5GKWUSFIWT65CUO3</UserId>
          <Account>131421611146</Account>
        </GetCallerIdentityResult>
        <ResponseMetadata>
          <RequestId>75ce0824-62c2-41a9-976c-6723b98d7315</RequestId>
        </ResponseMetadata>
      </GetCallerIdentityResponse>
    7. IAM으로부터 반환받은 UserId, User 또는 Role의 ARN을 kube-system 네임 스페이스의 ConfigMap aws-auth의 User/Group 정보와 매핑하고 API 서버에 TokenReview라는 데이터 타입으로 반환한다.

      # kubectl get cm -n kube-system aws-auth -o yaml
      apiVersion: v1
      data:
        mapRoles: |
          - groups:
            - system:bootstrappers
            - system:nodes
            rolearn: arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-COZS3070MAKG
            username: system:node:{{EC2PrivateDNSName}}
      	mapUsers: |
      	  - groups:
      	    - system: masters
      	    userarn: arn:aws:iam::131421611146:user/eljoe
      	    username: admin
      kind: ConfigMap
      metadata:
        creationTimestamp: "2023-05-31T14:28:19Z"
        name: aws-auth
        namespace: kube-system
      
      $kubectl api-resources | grep authentication
      tokenreviews  authentication.k8s.io/v1  false  TokenReview
      
      $kubectl explain tokenreviews
      KIND:     TokenReview
      VERSION:  authentication.k8s.io/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.
    8. 반환 받은 TokenReview를 활용하여 RBAC를 통해 요청을 허용/거부하는 인가 작업을 처리한다.

      # EKS를 설치한 IAM User는 aws-auth와 상관없이 system:masters 그룹에 속한다.
      $kubectl rbac-tool whoami
      {Username: "kubernetes-admin",
       UID:      "aws-iam-authenticator:131421611146:AIDAR5GKWUSFIWT65CUO3",
       Groups:   ["system:masters",
                  "system:authenticated"],
       Extra:    {accessKeyId:  ["AKIAR5GKWUSFNUELTDHK"],
                  arn:          ["arn:aws:iam::131421611146:user/eljoe"],
                  canonicalArn: ["arn:aws:iam::131421611146:user/eljoe"],
                  principalId:  ["AIDAR5GKWUSFIWT65CUO3"],
                  sessionName:  [""]}}
      
      $kubectl rbac-tool lookup system:master
        SUBJECT        | SUBJECT TYPE | SCOPE       | NAMESPACE | ROLE
      +----------------+--------------+-------------+-----------+---------------+
        system:masters | Group        | ClusterRole |           | cluster-admin
      
      $kubectl rolesum -k Group system:masters
      Group: system:masters
      
      Policies:
      • [CRB] */cluster-admin ⟶  [CR] */cluster-admin
        Resource  Name  Exclude  Verbs  G L W C U P D DC
        *.*       [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔
      
      # system:master 그룹이 사용 가능한 Cluster Role : cluster-admin
      $kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin
      Name:         cluster-admin
      Labels:       kubernetes.io/bootstrapping=rbac-defaults
      Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
      Role:
        Kind:  ClusterRole
        Name:  cluster-admin
      Subjects:
        Kind   Name            Namespace
        ----   ----            ---------
        Group  system:masters
      
      # PolicyRule : 모든 리소스 사용 가능
      $kubectl describe clusterrole cluster-admin
      Name:         cluster-admin
      Labels:       kubernetes.io/bootstrapping=rbac-defaults
      Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
      PolicyRule:
        Resources  Non-Resource URLs  Resource Names  Verbs
        ---------  -----------------  --------------  -----
        *.*        []                 []              [*]
                   [*]                []              [*]
  • Example - 임의 사용자(testuser) 권한 설정해보기

    1. IAM User 생성 - myeks-bastion

      $aws iam create-user --user-name testuser
      
      # 액세스 키 부여
      $aws iam create-access-key --user-name testuser
      {
          "AccessKey": {
              "UserName": "testuser",
              "AccessKeyId": "AKIAR5GK...",
              "Status": "Active",
              "SecretAccessKey": "+RI3Z28KkqegyUbHXDd....",
              "CreateDate": "2023-06-01T07:34:52+00:00"
          }
      }
      
      # AdministratorAccess 정책 부여
      $aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser
      
      # getCallerIdentity 확인
      $aws sts get-caller-identity --query Arn
      "arn:aws:iam::131421611146:user/eljoe"
    2. 자격증명 설정 - myeks-bastion-2

      $aws configure
      AWS Access Key ID [None]: AKIAR5...
      AWS Secret Access Key [None]: +RI3Z28Kkqeg...
      Default region name [None]: ap-northeast-2
      Default output format [None]:
      
      $aws sts get-caller-identity --query Arn
      "arn:aws:iam::131421611146:user/testuser"
      
      # kubectl 명령어 실패
      $kubectl get node
      E0601 16:44:28.272734    5811 memcache.go:265] couldn't get current server API group list: Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
    3. testuser > system:masters 그룹 부여 - myeks-bastion

      $eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/testuser
      
      # configmap > aws-auth mapUsers 확인
      $kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh
      apiVersion: v1
      data:
        mapRoles: |
          - groups:
            - system:bootstrappers
            - system:nodes
            rolearn: arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-COZS3070MAKG
            username: system:node:{{EC2PrivateDNSName}}
        mapUsers: |
          - groups:
            - system:masters
            userarn: arn:aws:iam::131421611146:user/testuser
            username: testuser
      kind: ConfigMap
      metadata:
        name: aws-auth
        namespace: kube-system
      
      # 확인
      $eksctl get iamidentitymapping --cluster $CLUSTER_NAME
      ARN                                                                                     USERNAME                                GROUPS                  ACCOUNT
      arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-COZS3070MAKG system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes
      arn:aws:iam::131421611146:user/testuser                                                 testuser                                system:masters
    4. testuser kubeconfig 생성 및 kubectl 확인 - myeks-bastion-2

      # kubeconfig 생성
      $aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser
      
      # kubectl 사용 확인
      $kubectl ns default
      $kubectl get node
      
      $kubectl krew install rbac-tool && kubectl rbac-tool whoami
      ...
      {Username: "testuser",
       UID:      "aws-iam-authenticator:131421611146:AIDAR5GKWUS...",
       Groups:   ["system:masters",
                  "system:authenticated"],
       Extra:    {accessKeyId:  ["AKIAR5GKWUS..."],
                  arn:          ["arn:aws:iam::131421611146:user/testuser"],
                  canonicalArn: ["arn:aws:iam::131421611146:user/testuser"],
                  principalId:  ["AIDAR5GKWUS..."],
                  sessionName:  [""]}}
    5. testuser > Group 변경(system:masters > system:authenticated) 후 RBAC 동작 확인 - myeks-bastion

      $kubectl edit cm -n kube-system aws-auth
      ...
      mapUsers: |
          - groups:
            - system:authenticated
            userarn: arn:aws:iam::131421611146:user/testuser
            username: testuser
      ...
      
      $eksctl get iamidentitymapping --cluster $CLUSTER_NAME
      ...
      arn:aws:iam::131421611146:user/testuser testuser system:authenticated
    6. testuser kubectl 사용 확인 - myeks-bastion-2

      $kubectl get node
      Error from server (Forbidden): nodes is forbidden: User "testuser" cannot list resource "nodes" in API group "" at the cluster scope
      
      $kubectl api-resources
      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
      ...
    7. testuser IAM Mapping 삭제 - myeks-bastion

      $eksctl delete iamidentitymapping --cluster $CLUSTER_NAME --arn  arn:aws:iam::$ACCOUNT_ID:user/testuser
      
      $eksctl get iamidentitymapping --cluster $CLUSTER_NAME
      ARN                                                                                     USERNAME                                GROUPS                  ACCOUNT
      arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-COZS3070MAKG system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes
      
      $kubectl get cm -n kube-system aws-auth -o yaml | yh
      apiVersion: v1
      data:
        mapRoles: |
          - groups:
            - system:bootstrappers
            - system:nodes
            rolearn: arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-COZS3070MAKG
            username: system:node:{{EC2PrivateDNSName}}
        mapUsers: |
          []
      kind: ConfigMap
      metadata:
        name: aws-auth
        namespace: kube-system
    8. testuser kubectl 사용 확인

      $kubectl get node
      error: You must be logged in to the server (Unauthorized)
      
      $kubectl api-resources
      E0601 17:52:37.342753    6877 memcache.go:265] couldn't get current server API group list: the server has asked for the client to provide credentials
      NAME   SHORTNAMES   APIVERSION   NAMESPACED   KIND
      error: You must be logged in to the server (the server has asked for the client to provide credentials)
    • 도전과제 - ReadOnlyAccess 부여
      $cat <<EOF | kubectl apply -f -
      kind: ClusterRoleBinding
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: resource-readonly
      subjects:
      - kind: Group
        name: readonly
        apiGroup: rbac.authorization.k8s.io
      roleRef:
        kind: ClusterRole
        name: resource-readonly
        apiGroup: rbac.authorization.k8s.io
      EOF
      
      $cat <<EOF | kubectl apply -f -
      kind: ClusterRole
      apiVersion: rbac.authorization.k8s.io/v1
      metadata:
        name: resource-readonly
      rules:
      - apiGroups: ["*"]
        resources: ["*"]
        verbs: ["get", "watch", "list"]
      EOF
      
      # 'readonly' 그룹으로 수정
      $kubectl edit cm -n kube-system aws-auth
      ...
      mapUsers: |
      	- groups:
      	  - readonly
      	  userarn: arn:aws:iam::123456789:user/testuser
      	  username: testuser
      ...
      
      $eksctl get iamidentitymapping --cluster $CLUSTER_NAME
      ARN                                                                                             USERNAME                                GROUPS                                  ACCOUNT
      arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1GNS41CWX1J3T        system:node:{{EC2PrivateDNSName}}       system:bootstrappers,system:nodes
      arn:aws:iam::131421611146:user/testuser                                                         testuser                                readonly
      
      $kubectl get all
      NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
      service/kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   4h24m

IAM Roles for Service Account

  • IAM Instance Profile을 부여한 EC2 인스턴스를 EKS의 Worker Node로 사용할 경우 해당 노드 내에 배포된 모든 파드가 동일한 권한을 갖게 되므로, 최소 권한 부여 원칙을 위배하여 보안상 권고하지 않는다.

  • 따라서 AWS에서는 파드별로 사용하는 Sevice Account마다 서로 다른 IAM Role의 매핑이 가능한 IRSA를 제공한다.

  • 전체적인 플로우는 아래와 같다.

  • 실습 1 - Service Account가 없는 Pod
    # aws-cli 명령어를 실행하는 pod 생성
    $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
    
    # SA가 없으므로 Access Denied이 되었음을 확인할 수 있다.
    $kubectl logs eks-iam-test1
    An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
    
    # CloudTrail Event로도 조회할 수 있다.
    $aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=ListBuckets --max-items 5 --query "Events[].CloudTrailEvent"| jq
    {
        "eventVersion": "1.08",
        "userIdentity": {
            "type": "AssumedRole",
            "principalId": "xxx",
            "arn": "arn:aws:sts::123456789:assumed-role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-xxxxx/xxxx",
            "accountId": "123456789",
            "accessKeyId": "ASIAR5...",
            "sessionContext": {
                "sessionIssuer": {
                    "type": "Role",
                    "principalId": "AROAR5GKWU...",
                    "arn": "arn:aws:iam::131421611146:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-...",
                    "accountId": "123456789",
                    "userName": "eksctl-myeks-nodegroup-ng1-NodeInstanceRole-..."
                },
               ...
            }
        },
        "eventTime": "2023-06-02T03:51:11Z",
        "eventSource": "s3.amazonaws.com",
        "eventName": "ListBuckets",
        "awsRegion": "ap-northeast-2",
        "sourceIPAddress": "3.35.5.21",
        "userAgent": "[aws-cli/2.11.24 Python/3.11.3 Linux/5.10.179-166.674.amzn2.x86_64 docker/x86_64.amzn.2 prompt/off command/s3.ls]",
        "errorCode": "AccessDenied",
        "errorMessage": "Access Denied",
        "requestParameters": {
            "Host": "s3.ap-northeast-2.amazonaws.com"
        },
        ...
    }
  • 실습 2 - Service Account가 있는 Pod
    # aws-cli 명령어를 실행하는 pod 생성
    $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
    
    # SA를 생성했음에도 Access Denied 확인
    $kubectl exec -it eks-iam-test2 -- aws s3 ls
    An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied
    command terminated with exit code 254
    
    # SA 확인
    $SA_TOKEN=$(kubectl exec -it eks-iam-test2 -- cat /var/run/secrets/kubernetes.io/serviceaccount/token)
    $echo $SA_TOKEN
    eyJhbGciOiJSUzI...
    • 아래와 같이 SA 토큰 값을 디코딩하면 아래와 같은 내용을 확인할 수 있다.
      • projectedServiceAccountToken 기능으로 토큰에 aud, exp 항목 추가

      • iss는 EKS OpenID Connect Provider(EKS IdP) 주소로 작성되어있다. 즉, K8S가 발급한 토큰의 유효성 검증은 EKS IdP에서 수행한다.

        {
          "aud": [
            "https://kubernetes.default.svc"
          ],
          "exp": 1717214976,
          "iat": 1685678976,
          "iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/B4EAA30DD353145BF5DD356107D1A0D4",
          "kubernetes.io": {
            "namespace": "default",
            "pod": {
              "name": "eks-iam-test2",
              "uid": "11e6d9f8-d0e7-4102-ab4f-0ba5dd37efc9"
            },
            "serviceaccount": {
              "name": "default",
              "uid": "24ab5d1a-58cf-487b-9a83-86a3e77e2e3d"
            },
            "warnafter": 1685682583
          },
          "nbf": 1685678976,
          "sub": "system:serviceaccount:default:default"
        }
        • iss: 토큰 발행자
        • sub: 사용자를 구분하기 위한 유니크한 구분자
        • email: 사용자의 이메일
        • iat: 토큰이 발행되는 시간을 Unix time으로 표기한 것
        • exp: 토큰이 만료되는 시간을 Unix time으로 표기한 것
        • aud: ID Token이 어떤 Client를 위해 발급된 것인지.

  • 실습 3 - IRSA 적용
    # IRSA 생성
    $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)
    
    # SA 확인
    $eksctl get iamserviceaccount --cluster $CLUSTER_NAME
    NAMESPACE       NAME                            ROLE ARN
    default         my-sa                           arn:aws:iam::131421611146:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-FK6GGUC9B133
    kube-system     aws-load-balancer-controller    arn:aws:iam::131421611146:role/eksctl-myeks-addon-iamserviceaccount-kube-sy-Role1-F55Y1OOUV3JW
    
    $kubectl get sa
    NAME      SECRETS   AGE
    default   0         3h23m
    my-sa     0         13m
    
    $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::131421611146:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-FK6GGUC9B133
    Image pull secrets:  <none>
    Mountable secrets:   <none>
    Tokens:              <none>
    Events:              <none>
    
    # 역할 조회 : sts:AssumeRoleWithWebIdentity > system:serviceaccount:default:my-sa
    $aws iam get-role \
    --role-name $(aws cloudformation describe-stacks --stack-name eksctl-myeks-addon-iamserviceaccount-default-my-sa --query 'Stacks[*].Outputs[0].OutputValue' --output text | cut -d '/' -f2)
    
    {
        "Role": {
            "Path": "/",
            "RoleName": "eksctl-myeks-addon-iamserviceaccount-default-Role1-FK6GGUC9B133",
            "RoleId": "AROAR5G...",
            "Arn": "arn:aws:iam::131421611146:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-FK6GGUC9B133",
            "CreateDate": "2023-06-02T04:29:24+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Federated": "arn:aws:iam::123456789:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/xxxx"
                        },
                        "Action": "sts:AssumeRoleWithWebIdentity",
                        "Condition": {
                            "StringEquals": {
                                "oidc.eks.ap-northeast-2.amazonaws.com/id/xxxx:sub": "system:serviceaccount:default:my-sa",
                                "oidc.eks.ap-northeast-2.amazonaws.com/id/xxxx:aud": "sts.amazonaws.com"
                            }
                        }
                    }
                ]
            },
           ...
        }
    }
    # aws-cli 명령어를 실행하는 pod 생성 > SA 값 삽입
    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
    
    # 파드 생성 시 작성한 YAML에 없는 내용이 추가되었다. - Env, Volume
    $kubectl describe pod eks-iam-test3
    ...
    Containers:
      my-aws-cli:
        ...
        Environment:
          AWS_STS_REGIONAL_ENDPOINTS:   regional
          AWS_DEFAULT_REGION:           ap-northeast-2
          AWS_REGION:                   ap-northeast-2
          AWS_ROLE_ARN:                 arn:aws:iam::131421611146:role/eksctl-myeks-addon-iamserviceaccount-default-Role1-FK6GGUC9B133
          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-7jfkk (ro)
    ...
    Volumes:
      aws-iam-token:
        Type:                    Projected (a volume that contains injected data from multiple sources)
        TokenExpirationSeconds:  86400
      kube-api-access-7jfkk:
        Type:                    Projected (a volume that contains injected data from multiple sources)
        TokenExpirationSeconds:  3607
        ConfigMapName:           kube-root-ca.crt
        ConfigMapOptional:       <nil>
        DownwardAPI:             true
    ...
    
    # Pod Identity Webhook은 mutating webhook을 통해 Env, Volume 값을 추가함
    $kubectl get mutatingwebhookconfigurations pod-identity-webhook -o yaml | kubectl neat | yh
    
    # 파드에서 aws-cli 사용 확인 - AmazonS3ReadOnlyAccess 권한만 부여했으므로 다른 작업은 되지않음!
    $kubectl exec -it eks-iam-test3 -- aws s3 ls
    2023-04-13 07:11:55 cdk-hnb659fds-assets-131421611146-ap-northeast-2
    ...
    
    $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
    
    # 도전과제 - ReadOnlyAccess 부여
    $eksctl create iamserviceaccount \
    --name my-sa-readonly \
    --namespace default \
    --cluster $CLUSTER_NAME \
    --approve \
    --attach-policy-arn $(aws iam list-policies --query 'Policies[?PolicyName==`ReadOnlyAccess`].Arn' --output text)
    
    $kubectl get sa
    NAME             SECRETS   AGE
    default          0         3h46m
    my-sa            0         36m
    my-sa-readonly   0         14s
    
    $cat <<EOF | kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: eks-iam-test3
    spec:
      serviceAccountName: my-sa-readonly
      containers:
        - name: my-aws-cli
          image: amazon/aws-cli:latest
          command: ['sleep', '36000']
      restartPolicy: Never
    EOF
    
    $kubectl exec -it eks-iam-test3 -- aws ec2 describe-vpcs --region ap-northeast-2
    {
      "Vpcs": [
    ... 
profile
DevOps Engineer

0개의 댓글