Certified Kubernetes Administrator (CKA) #9 RBAC: Role/ClusterRole, RoleBinding, ServiceAccount, kubectl auth can-i

#8 인증서 관리에서 PKI와 kubeconfig를 다루며 누가 클러스터에 들어오는가, 즉 인증(authentication)을 정리했습니다. CSR로 사용자 인증서를 발급하면 그 사용자는 apiserver에 자신이 누구인지 증명할 수 있습니다. 그런데 들어온 사람이 무엇이든 다 할 수 있다면 그건 운영이 아닙니다. 이번 글은 그다음 질문인 누가 무엇을 할 수 있는가, 즉 인가(authorization)를 다룹니다.

쿠버네티스의 기본 인가 모드가 **RBAC(Role-Based Access Control)**입니다. CKAD에서도 RBAC을 짧게 짚었지만, CKA는 운영자 관점에서 한 단계 더 들어갑니다. ClusterRole을 RoleBinding으로 묶어 네임스페이스를 한정하는 조합, ServiceAccount에 앱 권한을 부여하는 패턴, auth can-i --as로 남의 권한을 대신 확인하는 검증까지 손에 익어야 합니다. RBAC은 #25 Troubleshooting 4에서 “권한이 없어 작업이 막히는” 장애의 원인으로도 다시 나오므로, 여기서 구조를 확실히 잡아 두겠습니다.

인증 다음의 인가: 누가 무엇을 할 수 있는가 #

apiserver에 도착한 모든 요청은 세 관문을 차례로 통과합니다. 먼저 인증에서 “너는 누구냐"를 확인하고, 다음 인가에서 “그 일을 해도 되느냐"를 판정하며, 마지막 admission control에서 “그 내용이 정책에 맞느냐"를 검사합니다. RBAC은 이 가운데 두 번째 관문을 담당합니다.

RBAC의 판정 방식은 단순합니다. 기본은 모두 거부이며, 어떤 규칙이 그 요청을 명시적으로 허용할 때만 통과합니다. 즉 RBAC에는 “거부” 규칙이 없습니다. 허용 규칙을 쌓아 올리는 방식이고, 어디에도 허용이 없으면 그 요청은 거부됩니다. 이 가산(additive) 모델을 머릿속에 박아 두면 “왜 권한이 없지"라는 질문에 “허용 규칙이 없으니까"라고 곧장 답할 수 있습니다.

RBAC의 네 객체 #

RBAC은 네 종류의 객체로만 이루어집니다. 두 개는 권한의 묶음을 정의하고, 나머지 두 개는 그 묶음을 누구에게 줄지 연결합니다.

객체역할범위
Role권한 규칙의 묶음한 네임스페이스 안
ClusterRole권한 규칙의 묶음클러스터 전체 / 모든 네임스페이스 / 비네임스페이스 리소스
RoleBinding묶음을 subject에 연결한 네임스페이스 안
ClusterRoleBinding묶음을 subject에 연결클러스터 전체

권한을 정의하는 객체(Role/ClusterRole)와 그것을 부여하는 객체(RoleBinding/ClusterRoleBinding)가 분리되어 있다는 점이 핵심입니다. 같은 ClusterRole 하나를 여러 RoleBinding이 각자 다른 네임스페이스에서 재사용할 수 있는 것이 이 분리 덕분입니다.

rules: apiGroups / resources / verbs #

Role과 ClusterRole의 알맹이는 rules 배열입니다. 규칙 한 줄은 세 축으로 “어떤 리소스에 어떤 동작을 허용할지"를 적습니다.

  • apiGroups: 리소스가 속한 API 그룹. core 그룹(Pod, Service, ConfigMap 등)은 빈 문자열 ""로 적습니다. Deployment,ReplicaSet은 apps, Job은 batch, Ingress,NetworkPolicy는 networking.k8s.io에 속합니다.
  • resources: 대상 리소스의 복수형 이름. pods, deployments, services 식입니다. pods/logpods/exec 같은 서브리소스도 여기서 따로 지정합니다.
  • verbs: 허용할 동작. get, list, watch, create, update, patch, delete, deletecollection가 있습니다. 흔히 읽기 전용은 get/list/watch 세 개를 함께 줍니다.

특정 객체만 한정하려면 resourceNames로 이름을 못박을 수도 있습니다. 다만 list,watch,create에는 resourceNames가 적용되지 않으므로, 운영에서는 “이 이름의 ConfigMap만 get/update” 같은 좁은 권한에 주로 씁니다.

subjects: User / Group / ServiceAccount #

RoleBinding과 ClusterRoleBinding의 subjects는 권한을 받을 주체입니다. 세 종류가 있습니다.

  • User: 사람 사용자. 쿠버네티스에는 User 객체가 없습니다. #8에서 본 것처럼 인증서의 CN 같은 외부 신원이 곧 User 이름입니다.
  • Group: 사용자 그룹. 인증서의 O 필드나 토큰의 group claim으로 정해집니다. system:masters처럼 클러스터가 미리 정의한 그룹도 있습니다.
  • ServiceAccount: 앱(Pod)의 신원. 네임스페이스에 속하는 실제 객체이며, Pod가 apiserver를 호출할 때 쓰는 권한 주체입니다.

User와 Group은 클러스터가 관리하지 않는 외부 신원이고, ServiceAccount만 클러스터 안의 객체라는 차이를 기억해 두면 바인딩을 쓸 때 헷갈리지 않습니다.

Role vs ClusterRole, RoleBinding vs ClusterRoleBinding #

CKA에서 가장 자주 묻는 것이 이 네 객체의 조합 규칙입니다. 권한 묶음(Role/ClusterRole)과 바인딩(RoleBinding/ClusterRoleBinding)을 어떻게 짝짓느냐에 따라 권한이 미치는 범위가 달라집니다.

권한 묶음바인딩결과 권한 범위
RoleRoleBinding그 RoleBinding이 있는 한 네임스페이스 안의 리소스
ClusterRoleClusterRoleBinding모든 네임스페이스 + 비네임스페이스 리소스 (클러스터 전체)
ClusterRoleRoleBindingClusterRole에 정의된 권한을, 그 RoleBinding이 있는 한 네임스페이스로 한정해 부여
RoleClusterRoleBinding불가능. Role은 네임스페이스에 묶이므로 클러스터 범위로 부여할 수 없음

세 번째 줄, ClusterRole을 RoleBinding으로 묶는 조합이 운영에서 특히 유용합니다. “Pod를 읽는 권한” 같은 ClusterRole을 한 번만 정의해 두고, 팀마다 자기 네임스페이스에서 RoleBinding으로 그 ClusterRole을 가리키면, 각 팀은 자기 네임스페이스의 Pod만 읽을 수 있습니다. 권한 묶음은 한 벌만 유지하면서 적용 범위는 네임스페이스로 좁히는 셈입니다.

비네임스페이스 리소스는 ClusterRole로만 #

노드(Node), PersistentVolume, Namespace 자체, CertificateSigningRequest 같은 리소스는 어느 네임스페이스에도 속하지 않습니다. 이런 클러스터 범위 리소스에 대한 권한은 Role로는 표현할 수 없고 반드시 ClusterRole로 정의해야 합니다. “노드를 list하는 권한을 만들라"는 문제에서 Role을 쓰면 답이 틀어지는 이유가 이것입니다.

generator로 빠르게 만들기 #

시험에서 RBAC을 YAML로 손편집하면 시간을 잃습니다. kubectl create generator로 골격을 만들고, 필요할 때만 $do(=--dry-run=client -o yaml)로 빼서 손보는 흐름이 빠릅니다.

Role과 ClusterRole #

# 네임스페이스 Role: pods를 읽기 전용으로
k create role pod-reader \
  --verb=get,list,watch \
  --resource=pods \
  -n dev

# 서브리소스 포함 (pods/log 까지)
k create role log-reader \
  --verb=get,list \
  --resource=pods,pods/log \
  -n dev

# ClusterRole: 클러스터 범위 (모든 ns / Node 등)
k create clusterrole deploy-manager \
  --verb=get,list,watch,create,update,patch,delete \
  --resource=deployments.apps

# 노드를 읽는 ClusterRole
k create clusterrole node-viewer \
  --verb=get,list,watch \
  --resource=nodes

--resource=deployments.apps처럼 리소스.그룹 형식을 쓰면 apiGroup을 정확히 지정할 수 있습니다. core 그룹 리소스는 pods처럼 그룹 없이 적습니다.

RoleBinding과 ClusterRoleBinding #

# Role을 사용자에게 (그 ns 안에서만)
k create rolebinding pod-reader-bind \
  --role=pod-reader \
  --user=jane \
  -n dev

# ClusterRole을 RoleBinding으로: dev ns 안에서만 deploy 관리
k create rolebinding deploy-mgr-bind \
  --clusterrole=deploy-manager \
  --user=jane \
  -n dev

# ClusterRole을 ServiceAccount에 (클러스터 전체)
k create clusterrolebinding node-viewer-bind \
  --clusterrole=node-viewer \
  --serviceaccount=monitoring:metrics-sa

# ClusterRole을 그룹 전체에 (클러스터 전체)
k create clusterrolebinding dev-admins \
  --clusterrole=admin \
  --group=dev-team

--role은 같은 네임스페이스의 Role을, --clusterrole은 ClusterRole을 가리킵니다. subject는 --user, --group, --serviceaccount=<ns>:<name> 중에서 고릅니다. ServiceAccount는 반드시 네임스페이스:이름 형식으로 적어야 한다는 점에 주의하겠습니다.

auth can-i: 권한을 검증한다 #

RBAC을 만든 뒤 실제로 그 권한이 통하는지 확인하지 않고 넘어가면 시험에서 점수를 잃습니다. kubectl auth can-i가 이 검증 도구입니다.

# 내 권한 확인
k auth can-i create deployments -n dev
# yes 또는 no로 답함

# 특정 사용자인 척 확인 (--as)
k auth can-i get pods --as jane -n dev

# 그룹까지 흉내내기
k auth can-i delete nodes --as jane --as-group dev-team

# ServiceAccount의 권한 확인
k auth can-i list pods \
  --as=system:serviceaccount:monitoring:metrics-sa -n dev

# 그 subject가 무엇을 할 수 있는지 한눈에
k auth can-i --list --as jane -n dev

--asimpersonation(가장) 기능입니다. 관리자 권한으로, 마치 그 사용자가 요청한 것처럼 apiserver에 물어보고 RBAC 판정 결과만 받아 옵니다. 실제로 kubeconfig를 바꾸지 않고도 “jane이 이 일을 할 수 있나"를 즉시 확인할 수 있어, RBAC 작업의 정답 확인에 가장 빠릅니다.

ServiceAccount를 흉내낼 때는 --as=system:serviceaccount:<네임스페이스>:<이름> 형식을 씁니다. 이 system:serviceaccount:... 문자열이 곧 ServiceAccount의 내부 User 이름이기도 합니다.

ServiceAccount: 앱에 권한을 준다 #

지금까지의 User/Group은 사람을 위한 것이었습니다. 그런데 클러스터 안에서 도는 앱이 apiserver를 호출해야 할 때도 권한이 필요합니다. 예를 들어 컨트롤러가 Pod를 watch하거나, 모니터링 앱이 노드 지표를 읽는 경우입니다. 이때 쓰는 신원이 ServiceAccount입니다.

# ServiceAccount 생성
k create serviceaccount metrics-sa -n monitoring

# Pod에 연결 (deployment의 경우 spec.template.spec)
k set serviceaccount deployment/metrics metrics-sa -n monitoring

Pod의 spec.serviceAccountName에 ServiceAccount 이름을 적으면, 그 Pod 안에는 ServiceAccount 토큰이 자동으로 마운트됩니다. Pod 안의 앱은 이 토큰으로 apiserver에 인증하고, 그 ServiceAccount에 바인딩된 Role/ClusterRole이 허용하는 범위에서만 동작할 수 있습니다.

운영의 원칙은 최소 권한입니다. 앱마다 전용 ServiceAccount를 두고, 그 앱이 실제로 필요한 동작만 허용하는 Role을 바인딩합니다. 모든 네임스페이스에는 default ServiceAccount가 있지만, 거기에 권한을 몰아주면 그 네임스페이스의 모든 Pod가 같은 권한을 갖게 되므로 전용 ServiceAccount를 쓰는 편이 안전합니다.

#8에서 만든 사용자를 연결하기 #

#8에서 CSR로 사용자 인증서를 발급하면, 그 인증서의 CN이 User 이름이 됩니다. 이 사용자는 인증은 되지만 아직 아무 권한이 없습니다. RBAC으로 권한을 붙여야 비로소 작업할 수 있습니다.

# #8에서 CN=jane으로 발급한 사용자에게 dev ns 권한 부여
k create role developer \
  --verb=get,list,watch,create,update,patch,delete \
  --resource=pods,deployments.apps,services \
  -n dev

k create rolebinding jane-dev \
  --role=developer \
  --user=jane \
  -n dev

# 검증
k auth can-i create deployments --as jane -n dev   # yes
k auth can-i create deployments --as jane -n prod   # no

이렇게 인증서로 신원을 만들고(#8), RBAC으로 권한을 붙이는(이번 글) 두 단계가 합쳐져 “특정 사용자에게 특정 네임스페이스 권한 부여"라는 시험 문제가 완성됩니다.

aggregated ClusterRole 한 줄 #

ClusterRole에는 여러 ClusterRole을 라벨로 묶어 자동으로 합성하는 aggregated ClusterRole 기능이 있습니다. aggregationRule에 라벨 셀렉터를 적은 ClusterRole은 그 라벨을 가진 다른 ClusterRole들의 rules를 자동으로 흡수하므로, admin,edit,view 같은 기본 ClusterRole에 새 리소스 권한을 라벨만 붙여 확장할 수 있습니다.

YAML 예제 #

generator로 충분하지만, 구조를 눈으로 확인하고 손볼 수 있어야 합니다. 두 가지 대표 조합을 YAML로 보겠습니다.

Role + RoleBinding (네임스페이스 한정) #

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev
  name: pod-reader
rules:
  - apiGroups: [""]            # core 그룹
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: dev
  name: pod-reader-bind
subjects:
  - kind: User
    name: jane              # 인증서 CN 등 외부 신원
    apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

roleRef는 한 번 만들면 수정할 수 없습니다. 바인딩의 대상 Role을 바꾸려면 RoleBinding을 지우고 다시 만들어야 합니다. subject의 apiGroup은 User/Group일 때 rbac.authorization.k8s.io이고, ServiceAccount일 때는 빈 문자열("")이라는 차이도 시험에서 자주 걸립니다.

ClusterRole을 RoleBinding으로 (재사용 + 범위 한정) #

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole         # 한 번 정의해 여러 ns에서 재사용
metadata:
  name: deployment-reader
rules:
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding         # ClusterRole을 dev ns로만 한정 부여
metadata:
  namespace: dev
  name: deploy-reader-bind
subjects:
  - kind: ServiceAccount
    name: ci-bot
    namespace: dev
roleRef:
  kind: ClusterRole       # roleRef.kind가 ClusterRole
  name: deployment-reader
  apiGroup: rbac.authorization.k8s.io

roleRef.kindClusterRole이지만 RoleBinding으로 묶었기 때문에, ci-bot ServiceAccount는 dev 네임스페이스의 Deployment만 읽을 수 있습니다. 같은 ClusterRole을 prod 네임스페이스의 RoleBinding에서도 가리키면, 그쪽 subject는 prod의 Deployment만 읽습니다. 권한 묶음은 하나, 적용 범위는 네임스페이스별로 분리되는 패턴입니다.

시험 포인트 #

  • 가산 모델. RBAC에는 거부 규칙이 없습니다. 허용이 하나도 없으면 거부이고, 허용 규칙은 쌓입니다.
  • 네 객체의 조합 표를 외운다. 특히 ClusterRole + RoleBinding(재사용 + ns 한정)과 Role + ClusterRoleBinding은 불가능을 구분합니다.
  • 비네임스페이스 리소스(Node, PV, Namespace 등)는 ClusterRole로만 권한을 줄 수 있습니다. Role로 만들면 틀립니다.
  • apiGroups. core 리소스는 "", Deployment는 apps, Job은 batch, Ingress,NetworkPolicy는 networking.k8s.io입니다.
  • generator 손에 익히기. k create role/clusterrole--verb,--resource, k create rolebinding/clusterrolebinding--role/--clusterrole,--user/--group/--serviceaccount.
  • --serviceaccount=ns:name 형식과, impersonation의 --as=system:serviceaccount:ns:sa 형식을 구분합니다.
  • 검증은 auth can-i. --as, --as-group, --list로 작업 직후 정답을 확인합니다.
  • roleRef는 불변. 대상을 바꾸려면 바인딩을 재생성합니다.
  • subject apiGroup. User/Group은 rbac.authorization.k8s.io, ServiceAccount는 "".

정리 #

이번 글에서 잡은 것:

  • RBAC은 인증 다음의 인가. apiserver는 인증 → 인가 → admission 순으로 요청을 검사하며, RBAC이 두 번째 관문을 맡습니다.
  • 네 객체. Role/ClusterRole이 권한 묶음을, RoleBinding/ClusterRoleBinding이 그 묶음을 subject에 연결합니다.
  • rules는 apiGroups/resources/verbs, subjects는 User/Group/ServiceAccount의 세 종류입니다.
  • 조합 규칙. ClusterRole을 RoleBinding으로 묶으면 권한을 재사용하면서 네임스페이스로 한정할 수 있고, 비네임스페이스 리소스는 ClusterRole로만 다룹니다.
  • ServiceAccount로 앱에 최소 권한을 주고, #8의 인증서 사용자에는 RBAC으로 권한을 붙여 작업을 완성합니다.
  • auth can-i --as로 검증하는 습관이 시험에서 점수를 지킵니다.

RBAC의 기본기는 K8s 중급 트랙의 #7 RBAC / NetworkPolicy / ResourceQuota에서 NetworkPolicy,ResourceQuota와 함께 멀티테넌트 관점으로도 정리했으니, 권한,트래픽,자원의 세 정책을 한데 묶어 보고 싶다면 함께 읽어 두면 좋습니다.

다음: Workloads 1 #

#2부터 여기까지 Cluster Architecture도메인을 마무리했습니다. control plane 구조, 설치, HA, 업그레이드, etcd 백업, 인증서, 그리고 이번 RBAC까지 클러스터 자체를 세우고 지키는 일을 다뤘습니다.

#10 Workloads 1부터는 클러스터 위에서 도는 워크로드로 들어갑니다. Deployment의 동작 원리를 ReplicaSet과 함께 깊게 보고, rolling update가 어떻게 진행되는지, 문제가 생겼을 때 어떻게 rollback하는지를 운영자 관점에서 정리하겠습니다.

X