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/log나pods/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)을 어떻게 짝짓느냐에 따라 권한이 미치는 범위가 달라집니다.
| 권한 묶음 | 바인딩 | 결과 권한 범위 |
|---|---|---|
| Role | RoleBinding | 그 RoleBinding이 있는 한 네임스페이스 안의 리소스 |
| ClusterRole | ClusterRoleBinding | 모든 네임스페이스 + 비네임스페이스 리소스 (클러스터 전체) |
| ClusterRole | RoleBinding | ClusterRole에 정의된 권한을, 그 RoleBinding이 있는 한 네임스페이스로 한정해 부여 |
| Role | ClusterRoleBinding | 불가능. 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--as는 impersonation(가장) 기능입니다. 관리자 권한으로, 마치 그 사용자가 요청한 것처럼 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 monitoringPod의 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.ioroleRef는 한 번 만들면 수정할 수 없습니다. 바인딩의 대상 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.ioroleRef.kind가 ClusterRole이지만 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하는지를 운영자 관점에서 정리하겠습니다.