IAM Role for Service Account (IRSA)
Kubernetes 클러스터 내에서 실행되는 특정 애플리케이션이 제대로 작동하려면 Kubernetes API를 호출할 수 있는 권한이 필요합니다. 예를 들어, AWS 로드 밸런서 컨트롤러는 서비스의 엔드포인트를 나열할 수 있어야 합니다. 또한 컨트롤러는 AWS API를 호출하여 ALB를 프로비저닝하고 구성할 수 있어야 합니다. 이 섹션에서는 Pod에 권한을 할당하는 모범 사례를 살펴보고 IAM Role for Service Account (IRSA)를 사용하여 AWS IAM 역할을 Kubernetes Service Account에 연결하는 방법을 설명합니다.
1. Kubernetes Service Accounts (서비스 어카운트)
Kubernetes Service Accounts (서비스 어카운트)
Kubernetes 서비스 어카운트은 Pod에 Kubernetes RBAC 역할을 할당할 수 있는 특별한 유형의 객체입니다. 클러스터 내의 각 네임스페이스에 대해 기본 서비스 어카운트이 자동으로 생성됩니다. 특정 서비스 어카운트을 참조하지 않고 포드를 네임스페이스에 배포하면 해당 네임스페이스의 기본 서비스 어카운트이 자동으로 포드에 할당되고 Kubernetes Secret, 즉 해당 서비스 어카운트의 서비스 어카운트 (JWT) 토큰이 포드의 /var/run/secrets/kubernetes.io/serviceaccount에 볼륨으로 마운트됩니다. game-2048 네임스페이스에 생성된 game-2048 포드의 해당 디렉터리에서 서비스 어카운트 토큰을 디코딩해 보도록 하겠습니다.
(참고)
game-2048네임스페이스 및game-2048포드는 테라폼을 통해 EKS를 배포하는 과정으로 함께 생성되었습니다.위에서 생성된 JWT 토큰은 포드에서 Kubernetes API 서버로의 요청을 인증하는 데 사용됩니다. 토큰은
Kubernetes Secret에 저장되지만 전통적인 의미의Secret으로 직접 생성되지는 않습니다. 대신 Kubernetes에서 자동으로 관리되며 볼륨 마운트를 통해 Pod에서 사용할 수 있습니다. Pod 내부의 이 토큰에 대한 경로는 일반적으로/var/run/secrets/kubernetes.io/serviceaccount/token입니다.
NAMESPACE="game-2048"
# "game-2048" 포드의 서비스 어카운트 이름을 참고용으로 얻어옵니다.
SERVICE_ACCOUNT_NAME=$(kubectl describe pod game-2048 -n $NAMESPACE | grep -m 1 "Service Account:" | awk -F":" '{print $2}' | tr -d ' ') && echo "Servvice Account="$SERVICE_ACCOUNT_NAME
# Decorated된 Pod 이름을 얻어옵니다.
POD_NAME=$(kubectl describe pod game-2048 -n $NAMESPACE | grep -m 1 "Name:" | awk -F":" '{print $2}' | tr -d ' ') && echo "Pod Name="$POD_NAME
# Pod에 주입된 (마운드된) 서비스 어카운트의 시크릿 (JWT)을 얻어옵니다.
SERVICE_ACCOUNT_SECRET=$(kubectl exec -it $POD_NAME -n $NAMESPACE -- /bin/sh -c 'cat /var/run/secrets/kubernetes.io/serviceaccount/token') && echo "Service Account Secret="$SERVICE_ACCOUNT_SECRET
위에서 얻어진 Service Account Secret를 디코딩하여 확인합니다.
# 서비스 어카운트의 시크릿 (JWT)을 디코딩하여 확인합니다.
jwt $SERVICE_ACCOUNT_SECRET
Kubernetes의 API 서버는 기본 ClusterRole 및 ClusterRoleBinding 객체 세트를 생성합니다. 이들 중 다수는 system: 접두사가 붙어 있으며, 이는 리소스가 클러스터 제어 영역에서 직접 관리됨을 나타냅니다. 모든 기본 ClusterRole 및 ClusterRoleBindings에는 kubernetes.io/bootstrapping=rbac-defaults라는 레이블이 지정되어 있습니다.
이러한 기본 ClusterRole 및 ClusterRoleBinding의 대표적인 것이 Kubernetes RBAC API Discovery Roles인데, kube-apiserver 프로세스가 시작될 때 자동으로 (재)생성되고 (Auto-reconciliation) 인증되지 않은 사용자와 인증된 사용자가 공개적으로 액세스할 수 있는 것으로 안전한 것으로 간주되는 API 정보(CustomResourceDefinitions 포함)를 읽을 수 있는 권한을 부여합니다.
Default ClusterRole
Default ClusterRoleBinding
설명
system:basic-user
system:authenticated 그룹
사용자에게 자신에 대한 기본 정보에 대한 읽기 전용 액세스를 허용합니다. v1.14 이전에는 이 역할이 기본적으로 system:unauthenticated에도 바인딩되었습니다.
system:discovery
system:authenticated 그룹
API 수준을 검색하고 협상하는 데 필요한 API 검색 엔드포인트에 대한 읽기 전용 액세스를 허용합니다. v1.14 이전에는 이 역할이 기본적으로 system:unauthenticated에도 바인딩되었습니다.
system:public-info-viewer
system:authenticated 및 system:unauthenticated 그룹
클러스터에 대한 중요하지 않은 정보에 대한 읽기 전용 액세스를 허용합니다. Kubernetes v1.14에서 도입되었습니다.
(참고) 위 사항에 대한 자세한 내용은 아래 쿠버네테스 공식 문서를 참조하세요.
정리를 해보자면,
Kubernetes클러스터 내에서 실행되는Pod는Kubernetes API에 대한 액세스를 위해Service Account를 사용하여 인증됩니다 (지정되지 않으면Default부여).Service Account는Kubernetes RBAC역할을 할당받는데 기본적으로Kubernetes의API Server가 제공하는Kubernetes RBAC API Discovery Roles이 있으며 이를 통해 기본적인 API 정보를 읽을 수 있는 권한을 부여받습니다.위 2에서 포드는
"system:authenticated"그룹에 속하게 되어Kubernetes API에 대한 읽기 전용 액세스가 허용되며 이에 대한ClusterRoleBinding을 살펴보면 다음과 같습니다.
(참고)
기본 서비스 어카운트가의API Server접근에 대한 상세한 내용은 아래 쿠버네테스 문서를 참조하세요.
마지막으로 위에서 설명된 system:authenticated 그룹을 Cluster Role에 바인딩시켜주는 Cluster Role Binding과, 이에 의해 바인딩된 Cluster Role들, 그리고 이 중에서 system:discovery Cluster Role 을 확인해 보겠습니다.
cd ~/environment/eks-workshop/cloud9
kind=Group
name="system:authenticated"
# Cluster Role Binding 확인
kubectl get clusterrolebinding -o json | jq -r ".items[] | select(.subjects[]? | select(.kind == \"${kind}\" and .name == \"${name}\"))"
# Cluster Role 확인
kubectl get clusterrolebinding -o json | jq -r ".items[] | select(.subjects[]? | select(.kind == \"${kind}\" and .name == \"${name}\")) | (.roleRef.kind + \"/\" + .roleRef.name)"
# 위 명령을 포함한 쉘 스크립트로 다시 한번 실행해 봅니다.
./get-roles-system-authenticated.sh
# 마지막으로 "system:discovery" Role에 대해 확인합니다.
kubectl get clusterrole system:discovery -o yaml
kubectl describe clusterrole system:discovery
그렇다면 기본 서비스 어카운트를 확장하는 목적으로 서비스 어카운트를 사용할 수는 없을까요?
당연히 가능하며 사실 오늘 다루고자 하는 IAM Role for Service Account (IRSA)가 바로 이러한 목적으로 사용됩니다. 이를 통해 Pod에 IAM Role을 할당하여 AWS IAM 역할을 Kubernetes Service Account에 연결할 수 있습니다.
다음 섹션에서 서비스 어카운트를 사용하여 AWS IAM 역할을 포드에 부여하는 방법을 알아보고 앞서 발생했던 AWS 권한 오류를 해결해 보도록 하겠습니다.
(참고)
Kubernetes 1.24이전에는Kubernetes가 각 서비스 어카운트에 대한Secret을 자동으로 생성했습니다. 이Secret값은 포드의/var/run/secrets/kubernetes.io/serviceaccount경로에 마운트되었으며 포드가Kubernetes API 서버에 인증하는 데 사용됩니다.Kubernetes 1.24에서는 포드가 실행될 때 서비스 어카운트 토큰이 동적으로 생성되며 기본적으로 한 시간 동안만 유효합니다 (Bound Service Account Token Volume). 서비스 어카운트의Secrets은 생성되지 않습니다. Kubernetes API에 인증해야 하는 클러스터 외부에서 실행되는 애플리케이션이 있는 경우, 예를 들어 Jenkins의 경우,metadata.annotations.kubernetes.io/service-account.name: <SERVICE_ACCOUNT_NAME>과 같이 서비스 어카운트을 참조하는 주석과 함께kubernetes.io/service-account-token유형의Secrets을 생성해야 합니다. 이러한 방식으로 생성된Secrets`은 만료되지 않습니다.Bound Service Account Token Volume은
Secret기반 Volume이 아닌Projected Volume을 사용합니다.
https://kubernetes.io/docs/concepts/storage/projected-volumes/
Projected Volume은 다음 4가지 타입을 지원합니다. Projected Volume은 All-in-One 컨셉의 볼륨으로, 여러 소스들을 하나의 볼륨에 담아서 쓸 수 있게 해줍니다.
Secret
Downward API
Config Map
Service Account Token
2. IAM Role for Service Account (IRSA)
IAM Role for Service Account (IRSA)
IAM Role for Service Account (IRSA)는 Kubernetes 서비스 어카운트에 IAM 역할을 할당할 수 있는 기능입니다. 서비스 어카운트 토큰 볼륨 프로젝션 (Service Account Token Volume Projection)(https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#serviceaccount-token-volume-projection)이라는 Kubernetes 기능을 활용하여 작동합니다. IAM 역할을 참조하는 서비스 어카운트를 사용하도록 포드가 구성되면 Kubernetes API 서버는 시작 시 클러스터에 대한 공개 OIDC 검색 엔드포인트를 호출합니다. 엔드포인트는 Kubernetes에서 발행한 OIDC 토큰과 볼륨으로 마운트된 서비스 어카운트 토큰을 암호화 서명합니다. 이 서명된 토큰을 통해 포드는 AWS API 관련 IAM 역할을 호출할 수 있습니다. AWS API가 호출되면 AWS SDK는 sts:AssumeRoleWithWebIdentity를 호출합니다. 이는 AWS SDK에서 구현된 WebIdentityTokenFileCredentialsProvider에 의해 수행되면, IAM은 토큰 서명을 확인한 후 Kubernetes에서 발급한 토큰을 임시 AWS 역할 자격 증명으로 교환합니다.
서비스 계정에 대한 IAM 역할 기능은 다음과 같은 이점을 제공합니다.
최소 권한 - 서비스 계정에 대한 IAM 역할 기능을 사용하면 해당 노드의 포드가 AWS API를 호출할 수 있도록 더 이상 노드 IAM 역할에 확장 권한을 제공할 필요가 없습니다. IAM 권한 범위를 서비스 계정으로 지정할 수 있으며, 해당 서비스 계정을 사용하는 포드만 해당 권한에 액세스할 수 있습니다.
자격 증명 격리 — 컨테이너는 자신이 속한 서비스 어카운트와 연결된
IAM 역할에 대한 자격 증명만 검색할 수 있습니다. 컨테이너는 다른 포드에 속한 다른 컨테이너를 위한 자격 증명에 절대 액세스할 수 없습니다.
(참고) 위 설명에 대한 추가적인 참고 자료는 아래와 같습니다.
IRSA 구성을 통해 생성된 JWT 토큰을 디코딩하면 아래 예시와 유사한 출력이 생성됩니다.
{
"aud": [
"sts.amazonaws.com"
],
"exp": 1582306514,
"iat": 1582220114,
"iss": "https://oidc.eks.ap-northeast-2.amazonaws.com/id/D43CF17C27A865933144EA99A26FB128",
"kubernetes.io": {
"namespace": "default",
"pod": {
"name": "alpine-57b5664646-rf966",
"uid": "5a20f883-5407-11ea-a85c-0e62b7a4a436"
},
"serviceaccount": {
"name": "s3-read-only",
"uid": "a720ba5c-5406-11ea-9438-063a49b60fba"
}
},
"nbf": 1582220114,
"sub": "system:serviceaccount:default:s3-read-only"
}이 토큰은 IAM 역할을 Assume하게 함으로써 포드에 S3 읽기 전용 권한을 부여합니다. 애플리케이션이 S3에서 읽으려고 시도하면 토큰은 다음과 유사한 임시 IAM 자격 증명 세트로 교환됩니다.
{
"AssumedRoleUser": {
"AssumedRoleId": "AROA36C6WWEJULFUYMPB6:abc",
"Arn": "arn:aws:sts::123456789012:assumed-role/eksctl-winterfell-addon-iamserviceaccount-de-Role1-1D61LT75JH3MB/abc"
},
"Audience": "sts.amazonaws.com",
"Provider": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/D43CF17C27A865933144EA99A26FB128",
"SubjectFromWebIdentityToken": "system:serviceaccount:default:s3-read-only",
"Credentials": {
"SecretAccessKey": "ORJ+8Adk+wW+nU8FETq7+mOqeA8Z6jlPihnV8hX1",
"SessionToken": "FwoGZXIvYXdzEGMaDMLxAZkuLpmSwYXShiL9A1S0X87VBC1mHCrRe/pB2oes+l1eXxUYnPJyC9ayOoXMvqXQsomq0xs6OqZ3vaa5Iw1HIyA4Cv1suLaOCoU3hNvOIJ6C94H1vU0siQYk7DIq9Av5RZe+uE2FnOctNBvYLd3i0IZo1ajjc00yRK3v24VRq9nQpoPLuqyH2jzlhCEjXuPScPbi5KEVs9fNcOTtgzbVf7IG2gNiwNs5aCpN4Bv/Zv2A6zp5xGz9cWj2f0aD9v66vX4bexOs5t/YYhwuwAvkkJPSIGvxja0xRThnceHyFHKtj0H+bi/PWAtlI8YJcDX69cM30JAHDdQH+ltm/4scFptW1hlvMaP+WReCAaCrsHrAT+yka7ttw5YlUyvZ8EPog+j6fwHlxmrXM9h1BqdikomyJU00gm1++FJelfP+1zAwcyrxCnbRl3ARFrAt8hIlrT6Vyu8WvWtLxcI8KcLcJQb/LgkW+sCTGlYcY8z3zkigJMbYn07ewTL5Ss7LazTJJa758I7PZan/v3xQHd5DEc5WBneiV3iOznDFgup0VAMkIviVjVCkszaPSVEdK2NU7jtrh6Jfm7bU/3P6ZG+CkyDLIa8MBn9KPXeJd/y+jTk5Ii+fIwO/+mDpGNUribg6TPxhzZ8b/XdZO1kS1gVgqjXyVC+M+BRBh6C4H21w/eMzjCtDIpoxt5rGKL6Nu/IFMipoC4fgx6LIIHwtGYMG7SWQi7OsMAkiwZRg0n68/RqWgLzBt/4pfjSRYuk=",
"Expiration": "2020-02-20T18:49:50Z",
"AccessKeyId": "XXXX36C6WWEJUMHA3L7Z"
}
}EKS 제어 플레인의 일부로 실행되는 Mutating Admission Webhook은 AWS 역할 ARN과 웹 자격 증명 토큰 파일 경로를 환경 변수로 포드에 삽입합니다. 이러한 값은 수동으로 제공할 수도 있습니다.
AWS_ROLE_ARN=arn:aws:iam::AWS_ACCOUNT_ID:role/IAM_ROLE_NAME
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/tokenKubelet은 프로젝션된 토큰이 총 TTL의 80%보다 오래되거나 24시간 후에 자동으로 로테이션해 줍니다. 토큰이 로데이트되면 AWS SDK는 토큰을 다시 로드하도록 구현되어 있습니다. IRSA에 대한 자세한 내용은 https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html을 참조하십시오.
2.1. IAM Role for Service Account (IRSA) 설정
IAM Role for Service Account (IRSA) 설정
위에서 우리는 다소 복잡해 보이는 Kubernetes 서비스 어카운트와 이에 기반한 IAM Role for Service Account (IRSA)에 대한 기술적인 사항을 조금은 깊이 살펴보았습니다.
Amazon EKS 상에서 동작하는 포드의 IRSA 설정을 이해하기 위한 선수 지식을 다시 간략하게 정리해 보자면 다음과 같습니다.
Pod 내에서 AWS CLI, API, SDK 등이 AWS 자원에 접근하기 전에 호출하는
AssumeRoleWithWebIdentityAPI 요청Pod 내에 주입된 (Injection)
AWS_ROLE_ARN,AWS_WEB_IDENTITY_TOKEN_FILE환경 변수AWS_WEB_IDENTITY_TOKEN_FILE환경 변수가 가리키는 토큰 파일의 내용Pod에 쉘 접속
cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token
Amazon EKS Control Plane에 설정된 OIDC Provider 및 AWS IAM 자격 증명 공급자 설정, 그리고 이들이 Pod의
AssumeRoleWithWebIdentity에 미치는 영향
위 값들을 Pod에 주입하기 위하여 Pod Lifecycle 상에서 호출되는
Mutating Admission Webhook및 Amazon EKS 구현체인 Amazon EKS Pod Identity WebhookKubernetes의
Service Account Annotation에 설정된 AWS IAM Role, 그리고 Pod의serviceAccountNamaeSpec의 관계
다시 한번 정리 및 설명을 위해 IRSA를 통한 Kubernetes Pod -> AWS로의 인증/인가 과정을 살펴보자면 다음과 같습니다.

이제 우리의 워크로드를 정상적으로 동작시키기 위힌 실질적인 설정을 해보도록 하겠습니다.
사실 우리가 배포한 Helm Chart에는 이미 IRSA 설정을 위한 Service Account 값이 포함되어 있으며 아래와 같이 이 값들을 설정할 수 있습니다. k9s 등을 통해 hands-on 네임스페이의 포드 상태를 확인하면서 명령을 실행해 봅니다.
cd ~/environment/eks-workshop
make helm-upgrade-env-for-irsa ENV=prod
정상적으로 적용되었다면 각 마이크로서비스 워크로드에서는 Amazon MSK, Amazon RDS Auroray MySQL, Amazon DocumentDB에 정상적으로 접속할 수 있게 되고 특별한 오류 없이 정상 구동되었을 것입니다.

2.2. IAM Role for Service Account (IRSA) 적용 사항 분석
IAM Role for Service Account (IRSA) 적용 사항 분석
진행자와 함께 IRSA가 적용된 사항을 살펴보고 이를 통해 AWS 자원에 접근하는 과정을 이해해 봅니다. 여기에는 다음과 같은 것이 포함됩니다.
각 포드에 설정된 환경 변수 중
IRSA에 관련된 내용을 확인하고 아울러 포드에 접속하여 서비스 어카운트 토큰 파일을 확인합니다. 그리고AWS CLI를 설치하여 포드에 할당된IAM 역할을 확인합니다.확인된 토큰을 디코딩하여 내용을 확인합니다.
AWS 콘솔에서Amazon EKS서비스로 이동하여 클러스터에 설정된OIDC 공급자를 확인합니다.AWS IAM콘솔에서IAM 역할을 확인하고 이 역할이 어떻게IRSA와 연결되어 있는지 확인합니다. 또한 이 역할이 어떤 정책을 가지고 있는지 확인합니다.
2.3. Helm을 삭제해 보고 템플릿 값 (Values)을 수정하여 배포
Helm을 삭제해 보고 템플릿 값 (Values)을 수정하여 배포
(도전 과제) 위 2.2.에서 Helm Chart의 서비스 어카운트와 관련된 값만을 수정한 후 Helm Upgrad 명령으로 정상 동작함을 확인하였습니다. 진행자의 안내를 받아 이제 Helm Chart의 값을 실제로 수정하여 다시 배포해 보도록 하십시요.
Last updated


