K8s RBAC이란?
Kubernetes RBAC(Role-Based Access Control)은 클러스터 리소스에 대한 접근 권한을 역할 기반으로 제어하는 인가 메커니즘이다. 누가(Subject) 무엇을(Resource) 어떻게(Verb) 할 수 있는지를 선언적으로 정의한다. 멀티 팀 환경에서 보안과 운영 안정성을 확보하려면 RBAC 설계가 핵심이다.
RBAC 4대 리소스
| 리소스 | 범위 | 역할 |
|---|---|---|
| Role | 네임스페이스 | 특정 네임스페이스 내 권한 정의 |
| ClusterRole | 클러스터 전체 | 클러스터 범위 권한 정의 (노드, PV 등 포함) |
| RoleBinding | 네임스페이스 | Role/ClusterRole을 주체에 바인딩 |
| ClusterRoleBinding | 클러스터 전체 | ClusterRole을 클러스터 범위로 바인딩 |
핵심은 Role은 권한을 정의하고, Binding은 권한을 부여한다는 것이다. 이 분리 덕분에 하나의 ClusterRole을 여러 네임스페이스에서 재사용할 수 있다.
Role과 ClusterRole 정의
# 네임스페이스 한정 Role: 앱 팀 개발자용
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-developer
namespace: app-team-a
rules:
# Pod 조회·로그·exec 허용
- apiGroups: [""]
resources: ["pods", "pods/log", "pods/exec"]
verbs: ["get", "list", "watch", "create", "delete"]
# Deployment 관리
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# ConfigMap, Secret 읽기만
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list"]
# Service 관리
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
# 클러스터 범위 ClusterRole: 읽기 전용 모니터링
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-monitor
rules:
- apiGroups: [""]
resources: ["nodes", "namespaces", "pods", "services", "events"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets", "daemonsets"]
verbs: ["get", "list", "watch"]
- apiGroups: ["metrics.k8s.io"]
resources: ["nodes", "pods"]
verbs: ["get", "list"]
RoleBinding과 ClusterRoleBinding
# RoleBinding: 개발자 그룹에 Role 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-developer-binding
namespace: app-team-a
subjects:
# 그룹 바인딩 (OIDC groups 클레임과 매핑)
- kind: Group
name: team-a-developers
apiGroup: rbac.authorization.k8s.io
# 개별 사용자 바인딩
- kind: User
name: alice@company.com
apiGroup: rbac.authorization.k8s.io
# ServiceAccount 바인딩
- kind: ServiceAccount
name: ci-deployer
namespace: ci-cd
roleRef:
kind: Role
name: app-developer
apiGroup: rbac.authorization.k8s.io
---
# ClusterRoleBinding: 모니터링 팀에 클러스터 읽기 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: monitor-team-binding
subjects:
- kind: Group
name: monitoring-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-monitor
apiGroup: rbac.authorization.k8s.io
ClusterRole을 네임스페이스에 바인딩하는 패턴
ClusterRole을 RoleBinding으로 바인딩하면, 클러스터 범위 역할을 특정 네임스페이스에만 적용할 수 있다. 이것이 RBAC의 가장 강력한 패턴이다.
# 공통 ClusterRole 정의 (한 번만)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: namespace-admin
rules:
- apiGroups: ["", "apps", "batch", "networking.k8s.io"]
resources: ["*"]
verbs: ["*"]
---
# Team A 네임스페이스에만 적용
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-a-admin
namespace: team-a
subjects:
- kind: Group
name: team-a-leads
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole # ClusterRole이지만
name: namespace-admin
apiGroup: rbac.authorization.k8s.io
# → team-a 네임스페이스에서만 admin 권한 적용
ServiceAccount RBAC: 워크로드 권한 제어
Pod가 Kubernetes API를 호출하려면 ServiceAccount에 적절한 권한이 필요하다. 최소 권한 원칙에 따라 필요한 리소스와 동작만 허용해야 한다.
# CronJob이 사용할 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: cleanup-job
namespace: maintenance
automountServiceAccountToken: true
---
# 최소 권한 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cleanup-job-role
namespace: maintenance
rules:
# 완료된 Job만 삭제 가능
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["get", "list", "delete"]
# Pod 조회만 (삭제 불가)
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cleanup-job-binding
namespace: maintenance
subjects:
- kind: ServiceAccount
name: cleanup-job
namespace: maintenance
roleRef:
kind: Role
name: cleanup-job-role
apiGroup: rbac.authorization.k8s.io
---
# CronJob에서 ServiceAccount 지정
apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup-completed-jobs
namespace: maintenance
spec:
schedule: "0 2 * * *"
jobTemplate:
spec:
template:
spec:
serviceAccountName: cleanup-job # 여기서 지정
containers:
- name: cleanup
image: bitnami/kubectl:latest
command: ["/bin/sh", "-c"]
args:
- |
kubectl delete jobs --field-selector status.successful=1 -n maintenance
restartPolicy: OnFailure
K8s Job·CronJob 배치 처리에서 다룬 CronJob 패턴에 RBAC을 결합하면 안전한 자동화 파이프라인이 완성된다.
리소스명 제한: resourceNames
resourceNames를 사용하면 특정 이름의 리소스에만 접근을 제한할 수 있다. Secret이나 ConfigMap 중 민감한 항목만 선별적으로 허용할 때 유용하다.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-config-reader
namespace: production
rules:
# 특정 ConfigMap만 읽기 허용
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["app-config", "feature-flags"]
verbs: ["get", "watch"]
# 특정 Secret만 읽기 허용 (DB 크레덴셜 제외)
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["app-tls-cert"]
verbs: ["get"]
Aggregated ClusterRole
레이블 기반으로 여러 ClusterRole을 자동 합성하는 Aggregation은 CRD(Custom Resource Definition) 권한 관리에 특히 유용하다. 새로운 CRD가 추가될 때 기존 역할을 수정하지 않아도 된다.
# 집계 대상 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: platform-admin
aggregationRule:
clusterRoleSelectors:
- matchLabels:
rbac.platform.io/aggregate-to-admin: "true"
rules: [] # 자동 채워짐
---
# CRD별 권한 조각 (설치 시 자동 집계)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cert-manager-admin-fragment
labels:
rbac.platform.io/aggregate-to-admin: "true"
rules:
- apiGroups: ["cert-manager.io"]
resources: ["certificates", "issuers", "clusterissuers"]
verbs: ["*"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gateway-admin-fragment
labels:
rbac.platform.io/aggregate-to-admin: "true"
rules:
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["gateways", "httproutes", "grpcroutes"]
verbs: ["*"]
RBAC 디버깅과 감사
권한 문제 디버깅은 kubectl auth can-i와 kubectl auth whoami로 수행한다.
# 현재 사용자 권한 확인
kubectl auth can-i create deployments -n app-team-a
# yes
kubectl auth can-i delete nodes
# no
# 특정 사용자/SA 시뮬레이션
kubectl auth can-i list secrets -n production
--as=system:serviceaccount:ci-cd:ci-deployer
# no
# 네임스페이스 내 모든 권한 확인
kubectl auth can-i --list -n app-team-a
# 현재 인증 정보
kubectl auth whoami
# ATTRIBUTE VALUE
# Username alice@company.com
# Groups [team-a-developers system:authenticated]
# 누가 어떤 권한을 가지는지 역추적
# (rbac-lookup 플러그인 사용)
kubectl rbac-lookup alice
# SUBJECT SCOPE ROLE
# alice@company.com app-team-a Role/app-developer
# alice@company.com cluster ClusterRole/cluster-monitor
K8s External Secrets 운영 글에서 다룬 시크릿 관리와 RBAC을 결합하면, 누가 어떤 시크릿에 접근할 수 있는지까지 완전한 보안 체계를 구축할 수 있다.
실전 멀티 팀 RBAC 설계
실제 조직에서는 팀별 네임스페이스 격리 + 공통 ClusterRole 재사용 패턴이 가장 많이 쓰인다.
# 역할 계층 설계 예시:
#
# cluster-admin (빌트인)
# └── platform-admin (Aggregated ClusterRole)
# ├── namespace-admin (팀 리드)
# │ └── RoleBinding per namespace
# ├── app-developer (개발자)
# │ └── RoleBinding per namespace
# └── app-viewer (읽기 전용)
# └── RoleBinding per namespace
#
# 원칙:
# 1. cluster-admin은 플랫폼 팀 2~3명만
# 2. 팀 리드에게 자기 네임스페이스 admin
# 3. 개발자는 deploy/pod 관리만
# 4. CI/CD SA는 deploy만 가능, secret 접근 불가
# 5. 모니터링은 클러스터 읽기 전용
마무리
K8s RBAC은 클러스터 보안의 첫 번째 방어선이다. Role/ClusterRole로 권한을 정의하고, Binding으로 주체에 부여하는 단순한 구조지만, Aggregation·resourceNames·네임스페이스 격리를 조합하면 복잡한 조직 구조도 안전하게 모델링할 수 있다. 최소 권한 원칙을 기본으로, kubectl auth can-i로 항상 검증하는 습관이 중요하다.