본문 바로가기
  • lakescript
스터디 이야기/AWS EKS

[AEWS] 6-1. Amazon EKS - Security (EKS 인증/인가)

by lakescript 2024. 4. 9.

사전 준비

더보기

 

위와 같이 사전 준비가 필요합니다. 저번 글에서 설명했듯이, EKS를 배포하기 위한 VPC를 생성하고, Public Subnet, Private Subnet을 생성합니다. 그 후 EKS Cluster에 접근하기 위한 bastion EC2를 미리 생성합니다.
추가로 지난번 실습 때 진행했었던 ExternalDNS와 AWS LB Controller, EBS csi driver 설치, gp3 스토리지 클래스 생성까지 해주시고, Prometheus와 Grafana까지 설치합니다.

 

 

EKS 인증/인가

쿠버네티스의 기본적인 인증/인가 방식은 service accont와 권한 범위를 담은 role, cluster role을 생성하고 해당 service account와 role, cluster role을 binding함으로써 처리합니다.

 

EKS에서는 조금 다른데요. 인증은 AWS IAM을 통해서 제어하고, 인가는 K8S RBAC를 통해 제어합니다.

 

RBAC

ChatGPT가 알려주는 RBAC
RBAC(Role-Based Access Control)은 역할 기반 접근 제어를 의미합니다. 이는 사용자의 역할에 따라 시스템이나 네트워크 자원에 대한 접근 권한을 제어하는 보안 메커니즘입니다. RBAC의 주요 목적은 최소 권한 원칙을 적용하여 사용자가 자신의 업무 수행에 필요한 최소한의 권한만을 가지도록 하는 것입니다.

 

RBAC 실습

krew 플러그인 설치

kubectl krew install rbac-tool rbac-view rolesum whoami

 

인증된 주체 확인

kubectl whoami

 

kubectl rbac-tool whoami

 

 

일반적인 k8s의 RBAC와의 차이점은 Username이 kubernetes-admin에서 user/eks-user로 달라진 것입니다. 또한, aws의 configmap 파일과 최근에 신규로 추가된 Access conrole 기능으로 인해서  처리되기 때문에 Group의 system:master는 보이지 않습니다.

 

 

RBAC permissions 확인

터미널을 하나 새롭게 킨 후 EC2에 연결하고 아래의 명령어를 통해 8800 port를 open합니다.

kubectl rbac-view

 

 

그 후 작업중이던 EC2 터미널에서 아래의 명령어를 통해 8800 port로 접근합니다.

http://$(curl -s ipinfo.io/ip):8800"

 

 

 

그러면 위의 사진과 같이 ClusterRole과 Role등 RBAC를 한눈에 볼 수 있는 page가 띄어지게 되는데 port 노출 후 바로 보시게 되면 아무런 데이터가 없습니다. (데이터를 수집하는 2~3분 소요)

 

 

 

가로축이 role name을 나타내고 세로축이 세부적으로 mapping된 리소스를 나타냅니다. 또한 verb를 C(create), D(delete), G(get), L(list), W(watch), P(patch), U(update), DC(deletecollection), *의 tag 형식으로 나타냅니다.

 

 

EKS 인증/인가

 

위의 장표가 EKS의 인증/인가를 한눈에 보기 좋게 정리된 자료인데요.

 

사용자가 kubectl을 통해 명령어를 요청합니다. 그러면 해당 사용자의 Bearer Token등이 kube-apiserver를 통해 전달됩니다. 그 후 바로 cluster내의 k8s resource로 전달되는 것이 아닌 AWS쪽으로 넘어가 Token Review를 하게 됩니다.  그러면 AWS의 Authentication을 통해 webhook Token Authentication을 진행하고 해당 인증정보를 확인하고 IAM을 통해 User의 정보들이 return됩니다. Token Review가 끝나게 되면 다시 kube-apiserver로 해당 인증 정보를 전달하고 해당 RBAC에 맞게 인가 처리를 하는 것이 EKS의 인증/인가 방식입니다.

 

즉, EKS 인증/인가의 핵심은 "인증은 AWS IAM에서 처리하고 인가는 K8S RBAC에서 처리한다!!" 입니다.

 

 

 

인증/인가 실습

Token 발급

sts를 통해 명령 요청 주체자의 ID 확인

aws sts get-caller-identity --query Arn

 

위의 명령어를 통해 aws sts로 임시 보안 토큰을 조회합니다.

ChatGPT가 알려주는 AWS STS
AWS STS(Amazon Web Services Security Token Service)는 AWS에서 제공하는 웹 서비스로, 사용자나 시스템이 AWS 리소스에 임시로 접근할 수 있도록 하는 보안 토큰을 발급합니다. 이 서비스는 AWS Identity and Access Management(IAM)와 긴밀하게 통합되어, 사용자가 AWS 서비스에 안전하게 임시 접근 권한을 부여받을 수 있게 해줍니다.

 

 

kubeconifg 정보 확인

cat ~/.kube/config | yh

 

 

지금 현재 유저가 AWS IAM의 administrator 권한이 있고, exec 부분의 명령어를 요청할 수 있습니다.

 

임시 보안 자격 증명(토큰) 요청

aws eks get-token --cluster-name $CLUSTER_NAME | jq

 

aws eks get-token 명령를 통해 현재 cluster내의 임시 보안 자격 증명을 조회할 수 있습니다.

 

 

해당 명령어를 요청할 때마다 token의 값이 바뀌게 되니 유의하셔야 합니다.

 

Token을 EKS API Cluster Endpoint로 요청을 보냄

임시로 자격증명을 받은 Token을 이제 EKS API Cluster Endpoint로 요청을 보냅니다.

 

EKS API Cluster Endpoint는 위에서 살펴본 config 파일안에 명시되어 있습니다.

 

위 주소는 EKS의 public endpoint 주소와 같습니다.

 

만약 public EKS가 아니라면 해당 private 주소로 바뀌게 됩니다! 이점 유의하세요!

 

 

 

Token을 Decode

 

 

Token Review

token review를 위해 Webhook token authenticator에 요청합니다. 즉, STS GetCallerIdentity 호출하고 AWS IAM 해당 호출 인증 완료 후 User/Role에 대한 ARN을 반환하게 됩니다.

 

kubectl api-resources | grep authentication

 

kubernetes의 api resource에서 authenticatoin을 필터 후 조회하면 아래와 같이 TokenReviewer가 존재하는 것을 확인하실 수 있습니다.

 

 

해당 resource를 자세히 살펴보면 아래와 같습니다.

 

즉, token reviewer는 사용자의 token에 대해서 인증한다는 것을 알 수 있습니다. (인증 플러그인중 하나)

 

 

https://ap-northeast-2.console.aws.amazon.com/cloudtrailv2/home?region=ap-northeast-2#/events?EventName=GetCallerIdentity

 

https://ap-northeast-2.console.aws.amazon.com/cloudtrailv2/home?region=ap-northeast-2#/events?EventName=GetCallerIdentity

 

ap-northeast-2.console.aws.amazon.com

 

위의 url에 접근하시게 되면 서울 resion의 cloudTail에서 이벤트기록 메뉴에 바로 접근이 가능합니다. 

 

 

 

위의 사진처럼 GetCallerIdentity 이벤트를 호출하면서 AWS IAM 서비스에 사용자 검증을 요청하는 것을 확인하실 수 있습니다.

 

 

 RBAC 인가

해당 IAM User/Role 확인이 되면 k8s aws-auth configmap에서 mapping 정보를 확인하게 됩니다. 그 후 aws-auth 컨피그맵에 'IAM 사용자, 역할 arm, K8S 오브젝트' 로 권한 확인 후 k8s 인가 허가가 되면 최종적으로 동작 실행을 합니다

aws-auth 컨피그맵 확인

kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh

해당 유저가 aws-auth configmap에 있는지 확인합니다.

 

 

하지만 EKS를 설치한 AWS IAM의 ARN은 해당 조회에서 보이지 않습니다. (아마 여기 있었을경우 만약 실수로 삭제 시 복구가 불가능하기 때문에 생략한 듯 싶습니다.)

 

 

 

새로운 유저를 추가하기

위에서 실습으로 진행헀던 인증/인가 방식을 조금 더 자세히 알아보기 위해 새로운 사용자(devops engineer)가 입사를 하였고 그에게 eks 인증/인가를 적용하는 실습을 진행해보겠습니다.

 

testuser 사용자 생성

aws iam create-user --user-name testuser

 

aws iam create-user 명령어를 통해 testuser라는 새로운 iam user를 생성합니다.

 

프로그래밍 방식 액세스 권한 부여

aws iam create-access-key --user-name testuser

 

그 후 access-key를 생성하기 위해 위의 명령어 실행합니다.

 

(여기서 나온 AccessKeyId와 SecretAccessKey는 잘 복사해주세요!)

 

IAM에 정책 부여

aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name testuser

 

위에서 생성한 testuser에 admin 정책을 부여합니다.

 

신규 ec2에 접근

새로운 EC2에 위에서 생성했던 testuser의 권한을 부여하도록 하겠습니다.

 

aws 권한 설정

aws configure

 

위의 명령어를 통해서 앞서 저장해놨던 AccessKeyId와 SecretAccessKey를 붙여넣고 자격증명을 저장해줍니다.

 

aws sts get-caller-identity --query Arn

 

그 후 위의 명령어를 통해 자격증명 임시 토큰을 발급 받습니다.

 

 

 

kubectl 명령어 실행

administrator 권한이 있는 IAM도 생성했고, 해당 권한을 부여했으니 이제 명령어를 쳐서 인증/인가를 무사히 통과하는지 확인해보겠습니다.

kubectl get node -v6

 

위의 명령어를 통해 node 정보를 살펴보겠습니다.

 

 

 

띠용!

 

api 호출이 정상적으로 이루저지지 않는 것을 확인하실 수 있습니다. 왜 administrator 권한까지 부여한 IAM 정책을 연결시켰는데 API 호출이 안될까요? 

 

 

 

그것은 바로 kubernetes의 설정 정보를 담은 .kube 파일이 없기 때문입니다.

 

 

기존 EC2에서 새로운 EC2의 권한 제어

eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/testuser

 

위의 명령어를 기존 EC2에서 입력하여 testuser 사용자에게 system:masters 권한을 부여합니다.

 

kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh

 

그 후 위의 명령어를 통해 configmap에 설정된 aws-auth 정보를 확인하여 system:masters가 testuser에 부여된 것을 확인합니다.

 

 

eksctl get iamidentitymapping --cluster $CLUSTER_NAME

 

최종적으로 iamidentitymapping 리소스를 통해 현재 cluster에 mapping된 AWS IAM 권한들을 살펴보면 아래와 같이 testuser가 system:masters 그룹에 매칭된것을 확인하실 수 있습니다.

 

 

edit으로 직접 수정

kubectl edit cm -n kube-system aws-auth

 

edit 명령어를 통해 aws-auth를 직접 수정하여 권한을 설정해줄 수 도 있습니다. 

 

 

신규 EC2에서 kubeconfig 설정

이제 다시 신규 EC2로 돌아와 아래의 명령어를 통해 testuser의 권한으로 eks에 설정되어 있는 kubeconfig 파일을 업데이트합니다.

 

kubeconfig 업데이트

aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser

 

 

kubeconfig 확인

cat ~/.kube/config | yh

 

정상적으로 context가 추가된 것을 보실 수 있습니다.

 

kubectl 명령어 실행

kubectl get node -v6

 

이제 kubeconfig 설정이 완료되었으니 위의 명령어를 통해 kubectl 명령어를 요청해보겠습니다.

 

정상적으로 호출됩니다!

 

 


 

EKS API로만 관리하기

EKS API + Configmap

위의 방식대로 configmap과 EKS API를 동시에 mapping해서 관리하기엔 너무 부담이 되는 것이 현실입니다.

 

AWS에서는 이를 방지하기 위해 EKS의 API로만 관리할 수 있게끔 기능을 지원하기 시작했습니다.

 

EKS API

API 엑세스 모드 변경

aws eks update-cluster-config --name $CLUSTER_NAME --access-config authenticationMode=API

 

 

update-cluster-config 명령어로 access-config를 수정해주시거나 AWS Managed Console에서 직접 수정이 가능합니다.

 

 

변경된 것을 확인하실 수 있습니다.

 

Access policies 목록 확인

aws eks list-access-policies | jq

 

list-access-policies 명령어를 통해 access policy의 목록을 확인해보겠습니다.

 

- AmazonEKSClusterAdminPolicy - 클러스터 관리자

- AmazonEKSAdminPolicy – 관리자 

- AmazonEKSEditPolicy – 편집

- AmazonEKSViewPolicy – 보기

 

ClusterRole  확인

kubectl get clusterroles -l 'kubernetes.io/bootstrapping=rbac-defaults' | grep -v 'system:'

 

kubernetes clusterrole에 'kubernetes.io/bootstrapping=rbac-defaults' label을 갖고 있는 cluster role을 확인합니다.

 

각 정보는 공식문서에 자세히 나와있으니 참고해주세요!

 

 

access-entries 확인

aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq

 

위의 명령어를 통해 cluster에 적용되어있는 access entries를 확인합니다.

현재는 node에 대한 accessEntry와 user:eks-user에 entry만 보이게 됩니다.

 

 

access-entry의 특정 ARN에 연결된 policy 확인

 aws eks list-associated-access-policies --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/eks-user | jq

 

list-associated-access-policies 명령어를 통해 cluster에 있는 arn(eks-user)에 연결된 IAM Policy를 확인합니다.

 

 

access-entry 상세 확인

aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/eks-user | jq

 

describe-access-entry를 통해 클러스터에 있는 access-entry의 ARN에 대하여 상세 정보를 확인합니다.

 

 

 

 

testuser를 통한 실습

testuser 의 access entry 생성

aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser

 

create-access-entry를 통해 testuser를 생성합니다.

 

 

 

 

testuser access entry 확인

aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]

 

list-access-entries를 통해 cluster에 있는 access entry 목록을 확인해보겠습니다.

 

 

user/testuser가 생성된 것을 확인하실 수 있습니다!

 

testuser에 AmazonEKSClusterAdminPolicy 연동

aws eks associate-access-policy --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser \
  --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster

 

associate-access-policy 명령어를 통해 IAM의 AmazonEKSClusterAdminPolicy와 mapping 시켜줍니다.

 

 

 

그후 AWS Managed Console에서 cluster에 접근하신 후 IAM 엑세스 항목 탭을 보시면 위와 같이 testuser가 추가된 것을 확인하실 수 있습니다.

 

 

새로운 EC2에서 testuser 확인

testuser 정보 확인

aws sts get-caller-identity --query Arn

 

sts를 통해 ARN 자격증명을 확인합니다.

 

 

kubectl 명령어 처리

kubectl get node -v6

 

kubectl 로 인증/인가를 확인해보겠습니다.

 

위의 사진처럼 confimap 추가나 다른 role binding이 필요없이 access-entry만 생성하고 IAM 연결만 해주었는데, 너무나도 간단히 인증/인가가 처리된 것을 확인하실 수 있습니다.

 

 

testuser entry 삭제

aws eks delete-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser

 

delete-access-entry 명령어를 통해 testuser를 삭제하도록 하겠습니다.

 

 

바로 삭제된 것을 확인하실 수 있습니다.

 

kubectl 명령어 실행

kubectl get node -v-6

 

삭제한 후 kubectl 명령어를 실행하면 아래와 같이 error가 발생하는 것을 확인하실 수 있습니다.

 

 

 

권한을 Custom 해서 적용해보자!

위의 실습 예시들은 이미 만들어진 rule에 대한 적용 실습이었습니다. 근데 실무를 하다보면 어떤 사용자는 pod를 get만 설정해야하고, 어떤 사용자는 create만 설정해야하고 각각 verb를 다르게 설정해야 하는데, 이런 부분을 실습해보도록 하겠습니다.

 

ClusterRole 생성

testuser는 pod를 list, get, watch 권한만 주어지도록 설정하겠습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-viewer-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list", "get", "watch"]

 

ClusterRole 적용

kubectl apply -f pod-viewer-role.yaml

 

위에서 생성한 yaml 파일을 cluster에 배포합니다.

 

ClusterRoleBinding 생성

kubectl create clusterrolebinding viewer-role-binding --clusterrole=pod-viewer-role --group=pod-viewer

 

pod-viewer-role이라는 clusterRole과 group을 binding 시켜줍니다.

 

 

access-entry 적용

aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-viewer

 

testuser ARN에 위에서 생성한 ClusterRoleBinding의 kubernetes-group으로 연결시켜줍니다.

 

access-entry 상세 보기

aws eks describe-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser | jq

 

describe-access-enrty 명령어를 통해 testuser access-entry의 상세 정보를 확인합니다.

 

 

이전과 다르게 kubernetesGroups이 추가된 것을 확인하실 수 있습니다.

 

kubernetesGroups 업데이트

aws eks update-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/testuser --kubernetes-group pod-admin | jq -r .accessEntry

 

update-access-entry 명령어를 통해 testuser에 kubernetes group을 업데이트 시켜줍니다.

 

 

 

다른 EC2에서 testuser 확인

이제 다른 EC2에서 testuser access-entry를 부여한 것을 토대로 확인해보도록 하겠습니다.

 

kubectl 명령어 실행

kubectl get pod -A -v6

 

pod의 list, get, watch 권한을 부여했으니 위의 명령어를 통해 pod의 목록을 출력해보겠습니다.

 

 

 

아주 정상적으로 잘 호출되는 것을 확인하실 수 있습니다.

 

그렇다면 node의 정보를 출력하면 어떻게 될까요?

 

kubectl get node -v6

 

 

kubernetes group에서 resource와 verb를 허용해주지 않았기 때문에 node 호출 시 처리가 안되는 것을 확인하실 수 있습니다!

 

 


 

Reference

- https://aws.amazon.com/ko/blogs/containers/a-deep-dive-into-simplified-amazon-eks-access-management-controls/