전공영역 공부 기록

EKS IRSA 동작원리 톺아보기

악분 2024. 4. 13. 21:26
반응형

 

1. IRSA란?

IRSA(IAM Roles for Service Accounts)쿠버네티스 service accountIAM role을 설정하는 기능입니다. pod service account에 설정된 IAM role을 사용하여 AWS리소스 작업을 합니다. podIAM role을 사용할 때,  AssumeRoleWithWebIdentity API가 호출되어 assume role이 수행됩니다.

 

2. 사용방법

사용방법은 매우 간단합니다. service account annotation에 IAM role arn을 설정하면 됩니다. 그리고 2가지 설정이 필요한데 다음 챕터인 [IRSA를 사용하기 위한 설정]에서 설명합니다.

 

3. IRSA를 사용하기 위한 설정

pod가 쿠버네티스 service account에 설정한 IAM Role을 사용하려면 2가지 설정이 필요합니다.

  1. EKS OIDC idenity provider 생성
  2. AWS IAM Role TrustRelationship 설정

 

3.1. EKS OIDC identity provider 등록

EKS OIDC identity provider는 EKS생성시에 자동으로 생성됩니다.

 

자동으로 생성된 EKS OIDC identity provider AWS에 등록해줘야 사용할 수 있습니다. AWS IAMIdentity provider메뉴에서 등록합니다.

 

생성입력 폼에는 아래 그림과 같이 설정합니다

  1. Provider type: OpenID Connect
  2. Provider URL: EKS 클러스터에서 확인한 OpenID Connect provider URL
  3. Audience: sts.amazonaws.com

 

3.2. AWS IAM Role TrustRelationship 설정

pod에서 Assume role을 할 수 있도록 IAM role에서 TrustRelationship을 설정합니다. 예제 코드는 저의 github에 공개되어 있습니다.

  • Principal: EKS OIDC idenity provider arn
  • Action: sts:AssumeRoleWithWebIdentity
  • Condition:
    • aud: sts.amazonaws.com
    • sub: system:{namespace}:{service account이름}

 

4. 동작원리

EKS IRSA동작원리는 EKS OIDC identity provider를 왜 사용했는지 이해하면 됩니다.

 

4.1. IRSA에서 EKS OIDC idenity provider를 왜 사용할까?

EKS IRSA 동작 원리의 시작은 pod인증에서 시작합니다. AWS는 pod 인증을 위해 OIDC프로토콜을 적용했습니다. 그래서 IRSA에서 EKS OIDC identity provider를 사용했습니다.

 

IRSA가 등장하기 이전 Assume role을 직접 구현한 경험을 회상해봅시다. IAM userAssume role을 했을 때는 Access key, Secret key를 사용하여 IAM user가 맞는지 인증을 했습니다.

 

그렇다면 podIRSA를 사용하여 Assume role을 한다면, AWS에서는 어떻게 내가 관리하는 pod인지 인증을 어떻게 할까요? Access key 등 인증수단이 없기 때문에 pod인증을 못합니다.

 

만약 IRSA에서 pod 인증과정이 없다면 어떻게 될까요? 모든 podAssume role을 성공하여 AWS권한을 얻습니다. Assume role에 권한이 Administrator가 있다면 피해가 커지겠죠.

 

IRSA에서 pod인증을 안하면 보안문제가 발생하기 때문에, AWSIRSA pod인증 메커니즘으로 OIDC프로토콜을 적용했습니다. AWS에서는 pod마다 JWT를 발급하고, podAssume role을 요청할 때 JWTpod 인증을 수행합니다. podAssume role을 할 때, 인증수단을 JWT을 사용하는 AssumeRoleWithWebIdentity API를 호출합니다.

 

4.2 JWT는 pod 어디에 있을까?

JWT는 pod의 /var/run/secrets/eks.amazonaws.com/serviceaccount 디렉터리에 있습니다. 예제코드는 저의 github을 참고해주세요.

$ ls -l /var/run/secrets/eks.amazonaws.com/serviceaccount/
lrwxrwxrwx 1 root root 12 Apr 13 04:55 token -> ..data/token

 

JWT는 모든 pod에 있지 않습니다. IAM role을 설정한 serviceaccount를 사용하는 pod에만 JWT가 있습니다.

 

4.3 JWT 내용 확인 하는 방법

JWT 내용는 cat명령어로 확인할 수있습니다.

$ cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token

 

 

 

JWT내용은 해석하려면 디코딩이 필요한데 jwt.io에서 쉽게 디코딩할 수 있습니다.

 

4.4. JWT가 어떻게 생성되는 걸까?

쿠버네티스 manifest에 JWT설정이 없지만 pod에 JWT가 있었습니다. 어떻게 JWT가 pod에 존재한걸까요?

 

JWT는 3가지 기술을 사용하여 pod에 JWT를 생성합니다.

  • EKS OIDC identity provider
  • kubernetes amdmision controller
  • kubernetes projected service account

 

JWTEKS OIDC identity provider가 생성합니다. 그래서 JWT issuer(발급자)EKS OIDC identity provider URL입니다.

 

JWT생성 시기는 pod가 생성되거나 수정될 때입니다. mutatingwebhook을 사용해서 pod가 생성 또는 수정될 때 EKS OIDC identity provider가 생성한 JWTvolume으로 mount합니다.

kubectl get mutatingwebhookconfigurations                                                                                                                          1 ↵
NAME                            WEBHOOKS   AGE
pod-identity-webhook            1          135m

 

 

4.4.1. EKS OIDC identity provider을 연동

projected serivce account를 사용하는 가장 중요한 이유는 EKS OIDC identity provider를 쿠버네티스 serviceaccount에 연동하기 위해서입니다.

 

기본 쿠버네티스 serviceaccount 토큰 audience(대상자)는 쿠버네티스로 되어 있습니다. JWT audiencehttps://kubernetes.default.svc입니다.

 

그리고 volume 마운트 경로도 IRSA마운트 경로와 다릅니다.

ls -l /var/run/secrets/kubernetes.io/serviceaccount/token
lrwxrwxrwx 1 root root 12 Apr 13 04:55 /var/run/secrets/kubernetes.io/serviceaccount/token -> ..data/token

 

JWT audience를 수정하려면 project service account를 사용할 수 밖에 없습니다.

volumes:
  - name: aws-iam-token
    projected:
      sources:
      - serviceAccountToken:
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token

 

4.4.2 JWT 만료시간 설정과 자동갱신

projected serivce account는 expirationSeconds필드를 사용하여 JWT 만료시간을 설정합니다. JWT 데이터를 보면 exp필드가 만료시간입니다.

 

그리고 JWT는 최소 7일에 1번 자동 갱신을 해야합니다. JWT를 생성할 때 만드는 키가 7일에 한번 갱신되기 때문입니다. projected serivce accountJWT가 만료되면 자동갱신 하기 때문에 관리입장에 매우 좋습니다.

출처:  https://docs.aws.amazon.com/ko_kr/ko_kr/eks/latest/userguide/iam-roles-for-service-accounts.html#irsa-oidc-background

 

4.5. JWT 검증은 어떻게 할까?

JWT검증은 AWS IAM이 서명검증 방법으로 진행합니다. JWT를 만들 때 private key가 필요하기 때문에 private key에 대응하는 public key로 검증할 수 있습니다. 검증이 성공하면 에러가 발생하지 지만 검증이 실패하면 오류가 발생합니다. 검증에 대한 코드는 제 github을 참고해주세요.

public_keys = get_aws_public_keys()

# 토큰에서 'kid' 헤더 추출
headers = jwt.get_unverified_header(token)
key_id = headers["kid"]

# 적합한 공개 키로 서명 검증
public_key = public_keys[key_id]
jwt.decode(token, public_key, algorithms=["RS256"], audience="sts.amazonaws.com")

 

검증 단계에서 필요한 public key“EKS OIDC identity provider URL” + “/keys” API로 조회할 수 있습니다.

 

podAWS IAMJWT를 검증할 수 있도록 AssumeRole API대신 AssumeRoleWithWebIdentity API를 호출합니다.

AssumeRoleWithWebIdentity API를 호출하려면 약속된 환경변수 “AWS_WEB_IDENTITY_TOKEN_FILE”을 설정해야 합니다. 환경변수 값은 JWT경로입니다.

 

5. 마치며

사실 EKS IRSA글을 쓰기 위해 약 30시간 이상 고민하고 글을 작성했습니다. 글을 썼다가 지웠다가 여러번 반복했습니다.

 

많이 고민했던 이유는 OIDC 프로토콜을 왜 사용하는지 스스로 납득하지 못했습니다. 우연히 지쳐서 멍 때리고 있다가, 머리속에 갑자기 쿠버네티스 service account는 어떻게 AWS가 인증할 건데?라는 생각이 스쳐지나갔습니다.

 

그래서 저는 이 글의 주제를 AWS가 OIDC 프로토콜을 사용하여 쿠버네티스 servicea account를 인증하는 방법으로 방향을 결정했습니다. 이 생각이 틀릴 수 있지만 저처럼 IRSA가 왜 OIDC를 사용하는지 고민하시는 분에게 많은 도움이 됐으면 좋겠습니다.

 

6. 참고자료

반응형