IAM role을 EKS pod별로 설정하기
.
Data_Engineering_TIL(20211024)
[학습자료]
“클라우드 네이티브를 위한 쿠버네티스 실전 프로젝트” 책을 읽고 정리한 내용입니다.
** 동양북스, 아이자와 고지&사토 가즈히코 지음, 박상욱 옮김
참고자료 URL : https://github.com/dybooksIT/k8s-aws-book
“EKS 어플리케이션 로그 관리방안 및 운영 노하우”에 이어서 공부한 내용을 정리한 내용임
** URL : https://minman2115.github.io/DE_TIL299
[기본개념]
앞서 실습한 cloudwatch 에이전트나 fluentd를 배포할때 cloudwatch로 데이터를 전송할 수 있도록 아래와 같이 EC2 노드에 IAM 역할을 연결했다.
현재 EC2 노드에 CloudWatchAgentServerPolicy 정책이 설정되어 있다면 이거를 먼저 제거해준다.
- EKS 운영시 위와 같이 EC2 노드별로 IAM 역할을 설정할때 발생할 수 있는 문제
클러스터상에 배포된 파드에서 AWS 리소스를 사용하려면 필요한 IAM 정책을 EC2 노드에 부여해야했는데 이 방법의 경우 노드에 파드 각각에 필요한 IAM 정책을 모두 부여하게 되므로 모든 파드에서 필요하지 않은 권한이 일괄적으로 설정될 여지가 크다. 이는 보안상 바람직하지 않는다. 최근에 그래서 IAM Role for Service Account(IRSA)라는게 발표되었는데 이를 통해서 파드별로 IAM Role을 각각 부여할 수 있게 되었다.
- IRSA란
1) EKS 클러스터 내의 서비스 계정과 IAM role을 안전하게 연결시키는 구조
2) 서비스 계정을 설정하여 파드를 동작시키면 이 파드에서 연결된 IAM Role을 사용할 수 있음.
- IRSA를 사용하기 위해 아래와 같은 세가지 순서를 지켜야 한다.
1) EKS 클러스터의 OpenID Connect(OIDC) 공급자 기능을 활성화 하고 IAM과 연결
** OIDC : 신뢰받는 ID 발급자의 인증정보나 속성정보를 다른 컴포넌트와 안전하게 공유하는 시스템이다.
2) 서비스 계쩡과 IAM Role 연결
3) 서비스 계정을 설정하고 Pod 동작
[실습]
STEP 1) EKS 클러스터의 OpenID Connect(OIDC) 공급자 기능을 활성화 하고 IAM과 연결
EKS에서는 서비스 계정과 IAM을 연결하기 위해 OpenID Connect를 사용한다. 구체적으로 말하면 EKS 클러스터의 OIDC 공급자 기능을 활성화하고 그 공급자 정보를 IAM에 등록해 EKS의 서비스 계정 인증과 IAM 인가구조를 연결하는 것이다.
이 작업을 위해 아래와 같은 명령어를 실행한다.
[ec2-user@ip-10-10-1-195 ~]$ eksctl utils associate-iam-oidc-provider --name eks-work-cluster --approve
Flag --name has been deprecated, use --cluster
2021-10-24 10:08:36 [ℹ] eksctl version 0.70.0
2021-10-24 10:08:36 [ℹ] using region ap-northeast-2
2021-10-24 10:08:37 [ℹ] will create IAM Open ID Connect provider for cluster "eks-work-cluster" in "ap-northeast-2"
2021-10-24 10:08:37 [✔] created IAM Open ID Connect provider for cluster "eks-work-cluster" in "ap-northeast-2"
그러면 IAM에는 EKS 클러스터의 OIDC 공급자 URL이 설정된 자격증명 공급자가 아래 그림과 같이 생성된다. 이 명령으로 EKS 클러스터가 발행한 ID 토큰과 IAM을 연결할 수 있게 된다.
STEP 2) 서비스 계정과 IAM 역할 연결
그런 다음에 서비스 계정과 IAM 역할을 연결한다. 구체적으로는 서비스 계정이 사용할 권한을 부여받은 IAM 역할을 생성하고, 서비스 계정을 생성할때 그 IAM 역할의 ARN을 연결한다. 아래와 같이 명령어를 실행한다.
그러면 아래와 같이 자동으로 서비스 계정과 IAM 역할이 생성된다.
[ec2-user@ip-10-10-1-195 ~]$ eksctl create iamserviceaccount --name cloudwatch-agent --cluster eks-work-cluster --attach-policy-arn arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy --namespace amazon-cloudwatch --override-existing-serviceaccounts --approve
2021-10-24 11:22:01 [ℹ] eksctl version 0.70.0
2021-10-24 11:22:01 [ℹ] using region ap-northeast-2
2021-10-24 11:22:02 [ℹ] 1 iamserviceaccount (amazon-cloudwatch/cloudwatch-agent) was included (based on the include/exclude rules)
2021-10-24 11:22:02 [!] metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set
2021-10-24 11:22:02 [ℹ] 1 task: {
2 sequential sub-tasks: {
create IAM role for serviceaccount "amazon-cloudwatch/cloudwatch-agent",
create serviceaccount "amazon-cloudwatch/cloudwatch-agent",
} }2021-10-24 11:22:02 [ℹ] building iamserviceaccount stack "eksctl-eks-work-cluster-addon-iamserviceaccount-amazon-cloudwatch-cloudwatch-agent"
2021-10-24 11:22:02 [ℹ] deploying stack "eksctl-eks-work-cluster-addon-iamserviceaccount-amazon-cloudwatch-cloudwatch-agent"
2021-10-24 11:22:02 [ℹ] waiting for CloudFormation stack "eksctl-eks-work-cluster-addon-iamserviceaccount-amazon-cloudwatch-cloudwatch-agent"
2021-10-24 11:22:19 [ℹ] waiting for CloudFormation stack "eksctl-eks-work-cluster-addon-iamserviceaccount-amazon-cloudwatch-cloudwatch-agent"
2021-10-24 11:22:36 [ℹ] waiting for CloudFormation stack "eksctl-eks-work-cluster-addon-iamserviceaccount-amazon-cloudwatch-cloudwatch-agent"
2021-10-24 11:22:36 [ℹ] created namespace "amazon-cloudwatch"
2021-10-24 11:22:36 [ℹ] created serviceaccount "amazon-cloudwatch/cloudwatch-agent"
# 그러면 아래와 같이 서비스 계정에는 생성된 IAM 역할의 ARN이 설정된다.
# 생성된 서비스 계정 확인
[ec2-user@ip-10-10-1-195 ~]$ kubectl get sa -n amazon-cloudwatch -o yaml
apiVersion: v1
items:
- apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::xxxxxxx:role/eksctl-eks-work-cluster-addon-iamserviceacco-Role1-CTCH3P4P9GV9
creationTimestamp: "2021-10-24T11:22:36Z"
labels:
app.kubernetes.io/managed-by: eksctl
name: cloudwatch-agent
namespace: amazon-cloudwatch
resourceVersion: "1646693"
selfLink: /api/v1/namespaces/amazon-cloudwatch/serviceaccounts/cloudwatch-agent
uid: 34e54bfe-85d4-43fc-b190-ab0b9bf0c928
secrets:
- name: cloudwatch-agent-token-gchmf
- apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2021-10-24T11:22:36Z"
name: default
namespace: amazon-cloudwatch
resourceVersion: "1646692"
selfLink: /api/v1/namespaces/amazon-cloudwatch/serviceaccounts/default
uid: 966ebecb-aef2-48e9-829f-43216740472c
secrets:
- name: default-token-g7rvs
kind: List
metadata:
resourceVersion: ""
selfLink: ""
아래와 같이 aws 콘솔에서 arn:aws:iam::xxxxxxx:role/eksctl-eks-work-cluster-addon-iamserviceacco-Role1-CTCH3P4P9GV9
IAM role이 생성된 것을 확인할 수 있다.
STEP 3) 서비스 계정을 설정하여 파드 동작시키기
그런 다음에 생성한 서비스 계정을 설정하여 파드를 동작시키면 된다. 예를 들어서 여기서 배포한 Cloudwatch 에이전트의 데몬셋 매니페스트 파일 내용은 아래와 같다.
[ec2-user@ip-10-10-1-195 ~]$ ll
total 45824
-rw-rw-r-- 1 ec2-user ec2-user 141 Oct 19 13:33 cloudwatch-namespace.yaml
-rw-rw-r-- 1 ec2-user ec2-user 522 Oct 19 13:41 cwagent-configmap.yaml
-rw-rw-r-- 1 ec2-user ec2-user 2560 Oct 19 13:43 cwagent-daemonset.yaml
-rw-rw-r-- 1 ec2-user ec2-user 1120 Oct 19 13:35 cwagent-serviceaccount.yaml
drwxrwxr-x 2 ec2-user ec2-user 59 Oct 23 06:21 eks_log_exam
drwxrwxr-x 15 ec2-user ec2-user 315 Oct 18 13:49 k8s-aws-book
-rw-rw-r-- 1 ec2-user ec2-user 46907392 Oct 18 12:16 kubectl
# 서비스 계정을 설정하여 파드를 동작시키는 매니페스트 cwagent-daemonset.yaml
[ec2-user@ip-10-10-1-195 ~]$ cat cwagent-daemonset.yaml
# deploy cwagent as daemonset
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: cloudwatch-agent
namespace: amazon-cloudwatch
spec:
selector:
matchLabels:
name: cloudwatch-agent
template:
metadata:
labels:
name: cloudwatch-agent
spec:
containers:
- name: cloudwatch-agent
image: amazon/cloudwatch-agent:1.247348.0b251302
#ports:
# - containerPort: 8125
# hostPort: 8125
# protocol: UDP
resources:
limits:
cpu: 200m
memory: 200Mi
requests:
cpu: 200m
memory: 200Mi
# Please don't change below envs
env:
- name: HOST_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP
- name: HOST_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: K8S_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CI_VERSION
value: "k8s/1.3.8"
# Please don't change the mountPath
volumeMounts:
- name: cwagentconfig
mountPath: /etc/cwagentconfig
- name: rootfs
mountPath: /rootfs
readOnly: true
- name: dockersock
mountPath: /var/run/docker.sock
readOnly: true
- name: varlibdocker
mountPath: /var/lib/docker
readOnly: true
- name: containerdsock
mountPath: /run/containerd/containerd.sock
readOnly: true
- name: sys
mountPath: /sys
readOnly: true
- name: devdisk
mountPath: /dev/disk
readOnly: true
volumes:
- name: cwagentconfig
configMap:
name: cwagentconfig
- name: rootfs
hostPath:
path: /
- name: dockersock
hostPath:
path: /var/run/docker.sock
- name: varlibdocker
hostPath:
path: /var/lib/docker
- name: containerdsock
hostPath:
path: /run/containerd/containerd.sock
- name: sys
hostPath:
path: /sys
- name: devdisk
hostPath:
path: /dev/disk/
terminationGracePeriodSeconds: 60
serviceAccountName: cloudwatch-agent
이렇게 하면 EKS 클러스터가 IAM 역할을 부여하기 위해 필요한 토큰을 생성하고 그것이 파드 내의 특정 디렉토리에 마운트된다. 이 상태에서 파드 내부의 어플리케이션이 AWS SDK를 경유해서 각종 처리를 요청하면 자동으로 이 토큰을 사용해서 IAM 역할을 연결하고 AWS 리소스를 컨트롤 할 수 있게 된다.