K8s RBAC 권한 관리 심화

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-ikubectl 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로 항상 검증하는 습관이 중요하다.

위로 스크롤
WordPress Appliance - Powered by TurnKey Linux