RBAC — 누가 어떤 리소스에 접근할 수 있는지 제어하는 방법
클러스터에 접근하는 모든 사람이 모든 리소스를 생성/삭제할 수 있다면 어떤 일이 벌어질까요?
Kubernetes 클러스터에 여러 팀이 접근하고, Pod 내부의 애플리케이션이 API Server를 호출하는 환경에서는 "누가 무엇을 할 수 있는지"를 명확하게 제어해야 합니다. RBAC(Role-Based Access Control)은 역할 기반으로 리소스 접근 권한을 세밀하게 관리하는 Kubernetes의 핵심 보안 메커니즘입니다.
RBAC의 구성 요소
RBAC는 네 가지 오브젝트로 구성됩니다.
Role / ClusterRole → "무엇을 할 수 있는가" (권한 정의)
RoleBinding / ClusterRoleBinding → "누가 할 수 있는가" (권한 부여)
| 오브젝트 | 범위 | 설명 |
|---|---|---|
| Role | 네임스페이스 | 특정 네임스페이스의 리소스 권한 |
| ClusterRole | 클러스터 | 클러스터 전체 또는 비네임스페이스 리소스 권한 |
| RoleBinding | 네임스페이스 | Role 또는 ClusterRole을 사용자/SA에 바인딩 |
| ClusterRoleBinding | 클러스터 | ClusterRole을 클러스터 전체에 바인딩 |
Role — 네임스페이스 수준 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: production
name: pod-reader
rules:
- apiGroups: [""] # 코어 API 그룹
resources: ["pods"]
verbs: ["get", "watch", "list"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
verbs (동작)
| verb | 설명 |
|---|---|
get | 단일 리소스 조회 |
list | 리소스 목록 조회 |
watch | 변경 감시 |
create | 생성 |
update | 수정 |
patch | 부분 수정 |
delete | 삭제 |
deletecollection | 여러 리소스 일괄 삭제 |
apiGroups
| apiGroups | 포함 리소스 |
|---|---|
"" (빈 문자열) | Pod, Service, ConfigMap 등 코어 리소스 |
apps | Deployment, StatefulSet, DaemonSet |
batch | Job, CronJob |
networking.k8s.io | Ingress, NetworkPolicy |
rbac.authorization.k8s.io | Role, RoleBinding |
ClusterRole — 클러스터 수준 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: node-viewer
rules:
- apiGroups: [""]
resources: ["nodes"] # 비네임스페이스 리소스
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list"]
ClusterRole은 다음 경우에 사용합니다.
- 노드, PV, 네임스페이스 같은 비네임스페이스 리소스
- 여러 네임스페이스에 동일한 권한을 부여할 때 (RoleBinding과 조합)
RoleBinding / ClusterRoleBinding
# RoleBinding — 특정 네임스페이스에 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: production
subjects:
# 사용자
- kind: User
name: developer-kim
apiGroup: rbac.authorization.k8s.io
# 그룹
- kind: Group
name: dev-team
apiGroup: rbac.authorization.k8s.io
# ServiceAccount
- kind: ServiceAccount
name: app-sa
namespace: production
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
# ClusterRoleBinding — 클러스터 전체에 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-viewer
subjects:
- kind: Group
name: ops-team
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: view # 기본 제공 ClusterRole
apiGroup: rbac.authorization.k8s.io
중요한 조합 패턴
| 조합 | 효과 |
|---|---|
| Role + RoleBinding | 특정 네임스페이스에서만 권한 |
| ClusterRole + ClusterRoleBinding | 클러스터 전체에서 권한 |
| ClusterRole + RoleBinding | 특정 네임스페이스에서만 ClusterRole의 권한 (재사용) |
ServiceAccount
ServiceAccount는 Pod이 API Server에 접근할 때 사용하는 신원입니다.
# ServiceAccount 생성
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: production
---
# Pod에서 ServiceAccount 사용
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
serviceAccountName: app-sa
automountServiceAccountToken: true # 토큰 자동 마운트
containers:
- name: app
image: my-app:1.0
Kubernetes 1.24부터는 default ServiceAccount에 자동으로 토큰이 마운트되지 않으며, 필요한 경우 명시적으로 설정해야 합니다.
실무 권장 사항
# 불필요한 API 접근 차단
apiVersion: v1
kind: ServiceAccount
metadata:
name: no-api-access
automountServiceAccountToken: false # 토큰 마운트 비활성화
API Server에 접근하지 않는 일반 애플리케이션은 automountServiceAccountToken: false로 설정하는 것이 안전합니다.
기본 제공 ClusterRole
Kubernetes는 자주 사용하는 ClusterRole을 기본으로 제공합니다.
| ClusterRole | 권한 |
|---|---|
view | 대부분의 리소스 읽기 (Secret 제외) |
edit | 대부분의 리소스 읽기/쓰기 (Role, Binding 제외) |
admin | 네임스페이스 내 모든 권한 (ResourceQuota, 네임스페이스 자체 제외) |
cluster-admin | 클러스터 전체 모든 권한 |
# 기본 ClusterRole 확인
kubectl get clusterroles | grep -E "^(view|edit|admin|cluster-admin)"
최소 권한 원칙 적용
팀별 네임스페이스 격리
# 개발팀 — 자신의 네임스페이스에서 edit 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dev-team-edit
namespace: team-a
subjects:
- kind: Group
name: team-a-devs
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: edit
apiGroup: rbac.authorization.k8s.io
CI/CD 파이프라인 전용 권한
apiVersion: v1
kind: ServiceAccount
metadata:
name: cicd-sa
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cicd-deployer
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "update", "patch"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list"]
resourceNames: ["app-config", "app-secret"] # 특정 리소스만
resourceNames로 특정 이름의 리소스만 접근하도록 더 세밀하게 제한할 수 있습니다.
권한 확인과 디버깅
# 특정 사용자의 권한 확인
kubectl auth can-i create deployments --as developer-kim -n production
# yes
kubectl auth can-i delete pods --as developer-kim -n production
# no
# ServiceAccount의 권한 확인
kubectl auth can-i list pods --as system:serviceaccount:production:app-sa -n production
# 현재 사용자가 할 수 있는 모든 것 확인
kubectl auth can-i --list -n production
실무에서 주의할 점
- cluster-admin은 최소한으로: 인프라 관리자에게만 부여하세요
- default ServiceAccount 사용 지양: 각 워크로드에 전용 SA를 생성하세요
- Secret 접근 제한:
viewClusterRole은 Secret을 제외하지만, 명시적으로 확인하세요 - 정기 감사: 불필요한 RoleBinding을 정기적으로 정리하세요
정리
RBAC는 Role로 "무엇을 할 수 있는지" 정의하고, RoleBinding으로 "누구에게" 부여하는 구조입니다. ServiceAccount로 Pod의 API 접근 권한을 제어하고, 최소 권한 원칙을 적용하여 필요한 만큼만 권한을 부여하는 것이 보안의 핵심입니다.
댓글 로딩 중...