EC2 인스턴스내에서 AWS 서비스에 접근하기 위해서는 IAM User의 AccessKey Credential을 가져와서 사용하거나, 인스턴스에 IAM Role을 지정한 뒤 사용하고는 했다.
그렇다면 Kubernetes의 클러스터에 존재하는 pod에서는 어떨까?
pod 내에서도 마찬가지로 IAM User의 Credential을 넣고 사용하는 방법도 가능하다. 하지만 이러한 방법이 정말 안전하다고 말할 수는 없다.
IAM User의 AccessKey Credential은 탈취의 위협이 항상 존재하므로 Application내에 하드코딩하거나 Application 구동 환경의 환경변수 등에 삽입하여 사용하는 것은 권고되지 않는 방식이다.
이런 문제를 위해 EC2 인스턴스에 연결하는 IAM Role이 존재한다. 하지만 클러스터 노드에 IAM Role의 연결을 하게되면, 동일한 노드에 존재하는 모든 Pod들은 같은 Role을 갖게되어 각 Pod에 대한 미세한 권한조정이 불가능하다는 점이 있다.
Kubernetes의 클러스터에서 AWS 서비스에 접근하기 위해 사용하는 IAM Role 개념이 존재하는데, 이것이 바로 이번 주제인 IRSA이다.
IRSA
IAM Role for Service Account, kubernetes의 ServiceAccount에 IAM Role을 연결해 사용하는 방법이다.
Pod의 ServiceAccount와 AWS의 IAM Role을 연결함을 통해, 이 ServiceAccount가 특정 IAM Role로 Assume할 수 있게 하는 것이다.
IAM Role과 연결된 Kubernetes의 ServiceAccount를 이용해 생성한 모든 pod에 동일한 Role이 적용된다.
IRSA는 OIDC(OpenID Connect)를 이용해 IAM Role을 부여하는 방식으로 작동한다.
OIDC?
OAuth 2.0의 확장시킨 인증(Authentication) 시스템으로 클라이언트가 Google, Kakao, Facebook와 같은 OpenID Provider(IdP)에 인증함으로 서드파티 Application이 클라이언트 프로필을 획득할 수 있게 한다.
OAuth 2.0는 사용자가 서비스에 대해 접근을 허가하는 Access Token을 부여해주는 인가(Authorization) 프로토콜이였지만, OIDC는 IdP가 Access Token과 더불어 클라이언트 식별을 위한 ID Token을 발급해주어 사용자에 대한 인증을 진행할 수 있게 된다.
IRSA workflow
클러스터의 OIDC와 신뢰관계를 맺은 IAM Role을 연동한 ServiceAccount를 이용해 생성한 Pod 내에서 AWS 리소스 접근을 하는 과정은 아래와 같다.
- Pod 내의 Application 등에서 AWS API call에 사용할 token을 STS에 요청, 동시에 IAM Role의 ARN과 JWT Token 전달
- STS가 요청받은 서비스/유저의 Role이 해당 작업을 할 권한이 있는지를 IAM 서비스를 통해 확인
- IAM은 해당 Role의 신뢰관계에 설정된 OIDC IdP와 통신해, Pod를 생성한 ServiceAccount에 IAM Role ARN이 연결되었는지를 확인
- 해당 Role이 해당 작업의 권한을 확인 후 STS에 전달
- 확인내용을 전달받은 STS는 Pod의 Application에게 API Call을 수행할 수 있는 임시 Token 발급
- Pod의 Application은 STS에게 부여받은 임시 token으로 AWS API call을 수행
IRSA 구성과 연결
EKS 클러스터의 Pod를 대상으로 IRSA를 적용하여, S3 버킷에 접근하도록 구성해본다.
먼저 OIDC를 사용하기 위해 해당 EKS 클러스터에 대한 OIDC IdP를 생성해주어야 한다. 그러기에 앞서 EKS 클러스터에 이미 연결되어있는 OIDC Provider URL을 확인해야한다.
클러스터의 세부정보에서 OIDC Provider URL을 확인할 수 있다.
확인한 OIDC Provider URL을 바탕으로 IAM Role에서 사용하기 위해 OIDC IdP를 생성한다.
IAM의 Access Management > Identity Providers에서 OIDC IdP를 생성해줄 수 있다.
공급자 URL에 EKS 클러스터의 OIDC Provider URL, 대상에는 STS를 통해 IdP와 연동하기 위해 `sts.amazonaws.com`을 지정한다.
OIDC Provider의 생성은 eksctl을 통해서도 수행할 수 있다. 해당 커맨드를 통해 지정한 cluster에 연결되어있는 OIDC Provider URL을 바탕으로 IdP를 바로 생성할 수 있다.
eksctl utils associate-iam-oidc-provider --cluster [cluster명] --approve
이어서 Resource에 접근할 Permission을 갖는 IAM Role을 생성하도록 한다. IAM Role의 신뢰관계를 앞서 생성해준 OIDC IdP로, 대상 필드로 sts.amazonaws.com으로 지정한다.
버킷을 읽기 위한 Permission을 부여 후 Role을 생성한다.
신뢰관계 설정 후 아래와 같이 ServiceAccount의 annotations에 앞서 생성한 IAM Role의 ARN을 넣어줌으로써 IAM Role과 연결된 ServiceAccount를 생성할 수 있다.
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
# Role의 ARN을 지정
eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/irsa-role
name: irsa-test-sa
IdP와 마찬가지로 IRSA의 생성과 연결은 eksctl을 이용해서도 할 수 있다.
eksctl create iamserviceaccount \
--name [SA명] \
--namespace default \
--cluster [클러스터명] \
--approve \
--attach-policy-arn [Role에 연결할 Policy]
이렇게 OIDC IdP와 ServiceAccount를 생성하면 Pod를 생성해 AWS 서비스에 접근할 수 있다.
생성한 ServiceAccount를 이용해 Pod를 생성한다.
apiVersion: v1
kind: Pod
metadata:
name: irsa-access
spec:
# ServiceAccount 연결
serviceAccountName: irsa-test
containers:
- name: aws-cli
image: amazon/aws-cli
command:
- "sleep"
- "100000"
imagePullPolicy: IfNotPresent
이 Pod내에서 AWS API를 호출하면, 정상적으로 호출되어 결과를 가져오는 것을 확인할 수 있다.
이렇게 EKS 클러스터의 Pod에서 사용할 수 있는 IRSA에 대해 알아보았다.
이러한 IRSA는 worker node 레벨이 아닌 pod 레벨에 대해 세밀한 IAM 권한관리가 가능하다는 특징을 알 수 있었다.
하지만 이러한 IRSA는 각 EKS 클러스터마다 OIDC IdP를 따로 생성해주어야하며, 하나의 Role을 여러 클러스터에서 사용할 경우, 이 OIDC IdP를 Role의 신뢰관계에 작성을 해주어야하는 번거로운 점이 존재한다.
이러한 번거로움을 해결하기 위해 최근에 등장한 'Pod Identity'가 존재한다.
다음 글에서 Pod Identity를 알아보도록 한다.