EKS IRSA(IAM Role for ServiceAccount)

1. IRSA란?

IRSA(IAM Role for ServiceAccount)는 Kubernetes Service Account에 IAM Role을 연결하여 Pod가 AWS 리소스에 접근할 수 있도록 하는 방식이다.

irsa01

1.1 기존 방식의 문제점

Pod에서 실행되는 Application들이 EC2 인스턴스 IAM Role을 사용하게 될 경우 다음과 같은 문제가 발생한다.

하나의 EC2 인스턴스(워커노드)에 A, B, C, D 여러 개의 서로 다른 Pod가 동작하고 Pod에서 실행되는 Application이 각각 모두 다른 권한을 필요로 할 때 EC2 인스턴스의 IAM Role에는 A Policy, B Policy, C Policy, D Policy 총 4개의 권한이 필요하게 된다. 이렇게 되면 다른 Application에서 불필요하게 많은 권한을 가지고 동작할 수 있다.


1.2 IRSA의 장점

IRSA를 사용하면 다음과 같은 장점이 있다.

  1. 최소권한(Least Privilege): Pod별로 필요한 최소한의 권한만 부여
  2. 자격증명의 격리(Credential Isolation): Pod마다 독립적인 자격증명 사용
  3. 감사(Auditability): CloudTrail을 통해 어떤 Pod가 어떤 AWS API를 호출했는지 추적 가능



2. IRSA 동작 과정 Deep Dive

irsa02

IRSA의 전체 동작 과정은 다음과 같다.

  1. IAM 서비스에 EKS 클러스터의 OIDC Provider를 Identity Provider로 등록
  2. Service Account에 IAM Role을 설정하고, Pod는 Service Account를 사용하도록 설정
  3. Pod 배포
  4. pod-identity-webhook(MutatingWebhookConfiguration)에 의해서 Pod 환경변수에 AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_STS_REGIONAL_ENDPOINTS 등이 주입
  5. OIDC Identity Provider는 Pod에 JWT 발행
  6. Pod에서 동작하는 Application(SDK)은 JWT와 IAM Role ARN을 STS로 전달 (AssumeRoleWithWebIdentity API 호출)
  7. IAM 서비스는 전달된 JWT가 유효한 토큰인지 검증 후 이상이 없는 경우 임시자격증명 발급
  8. AWS SDK는 발급된 임시 자격증명을 통해 AWS API 호출


Service Account에 IAM Role을 연결하기 위해서는 annotation을 추가해야 한다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: awssdk-iam-sa
  namespace: aws
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::558846430793:role/AwsSdkIAMAppRole


2.2 Pod에 환경변수 주입

pod-identity-webhook(MutatingWebhookConfiguration)에 의해 Pod가 생성될 때 자동으로 다음과 같은 환경변수가 주입된다.


2.3 JWT Token

Pod 내부에서 JWT Token을 확인할 수 있다.

kubectl exec -it awssdk-iam-dev-deploy-767d486487-q7tmk -n aws -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token

발급된 JWT Token은 다음과 같은 형태다.

eyJhbGciOiJSUzI1NiIsImtpZCI6ImM2MmE5NWQ5NzIxNGI0MTQ0ZWEwMDllNDgyZjNkNzQ3OWIxNDVmZmMifQ.eyJhdWQiOlsic3RzLmFtYXpvbmF3cy5jb20iXSwiZXhwIjoxNjk2Mjc1NTU3LCJpYXQiOjE2OTYxODkxNTcsImlzcyI6Imh0dHBzOi8vb2lkYy5la3MuYXAtbm9ydGhlYXN0LTIuYW1hem9uYXdzLmNvbS9pZC9BODg0NUQzRjBFNUMzODUyMjcyMDREMzNCODYzNUFCQyIsImt1YmVybmV0ZXMuaW8iOnsibmFtZXNwYWNlIjoiYXdzIiwicG9kIjp7Im5hbWUiOiJhd3NzZGstaWFtLWRldi1kZXBsb3ktNzY3ZDQ4NjQ4Ny1xN3RtayIsInVpZCI6IjJmMTFlY2M1LTgxMDgtNDFjYi05MmFmLTQ0MTExMDk3MmFlOCJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiYXdzc2RrLWlhbS1zYSIsInVpZCI6Ijk0NzA2MzY4LTMzYjAtNGFhMS1hZTcwLTEyM2JjZTQ3ZjM0NCJ9fSwibmJmIjoxNjk2MTg5MTU3LCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6YXdzOmF3c3Nkay1pYW0tc2EifQ.p0SmXuX_v4I7eHA-111DAgHOxGJi7AZpfoKfi_5G7WHuVTHPAN6jCeLxOAcBwilKL54ezEonTQLYD1yG_j63UwAiKV0rWMo8-uDC2aoN88y84tlJWavZGyvWzcH8quQQu3vDmMlQ20djwypezAR8gym3Rzh8dmydDHpNDrZJ7lPDDmjGiP0-Ao8gMZZU9NBhP4ZQQHtwgJTZEQ58NFq9zSdRDFlqwSYefmRNsfPC0PngK2dwcSKmIQkSzl7RFGxVj8GyJd8XczRiT_cfbpgsifQXbDTAtMKZ6uv0F4L6xjmqOj2-uXAp4CqIa7e4q9_5RleHHB3dUbQZ7NSNEirRRw


JWT 사이트에서 Decode를 해보면 다음과 같은 정보를 확인할 수 있다.

Header

{
  "alg": "RS256",
  "kid": "c62a95d97214b4144ea009e482f3d7479b145ffc"
}

Payload

{
  "aud": [
    "sts.amazonaws.com"
  ],
  "exp": 1696275557,
  "iat": 1696189157,
  "iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/A8845D3F0E5C385227204D33B8635ABC",
  "kubernetes.io": {
    "namespace": "aws",
    "pod": {
      "name": "awssdk-iam-dev-deploy-767d486487-q7tmk",
      "uid": "2f11ecc5-8108-41cb-92af-441110972ae8"
    },
    "serviceaccount": {
      "name": "awssdk-iam-sa",
      "uid": "94706368-33b0-4aa1-ae70-123bce47f344"
    }
  },
  "nbf": 1696189157,
  "sub": "system:serviceaccount:aws:awssdk-iam-sa"
}


JWT Token의 각 Claim은 다음과 같은 의미를 가진다.


2.6 AssumeRoleWithWebIdentity

Pod 내부의 Application은 AWS SDK를 통해 자동으로 JWT Token과 IAM Role ARN을 STS로 전달하여 임시 자격증명을 받는다.

수동으로 테스트하려면 다음과 같이 실행할 수 있다.

aws sts assume-role-with-web-identity \
  --role-arn arn:aws:iam::558846430793:role/AwsSdkIAMAppRole \
  --role-session-name test-session \
  --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token



3. IRSA 설정 방법

3.1 OIDC Provider 생성

EKS 클러스터에 OIDC Provider를 생성한다.

export cluster_name=my-cluster
export region=ap-northeast-2

oidc_id=$(aws eks describe-cluster --name $cluster_name --region $region --query "cluster.identity.oidc.issuer" --output text | cut -d '/' -f 5)

aws iam create-open-id-connect-provider \
  --url https://oidc.eks.$region.amazonaws.com/id/$oidc_id \
  --client-id-list sts.amazonaws.com \
  --thumbprint-list 9e99a48a9960b14926bb7f3b02e22da2b0ab7280


3.2 IAM Role 생성

Service Account가 사용할 IAM Role을 생성한다.

Trust Relationship

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::558846430793:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/A8845D3F0E5C385227204D33B8635ABC"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.ap-northeast-2.amazonaws.com/id/A8845D3F0E5C385227204D33B8635ABC:sub": "system:serviceaccount:aws:awssdk-iam-sa",
          "oidc.eks.ap-northeast-2.amazonaws.com/id/A8845D3F0E5C385227204D33B8635ABC:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}


3.3 Service Account 생성

IAM Role을 annotation으로 지정한 Service Account를 생성한다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: awssdk-iam-sa
  namespace: aws
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::558846430793:role/AwsSdkIAMAppRole


3.4 Pod에서 Service Account 사용

Pod spec에서 생성한 Service Account를 지정한다.

apiVersion: v1
kind: Pod
metadata:
  name: awssdk-iam-app
  namespace: aws
spec:
  serviceAccountName: awssdk-iam-sa
  containers:
  - name: app
    image: my-app:latest



irsa03

이렇게 IRSA를 설정하면 Pod는 Service Account에 연결된 IAM Role의 권한으로 AWS 리소스에 접근할 수 있다. AWS SDK는 자동으로 JWT Token을 사용하여 임시 자격증명을 받아 AWS API를 호출한다.


📚 References

[1] Introducing fine-grained IAM roles for service accounts

[2] IAM roles for service accounts

[3] JWT Introduction