K8s RBAC이란?
Kubernetes의 RBAC(Role-Based Access Control)은 “누가(Subject) 무엇을(Resource) 어떻게(Verb) 할 수 있는가”를 정의하는 권한 관리 시스템입니다. 클러스터 보안의 핵심이며, kube-apiserver의 --authorization-mode=RBAC 플래그로 활성화됩니다. 대부분의 관리형 K8s(EKS, GKE, AKS)에서 기본 활성화되어 있습니다.
4가지 핵심 리소스
RBAC는 4개의 API 오브젝트로 구성됩니다.
| 리소스 | 스코프 | 역할 |
|---|---|---|
Role |
네임스페이스 | 특정 네임스페이스 내 권한 정의 |
ClusterRole |
클러스터 전체 | 클러스터 범위 권한 정의 |
RoleBinding |
네임스페이스 | Role/ClusterRole을 주체에 바인딩 |
ClusterRoleBinding |
클러스터 전체 | ClusterRole을 클러스터 범위로 바인딩 |
핵심 포인트: ClusterRole을 RoleBinding으로 바인딩하면, 해당 네임스페이스에서만 권한이 적용됩니다. 재사용 가능한 권한 템플릿으로 활용할 수 있습니다.
Role과 ClusterRole 작성
네임스페이스 스코프 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""] # core API group
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
apiGroups: [""]는 core API(v1)를 의미합니다. Deployment는 apiGroups: ["apps"], Ingress는 apiGroups: ["networking.k8s.io"]입니다.
ClusterRole — 클러스터 전체 또는 재사용 템플릿
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: ["", "apps", "batch"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "create", "update", "delete"]
# 노드, PV 등 클러스터 리소스는 제외
---
# 읽기 전용 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-viewer
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: [] # 시크릿은 읽기도 차단
Binding 실전 패턴
패턴 1: 개발팀별 네임스페이스 격리
# backend 팀 → backend 네임스페이스 관리 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: backend-team-admin
namespace: backend
subjects:
- kind: Group
name: backend-developers # OIDC 그룹 또는 인증서 O 필드
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: namespace-admin # ClusterRole을 네임스페이스 범위로 재사용
apiGroup: rbac.authorization.k8s.io
패턴 2: CI/CD ServiceAccount 최소 권한
# CI/CD 파이프라인용 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: ci-deployer
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "update", "patch"] # create/delete 불가
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deployer-binding
namespace: production
subjects:
- kind: ServiceAccount
name: ci-deployer
namespace: production
roleRef:
kind: Role
name: deployer
apiGroup: rbac.authorization.k8s.io
최소 권한 원칙: CI/CD는 Deployment update/patch만 필요합니다. create나 delete는 부여하지 마세요. 실수로 리소스를 삭제하는 사고를 방지합니다.
패턴 3: 특정 리소스 이름 제한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: specific-configmap-editor
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config", "feature-flags"] # 이 2개만 수정 가능
verbs: ["get", "update", "patch"]
resourceNames를 사용하면 특정 이름의 리소스만 접근할 수 있습니다. 단, list와 create verb에는 resourceNames가 적용되지 않으니 주의하세요.
ServiceAccount 토큰과 Pod 권한
Pod 내부의 애플리케이션이 K8s API를 호출할 때 ServiceAccount의 권한을 사용합니다.
# Pod에서 특정 ServiceAccount 사용
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
serviceAccountName: my-app-sa # 기본값: default SA
automountServiceAccountToken: true
containers:
- name: app
image: my-app:latest
---
# my-app이 같은 네임스페이스의 ConfigMap만 읽을 수 있도록
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: configmap-reader
namespace: default
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-configmap
namespace: default
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: default
roleRef:
kind: Role
name: configmap-reader
apiGroup: rbac.authorization.k8s.io
보안 팁: API 접근이 불필요한 Pod는 automountServiceAccountToken: false를 설정하세요. default ServiceAccount의 토큰이 자동 마운트되면 불필요한 공격 표면이 됩니다.
RBAC 디버깅과 감사
kubectl auth can-i — 권한 확인
# 내 권한 확인
kubectl auth can-i create deployments -n production
# yes / no
# 특정 사용자의 권한 확인 (관리자)
kubectl auth can-i get secrets -n production --as=user@example.com
kubectl auth can-i list pods -n backend --as=system:serviceaccount:backend:ci-deployer
# 모든 권한 나열
kubectl auth can-i --list -n production
kubectl auth can-i --list --as=system:serviceaccount:default:my-app-sa
누가 어떤 권한을 갖고 있는지 역추적
# 특정 네임스페이스의 모든 RoleBinding 확인
kubectl get rolebindings -n production -o wide
# ClusterRoleBinding 전체 조회
kubectl get clusterrolebindings -o wide | grep -v system:
# 특정 Role에 바인딩된 주체 확인
kubectl describe rolebinding deployer-binding -n production
위험한 권한 탐지
# 와일드카드(*) 권한을 가진 ClusterRoleBinding 찾기
kubectl get clusterrolebindings -o json |
jq '.items[] | select(.roleRef.name == "cluster-admin") | .subjects'
# escalate, bind verb 확인 — 권한 상승 가능
kubectl get clusterroles -o json |
jq '.items[] | select(.rules[]?.verbs[]? == "escalate" or .rules[]?.verbs[]? == "bind") | .metadata.name'
반드시 확인해야 할 위험 권한:
cluster-admin— 모든 리소스에 모든 작업 가능secrets에 대한get/list— 인증 정보 탈취 가능pods/exec— 컨테이너 내부 접근 가능escalate,bindverb — RBAC 자체를 수정해 권한 상승
Aggregated ClusterRole
여러 ClusterRole을 하나로 합치는 패턴입니다. aggregationRule의 라벨 셀렉터로 자동 결합됩니다.
# 기본 뷰어 역할
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: monitoring-viewer
labels:
rbac.theokei.com/aggregate-to-viewer: "true"
rules:
- apiGroups: ["monitoring.coreos.com"]
resources: ["prometheusrules", "servicemonitors"]
verbs: ["get", "list", "watch"]
---
# 커스텀 리소스 뷰어
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: custom-resource-viewer
labels:
rbac.theokei.com/aggregate-to-viewer: "true"
rules:
- apiGroups: ["myapp.theokei.com"]
resources: ["widgets"]
verbs: ["get", "list", "watch"]
---
# 자동 집계 — 위 2개의 rules가 합쳐짐
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: aggregate-viewer
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.theokei.com/aggregate-to-viewer: "true"
rules: [] # 자동 채워짐
CRD를 추가할 때마다 기존 ClusterRole을 수정하지 않고, 라벨만 붙인 새 ClusterRole을 만들면 자동으로 포함됩니다. K8s 시크릿 관리와 함께 사용하면 보안 체계가 더욱 단단해집니다.
실전 RBAC 설계 원칙
| 원칙 | 실천 방법 |
|---|---|
| 최소 권한 | 필요한 verb만, 필요한 리소스만, 필요한 네임스페이스에만 |
| 그룹 바인딩 | 개인이 아닌 팀/그룹 단위로 바인딩 |
| SA 토큰 최소화 | 불필요한 Pod는 automountServiceAccountToken: false |
| 와일드카드 금지 | resources: [“*”], verbs: [“*”] 사용 자제 |
| 정기 감사 | kubectl auth can-i –list로 주기적 점검 |
RBAC는 NetworkPolicy와 함께 K8s 보안의 양대 축입니다. NetworkPolicy가 네트워크 레벨 격리라면, RBAC는 API 레벨 격리입니다. 둘 다 적용해야 진정한 멀티테넌트 환경을 구축할 수 있습니다.
정리
K8s RBAC의 핵심은 “기본 거부, 명시 허용”입니다. Role/ClusterRole로 권한을 정의하고, Binding으로 주체에 연결하는 단순한 모델이지만, 최소 권한 원칙을 지키려면 세밀한 설계가 필요합니다. kubectl auth can-i로 정기적으로 감사하고, CI/CD ServiceAccount는 필요한 verb만 부여하며, 위험 권한(cluster-admin, secrets, pods/exec)은 반드시 추적하세요.