6주차 - EKS Security - 사용자 인증/인가

728x90

 

K8S 인증/인가

 

Kubernetes에서는 API 통신을 위하여 인증(Authentication), 인가/권한(Authorization), Admission Control(승인제어) 단계를 거치게 된다.

  • 인증(Authentication): Kubernetes를 사용하는 사용자가 검증된 사용자인지를 확인하는 절차
    - User Account: Kubernetes를 사용하는 사용자 계정
    ex) AWS 로그인 계정
    - Service Account: Pod에서 실행되는 프로세스에 대한 식별자를 제공 / Namespace로 구분
    ex) AWS IAM

  • 인가/권한(Authorization): 사용자 행위에 대해서 권한이 있는지를 확인하는 절차 / RBAC기반으로 동작
    - User Account 별 Role/Rolebinding / Cluster Role/ Cluster Rolebinding
    - Service Account 별로 Role/Rolebinding / Cluster Role/ Cluster Rolebinding

  • Admission Control(승인제어): API 요청 검증 / API 요청에 대한 특정 기능을 제한 / 변경(ResourceQuota, LimitRange)

Service Account 실습 시나리오

  1. 서비스 어카운트(Service Account, SA)를 생성 : dev-k8s, infra-k8s
  2. 서비스 어카운트 별 Pod 생성 및 권한 Test
  3. 서비스 어카운트 별 권한(Role, 인가)생성 : dev-k8s(dev-team 네임스페이스 내 모든 동작) , infra-k8s(dev-team 네임스페이스 내 모든 동작)
  4. SA 를 지정하여 권한에 대한 테스트를 진행

 

1. 네임스페이스와 서비스 어카운트 생성 후 확인

# 네임스페이스(Namespace, NS) 생성 및 확인
kubectl create namespace dev-team
kubectl create ns infra-team

# 네임스페이스 확인
kubectl get ns

# 네임스페이스에 각각 서비스 어카운트 생성 : serviceaccounts 약자(=sa)
kubectl create sa dev-k8s -n dev-team
kubectl create sa infra-k8s -n infra-team

# 서비스 어카운트 정보 확인
kubectl get sa -n dev-team
kubectl get sa dev-k8s -n dev-team -o yaml | yh

kubectl get sa -n infra-team
kubectl get sa infra-k8s -n infra-team -o yaml | yh

 

2. 서비스 어카운트 별 Pod 생성 및 권한 Test

# 각각 네임스피이스에 kubectl 파드 생성 - 컨테이너이미지
# docker run --rm --name kubectl -v /path/to/your/kube/config:/.kube/config bitnami/kubectl:latest
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.28.5
    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.28.5
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
EOF

# 확인
kubectl get pod -A
kubectl get pod -o dev-kubectl -n dev-team -o yaml
 serviceAccount: dev-k8s
 ...
kubectl get pod -o infra-kubectl -n infra-team -o yaml
 serviceAccount: infra-k8s
...

# 파드에 기본 적용되는 서비스 어카운트(토큰) 정보 확인
kubectl exec -it dev-kubectl -n dev-team -- ls /run/secrets/kubernetes.io/serviceaccount
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/token
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/namespace
kubectl exec -it dev-kubectl -n dev-team -- cat /run/secrets/kubernetes.io/serviceaccount/ca.crt

# 각각 파드로 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

# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
no

 

 

3. 서비스 어카운트 별 권한(Role, 인가)생성 : dev-k8s(dev-team 네임스페이스 내 모든 동작) , infra-k8s(dev-team 네임스페이스 내 모든 동작)

# 각각 네임스페이스내의 모든 권한에 대한 롤 생성
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 get roles -n dev-team
kubectl get roles -n infra-team
kubectl get roles -n dev-team -o yaml
kubectl describe roles role-dev-team -n dev-team
...
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]

# 롤바인딩 생성 : '서비스어카운트 <-> 롤' 간 서로 연동
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 get rolebindings -n dev-team
kubectl get rolebindings -n infra-team
kubectl get rolebindings -n dev-team -o yaml
kubectl describe rolebindings roleB-dev-team -n dev-team
...
Role:
  Kind:  Role
  Name:  role-dev-team
Subjects:
  Kind            Name     Namespace
  ----            ----     ---------
  ServiceAccount  dev-k8s  dev-team

 

4. 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 
k1 run nginx --image nginx:1.20-alpine
k1 get pods
k1 delete pods nginx
k1 get pods -n kube-system
k1 get nodes

k2 get pods 
k2 run nginx --image nginx:1.20-alpine
k2 get pods
k2 delete pods nginx
k2 get pods -n kube-system
k2 get nodes

# (옵션) kubectl auth can-i 로 kubectl 실행 사용자가 특정 권한을 가졌는지 확인
k1 auth can-i get pods
yes

 

 

EKS 인증/인가

 

  • AWS EKS의 경우 사용자 인증은 AWS IAM / 인가는 K8S의 RBAC을 사용

 

 

EKS 인증/인가 세부 과정

 

1. EKS Service endpoint(STS)에 토큰 요청

2. 전달받은 토큰을 Bearer Token 형식으로 EKS API Cluster EndPoint에 인증 요청

3. EKS API는 Token Review 를 Webhook token authenticator에 요청 ⇒ (STS GetCallerIdentity 호출) AWS IAM 해당 호출 인증 완료 후 User/Role에 대한 ARN 반환

3. 쿠버네티스 RBAC 인가를 처리

 

 

실습 - myeks-bastion-2에 burst사용자 생성

 

1. burst 사용자 생성(Bastion1 서버 실행)

# 사용자 생성
aws iam create-user --user-name burst

# 사용자에게 프로그래밍 방식 액세스 권한 부여
aws iam create-access-key --user-name burst

# 사용자에 정책을 추가
aws iam attach-user-policy --policy-arn arn:aws:iam::aws:policy/AdministratorAccess --user-name burst

# get-caller-identity 확인
aws sts get-caller-identity --query Arn
"arn:aws:iam::590183955668:user/yjsong"

kubectl whoami
"arn:aws:iam::590183955668:user/yjsong"

# EC2 IP 확인 : myeks-bastion-EC2-2 PublicIPAdd 확인
aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output table

 

2. burst 유저 자격증명 설정 및 확인 (Bastion2 서버 실행)

# get-caller-identity 확인 >> 왜 안될까요?
aws sts get-caller-identity --query Arn

# testuser 자격증명 설정
aws configure
AWS Access Key ID [None]: My-Access-Key
AWS Secret Access Key [None]: My-Secret-Key
Default region name [None]: ap-northeast-2

# get-caller-identity 확인
aws sts get-caller-identity --query Arn


# kubectl 시도 >> testuser도 AdministratorAccess 권한을 가지고 있는데, 실패 이유는?
kubectl get node -v6
ls ~/.kube

 

3. burst에 system:masters 그룹 부여로 EKS 관리자 수준 권한 설정 (Bastion1 서버 실행)

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

 

 

 

4. burst kubeconfig 생성 및 kubectl 사용 확인 (Bastion2 서버 실행)

# burst kubeconfig 생성 >> aws eks update-kubeconfig 실행이 가능한 이유는?, 3번 설정 후 약간의 적용 시간 필요
aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias burst


# kubectl 사용 확인
kubectl ns default
kubectl get node -v6

 

 

 

 

EKS 신규기능 access management controls

 

aws-auth configmap 잘못 수정 시 Node전체에 장애가 발생 할 수 있음

이를 보안하기 위해 신규 기능인 access management controls 기능이 추가

 

기존 복잡하고 configmap을 통한 사용자 관리를 보다 쉽게 제어 및 컨트롤 할 수 있는 장점이 있음

 

  • 기본 인증모드는 EKS API 및 ConfigMap으로 설정되어 있으나 정책 중복 시 EKS API가 우선되며, ConfigMap은 무시됨

 

 

 

 

 

실습 - EKS access management controls

 

1. EKS 인증방식을 EKS API모드로 변경

# EKS API 액세스모드로 변경
aws eks update-cluster-config --name $CLUSTER_NAME --access-config authenticationMode=API

# List all access policies : 클러스터 액세스 관리를 위해 지원되는 액세스 정책
## AmazonEKSClusterAdminPolicy – 클러스터 관리자
## AmazonEKSAdminPolicy – 관리자
## AmazonEKSEditPolicy – 편집
## AmazonEKSViewPolicy – 보기
aws eks list-access-policies | jq

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

2. burst 계정 설정

  • access-entry 생성 / associate-access-policy 연동
    • 간단하고 직관적으로 EKS 사용자를 관리 할 수 있음
# burst2 의 access entry 생성
aws eks create-access-entry --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/burst
aws eks list-access-entries --cluster-name $CLUSTER_NAME | jq -r .accessEntries[]

# burst에 AmazonEKSClusterAdminPolicy 연동
aws eks associate-access-policy --cluster-name $CLUSTER_NAME --principal-arn arn:aws:iam::$ACCOUNT_ID:user/burst \
  --policy-arn arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy --access-scope type=cluster

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

 

3. bastion2에서 burst2 확인

# burst2 정보 확인
aws sts get-caller-identity --query Arn
kubectl whoami

# kubectl 시도
kubectl get node -v6
kubectl api-resources -v5
kubectl rbac-tool whoami
kubectl auth can-i delete pods --all-namespaces
kubectl get cm -n kube-system aws-auth -o yaml | kubectl neat | yh
eksctl get iamidentitymapping --cluster $CLUSTER_NAME

 

4. 직접 생성한 Cluster-role 사용

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

cat <<EoF> ~/pod-admin-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-admin-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["*"]
EoF

kubectl apply -f ~/pod-viewer-role.yaml
kubectl apply -f ~/pod-admin-role.yaml

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

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

 

5. 직접 생성한 Cluster-role 사용 ( kubernetesGroups 업데이트 적용)

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

 

 

728x90