AEWS 6주차 - EKS Security(k8s 인증/인가, EKS 인증/인가, access management controls)
본 글은 가시다님이 진행하시는 AEWS(AWS EKS Workshop Study)를 참여하여 정리한 글입니다. 모르는 부분이 많아서 틀린 내용이 있다면 말씀 부탁드리겠습니다! |
k8s 인증/인가

Admission Controller란?
- Admission Controller는 Kubernetes API 서버에서 리소스 객체를 생성, 업데이트, 삭제하기 전에 실행되는 플러그인입니다.
- Admission Controller는 리소스 객체의 유효성을 검사하고, 필요에 따라 리소스 객체를 변경할 수 있습니다.
- Admission Controller를 통해 Kubernetes 클러스터의 보안, 정책, 구성 등을 관리할 수 있습니다.
Admission Controller의 종류의 두가지를 설명하겠습니다.
- Mutating Admission Controller
- Validating Admission Controller
Mutating Admission Controller
- Mutating Admission Controller는 리소스 객체를 생성, 업데이트, 삭제하기 전에 실행됩니다.
- 이 Controller는 리소스 객체의 내용을 변경할 수 있습니다.
- 예를 들어, 자동으로 레이블을 추가하거나 컨테이너 이미지 태그를 기본값으로 설정할 수 있습니다.
- Mutating Admission Controller는 리소스 객체의 최종 상태를 결정할 수 있습니다.
Validating Admission Controller
- Validating Admission Controller는 리소스 객체를 생성, 업데이트, 삭제하기 전에 실행됩니다.
- 이 Controller는 리소스 객체의 유효성을 검사할 수 있습니다.
- 예를 들어, 리소스 객체의 필수 필드가 채워졌는지, 리소스 객체의 사양이 유효한지 등을 확인할 수 있습니다.
- Validating Admission Controller는 리소스 객체가 유효하지 않은 경우 요청을 거부할 수 있습니다.
Admission Controller는 Kubernetes 클러스터의 보안, 정책, 구성 등을 관리하는 데 중요한 역할을 합니다. Mutating Admission Controller는 리소스 객체를 변경할 수 있고, Validating Admission Controller는 리소스 객체의 유효성을 검사할 수 있습니다. 이를 통해 Kubernetes 클러스터의 일관성과 보안을 유지할 수 있습니다.

API 서버 접근 과정 : 인증 → 인가 → Admission Control(API 요청 검증, 필요 시 변형 - 예. ResourceQuota, LimitRange)
여기서 잠깐 인증과 인가의 차이점은 무엇일까요?
=> 요약하면, 인증은 "누구인가?(허용된 사용자인가?)"를 확인하는 것이고,
인가는 "무엇을 할 수 있는가?(사용 권한이 있는가?)"를 결정하는 것입니다.
인증(Authentication)

- X.509 Client Certs : kubeconfig 에 CA crt(발급 기관 인증서) , Client crt(클라이언트 인증서) , Client key(클라이언트 개인키) 를 통해 인증
- kubectl : 여러 클러스터(kubeconfig)를 관리 가능 - contexts 에 클러스터와 유저 및 인증서/키 참고
- Service Account : 기본 서비스 어카운트(default) - 시크릿(CA crt 와 token)
인가(Authorization)

- 인가 방식 : RBAC(Role, RoleBinding), ABAC, Webhook, Node Authorization
- RBAC : 역할 기반의 권한 관리, 사용자와 역할을 별개로 선언 후 두가지를 조합(binding)해서 사용자에게 권한을 부여하여 kubectl or API로 관리 가능
- Namespace/Cluster - Role/ClusterRole, RoleBinding/ClusterRoleBinding, Service Account
- Role(롤) - (RoleBinding 롤 바인딩) - Service Account(서비스 어카운트) : 롤 바인딩은 롤과 서비스 어카운트를 연결
- Role(네임스페이스내 자원의 권한) vs ClusterRole(클러스터 수준의 자원의 권한)
권한 확인
실습을 위해 dev-team에는 sa dev-k8s를 infra-team에는 sa infra-k8s를 생성하였습니다.
사전 구성
ns : dev-team, infra-team
sa : dev-k8s, infra-k8s (각 네임스페이스에 올바르게)
kubectl get sa dev-k8s -n dev-team -o yaml
-----------------
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: "2025-03-13T08:59:35Z"
name: dev-k8s
namespace: dev-team
resourceVersion: "406963" #객체의 상태 변경 사항을 추적을 위한 리소스 버전
uid: 1f539de1-f6dc-4941-951d-cbd44f1cbef3
Pod에 spec아래에 sa를 지정해서 배포합니다. (2개)
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: dev-kubectl
namespace: dev-team
spec:
serviceAccountName: dev-k8s
containers:
- name: kubectl-pod
image: bitnami/kubectl:1.31.4
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
name: infra-kubectl
namespace: infra-team
spec:
serviceAccountName: infra-k8s
containers:
- name: kubectl-pod
image: bitnami/kubectl:1.31.4
command: ["tail"]
args: ["-f", "/dev/null"]
terminationGracePeriodSeconds: 0
EOF
# 파드에 기본 적용되는 서비스 어카운트(토큰) 정보 확인
kubectl exec -it dev-kubectl -n dev-team -- ls /run/secrets/kubernetes.io/serviceaccount

인증서와 namespace와 token이 존재합니다.
이제 각 sa가 가지고 있는 권한을 확인해봅니다.
* 저희가 지금까지 권한을 부연한적이 있을까요..?
# 각각 파드로 Shell 접속하여 정보 확인 : 단축 명령어(alias) 사용
alias k1='kubectl exec -it dev-kubectl -n dev-team -- kubectl'
alias k2='kubectl exec -it infra-kubectl -n infra-team -- kubectl'
# 권한 테스트
k1 get pods # kubectl exec -it dev-kubectl -n dev-team -- kubectl get pods 와 동일한 실행 명령이다!
k1 run nginx --image nginx:1.20-alpine
k1 get pods -n kube-system
k2 get pods # kubectl exec -it infra-kubectl -n infra-team -- kubectl get pods 와 동일한 실행 명령이다!
k2 run nginx --image nginx:1.20-alpine
k2 get pods -n kube-system


각기 다른 ns에 대해서 get pods도 파드 실행도 모두 실패하였습니다.
==> 저희는 role을 만들고 sa에 바인딩을 한적이 없기에 이제 진행해봅니다.
Role 생성 및 바인딩

롤(Role)
apiGroups 와 resources 로 지정된 리소스에 대해 verbs 권한을 인가
실행 가능한 조작(verbs)
*(모두 처리), create(생성), delete(삭제), get(조회), list(목록조회), patch(일부업데이트), update(업데이트), watch(변경감시)
# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-dev-team
namespace: dev-team
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
EOF
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: role-infra-team
namespace: infra-team
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["*"]
EOF
# 확인
kubectl describe roles role-dev-team -n dev-team

이제 모든 resource에 대해서 모든 verbs를 할 수 있는 슈퍼 role을 생성하였습니다.
role을 sa에 바인딩해봅니다.
# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: roleB-dev-team
namespace: dev-team
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-dev-team
subjects:
- kind: ServiceAccount
name: dev-k8s
namespace: dev-team
EOF
cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: roleB-infra-team
namespace: infra-team
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-infra-team
subjects:
- kind: ServiceAccount
name: infra-k8s
namespace: infra-team
EOF
# 확인
kubectl describe rolebindings roleB-dev-team -n dev-team

이제 dev-k8s에게 만들었던 role을 바인딩해보았으니, 이전에 실행했던 권한 테스트를 다시 진행합니다.
# 권한 테스트
k1 run nginx --image nginx:1.20-alpine
k1 get pods
k1 get nodes
k2 run nginx --image nginx:1.20-alpine
k2 get pods
k2 get nodes
# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes



이제 해당 권한으로 pod를 실행하고 get으로도 확인이 가능해졌습니다.
# 리소스 삭제
kubectl delete ns dev-team infra-team
RBAC 관련 krew 플러그인
# 설치
kubectl krew install access-matrix rbac-tool rbac-view rolesum whoami
# k8s 인증된 주체 확인
kubectl whoami
# Show an RBAC access matrix for server resources
kubectl access-matrix -h
kubectl access-matrix

아주 직관적으로 확인이 가능하니 설치하면 좋을 것 같습니다.
###간단한 사용법!
# RBAC Lookup by subject (user/group/serviceaccount) name
kubectl rbac-tool lookup system:masters
kubectl describe ClusterRole eks:node-bootstrapper
# Generate ClusterRole with all available permissions from the target cluster
kubectl rbac-tool show
# Shows the subject for the current context with which one authenticates with the cluster
kubectl rbac-tool whoami
kubectl rolesum -k Group system:authenticated



또한 8800 포트로 접근하면 웹으로 더욱 보기 쉽습니다

EKS 인증/인가

간단하게 설명하면 AWS STS에게 Token을 발급받고 이를 이용해서
AWS IAM에게 인증을 받습니다. 그리고 이 자격증명에 해당하는 요청을 RBAC에서 인가하여 처리합니다.
순서대로 해봅니다.
1. kubectl 명령 → aws eks get-token → STS에 토큰 요청 ⇒ 응답값 디코드(Pre-Signed URL 이며 GetCallerIdentity..)
여기서 어떻게 사용자가 AWS sts에게 Token을 발급받을 수 있을까요?
정답은 .kube/config에 권한이 정의되어져있습니다.

그리고 이 토큰은 pre-signed url로 expired time이 존재하기 때문에 보안에 더욱 안전합니다.

2. kubectl의 Client-Go 라이브러리는 Pre-Signed URL을 Bearer Token으로 EKS API Cluster Endpoint로 요청을 보냄

3. EKS API는 Token Review를 Webhook token authenticator를 통해 요청 ⇒ (STS GetCallerIdentity 호출) AWS IAM 해당 호출 인증 완료 후 User/Role에 대한 ARN 반환
-> 참고로 Webhook token authenticator 는 aws-iam-authenticator 를 사용
# tokenreviews api 리소스 확인
kubectl api-resources | grep authentication
selfsubjectreviews authentication.k8s.io/v1 false SelfSubjectReview
tokenreviews authentication.k8s.io/v1 false TokenReview TokenReview
# List the fields for supported resources.
kubectl explain tokenreviews
...
DESCRIPTION:
TokenReview attempts to authenticate a token to a known user. Note:
TokenReview requests may be cached by the webhook token authenticator
plugin in the kube-apiserver.

SelfSubjectReview를 통해 사용자는 자신의 권한을 확인할 수 있고,
TokenReview를 통해 인증 토큰의 유효성을 검증할 수 있습니다.
4. [ConfigMap 방식] 이제 쿠버네티스 RBAC 인가를 처리합니다.
# aws-auth 컨피그맵 확인 : 현재는 IAM access entry 방식 우선 적용으로 아래 출력 내용과 다를 수 있습니다.
kubectl get cm -n kube-system aws-auth -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: aws-auth
namespace: kube-system
data:
mapRoles: |
- groups:
- system:bootstrappers
- system:nodes
rolearn: arn:aws:iam::1471...:role/eksctl-myeks-nodegroup-ng1-NodeInstanceRole-NbC52SALCUqI
username: system:node:{{EC2PrivateDNSName}}
mapUsers: |
- groups:
- system:masters
userarn: arn:aws:iam::111122223333:user/admin
username: kubernetes-admin
# EKS 설치한 IAM User 정보
kubectl rbac-tool whoami
{Username: "kubernetes-admin",
UID: "aws-iam-authenticator:1471...:NbC52SALCUqI.....",
Groups: ["system:masters",
"system:authenticated"],
...
# system:masters , system:authenticated 그룹의 정보 확인
kubectl rbac-tool lookup system:masters
kubectl rbac-tool lookup system:authenticated
kubectl rolesum -k Group system:masters
kubectl rolesum -k Group system:authenticated
# system:masters 그룹이 사용 가능한 클러스터 롤 확인 : cluster-admin
kubectl describe clusterrolebindings.rbac.authorization.k8s.io cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
Role:
Kind: ClusterRole
Name: cluster-admin
Subjects:
Kind Name Namespace
---- ---- ---------
Group system:masters
# cluster-admin 의 PolicyRule 확인 : 모든 리소스 사용 가능!
kubectl describe clusterrole cluster-admin
Name: cluster-admin
Labels: kubernetes.io/bootstrapping=rbac-defaults
Annotations: rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
Resources Non-Resource URLs Resource Names Verbs
--------- ----------------- -------------- -----
*.* [] [] [*]
[*] [] [*]
# system:authenticated 그룹이 사용 가능한 클러스터 롤 확인
kubectl describe ClusterRole system:discovery
kubectl describe ClusterRole system:public-info-viewer
kubectl describe ClusterRole system:basic-user
kubectl describe ClusterRole eks:podsecuritypolicy:privileged




EKS access management controls


현재 EKS는 인증 방식을 aws-auth & EKS API 혹은 EKS API를 제공합니다.
aws-auth는 configmap으로 인증을 제공하는 방법인데, 이전에 EKS API를 제공하기 전에는
Cluster을 만든 주체만 aws-auth에 등록되어있어서 주체가 configmap을 수정하지 않으면 다른 사용자가 api 서버와 통신이 불가능했을뿐만아니라,
대책이 없이 모든 user를 삭제해버렸다면..? Case Open까지 해야하는데 매우 복잡했습니다.
이제는 EKS API를 제공하기에 IAM 사용자 인증과 더욱 편리하고 유기적으로 인증이 가능해져서 편리합니다.
만들어봅시다.
사전 구성 : 아무 권한이 없는 IAM 사용자
1. EKS -> 클러스터 -> 엑세스 -> 엑세스 항목 생성

2. IAM 보안 주체 선택

3. 권한 추가 -> 생성

4. 확인

추가 및 편집도 가능합니다.
-> 만약 AmazonEKSClusterAdminPolicy이 필요한거였다면?
5. 바꾸고 싶은 엑세스 항목 클릭 -> 엑세스 정책 추가

6. AmazonEKSClusterAdminPolicy 추가

해당 사용자로 자격 증명을 변경 후 kubectl을 날려보면 응답이 옵니다.

이제는 너무도 간편해진 EKS API 인증과 사용자 추가입니다.