1
2
AWS EKS Workshop Study (=AEWS)는 EKS Workshop 실습 스터디입니다.
CloudNet@ Gasida(가시다)님이 진행하시며,공개된 AWS EKS Workshop을 기반으로 진행하고 있습니다.

스터디도 어느덧 6주차다. 6주차에는 EKS 보안을 주제로 모임장님이 스터디를 진행해주셨다. 스터디 내용으로 EKS 인증 / 인가와 IRSA의 원리를 소개해주셨는데.. 개인적으로 여러 번 돌려볼 정도로 내용이 많이 어려웠다.

필자 스스로 보안이 다른 분야에 비해 미숙한 부분도 있고,, 아는 내용도 별로 없기 떄문이라 본다. 아마 필자에게 EKS 보안에 대해 소개해달라고 요청받으면 인증 → 인가 → RBAC 수준으로 밖에 답을 못할 것이라 예상한다. 이번 기회에 EKS 보안 원리를 손 쉽게 학습할 수 있는 기회가 생겨 운이 좋았다고 생각한다. 이번 블로그 글에서는 EKS 보안에 대해 필자가 학습 내용을 공유할 것이다. 스터디에서 학습한 EKS 인증/인가, IRSA 에 대한 내용과 워크샵에서 학습한 AWS 서비스를 통한 EKS 보안 구성이 주가 될 예정이다.

쿠버네티스 보안 체계

<a href="https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication/">https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication/</a>

https://kubetm.github.io/k8s/07-intermediate-basic-resource/authentication/

쿠버네티스에서는 API 서버가 인증→ 인가→ Admission Control을 통해 클러스터 접근에 대한 보안을 관리 및 제어한다.

  1. 인증(Authentication): 사용자의 신원을 확인하는 단계이다. 쿠버네티스에서는 X.509 Client Cert 를 쿠버네티스 접근 파일(kubeconfig)에 저장시키거나 서비스 어카운트를 통해 인증 작업을 수행한다.
  2. 인가(Authorization): 사용자가 시스템의 특정 리소스에 접근하거나 특정 작업을 수행할 권한이 있는지확인하는 단계이다. 쿠버네티스에서는 Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), Webhook, Node Auththorization 등의 메커니즘을 통해 인가 작업을 수행한다.
  3. Admission Control: 인증, 인가 요청을 처리하기 전에 요청을 검사하고 수정하거나 거부하는 일련의 플러그인 단계이다. Mutating Admission Webhooks, Validating Admission Webhooks 을 통해 요청된 오브젝트를 수정하여 추가 보안 플러그인(IRSA)에 확장 연결시켜주는 작업을 수행한다.

EKS 인증/인가

EKS에서 인증/인가 작업은 나눠서 진행된다. 인증은 AWS IAM, 인가는 k8s RBAC이 수행한다. 각 작업의 대한 세부 동작은 다음 그림과 같이 진행된다.

<a href="https://awskoreamarketingasset.s3.amazonaws.com/2022%20Summit/pdf/T10S1_EKS%20%ED%99%98%EA%B2%BD%EC%9D%84%20%EB%8D%94%20%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EB%8D%94%20%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C.pdf">https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf</a>

https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf

이해하기 쉽지 않다! 필자 또한 여러번 영상을 돌려보고 실습을 통해 겨우 이해했다. 쉬운 이해를 위해 직접 해당 과정을 실습해보도록 하겠다. 그림에 순서도가 나와있지 않지만 왼쪽 Authentication(인증) → 아래 Authorization(인가) 작업을 통해 진행된다. 여기서 봐야할 점은 인증 작업에서의 AWS IAM 와 연계 작업이다.

<a href="https://awskoreamarketingasset.s3.amazonaws.com/2022%20Summit/pdf/T10S1_EKS%20%ED%99%98%EA%B2%BD%EC%9D%84%20%EB%8D%94%20%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EB%8D%94%20%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C.pdf">https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf</a>

https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf

인증 과정을 IAM 와 연계해서 확인해보자면 다음과 같이 요약할 수 있다.

IAM Authenticator Client 에서 토큰을 발급받고 → 발급받은 토큰을 IAM Authenticator Server에 요청하여 인증 작업을 수행한다.

  1. 토큰 발급

    앞 서 과정에서 IAM Authenticator Client가 토큰을 발급해주는 객체인 것을 확인하였다. 그렇다면 토큰 발급은 누가 요청하는 것일까? eks 접근 파일인 kubeconfig를 확인하면 이를 확인할 수 있다 .

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    cat ~/.kube/config | yh
    ---
    ...
    - name: terraform-eks@hanhorang.ap-northeast-2.eksctl.io
      user:
        exec:
          apiVersion: client.authentication.k8s.io/v1beta1
          args:
          - eks
          - get-token
          - --output
          - json
          - --cluster-name
          - hanhorang
          - --region
          - ap-northeast-2
          command: aws
          env:
          - name: AWS_STS_REGIONAL_ENDPOINTS
            value: regional
          provideClusterInfo: false
    

    위의 커맨드를 입력하면 그대로 입력하면 아래와 같이 토큰을 확인할 수 있다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    aws eks get-token --cluster-name $CLUSTER_NAME | jq
    ---
    {
      "kind": "ExecCredential",
      "apiVersion": "client.authentication.k8s.io/v1beta1",
      "spec": {},
      "status": {
        "expirationTimestamp": "2023-06-03T07:17:27Z",
        "token": "k8s..."
      }
    }
    
    • 발급 정보를 확인하면 expirationTimestamp 필드를 확인할 수 있는데 해당 토큰의 수명이다. 이는 발급받은 토큰이 임시 보안 자격 증명으로 활용되는 것을 확인할 수 있다.

    발급받은 토큰을 jwt에서 확인하면 토큰 정보가 다음과 같이 구성됨을 확인할 수 있다.

    <a href="https://jwt.io/">https://jwt.io/</a>

    https://jwt.io/

    PAYLOAD 정보를 확인하면 해당 정보가 AWS API 호출시의 필드와 유사한 것을 확인할 수 있다. 자세히보면, AWS sts(임시자격증명 제공자)에 getcallerIdentity(토큰발급)을 요청(Action)한 것을 확인할 수 있다.

  2. 토큰 리뷰

    발급받은 토큰을 IAM Authenticator Server에 요청하면 인증 작업이 완료된다. 토큰 리뷰 요청은 API 서버에서 진행되어 과정에 대해 세부 확인을 못하지만 AWS CloudTrail 콘솔에서 리뷰 작업을 확인할 수 있다.

    eks-iam2.png

  3. 인가

    인증 작업이 완료되면 User/Role에 대한 ARN을 반환하게 되고 해당 ARN에 대한 RBAC 작업을 수행한다. 인가 작업에 대한 설정은 aws-auth 컨피그 맵에서 확인할 수 있다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    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::-:role/eksctl-hanhorang-nodegroup-ng1-NodeInstanceRole-1BT7EJGDT32FR
          username: system:node:{{EC2PrivateDNSName}}
    kind: ConfigMap
    metadata: 
      name: aws-auth
      namespace: kube-system
    
    • mapRoles에서 rolearn이 인증작업에서 반환된 arn이 입력되며 groups에서 설정한 역할에 바인딩되어 RBAC처리가 진행된다.

    RBAC 확인은 krew 플러그인 설치를 통해 자세히 확인할 수 있다.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    # 플러그인 설치
    kubectl krew install access-matrix rbac-tool rbac-view rolesum
    
    
    # EKS 설치한 IAM user 정보 
    kubectl rbac-tool whoami 
    --
    {Username: "kubernetes-admin",
     UID:      "aws-iam-authenticator:955963799952:AIDA55E7B7GIFCJDANOIO",
     Groups:   ["system:masters",
                "system:authenticated"],
     Extra:    {accessKeyId:  ["AKIA55E7B7GIPMN3X7NP"],
                arn:          ["arn:aws:iam::955963799952:user/terraform-eks"],
                canonicalArn: ["arn:aws:iam::955963799952:user/terraform-eks"],
                principalId:  ["AIDA55E7B7GIFC
    
    # system:master RBAC 확인
    kubectl rbac-tool lookup system:masters
    ---
    W0603 16:28:17.218380    9877 warnings.go:67] policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
      SUBJECT        | SUBJECT TYPE | SCOPE       | NAMESPACE | ROLE           
    +----------------+--------------+-------------+-----------+---------------+
      system:masters | Group        | ClusterRole |           | cluster-admin
    
    # role에 할당된 cluster-admin 확인
    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
      ---------  -----------------  --------------  -----
      *.*        []                 []              [*]
                 [*]                []              [*] 
    
    • aws-auth 컨피그맵에는 클러스터 생성 IAM 사용자(kubernetes-admin) 의 정보가 없는 것을 확인할 수 있는데 보안 이슈(탈취 및 삭제) 로 AWS 가 자체적으로 숨겨둔 것 같다.

EKS 에 사용자 추가하기

스터디에서 공유해주신 실습 예제로 EKS 클러스터 관리(모든 리소스 읽기 권한 부여)를 위한 사용자를 추가하고 새 베스천 서버에서 접근이 가능한 지 확인해보겠다.

  • [베스천 서버-1] IAM 사용자 추가 및 클러스터 접근 권한 부여

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    # testuser 사용자 생성 
    aws iam create-user --user-name testuser 
    
    # 사용자에게 프로그래밍 방식 액세스 권한 부여
    aws iam create-access-key --user-name testuser
    --
    {
        "AccessKey": {
            "UserName": "testuser",
            "AccessKeyId": "AKIA55E7B7GIOXM4OAVI",
            "Status": "Active",
            "SecretAccessKey": "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",
            "CreateDate": "2023-06-03T07:38:08+00:00"
        }
    }
    
    # testuser 사용자에 IAM 정책을 추가
    aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser
    
    # 구별을 위해 베스천 서버 1의 arn 확인 
    "arn:aws:iam::0000000000:user/hanohnrag-eks"
    

    다음은 클러스터 RBAC 권한(모든 리소스 읽기 권한) 을 생성하여 group:user 에 바인딩하자.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: readonly
    rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["get", "watch", "list"]
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: readonly-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: readonly
    subjects:
    - kind: Group
      name: user
      apiGroup: rbac.authorization.k8s.io
    

    생성한 Group에 IAM 유저(testuser)를 매핑하자.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group user --arn arn:aws:iam::$ACCOUNT_ID:user/testuser
    --
    2023-06-03 16:59:25 []  checking arn arn:aws:iam::0000000000:user/testuser against entries in the auth ConfigMap
    2023-06-03 16:59:25 []  adding identity "arn:aws:iam::0000000000:user/testuser" to auth ConfigMap
    
    # 매핑 확인
    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::0000000000:role/eksctl-hanhorang-nodegroup-ng1-NodeInstanceRole-1BT7EJGDT32FR
          username: system:node:{{EC2PrivateDNSName}}
      mapUsers: |
        - groups:
          - user
          userarn: arn:aws:iam::0000000000:user/testuser
          username: testuser
    
  • [베스천 서버-2] test-user 권한 부여 확인

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    # IAM ARN 확인 
    aws sts get-caller-identity --query Arn
    ---
    Unable to locate credentials. You can configure credentials by running "aws configure".
    
    # testuser 액세스 키 입력 
    aws configure 
    --
    AWS Access Key ID [None]: AKIA55E7B7GIOXM4OAVI
    AWS Secret Access Key [None]: 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
    Default region name [None]: ap-northeast-2
    Default output format [None]: json
    
    # 확인 
    aws sts get-caller-identity --query Arn
    ---
    "arn:aws:iam::955963799952:user/testuser"
    
    # 접근 파일 업데이트
    aws eks --region ap-northeast-2 update-kubeconfig --name hanhorang
    
    # 확인 
    kubectl get pods -A 
    ---
    NAMESPACE     NAME                                        READY   STATUS    RESTARTS   AGE
    default       mysql-9fd5797cc-d7r2g                       1/1     Running   0          4h47m
    default       sealed-secrets-855f5fbf78-d2j4b             1/1     Running   0          5h26m
    kube-system   aws-node-j6nq2                              1/1     Running   0          8h
    kube-system   aws-node-lg25d                              1/1     Running   0          8h
    kube-system   coredns-6777fcd775-68cql                    1/1     Running   0          8h
    kube-system   coredns-6777fcd775-jzxr2                    1/1     Running   0          8h
    kube-system   ebs-csi-controller-67dccdf78f-65hr5         6/6     Running   0          8h
    kube-system   ebs-csi-controller-67dccdf78f-hjgjm         6/6     Running   0          8h
    kube-system   ebs-csi-node-4jzmh                          3/3     Running   0          8h
    kube-system   ebs-csi-node-68n58                          3/3     Running   0          8h
    kube-system   kube-proxy-8bgrm                            1/1     Running   0          8h
    kube-system   kube-proxy-wvnfs                            1/1     Running   0          8h
    kube-system   sealed-secrets-controller-b97869575-d7prq   1/1     Running   0          5h17m
    
  • IAM User로 할당했지만 role로 할당도 가능하다. role로 할당하면 다수의 사용자에게 권한 부여 관리가 간편해지므로 추가로 작성한다.

    • test-role 생성

      iam-role2.png

    • role과 쿠버네티스 RBAC 매핑

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      
      # 매핑 
      eksctl create iamidentitymapping \
      --cluster $CLUSTER_NAME \
      --username testuser \
      --group user \
      --arn arn:aws:iam::$ACCOUNT_ID:role/test-role
      
      # 매핑 확인 
      kubectl get cm aws-auth -o yaml -n kube-system
      --
      ...
      - groups:
            - user
            rolearn: arn:aws:iam::00000000000:role/test-role
            username: testuser
      
    • 접근파일 업데이트 후 kubectl 사용

      접근 파일 업데이트 후 kubectl 사용 시 아래 와 같은 문제로 쿠버네티스에 접근이 안된다.

      1
      2
      3
      4
      5
      
      aws eks --region ap-northeast-2 update-kubeconfig --name hanhorang --role-arn arn:aws:iam::955963799952:role/test-role
      
      kubectl get pods -A 
      --
      An error occurred (AccessDenied) when calling the AssumeRole operation: User: arn:aws:iam::955963799952:user/testuser is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::955963799952:role/test-role
      

      이유는 role의 신뢰 관계를 업데이트하지 않았기 때문인데 iam role에서 신뢰관계에 유저를 추가하면 정상적으로 작동한다.

      iam-role3.png

      bestion3.png

      이번 예제에서는 사용자에게 role를 부여하여 클러스터에 접근했으나, role 을 베스천서버에 위임하여 사용할 수 있다.

EKS 인증/인가 한계

사용하기 편하지만, 최소 권한 부여 원칙에 위배되어 보안상 권고하지 않는다. 이유는 파드가 뚫리면 메타데이터를 활용하여 노드에 부여된 IAM 정책을 이용할 수 있기 때문이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 메타데이터를 통해 토큰 발급 후 조회 
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
echo $TOKEN

# 메타 정보를 통해 임시 접근 키 부여 
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/meta-data/iam/security-credentials/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-1DC6Y2GRDAJHK
--
{
    "AccessKey": {
        "UserName": "testuser",
        "AccessKeyId": "AKIA55E7B7GIOXM4OAVI",
        "Status": "Active",
        "SecretAccessKey": "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",
        "CreateDate": "2023-06-03T07:38:08+00:00"
    }
}

파드가 뚫리면 노드에 등록된 IAM 정책의 권한이 다 뚫리므로 치명적이다. 이에 대해 새로운 인증/인가의 접근 방법(IRSA)이 필요하다.

IRSA

IRSA(Iam Role for Service Account)는 쿠버네티스 서비스 어카운트에 IAM role을 부여하여 AWS 서비스에 대한 사용을 제어하는 방법이다. 기존의 EKS 인증/인가 체계와는 반대로로 서비스 어카운트(RBAC) 단계에서 IAM role을 부여하여 IAM OIDC를 통해 인증/인가가 진행되는 방식이다.

IRSA에 대한 원리는 다음의 그림을 통해 확인할 수 있다. 핵심은Admisstion Control 이다. Admisstion Control 의 Webhook으로 확장 API를 연결해서 IAM 에서 인증/인가를 대신 진행시켜준다라고 보면 된다.

<a href="https://awskoreamarketingasset.s3.amazonaws.com/2022%20Summit/pdf/T10S1_EKS%20%ED%99%98%EA%B2%BD%EC%9D%84%20%EB%8D%94%20%ED%9A%A8%EC%9C%A8%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EB%8D%94%20%EC%95%88%EC%A0%84%ED%95%98%EA%B2%8C.pdf">https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf</a>

https://awskoreamarketingasset.s3.amazonaws.com/2022 Summit/pdf/T10S1_EKS 환경을 더 효율적으로 더 안전하게.pdf

위 MutatingWebhook 이 Admisstion Control 의 구성 중 하나로 사용자가 요청한 request에 대해 관리가 임의로 값을 변경하는 해준다. 그림에 따라서 요청에 대해 환경 변수(AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE)와 토큰 데이터(볼륨) 을 추가하여 STS에서 인증과 인가 작업을 수행하는 것을 확인할 수 있다.

<a href="https://tech.devsisters.com/posts/pod-iam-role/">https://tech.devsisters.com/posts/pod-iam-role/</a>

https://tech.devsisters.com/posts/pod-iam-role/

위 과정에서 OIDC IdP 란 OIDC Identity Provider (IdP)는 사용자를 대신 인증하는 서비스이다. 예를 들어, 구글과 페이스북에서 로그인을 하면 여러 앱이나 사이트에 접근할 수 있는 과정이라고 이해하면 된다. 여기서는 EKS 가 OIDC Identity Provider를 사용하여 쿠버네티스 서비스 어카운트에 IAM 역할을 부여하는 역할을 담당한다. 이를 통해 쿠버네티스 내부에서 실행되는 워크로드에서 AWS 리소스에 대한 접근 권한을 부여할 수 있게 된다.

이 말은 MutatingWebhook 를 다른 보안 툴과 확장하여 사용할 수 있다는 말이다. 다른 보안 툴(dex, teleport, kube-oidc-prxo) 인증 및 액세스 관리 대체 할 수 있으므로 멀티 클러스터 구성시 활용해볼 수 있다.

이에 대한 실습은 이미 진행해왔다. 블로그 글에서 여러 번 다룬 ALB 컨트롤러 설치나 externalDNS설치시 IRSA를 활용했기 때문이다. 예제를 다시 확인하면 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# ALB controller 정책 설치
curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.7/docs/install/iam_policy.json
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam_policy.json

# 정책 arn 생성 확인 
ACCOUNT_ID=000000000000
aws iam get-policy --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --query 'Policy.Arn'
---
"arn:aws:iam::000000000000:policy/AWSLoadBalancerControllerIAMPolicy" 

# OIDC 서비스 어카운트 생성
CLUSTER_NAME=hanhorang 
eksctl create iamserviceaccount --cluster=$CLUSTER_NAME --namespace=kube-system --name=aws-load-balancer-controller \
--attach-policy-arn=arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve

# OIDC 서비스 어카운트 확인 
kubectl edit sa/aws-load-balancer-controller  -n kube-system
---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations: # annoation 에 role-arn이 추가된 것을 확인! 
    eks.amazonaws.com/role-arn: arn:aws:iam::000000000000:role/eksctl-hanhorang-addon-iamserviceaccount-kub-Role1-1MPK8ATNJVXQH
  creationTimestamp: "2023-05-08T05:32:22Z"
  labels:
    app.kubernetes.io/managed-by: eksctl
  name: aws-load-balancer-controller
  namespace: kube-system
  resourceVersion: "1236"
  uid: 5fe3e69b-8cfc-426c-a16a-509e1f7c4a86
  • eksctl create iamserviceaccount : 해당 명령어를 통해서 서비스 어카운트를 생성하고, IAM role에 정책을 부여하고 신뢰 관계를 설정시켜준다.
  • OIDC Idp 에 등록된 과정은 서비스 어카운트에 annotations를 확인하면 된다. 해당 필드에 role-arn이 정상적으로 부여된 것을 확인할 수 있고 sts를 통해서 해당 role을 확인하여 서비스에 접근/제어를 해준다고 보면 된다.

IRSA 도 잘 써야 한다

IRSA도 사용에 주의가 필요하다. 마찬가지로 정보 탈취(토큰과 role Arn)가 되면 임시 자격 증명이 되기 때문이다. role arn은 서비스 어카운트에서 쉽게 확인이 가능하며, 토큰은 IRSA 과정에서 환경 변수로 마운트되기 때문에 다음의 경로에서 확인이 가능하다. (아래 내용은 블로그 글을 참고하여 작성한다. )

irsa4.png

해당 토큰을 jwt 사이트에서 토큰을 분석하면 서비스 계정과 OIDC엔드 포인트를 확인할 수 있다.

1_TgycdRiNndnhFE57CTYozA.png

여기서 문제가 발생한다. AWS는 JWT 토큰의 유효성만 확인하지, 토큰 파일이나 서비스 계정에 지정된 IAM role에 대해 일관성을 보장하지 않기 때문에 아래와 같이 외부나 새로운 환경에서 AWS에 대한 자격 증명 발급이 가능하다!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19

aws sts assume-role-with-web-identity \ 
--role-arn arn:aws:iam::ACCOUNT_ID:role/eks-workshop-carts-dynamo \ 
--role-session-name test --web-identity-token eyJhbGciOiJSUzI1<SNIP> 
{ 
    "Credentials" : { 
        "AccessKeyId" : "ASIA<SNIP>" , 
        "SecretAccessKey" : "KZ9V<SNIP>" , 
        "SessionToken" : "IQoJb<SNIP>" , 
        "만료" : "2023-06-03T01:00:43+00:00"
     }, 
    "SubjectFromWebIdentityToken" : "system:serviceaccount:carts:carts", 
    "AssumedRoleUser" : { 
        "AssumedRoleId": "AROAWU22AXDEAGQGMY3XZ:test" , 
        "Arn" : "arn:aws:sts::ACCOUNT_ID:assumed-role/eks-workshop-carts-dynamo/test"
     }, 
    "제공자" : "arn:aws:iam::ACCOUNT_ID :oidc-provider/oidc.eks.us-east-2.amazonaws.com/id/9278920BDA929A8A54E92E18A4DECB2A" , 
    "대상" : "sts.amazonaws.com"
 }

이를 방지하기 위한 방법으로는 role 의 신뢰 정책에서 반드시 네임스페이스와 서비스 계정을 지정해야 한다. 서비스 계정을 지정하면 해당 서비스 계정에서만 해당 IAM 역할을 위임하여 사용할 수 있기 때문이다.

IRSA 사용하다면?

파드에서 메타데이터 접근을 허용하지 않도록 네트워크 정책을 통해 차단이 가능하다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-metadata-access
  namespace: example
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 169.254.169.254/32

특정 케이스가 생기면 다음과 같이 podselector를 통해서 해당 파드에서만 메타데이터 접근을 허용할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-metadata-access
  namespace: example
spec:
  podSelector:
    matchLabels:
      app: myapp  
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 169.254.169.254/32