ServiceAccount와 RoleBinding으로 최소 권한 검증하기

mizu·2026년 8월 29일

K8S

목록 보기
8/10

Overview

Kubernetes RBAC를 처음 배울 때 자주 헷갈리는 지점이 있다. RoleClusterRole, RoleBindingClusterRoleBinding, 그리고 --role--clusterrole의 경계다. 이름이 비슷해서 “권한을 준다”는 느낌만 남기 쉽지만, 실제 운영에서는 이 경계가 권한 범위를 결정한다.

이번 실습의 목표는 release bot이 한 namespace 안에서 workload 상태만 읽게 만드는 것이었다. 필요한 권한은 Pods, Deployments, ReplicaSets에 대한 read-only 접근이었다. Secrets 조회, Pod 삭제, 전체 namespace 조회는 허용하면 안 됐다.

핵심은 Role + RoleBinding을 쓰고, kubectl auth can-i로 허용되는 작업과 거부되는 작업을 모두 확인하는 것이다. RBAC 검증은 yes만 보면 부족하다. 최소 권한을 증명하려면 no가 나와야 하는 명령도 같이 확인해야 한다.

참고 문서:

최소 재현 예제

release bot 역할을 하는 ServiceAccount를 하나 만들고, 같은 namespace 안의 workload만 읽을 수 있는 Role을 붙인다.

apiVersion: v1
kind: ServiceAccount
metadata:
  name: release-reader
  namespace: cka-a04-retest
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: release-read-workloads
  namespace: cka-a04-retest
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: release-read-workloads
  namespace: cka-a04-retest
subjects:
  - kind: ServiceAccount
    name: release-reader
    namespace: cka-a04-retest
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: release-read-workloads

여기서 Role은 namespace-scoped 리소스다. 같은 이름의 Role이 있어도 namespace가 다르면 별개의 권한이다. RoleBinding은 이 Role을 ServiceAccount에 연결한다.

실습에서 만든 리소스

먼저 ServiceAccount, Role, RoleBinding이 namespace 안에 만들어졌는지 확인했다.

kubectl get sa,role,rolebinding -n cka-a04-retest
NAME                            SECRETS   AGE
serviceaccount/default          0         6m2s
serviceaccount/release-reader   0         5m49s

NAME                                                    CREATED AT
role.rbac.authorization.k8s.io/release-read-workloads   2026-08-29T08:08:14Z

NAME                                                           ROLE                          AGE
rolebinding.rbac.authorization.k8s.io/release-read-workloads   Role/release-read-workloads   9s

Role에는 Pods, Deployments, ReplicaSets 읽기 권한만 들어 있다.

kubectl describe role release-read-workloads -n cka-a04-retest
PolicyRule:
  Resources         Non-Resource URLs  Resource Names  Verbs
  ---------         -----------------  --------------  -----
  pods              []                 []              [get list watch]
  deployments.apps  []                 []              [get list watch]
  replicasets.apps  []                 []              [get list watch]

RoleBinding도 ClusterRole이 아니라 namespaced Role을 참조한다.

kubectl describe rolebinding release-read-workloads -n cka-a04-retest
Role:
  Kind:  Role
  Name:  release-read-workloads
Subjects:
  Kind            Name            Namespace
  ----            ----            ---------
  ServiceAccount  release-reader  cka-a04-retest

허용 확인

kubectl auth can-i는 특정 주체가 특정 API 작업을 할 수 있는지 확인하는 명령이다. ServiceAccount 권한을 확인할 때는 --as=system:serviceaccount:<namespace>:<serviceaccount> 형식을 사용한다.

이번 실습에서는 다음 작업이 허용되어야 했다.

get pods: yes
list deployments: yes
watch replicasets: yes

이 결과는 release bot이 rollout 상태를 읽는 데 필요한 기본 workload 조회 권한을 갖고 있음을 보여준다.

거부 확인

최소 권한은 허용 목록만으로는 증명되지 않는다. 필요 없는 권한이 실제로 막혀 있는지도 봐야 한다.

이번 실습에서는 다음 작업이 거부되어야 했다.

get secrets: no
delete pods: no
get pods --all-namespaces: no

이 세 가지는 의미가 다르다. Secrets 조회가 막혔다는 것은 민감한 설정과 토큰에 접근하지 못한다는 뜻이다. Pod 삭제가 막혔다는 것은 release bot이 workload를 파괴할 수 없다는 뜻이다. --all-namespaces 조회가 막혔다는 것은 권한이 특정 namespace 안에 갇혀 있다는 뜻이다.

ClusterRoleBinding도 만들어지지 않았는지 확인했다.

kubectl get clusterrolebinding | grep release-reader || echo "no clusterrolebinding for release-reader"
no clusterrolebinding for release-reader

왜 Role과 RoleBinding인가

이번 요구사항은 한 namespace 안의 workload 상태를 읽는 것이다. cluster-wide 권한이 필요하지 않다. 그래서 Role + RoleBinding이 맞다.

ClusterRole은 cluster-scoped 리소스에 대한 권한을 정의하거나 여러 namespace에 재사용할 수 있는 권한 묶음을 만들 때 쓴다. ClusterRoleBinding은 그 권한을 cluster 전체에 붙인다. 요구사항이 namespace 하나로 충분한데 ClusterRoleBinding을 쓰면 권한 경계가 넓어진다.

이번 실습에서 release bot은 cka-a04-retest 안의 Pods, Deployments, ReplicaSets만 읽으면 된다. Secrets도 필요 없고, Pod 삭제도 필요 없고, 다른 namespace 조회도 필요 없다. 이 정도 요구사항에는 namespaced Role이 더 작고 명확하다.

Troubleshooting 순서

RBAC가 예상대로 동작하지 않을 때는 리소스를 순서대로 분해해서 본다.

  1. ServiceAccount가 올바른 namespace에 있는지 확인한다.
kubectl get serviceaccount release-reader -n cka-a04-retest
  1. Role이 필요한 resource와 verb만 갖고 있는지 본다.
kubectl describe role release-read-workloads -n cka-a04-retest
  1. RoleBinding이 올바른 ServiceAccount를 subject로 갖는지 확인한다.
kubectl describe rolebinding release-read-workloads -n cka-a04-retest
  1. ServiceAccount로 impersonation해서 허용 권한을 확인한다.
kubectl auth can-i get pods -n cka-a04-retest --as=system:serviceaccount:cka-a04-retest:release-reader
kubectl auth can-i list deployments -n cka-a04-retest --as=system:serviceaccount:cka-a04-retest:release-reader
kubectl auth can-i watch replicasets -n cka-a04-retest --as=system:serviceaccount:cka-a04-retest:release-reader
  1. 허용하면 안 되는 권한도 확인한다.
kubectl auth can-i get secrets -n cka-a04-retest --as=system:serviceaccount:cka-a04-retest:release-reader
kubectl auth can-i delete pods -n cka-a04-retest --as=system:serviceaccount:cka-a04-retest:release-reader
kubectl auth can-i get pods --all-namespaces --as=system:serviceaccount:cka-a04-retest:release-reader

구조 설명

RBAC는 세 가지 질문으로 보면 이해하기 쉽다.

Who
  -> ServiceAccount release-reader

What
  -> pods, deployments, replicasets

Which action
  -> get, list, watch

Kubernetes 리소스로 풀면 이렇게 연결된다.

ServiceAccount
  -> RoleBinding subject
    -> Role
      -> rules: resources + verbs

Role은 “무엇을 할 수 있는가”를 정의한다. RoleBinding은 “누가 그 Role을 받는가”를 정한다. ServiceAccount는 workload가 Kubernetes API를 호출할 때 쓰는 identity다.

정리

이번 실습의 핵심은 RBAC를 만들었다는 사실보다 권한 범위를 증명했다는 점이다. get pods, list deployments, watch replicasetsyes가 나와야 했다. 반대로 get secrets, delete pods, get pods --all-namespacesno가 나와야 했다.

RBAC는 허용만 확인하면 반쪽짜리 검증이 된다. 운영에서 중요한 것은 필요한 작업은 되게 하고, 필요 없는 작업은 막는 것이다. kubectl auth can-i를 쓸 때도 이 습관을 들이면 권한 설계가 훨씬 선명해진다.

profile
문제를 해결해보자 ✨

0개의 댓글