Skip to main content Link Menu Expand (external link) Document Search Copy Copied

K8s 인증/인가 실습

쿠버네티스에서 dev-k8s 및 infra-k8s 서비스 어카운트를 생성하여, dev-team 네임스페이스 내에서 각각 다른 권한을 부여하고 테스트해보도록 한다.

SA, ns 생성

kubectl create namespace dev-team
namespace/dev-team created
 
kubectl create ns infra-team
namespace/infra-team created
 
kubectl get ns
NAME                 STATUS   AGE
default              Active   72m
dev-team             Active   6s
infra-team           Active   5s
kube-node-lease      Active   72m
kube-public          Active   72m
kube-system          Active   72m
local-path-storage   Active   72m
 
kubectl create sa dev-k8s -n dev-team
serviceaccount/dev-k8s created
 
kubectl create sa infra-k8s -n infra-team
serviceaccount/infra-k8s created

서비스 어카운트와 네임스페이스를 생성한다.

pod deploy

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 get pod -o dev-kubectl -n dev-team -o yaml |
grep service
      - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    serviceAccount: dev-k8s
    serviceAccountName: dev-k8s
        - serviceAccountToken:
      - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
 
kubectl get pod -o infra-kubectl -n infra-team -o yaml | grep service
      - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    serviceAccount: infra-k8s
    serviceAccountName: infra-k8s
        - serviceAccountToken:
      - mountPath: /var/run/secrets/kubernetes.io/serviceaccount

권한 확인

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
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:dev-team:dev-k8s" cannot list resource "pods" in API group "" in the namespace "dev-team"
 
k2 get pods
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:infra-team:infra-k8s" cannot list resource "pods" in API group "" in the namespace "infra-team"
 
k1 auth can-i get pods
no

현재 dev-k8s 및 infra-k8s 서비스 어카운트는 Kubernetes 리소스 조회 권한이 없어서 에러가 발생한다.

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
role.rbac.authorization.k8s.io/role-dev-team created
 
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
role.rbac.authorization.k8s.io/role-infra-team created
 
kubectl get roles -n dev-team
NAME            CREATED AT
role-dev-team   2025-03-15T18:56:26Z
 
kubectl get roles -n infra-team
NAME              CREATED AT
role-infra-team   2025-03-15T18:56:28Z

특정 네임스페이스에서만 리소스에 대한 접근 권한을 정의하는 객체인 롤을 생성한다.

롤은 네임스페이스 내에서만 적용되며, 클러스터 전체에 적용하려면 ClusterRole을 사용해야 한다.

apiGroups, resources, 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
rolebinding.rbac.authorization.k8s.io/roleB-dev-team created
 
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
rolebinding.rbac.authorization.k8s.io/roleB-infra-team created

특정 네임스페이스에서 Role을 특정 사용자 또는 서비스 어카운트(ServiceAccount)에 연결하는 객체인 롤 바인딩을 생성한다.

Role을 단독으로 생성해도 아무 의미가 없으며 RoleBinding을 통해 서비스 어카운트와 연결해야 롤이 적용된다.

kubectl describe rolebindings roleB-dev-team -n dev-team
Name:         roleB-dev-team
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  Role
  Name:  role-dev-team
Subjects:
  Kind            Name     Namespace
  ----            ----     ---------
  ServiceAccount  dev-k8s  dev-team

서비스 어카운트에 제대로 권한이 할당되었다

k1 get pods
NAME          READY   STATUS    RESTARTS   AGE
dev-kubectl   1/1     Running   0          8m31s
 
k2 get pods
NAME            READY   STATUS    RESTARTS   AGE
infra-kubectl   1/1     Running   0          8m24s
 
k1 auth can-i get pods
yes
 
k2 auth can-i get pods
yes

RBAC 권한 확인

kubectl krew install access-matrix rbac-tool rbac-view rolesum whoami

실습을 위한 도구를 설치한다.

  • access-matrix: 사용자의 RBAC 권한을 매트릭스로 확인
  • rbac-tool: RBAC 역할(Role)과 바인딩 정보를 조회
  • rbac-view: 웹 UI에서 RBAC 역할을 시각적으로 분석
  • rolesum: RBAC 요약 정보를 제공
  • whoami: 현재 컨텍스트에서의 인증된 사용자 확인
kubectl rolesum aws-node -n kube-system
ServiceAccount: kube-system/aws-node
Secrets:
 
Policies:
 
• [CRB] */aws-node ⟶  [CR] */aws-node
  Resource                                   Name  Exclude  Verbs  G L W C U P D DC
  cninodes.vpcresources.k8s.aws              [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✔ ✖ ✖
  eniconfigs.crd.k8s.amazonaws.com           [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  events.[,events.k8s.io]                    [*]     [-]     [-]   ✖ ✔ ✖ ✔ ✖ ✔ ✖ ✖
  namespaces                                 [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  nodes                                      [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  pods                                       [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  policyendpoints.networking.k8s.aws         [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  policyendpoints.networking.k8s.aws/status  [*]     [-]     [-]   ✔ ✖ ✖ ✖ ✖ ✖ ✖ ✖

aws-node SA는 AWS VPC CNI 플러그인이 네트워크 관련 리소스를 조작할 수 있도록 필요한 권한을 가지고 있다.

  • cninodes.vpcresources.k8s.aws VPC CNI 관련 노드 관리
  • eniconfigs.crd.k8s.amazonaws.com AWS ENI(Elastic Network Interface) 설정 관리
  • nodes 클러스터 내 노드 정보 조회 가능
  • pods Pod 정보 조회 가능
  • policyendpoints.networking.k8s.aws 네트워크 정책 적용
kubectl rolesum -k User system:kube-proxy
User: system:kube-proxy
 
Policies:
• [CRB] */system:node-proxier ⟶  [CR] */system:node-proxier
  Resource                         Name  Exclude  Verbs  G L W C U P D DC
  endpoints                        [*]     [-]     [-]   ✖ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  endpointslices.discovery.k8s.io  [*]     [-]     [-]   ✖ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  events.[,events.k8s.io]          [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✔ ✔ ✖ ✖
  nodes                            [*]     [-]     [-]   ✔ ✔ ✔ ✖ ✖ ✖ ✖ ✖
  services                         [*]     [-]     [-]   ✖ ✔ ✔ ✖ ✖ ✖ ✖ ✖

Kube-Proxy는 클러스터 네트워킹을 관리하기 위해 서비스 및 엔드포인트 정보를 가진다.

  • endpoints 클러스터 내 서비스의 엔드포인트 정보 조회 가능
  • endpointslices.discovery.k8s.io 서비스의 엔드포인트 슬라이스 정보 조회 가능
  • events.[,events.k8s.io] 이벤트 관련 정보 조회 가능
  • nodes 클러스터 내 노드 정보 조회 가능
  • services 서비스 정보 조회 가능
kubectl rolesum -k Group system:masters
Group: system:masters
 
Policies:
• [CRB] */cluster-admin ⟶  [CR] */cluster-admin
  Resource  Name  Exclude  Verbs  G L W C U P D DC
  *.*       [*]     [-]     [-]   ✔ ✔ ✔ ✔ ✔ ✔ ✔ ✔

클러스터 관리자 그룹으로 쿠버네티스 최고 권한인 cluster-admin 역할을 부여받아 모든 리소스를 수정 가능하다.

kubectl rolesum -k Group system:nodes
Group: system:nodes
 
Policies:
• [CRB] */eks:node-bootstrapper ⟶  [CR] */eks:node-bootstrapper
  Resource                                                       Name  Exclude  Verbs  G L W C U P D DC
  certificatesigningrequests.certificates.k8s.io/selfnodeserver  [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖

EKS(또는 Kubernetes 클러스터)에서 새로운 노드가 클러스터에 추가될 때 필요한 권한은 eks:node-bootstrapper로 부터 주어지는데,

노드(Kubelet)는 자신의 인증서를 요청(Certificate Signing Request, CSR)하고 관리자로부터 승인받아야 API 서버와 통신이 가능하게 된다.

노드는 API 서버와 안전하게 통신하기 위해 자체 인증서 요청을 생성할 수 있다.

kubectl rolesum -k Group system:authenticated
Group: system:authenticated
 
Policies:
• [CRB] */system:basic-user ⟶  [CR] */system:basic-user
  Resource                                       Name  Exclude  Verbs  G L W C U P D DC
  selfsubjectaccessreviews.authorization.k8s.io  [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
  selfsubjectreviews.authentication.k8s.io       [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
  selfsubjectrulesreviews.authorization.k8s.io   [*]     [-]     [-]   ✖ ✖ ✖ ✔ ✖ ✖ ✖ ✖
 
 
• [CRB] */system:discovery ⟶  [CR] */system:discovery
 
 
• [CRB] */system:public-info-viewer ⟶  [CR] */system:public-info-viewer

API 서버에 인증된 모든 사용자가 자동으로 포함되는 그룹으로 RBAC 정책을 통해 특정 리소스에 접근할 수 있다.

EKS 인증

EKS에서 액세스 제어는 AWS Identity and Access Management(IAM)과 쿠버네티스의 역할 기반 액세스 제어(RBAC)를 결합하여 이루어진다. IAM은 클러스터에 대한 인증을 처리하고 Kubernetes RBAC는 클러스터 내 리소스에 대한 권한을 관리한다.

  • IAM 사용자 및 역할의 쿠버네티스 API 액세스 부여: IAM 사용자 또는 역할이 Kubernetes API에 접근하려면 액세스 항목을 사용하여 Kubernetes RBAC 권한을 해당 IAM 엔터티와 연결하여 개발자나 애플리케이션이 클러스터와 상호 작용 가능하다.
  • AWS Management Console에서 Kubernetes 리소스 보기: AWS Management Console을 통해 클러스터의 네임스페이스, 노드, 파드와 같은 Kubernetes 리소스를 시각화하기 위해 콘솔이 Amazon EKS 클러스터와 통신하도록 구성해야 한다.
  • kubectl을 EKS 클러스터에 연결: AWS CLI를 사용하여 kubeconfig 파일을 생성하거나 업데이트함으로써 kubectl cli 도구가 Amazon EKS 클러스터의 API 서버와 통신할 수 있도록 설정한다.
  • Kubernetes 서비스 어카운트를 통한 AWS API 액세스: Kubernetes 워크로드가 AWS API를 호출할 수 있도록 하려면 서비스 어카운트와 IAM 역할을 설정하여 파드가 AWS 리소스에 안전하게 접근할 수 있다.

사용 가능한 롤 확인

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
  
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
  ---------  -----------------  --------------  -----
  *.*        []                 []              [*]
             [*]                []              [*]

cluster-admin은 Kubernetes 클러스터에서 모든 리소스를 관리할 수 있는 최고 권한을 가진 역할이다.

system:masters 그룹에 cluster-admin 역할을 부여하는데 system:masters 그룹에 속한 사용자는 클러스터의 모든 리소스를 관리 가능하다.

cluster-admin 역할을 가진 사용자는 쿠버네티스 클러스터 내 모든 리소스와 API 엔드포인트에 대해 제한 없이 접근 가능하다.

aws auth config map

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

실습을 위한 테스트 유저를 생성하고 어드민 액세스 권한을 부여한다.

kubectl get node -v6
I0316 05:40:16.553046    2768 round_trippers.go:553] GET http://localhost:8080/api?timeout=32s  in 0 milliseconds
E0316 05:40:16.553210    2768 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
I0316 05:40:16.554763    2768 cached_discovery.go:120] skipped caching discovery info due to Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.555075    2768 round_trippers.go:553] GET http://localhost:8080/api?timeout=32s  in 0 milliseconds
E0316 05:40:16.555135    2768 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
I0316 05:40:16.558345    2768 cached_discovery.go:120] skipped caching discovery info due to Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.559675    2768 shortcut.go:103] Error loading discovery information: Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.560892    2768 round_trippers.go:553] GET http://localhost:8080/api?timeout=32s  in 0 milliseconds
E0316 05:40:16.560975    2768 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
I0316 05:40:16.562193    2768 cached_discovery.go:120] skipped caching discovery info due to Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.562483    2768 round_trippers.go:553] GET http://localhost:8080/api?timeout=32s  in 0 milliseconds
E0316 05:40:16.562535    2768 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
I0316 05:40:16.563622    2768 cached_discovery.go:120] skipped caching discovery info due to Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.563803    2768 round_trippers.go:553] GET http://localhost:8080/api?timeout=32s  in 0 milliseconds
E0316 05:40:16.563844    2768 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"http://localhost:8080/api?timeout=32s\": dial tcp 127.0.0.1:8080: connect: connection refused"
I0316 05:40:16.564946    2768 cached_discovery.go:120] skipped caching discovery info due to Get "http://localhost:8080/api?timeout=32s": dial tcp 127.0.0.1:8080: connect: connection refused
I0316 05:40:16.565005    2768 helpers.go:264] Connection error: Get http://localhost:8080/api?timeout=32s: dial tcp 127.0.0.1:8080: connect: connection refused
The connection to the server localhost:8080 was refused - did you specify the right host or port?

AWS 자격 증명은 문제 없지만 Kubernetes RBAC 및 인증 설정을 확인해야 한다.

iam 매핑

# 1번 배스천 서버
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
eksctl create iamidentitymapping --cluster $CLUSTER_NAME --username testuser --group system:masters --arn arn:aws:iam::$ACCOUNT_ID:user/testuser
 
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
ARN											USERNAME				GROUPS					ACCOUNT
...
arn:aws:iam::390844768149:user/testuser							testuser				system:masters
# 2번 배스천 서버
aws eks update-kubeconfig --name $CLUSTER_NAME --user-alias testuser
Updated context testuser in /root/.kube/config
 
cat ~/.kube/config
...
- name: testuser
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - --region
      - ap-northeast-2
      - eks
      - get-token
      - --cluster-name
      - myeks
      - --output
      - json
      command: aws
      
kubectl ns default
Context "testuser" modified.
Active namespace is "default".
 
(testuser:default) [root@operator-host-2 ~]# kubectl get node -v6
I0316 06:04:22.045436    3159 loader.go:395] Config loaded from file:  /root/.kube/config
I0316 06:04:23.069865    3159 round_trippers.go:553] GET https://~~~.yl4.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 200 OK in 1015 milliseconds
NAME                                               STATUS   ROLES    AGE     VERSION
ip-192-168-1-31.ap-northeast-2.compute.internal    Ready    <none>   5h53m   v1.31.5-eks-5d632ec
ip-192-168-2-143.ap-northeast-2.compute.internal   Ready    <none>   5h53m   v1.31.5-eks-5d632ec
ip-192-168-3-145.ap-northeast-2.compute.internal   Ready    <none>   5h53m   v1.31.5-eks-5d632ec

testuser의 그룹 권한을 변경하면?

  kubectl edit cm -n kube-system aws-auth
  ...
  - groups:
      - system:authenticated
      userarn: arn:aws:iam::390844768149:user/testuser
      username: testuser
  
 eksctl get iamidentitymapping --cluster $CLUSTER_NAME 
 arn:aws:iam::390844768149:user/testuser							testuser				system:authenticated
 
 kubectl get node -v6
I0316 06:07:56.767482    3307 loader.go:395] Config loaded from file:  /root/.kube/config
I0316 06:07:57.923161    3307 round_trippers.go:553] GET https://~~.yl4.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 403 Forbidden in 1147 milliseconds
I0316 06:07:57.923812    3307 helpers.go:246] server response object: [{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "nodes is forbidden: User \"testuser\" cannot list resource \"nodes\" in API group \"\" at the cluster scope",
  "reason": "Forbidden",
  "details": {
    "kind": "nodes"
  },
  "code": 403
}]
Error from server (Forbidden): nodes is forbidden: User "testuser" cannot list resource "nodes" in API group "" at the cluster scope

testuser가 system:authenticated 그룹에 속해 있고, nodes 리소스에 대한 RBAC 권한이 없기 때문에 정상적으로 접근이 차단된다.

testuser IAM 매핑 삭제

eksctl delete iamidentitymapping --cluster $CLUSTER_NAME --arn  arn:aws:iam::$ACCOUNT_ID:user/testuser
2025-03-16 06:09:54 [ℹ]  removing identity "arn:aws:iam::390844768149:user/testuser" from auth ConfigMap (username = "testuser", groups = ["system:authenticated"])
 
eksctl get iamidentitymapping --cluster $CLUSTER_NAME
 
kubectl get cm -n kube-system aws-auth -o yaml
 
# 2번 배스천 서버
kubectl get node -v6
I0316 06:10:54.403658    3413 loader.go:395] Config loaded from file:  /root/.kube/config
I0316 06:10:56.447285    3413 round_trippers.go:553] GET https://~~~.yl4.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 401 Unauthorized in 2035 milliseconds
I0316 06:10:56.447752    3413 helpers.go:246] server response object: [{
  "kind": "Status",
  "apiVersion": "v1",
  "metadata": {},
  "status": "Failure",
  "message": "Unauthorized",
  "reason": "Unauthorized",
  "code": 401
}]
error: You must be logged in to the server (Unauthorized)

기존에 testuser는 aws-auth ConfigMap에 등록되어 있었는데 IAM 매핑을 제거한 후, kubectl get nodes를 실행하면 401 Unauthorized 오류 발생하게 된다.