Kubernetes 실전 가이드

Kubernetes의 핵심 개념과 실무 활용

TypeScript중급
10시간
7개 항목
학습 진행률0 / 7 (0%)

학습 항목

1. Kubernetes
Kubernetes|RBAC|권한|관리|완벽|가이드
퀴즈튜토리얼
2. Python
Kubernetes|Pod|관리|완벽|가이드
퀴즈튜토리얼
3. TypeScript
Kubernetes|Prometheus|모니터링|완벽|가이드
퀴즈튜토리얼
4. TypeScript
Kubernetes|기본|개념|완벽|가이드
퀴즈튜토리얼
5. TypeScript
초급
Kubernetes|실무|활용|팁
퀴즈튜토리얼
6. TypeScript
Kubernetes|오토스케일링|완벽|가이드
퀴즈튜토리얼
7. TypeScript
중급
Kubernetes|트러블슈팅|완벽|가이드
퀴즈튜토리얼
1 / 7

이미지 로딩 중...

Kubernetes RBAC 권한 관리 완벽 가이드 - 슬라이드 1/13

Kubernetes RBAC 권한 관리 완벽 가이드

Kubernetes 클러스터에서 사용자와 서비스의 권한을 체계적으로 관리하는 RBAC(Role-Based Access Control)의 핵심 개념부터 실전 활용까지 완벽하게 마스터해보세요. 초급 개발자도 쉽게 이해할 수 있도록 친절하게 설명합니다.


목차

  1. RBAC이란 무엇인가 - 쿠버네티스 권한 관리의 기초
  2. Role과 ClusterRole - 권한 범위의 이해
  3. RoleBinding과 ClusterRoleBinding - 권한 부여하기
  4. ServiceAccount와 RBAC - 애플리케이션 권한 관리
  5. API Groups와 Resources - 세밀한 권한 제어
  6. 실전 예제 - 다중 팀 환경 권한 설계
  7. 문제 해결과 디버깅 - RBAC 오류 해결하기
  8. 보안 모범 사례 - 안전한 RBAC 운영

1. RBAC이란 무엇인가 - 쿠버네티스 권한 관리의 기초

시작하며

여러분이 쿠버네티스 클러스터를 운영하면서 "이 개발자에게는 특정 네임스페이스의 Pod만 조회할 수 있는 권한을 주고 싶은데..."라고 고민해본 적 있나요? 또는 "CI/CD 파이프라인이 배포를 위해 필요한 최소한의 권한만 가지도록 하려면 어떻게 해야 하지?"라는 질문을 스스로에게 던져본 적이 있을 겁니다.

이런 문제는 실제 개발 현장에서 매우 자주 발생합니다. 쿠버네티스 클러스터에 여러 팀이 접근하게 되면, 누구에게 어떤 권한을 줄 것인지가 중요한 보안 이슈가 됩니다.

모든 사람에게 관리자 권한을 주면 편하지만, 실수로 중요한 리소스를 삭제하거나 보안 문제가 발생할 수 있습니다. 바로 이럴 때 필요한 것이 RBAC(Role-Based Access Control)입니다.

RBAC은 역할 기반으로 권한을 관리하여, 각 사용자나 서비스 계정이 꼭 필요한 작업만 수행할 수 있도록 제한합니다. 이를 통해 보안을 강화하고 실수를 방지할 수 있습니다.

개요

간단히 말해서, RBAC은 쿠버네티스에서 "누가 무엇을 할 수 있는지"를 정의하는 권한 관리 시스템입니다. 쿠버네티스는 기본적으로 모든 API 요청에 대해 인증(Authentication)과 인가(Authorization)를 수행합니다.

RBAC은 이 중 인가 단계에서 작동하며, 사용자나 서비스 계정이 특정 리소스에 대해 특정 작업을 수행할 권한이 있는지를 판단합니다. 예를 들어, 개발자 A는 개발 네임스페이스의 Pod를 조회하고 로그를 볼 수 있지만, 운영 네임스페이스에는 접근할 수 없도록 설정할 수 있습니다.

전통적인 방법에서는 모든 사용자에게 동일한 권한을 주거나, 관리자 권한을 남용하는 경우가 많았습니다. 하지만 RBAC을 사용하면 최소 권한 원칙(Principle of Least Privilege)을 쉽게 구현할 수 있습니다.

RBAC의 핵심 특징은 세 가지입니다. 첫째, 역할(Role)을 정의하여 권한을 그룹화할 수 있습니다.

둘째, 역할 바인딩(RoleBinding)을 통해 사용자나 그룹에 역할을 부여할 수 있습니다. 셋째, 네임스페이스 수준과 클러스터 수준의 권한을 분리하여 관리할 수 있습니다.

이러한 특징들이 복잡한 권한 관리를 체계적이고 안전하게 만들어줍니다.

코드 예제

# RBAC을 사용한 기본 권한 설정 예제
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: pod-reader
rules:
- apiGroups: [""]  # 코어 API 그룹
  resources: ["pods"]  # Pod 리소스에 대한 권한
  verbs: ["get", "list", "watch"]  # 조회, 목록, 감시 작업만 허용
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: development
subjects:
- kind: User  # 사용자에게 권한 부여
  name: jane
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader  # 위에서 정의한 Role을 연결
  apiGroup: rbac.authorization.k8s.io

설명

이것이 하는 일: 위 예제는 development 네임스페이스에서 Pod를 읽을 수 있는 역할을 정의하고, jane이라는 사용자에게 그 역할을 부여합니다. 첫 번째 단계로, Role 리소스를 정의합니다.

여기서 namespace: development는 이 역할이 development 네임스페이스 내에서만 유효함을 의미합니다. rules 섹션에서는 어떤 리소스에 대해 어떤 작업을 허용할지 정의합니다.

apiGroups가 빈 문자열인 것은 코어 API 그룹을 의미하며, resources: ["pods"]는 Pod 리소스를 대상으로 하고, verbs는 허용할 작업들(get, list, watch)을 나열합니다. 이렇게 하면 Pod를 조회하고 목록을 보고 변경사항을 감시할 수는 있지만, 생성하거나 삭제할 수는 없습니다.

그 다음으로, RoleBinding 리소스가 실행되면서 실제로 사용자에게 권한을 부여합니다. subjects 섹션에서 jane이라는 사용자를 지정하고, roleRef에서 앞서 정의한 pod-reader 역할을 참조합니다.

내부적으로 쿠버네티스 API 서버는 jane이 Pod에 대한 작업을 요청할 때마다 이 RoleBinding을 확인하여 권한이 있는지 검증합니다. 마지막으로, 이 설정이 적용되면 jane은 development 네임스페이스의 Pod만 조회할 수 있게 됩니다.

다른 네임스페이스의 Pod나, development 네임스페이스의 다른 리소스(Service, ConfigMap 등)에는 접근할 수 없습니다. 또한 Pod를 생성, 수정, 삭제하는 것도 불가능합니다.

여러분이 이 코드를 사용하면 팀원들에게 필요한 최소한의 권한만 부여할 수 있어 보안이 강화되고, 실수로 인한 장애를 예방할 수 있습니다. 또한 권한을 역할 단위로 관리하므로, 같은 역할이 필요한 여러 사용자에게 동일한 권한을 쉽게 부여할 수 있어 관리가 편리합니다.

감사(Audit) 로그를 통해 누가 언제 무엇을 했는지 추적하기도 쉬워집니다.

실전 팁

💡 항상 최소 권한 원칙을 따르세요. 처음에는 필요한 최소한의 권한만 부여하고, 필요할 때 점진적으로 추가하는 것이 안전합니다. "일단 모든 권한을 주고 나중에 제한하자"는 접근은 보안 사고의 지름길입니다.

💡 verbs를 정의할 때 와일드카드(*)는 가급적 피하세요. verbs: ["*"]는 모든 작업을 허용하므로, 구체적으로 get, list, create, update, delete 등 필요한 작업만 명시하는 것이 좋습니다.

💡 개발 환경과 운영 환경의 권한을 명확히 분리하세요. 개발자는 개발 네임스페이스에서는 자유롭게 작업하되, 운영 네임스페이스에는 읽기 전용 권한만 가지도록 설정하는 것이 일반적입니다.

💡 kubectl auth can-i 명령어로 권한을 테스트하세요. 예: kubectl auth can-i create pods --namespace=development --as=jane으로 jane이 development 네임스페이스에서 Pod를 생성할 수 있는지 확인할 수 있습니다.

💡 서비스 계정(ServiceAccount)에도 RBAC을 적용하세요. 애플리케이션 Pod가 쿠버네티스 API를 호출할 때는 서비스 계정을 사용하므로, 이들에게도 적절한 권한만 부여해야 합니다.


2. Role과 ClusterRole - 권한 범위의 이해

시작하며

여러분이 쿠버네티스 클러스터를 관리하면서 "특정 네임스페이스에서만 유효한 권한과 클러스터 전체에서 유효한 권한을 어떻게 구분하지?"라고 고민한 적 있나요? 또는 "노드나 PersistentVolume처럼 네임스페이스에 속하지 않는 리소스는 어떻게 권한을 관리해야 하지?"라는 의문이 들었을 겁니다.

이런 문제는 쿠버네티스의 리소스가 두 가지 유형으로 나뉘기 때문에 발생합니다. Pod, Service, ConfigMap처럼 특정 네임스페이스에 속하는 리소스가 있고, Node, PersistentVolume, Namespace처럼 클러스터 전체에 속하는 리소스가 있습니다.

권한 관리도 이 구조를 반영해야 합니다. 바로 이럴 때 필요한 것이 Role과 ClusterRole의 구분입니다.

Role은 특정 네임스페이스 내의 리소스에 대한 권한을 정의하고, ClusterRole은 클러스터 전체 리소스나 모든 네임스페이스에 걸친 권한을 정의합니다. 적절히 사용하면 권한을 정확하게 제어할 수 있습니다.

개요

간단히 말해서, Role은 네임스페이스 범위의 권한을, ClusterRole은 클러스터 범위의 권한을 정의하는 객체입니다. Role은 특정 네임스페이스 안에서만 유효합니다.

development 네임스페이스에 Role을 만들면, 그 권한은 development 네임스페이스의 리소스에만 적용됩니다. 반면 ClusterRole은 네임스페이스 경계를 넘어서 작동합니다.

예를 들어, 모든 네임스페이스의 Pod를 조회하거나, Node 같은 클러스터 수준 리소스에 접근하거나, 여러 네임스페이스에 걸쳐 동일한 권한을 재사용할 때 ClusterRole을 사용합니다. 기존에는 각 네임스페이스마다 동일한 Role을 중복해서 만들어야 했다면, 이제는 ClusterRole을 한 번 정의하고 여러 네임스페이스에서 RoleBinding을 통해 재사용할 수 있습니다.

이것이 ClusterRole의 강력한 장점 중 하나입니다. Role과 ClusterRole의 핵심 차이는 범위(scope)입니다.

Role은 metadata에 namespace를 반드시 명시해야 하고, ClusterRole은 namespace가 없습니다. 또한 ClusterRole은 Node, PersistentVolume, Namespace 같은 클러스터 수준 리소스에 대한 권한을 정의할 수 있지만, Role은 할 수 없습니다.

이러한 차이를 이해하면 권한 설계가 훨씬 명확해집니다.

코드 예제

# 네임스페이스 범위의 Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production  # 특정 네임스페이스에만 적용
  name: service-manager
rules:
- apiGroups: [""]
  resources: ["services"]  # Service 리소스 관리
  verbs: ["get", "list", "create", "update", "delete"]
---
# 클러스터 범위의 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: node-reader  # namespace가 없음
rules:
- apiGroups: [""]
  resources: ["nodes"]  # 클러스터 수준 리소스
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["pods"]  # 모든 네임스페이스의 Pod 조회
  verbs: ["get", "list"]

설명

이것이 하는 일: 위 예제는 네임스페이스 범위의 Role과 클러스터 범위의 ClusterRole을 각각 정의하여, 권한의 범위 차이를 보여줍니다. 첫 번째 단계로, Role인 service-manager를 살펴봅시다.

namespace: production이 명시되어 있어, 이 역할은 오직 production 네임스페이스 내의 Service 리소스에만 적용됩니다. verbs에 create, update, delete가 포함되어 있어 Service를 생성, 수정, 삭제할 수 있는 강력한 권한입니다.

만약 이 Role을 jane에게 RoleBinding으로 연결하면, jane은 production 네임스페이스의 Service는 자유롭게 관리할 수 있지만, development 네임스페이스나 다른 네임스페이스의 Service는 전혀 건드릴 수 없습니다. 그 다음으로, ClusterRole인 node-reader를 보면 metadata에 namespace가 없습니다.

이것이 Cl러스터 범위 리소스라는 신호입니다. 첫 번째 rule은 Node 리소스에 대한 읽기 권한입니다.

Node는 네임스페이스에 속하지 않는 클러스터 수준 리소스이므로 Role로는 정의할 수 없고 반드시 ClusterRole을 사용해야 합니다. 두 번째 rule은 Pod에 대한 권한인데, 여기서 중요한 점은 특정 네임스페이스를 지정하지 않았다는 것입니다.

ClusterRole에서 네임스페이스 범위 리소스를 정의하면, 이것을 ClusterRoleBinding으로 바인딩할 경우 모든 네임스페이스의 Pod를 조회할 수 있게 됩니다. 마지막으로, 이 두 가지를 언제 사용할지 구분하는 것이 중요합니다.

특정 팀이 자신의 네임스페이스만 관리하면 되는 경우 Role을 사용하고, 플랫폼 관리자처럼 여러 네임스페이스를 관리하거나 클러스터 수준 리소스를 다뤄야 하는 경우 ClusterRole을 사용합니다. 여러분이 이 개념을 사용하면 권한을 명확하게 분리할 수 있습니다.

개발 팀은 자신의 네임스페이스 내에서만 작업하도록 Role로 제한하고, SRE 팀은 ClusterRole로 클러스터 전체를 모니터링할 수 있도록 설정하는 식입니다. 또한 ClusterRole을 정의해두면 여러 네임스페이스에서 RoleBinding을 통해 재사용할 수 있어 중복 코드를 줄이고 일관성을 유지할 수 있습니다.

권한 변경이 필요할 때도 ClusterRole 하나만 수정하면 모든 곳에 반영됩니다.

실전 팁

💡 재사용 가능한 권한은 ClusterRole로 만드세요. 예를 들어 "Pod 읽기" 같은 공통 권한은 ClusterRole로 정의하고, 각 네임스페이스에서 RoleBinding으로 연결하면 관리가 쉽습니다.

💡 클러스터 수준 리소스(Node, PersistentVolume, StorageClass 등)에 접근해야 한다면 반드시 ClusterRole을 사용해야 합니다. Role로는 이런 리소스에 권한을 부여할 수 없습니다.

💡 네임스페이스별로 권한을 격리하고 싶다면 Role을 사용하세요. 예를 들어 team-a는 namespace-a에서만, team-b는 namespace-b에서만 작업하도록 각각 Role을 만들면 완전히 분리됩니다.

💡 기본 제공 ClusterRole을 활용하세요. 쿠버네티스는 view, edit, admin 같은 기본 ClusterRole을 제공하므로, 처음부터 만들지 말고 이것들을 먼저 확인해보세요. kubectl get clusterroles 명령어로 확인할 수 있습니다.

💡 ClusterRole을 RoleBinding과 연결하면 특정 네임스페이스로 범위를 제한할 수 있습니다. ClusterRole이라고 해서 항상 클러스터 전체 권한을 주는 것은 아닙니다. RoleBinding을 사용하면 해당 네임스페이스로만 권한이 적용됩니다.


3. RoleBinding과 ClusterRoleBinding - 권한 부여하기

시작하며

여러분이 Role이나 ClusterRole을 열심히 정의했는데, "이제 이걸 실제로 사용자나 서비스 계정에 어떻게 연결하지?"라고 막막해한 적 있나요? 또는 "왜 Role을 만들었는데도 사용자가 여전히 권한이 없다고 나오지?"라는 문제를 겪어본 적이 있을 겁니다.

이런 문제는 권한을 정의하는 것과 부여하는 것이 별개의 단계이기 때문에 발생합니다. Role이나 ClusterRole은 단지 "이런 권한이 존재한다"고 선언하는 것일 뿐, 실제로 누군가에게 그 권한을 주는 것은 Binding을 통해 이루어집니다.

마치 회사에서 직책을 정의하는 것과 누군가를 그 직책에 임명하는 것이 다른 것과 같습니다. 바로 이럴 때 필요한 것이 RoleBinding과 ClusterRoleBinding입니다.

이들은 Role이나 ClusterRole을 실제 사용자, 그룹, 또는 서비스 계정에 연결하여 권한을 부여합니다. 올바른 Binding 없이는 아무리 좋은 Role을 만들어도 소용이 없습니다.

개요

간단히 말해서, RoleBinding은 특정 네임스페이스에서 Role이나 ClusterRole을 주체(사용자, 그룹, 서비스 계정)에게 부여하고, ClusterRoleBinding은 클러스터 전체에서 ClusterRole을 부여합니다. RoleBinding은 항상 특정 네임스페이스 내에서 작동합니다.

development 네임스페이스에 RoleBinding을 만들면, 그것이 참조하는 Role이든 ClusterRole이든 권한은 development 네임스페이스로 제한됩니다. 이것이 중요한 이유는, ClusterRole을 만들어두고 여러 네임스페이스에서 RoleBinding으로 연결하면 각 네임스페이스별로 권한을 부여할 수 있기 때문입니다.

예를 들어, pod-reader라는 ClusterRole을 만들어두고, team-a 네임스페이스에서는 alice에게, team-b 네임스페이스에서는 bob에게 각각 RoleBinding으로 연결하는 식입니다. 기존에는 각 사용자에게 개별적으로 권한을 관리해야 했다면, 이제는 그룹을 활용하여 한 번에 여러 사용자에게 권한을 부여할 수 있습니다.

RoleBinding의 subjects에 그룹을 지정하면, 그 그룹에 속한 모든 사용자가 자동으로 권한을 받습니다. RoleBinding과 ClusterRoleBinding의 핵심 차이는 범위입니다.

RoleBinding은 네임스페이스 범위이고, ClusterRoleBinding은 클러스터 범위입니다. RoleBinding은 Role과 ClusterRole 둘 다 참조할 수 있지만, ClusterRoleBinding은 오직 ClusterRole만 참조할 수 있습니다.

또한 ClusterRoleBinding으로 권한을 부여하면 모든 네임스페이스와 클러스터 수준 리소스에 접근할 수 있어 매우 강력하므로 신중하게 사용해야 합니다.

코드 예제

# ClusterRole을 특정 네임스페이스에서 RoleBinding으로 연결
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods-binding
  namespace: development  # 이 네임스페이스로 권한 제한
subjects:
- kind: User
  name: alice
  apiGroup: rbac.authorization.k8s.io
- kind: ServiceAccount  # 서비스 계정에도 권한 부여 가능
  name: my-app
  namespace: development
- kind: Group  # 그룹 단위 권한 부여
  name: dev-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole  # ClusterRole을 참조하지만 범위는 이 네임스페이스
  name: view  # 쿠버네티스 기본 제공 ClusterRole
  apiGroup: rbac.authorization.k8s.io
---
# ClusterRoleBinding으로 클러스터 전체 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-binding
subjects:
- kind: User
  name: admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin  # 모든 권한을 가진 강력한 역할
  apiGroup: rbac.authorization.k8s.io

설명

이것이 하는 일: 위 예제는 RoleBinding과 ClusterRoleBinding을 사용하여 실제로 권한을 부여하는 방법을 보여줍니다. 첫 번째 단계로, RoleBinding인 read-pods-binding을 살펴봅시다.

namespace: development가 있어 이 바인딩은 development 네임스페이스에만 적용됩니다. subjects 섹션이 매우 중요한데, 여기에 세 가지 유형의 주체가 나열되어 있습니다.

첫째는 alice라는 사용자, 둘째는 my-app이라는 서비스 계정, 셋째는 dev-team이라는 그룹입니다. 이 세 주체 모두 동일한 권한을 받게 됩니다.

roleRef에서는 view라는 ClusterRole을 참조하고 있는데, 이것이 흥미로운 점입니다. ClusterRole을 참조하지만 RoleBinding을 통해 연결했으므로, 권한은 development 네임스페이스로만 제한됩니다.

그 다음으로, ClusterRoleBinding인 cluster-admin-binding을 보면, metadata에 namespace가 없습니다. 이것은 클러스터 전체에 적용된다는 의미입니다.

admin이라는 사용자에게 cluster-admin이라는 ClusterRole을 부여하고 있는데, cluster-admin은 쿠버네티스에서 기본 제공하는 가장 강력한 역할로 모든 리소스에 대한 모든 작업을 수행할 수 있습니다. 이 바인딩이 적용되면 admin 사용자는 모든 네임스페이스의 모든 리소스를 완전히 제어할 수 있게 됩니다.

마지막으로, subjects에 여러 주체를 나열할 수 있다는 점이 실무에서 매우 유용합니다. 예를 들어 개발 팀 전체에게 동일한 권한을 주려면 각 개발자를 일일이 나열하는 대신, dev-team 그룹 하나만 추가하면 됩니다.

그룹 멤버십은 외부 인증 시스템(OIDC, LDAP 등)에서 관리되므로, 쿠버네티스 설정을 변경하지 않고도 권한을 동적으로 관리할 수 있습니다. 여러분이 이 방법을 사용하면 권한 관리가 훨씬 유연해집니다.

한 명의 사용자가 여러 개의 RoleBinding을 통해 여러 네임스페이스에서 다른 권한을 가질 수 있습니다. 또한 ClusterRole을 재사용하여 일관된 권한 정책을 여러 네임스페이스에 적용할 수 있어 관리 부담이 줄어듭니다.

그룹 기반 권한 부여를 활용하면 조직의 변화에 빠르게 대응할 수 있고, 서비스 계정에 권한을 부여하여 애플리케이션이 안전하게 쿠버네티스 API를 호출할 수 있습니다.

실전 팁

💡 가능하면 그룹을 사용하세요. 개별 사용자를 일일이 나열하는 것보다 그룹으로 관리하면 인사 변동이나 팀 재편성 시 쿠버네티스 설정을 변경하지 않아도 됩니다.

💡 쿠버네티스 기본 제공 ClusterRole(view, edit, admin)을 활용하세요. 대부분의 경우 이것들로 충분하며, 처음부터 새로 만들 필요가 없습니다. kubectl describe clusterrole view로 어떤 권한이 포함되어 있는지 확인할 수 있습니다.

💡 ClusterRoleBinding은 매우 신중하게 사용하세요. 클러스터 전체 권한을 부여하므로, 정말 필요한 경우(클러스터 관리자, 모니터링 시스템 등)에만 사용하고, 대부분의 경우 RoleBinding으로 범위를 제한하는 것이 안전합니다.

💡 서비스 계정에는 항상 네임스페이스를 명시하세요. subjects에서 ServiceAccount를 지정할 때 namespace를 빠뜨리면 바인딩이 작동하지 않을 수 있습니다. User나 Group과 달리 ServiceAccount는 네임스페이스에 속하기 때문입니다.

💡 권한이 제대로 작동하는지 테스트하려면 kubectl auth can-i --as=alice create pods --namespace=development 같은 명령어를 사용하세요. 실제로 리소스를 만들어보기 전에 권한을 검증할 수 있습니다.


4. ServiceAccount와 RBAC - 애플리케이션 권한 관리

시작하며

여러분이 쿠버네티스에서 애플리케이션을 배포했는데, "이 Pod가 다른 Pod의 목록을 조회하려고 하니 권한 오류가 발생하네?"라는 상황을 겪어본 적 있나요? 또는 "CI/CD 파이프라인이 배포를 위해 쿠버네티스 API를 호출해야 하는데, 어떤 자격증명을 사용해야 하지?"라고 고민한 적이 있을 겁니다.

이런 문제는 사람이 아닌 애플리케이션이나 자동화 시스템이 쿠버네티스 API에 접근할 때 발생합니다. 사용자 계정은 사람을 위한 것이고, 쿠버네티스는 내부적으로 외부 인증 시스템(OIDC, LDAP)에 의존하지만, Pod나 자동화 스크립트는 다른 방식이 필요합니다.

바로 이럴 때 필요한 것이 ServiceAccount입니다. ServiceAccount는 애플리케이션이 쿠버네티스 API와 안전하게 통신할 수 있도록 만들어진 특별한 계정이며, RBAC과 결합하여 각 애플리케이션에 필요한 최소한의 권한만 부여할 수 있습니다.

이를 통해 애플리케이션 보안을 크게 향상시킬 수 있습니다.

개요

간단히 말해서, ServiceAccount는 Pod나 다른 쿠버네티스 컴포넌트가 API 서버와 통신할 때 사용하는 신원(Identity)입니다. 모든 네임스페이스에는 default라는 ServiceAccount가 자동으로 생성되며, 명시적으로 지정하지 않으면 모든 Pod는 이 default ServiceAccount를 사용합니다.

그러나 default는 기본적으로 거의 권한이 없어, 실제로 API를 호출해야 하는 애플리케이션은 별도의 ServiceAccount를 만들고 적절한 권한을 부여해야 합니다. 예를 들어, 모니터링 애플리케이션이 모든 Pod의 상태를 조회해야 한다면, 전용 ServiceAccount를 만들고 Pod 읽기 권한을 가진 Role을 RoleBinding으로 연결하는 식입니다.

기존에는 애플리케이션에 과도한 권한을 주거나, 모든 Pod가 동일한 권한을 가지는 경우가 많았습니다. 하지만 ServiceAccount와 RBAC을 결합하면 각 애플리케이션의 실제 요구사항에 맞춰 정확한 권한만 부여할 수 있습니다.

ServiceAccount의 핵심 특징은 자동화와 격리입니다. 첫째, ServiceAccount를 Pod에 연결하면 쿠버네티스가 자동으로 인증 토큰을 Pod 내부에 마운트합니다.

둘째, 각 애플리케이션에 전용 ServiceAccount를 만들어 권한을 격리할 수 있습니다. 셋째, ServiceAccount는 네임스페이스에 속하므로 네임스페이스별로 독립적으로 관리됩니다.

이러한 특징들이 멀티 테넌시 환경에서 안전한 애플리케이션 배포를 가능하게 합니다.

코드 예제

# ServiceAccount 생성
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-reader-sa
  namespace: production
---
# ServiceAccount에 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: pod-reader-role
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log"]  # Pod와 로그 조회
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-reader-binding
  namespace: production
subjects:
- kind: ServiceAccount  # ServiceAccount를 주체로 지정
  name: pod-reader-sa
  namespace: production
roleRef:
  kind: Role
  name: pod-reader-role
  apiGroup: rbac.authorization.k8s.io
---
# Pod에서 ServiceAccount 사용
apiVersion: v1
kind: Pod
metadata:
  name: monitoring-app
  namespace: production
spec:
  serviceAccountName: pod-reader-sa  # 생성한 ServiceAccount 지정
  containers:
  - name: app
    image: monitoring-app:1.0
    # 이 컨테이너는 자동으로 /var/run/secrets/kubernetes.io/serviceaccount/token에
    # ServiceAccount 토큰을 가지게 되어 API 호출 가능

설명

이것이 하는 일: 위 예제는 ServiceAccount를 생성하고, 권한을 부여하고, Pod에서 사용하는 전체 과정을 보여줍니다. 첫 번째 단계로, pod-reader-sa라는 ServiceAccount를 production 네임스페이스에 생성합니다.

ServiceAccount 자체는 매우 간단한 객체로, 단지 신원을 나타낼 뿐 권한은 포함하지 않습니다. 쿠버네티스는 이 ServiceAccount에 대한 인증 토큰을 자동으로 생성하고 Secret에 저장합니다.

그 다음으로, pod-reader-role이라는 Role을 만들어 Pod와 Pod 로그를 조회할 수 있는 권한을 정의합니다. resources: ["pods", "pods/log"]에서 pods/log는 서브리소스를 의미하며, 이를 추가해야 kubectl logs 같은 명령어를 사용할 수 있습니다.

그리고 RoleBinding으로 이 Role을 pod-reader-sa ServiceAccount에 연결합니다. 여기서 중요한 점은 subjects의 kind가 ServiceAccount이고, namespace를 명시해야 한다는 것입니다.

마지막으로, monitoring-app Pod를 배포할 때 serviceAccountName: pod-reader-sa를 지정합니다. 이렇게 하면 쿠버네티스가 자동으로 다음 작업을 수행합니다: (1) ServiceAccount의 토큰을 Secret에서 가져와 (2) Pod 내부의 /var/run/secrets/kubernetes.io/serviceaccount/token 경로에 마운트합니다.

(3) 또한 CA 인증서와 네임스페이스 정보도 함께 마운트됩니다. Pod 내부의 애플리케이션은 이 토큰을 사용하여 쿠버네티스 API 서버에 인증하고, RoleBinding으로 부여된 권한 범위 내에서 API를 호출할 수 있습니다.

여러분이 이 패턴을 사용하면 애플리케이션 보안이 크게 향상됩니다. 각 애플리케이션은 자신에게 필요한 권한만 가지므로, 만약 하나의 Pod가 공격당해도 피해 범위가 제한됩니다.

또한 default ServiceAccount를 사용하지 않으므로, 의도하지 않게 권한이 부여되는 것을 방지할 수 있습니다. CI/CD 파이프라인, 모니터링 시스템, 컨트롤러 같은 자동화 도구도 각각 전용 ServiceAccount를 가지고 명확하게 권한을 관리할 수 있어 감사와 추적이 쉬워집니다.

실전 팁

💡 각 애플리케이션에 전용 ServiceAccount를 만드세요. default ServiceAccount를 공유하는 대신, 애플리케이션마다 별도의 ServiceAccount를 만들어 권한을 정확하게 제어하세요.

💡 automountServiceAccountToken: false 옵션을 활용하세요. API를 호출하지 않는 Pod라면 ServiceAccount 토큰을 마운트할 필요가 없으므로, 이 옵션을 Pod spec에 추가하여 공격 표면을 줄일 수 있습니다.

💡 ServiceAccount 토큰이 컨테이너 내부 어디에 있는지 알아두세요. /var/run/secrets/kubernetes.io/serviceaccount/ 디렉토리에 token, ca.crt, namespace 파일이 있으며, 대부분의 쿠버네티스 클라이언트 라이브러리는 자동으로 이 경로를 읽습니다.

💡 외부에서 실행되는 도구(kubectl, CI/CD 도구)도 ServiceAccount를 사용할 수 있습니다. ServiceAccount의 토큰을 추출하여 kubeconfig 파일에 설정하면, 클러스터 외부에서도 해당 권한으로 API를 호출할 수 있습니다.

💡 Kubernetes 1.24 이상에서는 TokenRequest API를 사용하여 시간 제한이 있는 토큰이 자동으로 발급됩니다. 이전 버전의 영구 토큰보다 훨씬 안전하므로, 가능하면 최신 버전을 사용하세요.


5. API Groups와 Resources - 세밀한 권한 제어

시작하며

여러분이 RBAC 정책을 작성하다가 "apiGroups에 빈 문자열을 넣어야 할 때와 apps를 넣어야 할 때가 언제지?"라고 혼란스러웠던 적 있나요? 또는 "Deployment에 대한 권한을 주려고 하는데 자꾸 오류가 나는데, resources에 뭘 써야 하지?"라는 문제를 겪어본 적이 있을 겁니다.

이런 문제는 쿠버네티스의 리소스가 여러 API 그룹으로 나뉘어 있고, RBAC에서는 이를 정확하게 지정해야 하기 때문에 발생합니다. 쿠버네티스 API는 수백 개의 리소스를 체계적으로 관리하기 위해 그룹으로 분류하며, 권한도 이 구조를 따라야 합니다.

바로 이럴 때 필요한 것이 API Groups와 Resources에 대한 정확한 이해입니다. 어떤 리소스가 어떤 API 그룹에 속하는지 알면, RBAC 규칙을 정확하게 작성할 수 있고, 필요한 권한만 선택적으로 부여할 수 있습니다.

이를 통해 세밀한 권한 제어가 가능해집니다.

개요

간단히 말해서, API Groups는 쿠버네티스 리소스를 논리적으로 분류한 것이고, Resources는 실제 객체 타입(Pod, Service, Deployment 등)을 의미합니다. 쿠버네티스는 리소스를 여러 API 그룹으로 나눕니다.

코어 그룹(빈 문자열 "")에는 Pod, Service, ConfigMap, Secret 같은 기본 리소스가 속합니다. apps 그룹에는 Deployment, StatefulSet, DaemonSet이 속하고, batch 그룹에는 Job, CronJob이 속합니다.

각 그룹은 관련된 리소스들을 모아놓은 것이며, 버전 관리도 그룹 단위로 이루어집니다. 예를 들어, 개발 팀에게는 Deployment 생성 권한은 주지만 DaemonSet 생성 권한은 주지 않으려면, apps 그룹의 deployments 리소스만 허용하고 daemonsets는 제외하면 됩니다.

기존에는 모든 리소스에 대한 권한을 일괄적으로 주거나, 반대로 너무 제한적으로 주는 양극단이 많았습니다. 하지만 API 그룹과 리소스를 정확히 이해하면 "Deployment는 만들 수 있지만 수정은 할 수 없게", "ConfigMap은 조회할 수 있지만 Secret은 조회할 수 없게" 같은 세밀한 제어가 가능합니다.

API Groups의 핵심은 네임스페이스입니다. 같은 기능이라도 여러 그룹에 분산되어 있을 수 있고, 버전도 다를 수 있습니다.

kubectl api-resources 명령어를 실행하면 모든 리소스와 그들이 속한 API 그룹, 버전을 볼 수 있습니다. RBAC에서는 apiGroups와 resources를 조합하여 정확한 리소스를 지정하고, verbs로 허용할 작업을 명시합니다.

서브리소스(예: pods/log, deployments/scale)도 별도로 지정할 수 있어 더욱 세밀한 제어가 가능합니다.

코드 예제

# 다양한 API 그룹의 리소스에 대한 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: developer-role
rules:
- apiGroups: [""]  # 코어 그룹 (legacy group)
  resources: ["pods", "pods/log", "configmaps"]  # 서브리소스 포함
  verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
  resources: ["secrets"]  # Secret은 별도로 제한
  verbs: ["get", "list"]  # 읽기만 가능, 생성/수정 불가
- apiGroups: ["apps"]  # apps API 그룹
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["apps"]
  resources: ["deployments/scale"]  # scale 서브리소스
  verbs: ["update"]  # 스케일링만 가능
- apiGroups: ["batch"]  # batch API 그룹
  resources: ["jobs", "cronjobs"]
  verbs: ["get", "list", "create"]
- apiGroups: ["networking.k8s.io"]  # networking API 그룹
  resources: ["ingresses"]
  verbs: ["get", "list"]  # Ingress는 읽기만

설명

이것이 하는 일: 위 예제는 여러 API 그룹에 걸쳐 세밀하게 권한을 제어하는 Role을 보여줍니다. 첫 번째 단계로, 코어 그룹(빈 문자열)의 리소스들을 살펴봅시다.

첫 번째 rule에서는 Pod, ConfigMap에 대해 생성과 삭제를 포함한 광범위한 권한을 부여합니다. 주목할 점은 resources: ["pods", "pods/log"]에서 pods/log라는 서브리소스를 별도로 명시한다는 것입니다.

서브리소스는 슬래시(/)로 구분되며, 메인 리소스와는 독립적으로 권한을 제어할 수 있습니다. pods에 대한 권한이 있어도 pods/log 권한이 없으면 로그를 볼 수 없습니다.

두 번째 rule에서는 Secret을 별도로 분리하여 읽기만 가능하도록 제한합니다. 같은 코어 그룹이라도 보안이 중요한 Secret은 다르게 취급하는 것이 일반적입니다.

그 다음으로, apps 그룹을 보면 Deployment와 ReplicaSet에 대한 권한이 있습니다. 여기서 흥미로운 점은 별도의 rule로 deployments/scale 서브리소스에 대한 update 권한을 주고 있다는 것입니다.

이렇게 하면 Deployment의 전체 스펙을 수정하지 않고도 레플리카 수만 조정할 수 있습니다. kubectl scale deployment my-app --replicas=5 같은 명령어가 이 권한을 사용합니다.

batch 그룹에서는 Job과 CronJob에 대한 권한을 주고, networking.k8s.io 그룹에서는 Ingress에 대한 읽기 전용 권한을 줍니다. 마지막으로, 이런 세밀한 구성이 실무에서 왜 중요한지 살펴봅시다.

개발자에게는 자신의 애플리케이션(Deployment)을 자유롭게 배포하고 스케일링할 수 있는 권한을 주면서도, DaemonSet 같은 클러스터 전체에 영향을 주는 리소스는 제한할 수 있습니다. Secret은 읽을 수는 있지만 생성하거나 수정할 수는 없게 하여, 민감한 정보를 보호하면서도 애플리케이션 디버깅은 가능하게 합니다.

여러분이 이 방식을 사용하면 "필요한 만큼만" 권한을 주는 최소 권한 원칙을 정확하게 구현할 수 있습니다. 각 팀이나 역할에 맞는 권한 프로파일을 만들 수 있고, 보안 요구사항에 따라 리소스별로 다른 수준의 접근 제어를 적용할 수 있습니다.

또한 새로운 커스텀 리소스(CRD)를 도입할 때도 동일한 패턴으로 권한을 관리할 수 있어 일관성을 유지할 수 있습니다.

실전 팁

💡 kubectl api-resources 명령어를 자주 활용하세요. 이 명령어는 모든 리소스의 이름, API 그룹, 짧은 이름, 네임스페이스 여부를 보여줘서 RBAC 작성 시 참고하기 좋습니다.

💡 와일드카드(*)는 신중하게 사용하세요. apiGroups: ["*"]resources: ["*"]는 현재와 미래의 모든 리소스를 포함하므로, 정말 필요한 경우(클러스터 관리자)가 아니면 피하세요.

💡 서브리소스 권한을 잊지 마세요. pods/log, pods/exec, deployments/scale, services/proxy 같은 서브리소스는 별도로 권한을 부여해야 합니다. 메인 리소스 권한만으로는 부족합니다.

💡 resourceNames 필드로 특정 리소스만 지정할 수 있습니다. 예를 들어 resourceNames: ["my-config"]를 추가하면 my-config라는 이름의 ConfigMap에만 권한이 적용됩니다. 매우 민감한 리소스를 보호할 때 유용합니다.

💡 API 버전은 apiGroups에 포함되지 않습니다. apps/v1이 아니라 그냥 apps만 지정하면 됩니다. 버전은 리소스 자체를 정의할 때(kind, apiVersion)는 중요하지만, RBAC에서는 그룹만 사용합니다.


6. 실전 예제 - 다중 팀 환경 권한 설계

시작하며

여러분이 여러 팀이 함께 사용하는 쿠버네티스 클러스터를 운영하면서 "각 팀이 자신의 네임스페이스에서는 자유롭게 작업하되, 서로의 영역은 침범하지 못하게 하려면 어떻게 해야 하지?"라고 고민한 적 있나요? 또는 "개발 팀, 운영 팀, 보안 팀이 각자 필요한 권한만 가지도록 설계하려면 어디서부터 시작해야 할까?"라는 막연함을 느낀 적이 있을 겁니다.

이런 문제는 실제 기업 환경에서 가장 흔하게 발생합니다. 단일 클러스터를 여러 팀이 공유하면 비용은 절감되지만, 권한 관리가 복잡해지고 보안 사고의 위험이 커집니다.

한 팀의 실수가 다른 팀의 서비스에 영향을 줄 수 있고, 민감한 데이터가 노출될 수도 있습니다. 바로 이럴 때 필요한 것이 체계적인 다중 팀 권한 설계입니다.

네임스페이스로 리소스를 격리하고, RBAC으로 각 팀에 적절한 권한을 부여하며, 클러스터 관리자는 전체를 모니터링할 수 있도록 하는 완전한 권한 구조를 만들 수 있습니다. 실무에서 바로 적용할 수 있는 패턴을 익히면, 안전하고 효율적인 멀티 테넌시 환경을 구축할 수 있습니다.

개요

간단히 말해서, 다중 팀 환경에서는 네임스페이스별로 팀을 격리하고, Role과 RoleBinding으로 각 팀에 자신의 네임스페이스 내에서만 작동하는 권한을 부여하며, ClusterRole과 ClusterRoleBinding으로 클러스터 관리자에게 전체 권한을 부여합니다. 전형적인 설계는 다음과 같습니다.

각 팀마다 전용 네임스페이스를 만들고(team-a, team-b 등), 팀 멤버들에게는 자신의 네임스페이스에서 대부분의 작업을 할 수 있는 권한을 줍니다. 하지만 네임스페이스 자체를 삭제하거나, 다른 팀의 네임스페이스에 접근하는 것은 막습니다.

운영 팀에게는 모든 네임스페이스의 리소스를 조회할 수 있는 읽기 전용 권한을 주고, 보안 팀에게는 Secret과 RBAC 설정을 감사할 수 있는 권한을 줍니다. 클러스터 관리자만 Node 관리, 네임스페이스 생성, 클러스터 수준 리소스 제어 같은 강력한 권한을 가집니다.

기존에는 모든 팀에게 클러스터 전체 권한을 주거나, 반대로 너무 제한적이어서 매번 관리자에게 요청해야 하는 불편함이 있었습니다. 하지만 적절한 RBAC 설계를 하면 팀의 자율성과 보안을 동시에 달성할 수 있습니다.

이러한 설계의 핵심 원칙은 세 가지입니다. 첫째, 네임스페이스 기반 격리로 리소스를 분리합니다.

둘째, 역할 기반 권한 부여로 직무에 맞는 권한을 줍니다(개발자, 운영자, 관리자). 셋째, 최소 권한 원칙을 적용하여 필요한 것만 허용합니다.

이러한 원칙들을 따르면 확장 가능하고 안전한 권한 구조를 만들 수 있습니다.

코드 예제

# 1. 팀별 네임스페이스 생성 (관리자가 수행)
# kubectl create namespace team-alpha
# kubectl create namespace team-beta

# 2. 팀 내부에서 사용할 ClusterRole (재사용 가능)
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: team-member
rules:
- apiGroups: ["", "apps", "batch"]
  resources: ["pods", "services", "configmaps", "deployments", "jobs"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]  # Secret은 읽기만
---
# 3. Team Alpha 멤버들에게 권한 부여
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: team-alpha-binding
  namespace: team-alpha
subjects:
- kind: Group
  name: team-alpha-devs  # OIDC/LDAP 그룹
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: team-member  # 위에서 정의한 ClusterRole 재사용
  apiGroup: rbac.authorization.k8s.io
---
# 4. 운영팀에게 모든 네임스페이스 읽기 권한
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ops-viewer
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["get", "list", "watch"]  # 읽기 전용
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ops-team-binding
subjects:
- kind: Group
  name: ops-team
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: ops-viewer
  apiGroup: rbac.authorization.k8s.io

설명

이것이 하는 일: 위 예제는 여러 팀이 안전하게 공존할 수 있는 완전한 RBAC 구조를 보여줍니다. 첫 번째 단계로, 네임스페이스를 생성합니다.

team-alpha와 team-beta 네임스페이스를 만들어 각 팀의 작업 공간을 물리적으로 분리합니다. 네임스페이스는 쿠버네티스의 가장 기본적인 격리 단위이며, 네트워크 정책, 리소스 쿼터, RBAC 모두 네임스페이스 단위로 작동합니다.

각 팀은 자신의 네임스페이스 안에서는 자유롭게 리소스를 만들고 삭제할 수 있지만, 다른 팀의 네임스페이스는 볼 수도 없습니다. 그 다음으로, team-member라는 ClusterRole을 정의합니다.

이것이 핵심 패턴인데, ClusterRole로 만들면 한 번 정의하고 여러 네임스페이스에서 재사용할 수 있습니다. 이 역할은 Pod, Service, Deployment 같은 일반적인 리소스에 대해 거의 모든 작업을 허용하지만, Secret은 읽기만 가능하도록 제한합니다.

그리고 team-alpha 네임스페이스에 RoleBinding을 만들어, team-alpha-devs 그룹의 모든 멤버에게 이 ClusterRole을 부여합니다. 중요한 점은 RoleBinding이기 때문에 권한이 team-alpha 네임스페이스로만 제한된다는 것입니다.

team-beta에서도 동일한 ClusterRole을 사용하되 별도의 RoleBinding을 만들면, 각 팀이 독립적으로 권한을 받습니다. 마지막으로, 운영 팀을 위한 설정을 봅시다.

ops-viewer ClusterRole은 모든 리소스에 대해 읽기 전용 권한을 가집니다. 그리고 ClusterRoleBinding으로 ops-team 그룹에 연결하여, 운영 팀은 모든 네임스페이스의 모든 리소스를 조회할 수 있게 됩니다.

이렇게 하면 운영 팀이 장애 대응이나 모니터링을 위해 전체 클러스터 상태를 파악할 수 있지만, 실수로 무언가를 삭제하거나 수정할 위험은 없습니다. ClusterRoleBinding을 사용했기 때문에 네임스페이스 경계를 넘어 모든 곳을 볼 수 있는 것입니다.

여러분이 이 패턴을 사용하면 조직의 구조를 쿠버네티스 권한에 그대로 반영할 수 있습니다. 새로운 팀이 추가되면 네임스페이스를 만들고 RoleBinding 하나만 추가하면 되며, 팀 멤버 변경은 외부 인증 시스템(OIDC, LDAP)의 그룹 관리로 해결됩니다.

보안 감사도 쉬워지는데, 각 네임스페이스의 RoleBinding만 확인하면 누가 어떤 권한을 가지는지 한눈에 파악할 수 있습니다. 또한 리소스 쿼터와 네트워크 정책을 함께 사용하면 완전한 멀티 테넌시 환경을 구축할 수 있습니다.

실전 팁

💡 ClusterRole을 만들고 RoleBinding으로 연결하는 패턴을 표준으로 삼으세요. Role을 각 네임스페이스마다 중복 생성하는 것보다 훨씬 관리하기 쉽습니다.

💡 그룹 기반 권한 부여를 최대한 활용하세요. 개별 사용자 대신 그룹을 subjects에 넣으면, 인사 이동이나 팀 재편성 시 쿠버네티스 설정을 전혀 변경할 필요가 없습니다.

💡 리소스 쿼터(ResourceQuota)를 함께 설정하세요. RBAC은 "할 수 있는지"를 제어하지만, 쿼터는 "얼마나 할 수 있는지"를 제어합니다. CPU, 메모리, Pod 수 같은 제한을 걸어 한 팀이 클러스터 전체를 독점하는 것을 방지할 수 있습니다.

💡 네트워크 정책(NetworkPolicy)으로 네임스페이스 간 통신을 제어하세요. RBAC은 API 접근을 제어하지만, Pod 간 네트워크 통신은 별개입니다. 네트워크 정책을 설정해야 team-alpha의 Pod가 team-beta의 Pod에 직접 접근하는 것을 막을 수 있습니다.

💡 정기적으로 권한을 검토하세요. kubectl get rolebindings,clusterrolebindings --all-namespaces -o wide로 모든 바인딩을 확인하고, 더 이상 필요하지 않은 권한은 제거하세요. 권한은 시간이 지나면서 누적되기 쉽습니다.


7. 문제 해결과 디버깅 - RBAC 오류 해결하기

시작하며

여러분이 쿠버네티스에서 작업하다가 "forbidden: User 'john' cannot create pods in namespace 'production'"이라는 오류를 보고 당황한 적 있나요? 또는 "RBAC 설정을 분명히 했는데도 계속 권한 오류가 나는데, 뭐가 잘못된 거지?"라고 머리를 쥐어뜯은 적이 있을 겁니다.

이런 문제는 RBAC을 처음 사용할 때 누구나 겪는 어려움입니다. RBAC은 Role, RoleBinding, ServiceAccount 등 여러 객체가 서로 연결되어 작동하므로, 어느 한 곳이라도 잘못 설정되면 권한이 작동하지 않습니다.

또한 오류 메시지만으로는 정확히 어디가 문제인지 파악하기 어려울 때가 많습니다. 바로 이럴 때 필요한 것이 체계적인 RBAC 디버깅 기법입니다.

kubectl의 권한 검증 명령어, 로그 확인, 그리고 단계별 점검 방법을 알면 대부분의 권한 문제를 빠르게 해결할 수 있습니다. 실무에서 자주 발생하는 문제 패턴을 익혀두면, 시행착오를 크게 줄일 수 있습니다.

개요

간단히 말해서, RBAC 문제를 해결하려면 권한이 작동하는 전체 체인을 순서대로 확인해야 합니다: 사용자/ServiceAccount 확인 → RoleBinding/ClusterRoleBinding 확인 → Role/ClusterRole 확인 → API 그룹과 리소스 이름 확인. 대부분의 RBAC 오류는 몇 가지 패턴으로 분류됩니다.

첫째, RoleBinding이 잘못된 Role을 참조하거나 아예 존재하지 않는 경우입니다. 둘째, Role의 rules에서 apiGroups나 resources를 잘못 지정한 경우입니다.

예를 들어 Deployment는 apps 그룹에 속하는데 코어 그룹("")으로 지정하면 권한이 작동하지 않습니다. 셋째, ServiceAccount의 네임스페이스가 맞지 않거나, Pod가 잘못된 ServiceAccount를 사용하는 경우입니다.

넷째, 서브리소스(pods/log, deployments/scale)에 대한 권한을 빠뜨린 경우입니다. 기존에는 권한 오류가 나면 무작정 더 많은 권한을 주거나, 심지어 cluster-admin 권한을 주는 경우가 많았습니다.

하지만 체계적인 디버깅 방법을 사용하면 정확히 어떤 권한이 부족한지 찾아서 최소한만 추가할 수 있습니다. RBAC 디버깅의 핵심 도구는 세 가지입니다.

첫째, kubectl auth can-i 명령어로 특정 작업이 허용되는지 미리 테스트합니다. 둘째, kubectl describe 명령어로 RoleBinding과 Role의 세부 내용을 확인합니다.

셋째, API 서버의 감사 로그를 확인하여 실제로 어떤 권한 검사가 실패했는지 파악합니다. 이러한 도구들을 조합하면 거의 모든 RBAC 문제를 해결할 수 있습니다.

코드 예제

# 1. 현재 사용자로 권한 테스트
# kubectl auth can-i create pods --namespace=production
# 출력: yes 또는 no

# 2. 다른 사용자로 권한 테스트 (관리자가 확인할 때)
# kubectl auth can-i create pods --namespace=production --as=john
# kubectl auth can-i create deployments --namespace=production --as=system:serviceaccount:production:my-app

# 3. 모든 권한 목록 확인
# kubectl auth can-i --list --namespace=production

# 4. RoleBinding 확인
# kubectl get rolebindings -n production
# kubectl describe rolebinding read-pods-binding -n production

# 5. Role 내용 확인
# kubectl get role pod-reader -n production -o yaml

# 6. ServiceAccount 확인
# kubectl get serviceaccount -n production
# kubectl describe pod my-pod -n production | grep "Service Account"

# 7. RBAC 문제 해결을 위한 간단한 스크립트 예시
# 특정 사용자의 모든 권한을 한눈에 확인
#!/bin/bash
USER="john"
NAMESPACE="production"

echo "=== Checking permissions for $USER in $NAMESPACE ==="
echo ""
echo "Can create pods?"
kubectl auth can-i create pods -n $NAMESPACE --as=$USER

echo "Can delete deployments?"
kubectl auth can-i delete deployments -n $NAMESPACE --as=$USER

echo "Can view secrets?"
kubectl auth can-i get secrets -n $NAMESPACE --as=$USER

echo ""
echo "=== All permissions ==="
kubectl auth can-i --list -n $NAMESPACE --as=$USER

설명

이것이 하는 일: 위 예제는 RBAC 권한 문제를 진단하고 해결하는 실용적인 명령어들을 보여줍니다. 첫 번째 단계로, kubectl auth can-i 명령어가 가장 강력한 도구입니다.

이 명령어는 실제로 리소스를 만들거나 삭제하지 않고도 권한이 있는지 미리 확인할 수 있습니다. kubectl auth can-i create pods --namespace=production을 실행하면 현재 사용자(kubeconfig에 설정된 사용자)가 production 네임스페이스에서 Pod를 만들 수 있는지 yes 또는 no로 알려줍니다.

더 중요한 것은 --as 플래그인데, 이것을 사용하면 다른 사용자나 ServiceAccount의 권한을 관리자가 대신 테스트할 수 있습니다. 예를 들어 john이라는 개발자가 권한 오류를 겪고 있다면, 관리자는 --as=john을 사용해 john의 시각에서 권한을 확인할 수 있습니다.

그 다음으로, kubectl auth can-i --list 명령어는 특정 네임스페이스에서 사용자가 가진 모든 권한을 나열합니다. 출력은 리소스와 동사(verbs)의 조합으로 표시되어, 어떤 리소스에 어떤 작업을 할 수 있는지 한눈에 파악할 수 있습니다.

이것은 "내가 어떤 권한을 가지고 있지?"라는 질문에 답하는 가장 빠른 방법입니다. 그리고 kubectl describe rolebindingkubectl get role -o yaml로 실제 RBAC 객체들을 확인합니다.

describe 명령어는 사람이 읽기 편한 형식으로 RoleBinding이 어떤 주체에게 어떤 Role을 부여하는지 보여줍니다. 만약 RoleBinding이 존재하지 않거나, 잘못된 Role을 참조하거나, subjects에 사용자가 빠져있다면 여기서 발견할 수 있습니다.

마지막으로, 스크립트 예시는 실무에서 유용한 패턴을 보여줍니다. 특정 사용자의 일반적인 작업들(Pod 생성, Deployment 삭제, Secret 조회 등)을 한 번에 테스트하는 스크립트를 만들어두면, 권한 문제가 보고되었을 때 빠르게 진단할 수 있습니다.

각 팀이나 역할에 맞는 테스트 스크립트를 준비해두면, 새로운 멤버가 합류했을 때 권한이 제대로 설정되었는지 검증하기도 쉽습니다. 여러분이 이러한 디버깅 기법을 사용하면 RBAC 문제를 빠르게 해결할 수 있습니다.

사용자가 "권한이 없다"고 보고하면, can-i 명령어로 즉시 확인하고, describe로 설정을 점검하여 정확히 무엇이 부족한지 파악할 수 있습니다. 또한 배포 전에 can-i로 테스트하여, 운영 환경에서 권한 오류가 발생하는 것을 미리 방지할 수 있습니다.

API 서버 감사 로그를 활성화하면 누가 언제 어떤 작업을 시도했고 왜 거부되었는지 상세히 추적할 수 있어, 보안 감사와 문제 해결 모두에 도움이 됩니다.

실전 팁

💡 can-i 명령어를 자동화 스크립트에 포함하세요. CI/CD 파이프라인에서 배포 전에 필요한 권한이 있는지 자동으로 검증하면, 운영 환경에서 권한 오류로 배포가 실패하는 것을 방지할 수 있습니다.

💡 네임스페이스를 항상 명시하세요. can-i 명령어에서 -n 옵션을 빠뜨리면 default 네임스페이스에서 테스트되므로, 의도한 것과 다른 결과가 나올 수 있습니다.

💡 ServiceAccount 권한을 테스트할 때는 --as=system:serviceaccount:NAMESPACE:SERVICEACCOUNT 형식을 사용하세요. 예: --as=system:serviceaccount:production:my-app

💡 API 서버 감사 로그를 활성화하세요. 감사 로그는 모든 API 요청과 응답을 기록하므로, 권한 거부의 정확한 원인(어떤 user, 어떤 verb, 어떤 resource)을 파악할 수 있습니다. /var/log/kubernetes/audit/audit.log에서 확인할 수 있습니다.

💡 RBAC이 비활성화되어 있는지 확인하세요. API 서버가 --authorization-mode에 RBAC을 포함하지 않으면 RBAC 설정이 전혀 작동하지 않습니다. kubectl cluster-info dump | grep authorization-mode로 확인할 수 있습니다.


8. 보안 모범 사례 - 안전한 RBAC 운영

시작하며

여러분이 RBAC을 설정하고 운영하면서 "이 정도 권한이면 안전한 건가?"라고 불안해한 적 있나요? 또는 "권한을 너무 많이 준 것 같은데, 나중에 보안 감사를 받으면 문제가 되지 않을까?"라고 걱정한 적이 있을 겁니다.

이런 우려는 매우 타당합니다. 쿠버네티스는 강력한 플랫폼이지만, 잘못 설정된 권한은 심각한 보안 사고로 이어질 수 있습니다.

예를 들어, 한 개발자에게 Secret 생성 권한을 주면 imagePullSecret을 조작하여 악의적인 컨테이너 이미지를 실행할 수 있고, Pod 생성 권한이 있으면 hostPath 볼륨을 마운트하여 노드의 파일 시스템에 접근할 수도 있습니다. 바로 이럴 때 필요한 것이 RBAC 보안 모범 사례입니다.

최소 권한 원칙, 위험한 권한 조합 회피, 정기적인 권한 검토, 그리고 Pod Security Standards와의 결합 등을 통해 안전한 쿠버네티스 환경을 만들 수 있습니다. 이러한 모범 사례를 따르면 보안과 생산성을 모두 달성할 수 있습니다.

개요

간단히 말해서, 안전한 RBAC 운영은 최소 권한 원칙을 기본으로 하고, 위험한 권한(escalate, bind, impersonate)을 신중하게 관리하며, Pod Security Standards와 Network Policy 같은 다른 보안 계층과 함께 사용하는 것입니다. RBAC만으로는 완벽한 보안을 달성할 수 없다는 것을 이해하는 것이 중요합니다.

RBAC은 "쿠버네티스 API에 무엇을 요청할 수 있는가"를 제어하지만, "그 요청이 안전한가"는 보장하지 않습니다. 예를 들어, Pod 생성 권한이 있으면 privileged: true를 설정하여 노드에 대한 거의 완전한 접근 권한을 가진 컨테이너를 실행할 수 있습니다.

이것을 막으려면 Pod Security Standards(또는 PodSecurityPolicy, Admission Controllers)와 RBAC을 함께 사용해야 합니다. 기존에는 "일단 작동하게 만들고 나중에 보안을 강화하자"는 접근이 많았습니다.

하지만 권한은 한 번 주면 회수하기 어렵고, 나중에 강화하려면 서비스 중단이나 사용자 불만이 발생할 수 있습니다. 처음부터 보안을 고려하여 설계하는 것이 훨씬 효율적입니다.

RBAC 보안의 핵심 원칙은 다섯 가지입니다. 첫째, 최소 권한 원칙(Principle of Least Privilege)을 항상 적용합니다.

둘째, 위험한 verbs(escalate, bind, impersonate, create pods, patch secrets)를 신중하게 제어합니다. 셋째, 와일드카드(*)는 클러스터 관리자에게만 사용합니다.

넷째, 정기적인 권한 검토와 감사를 수행합니다. 다섯째, 다층 방어(defense in depth) 전략으로 RBAC, Pod Security, Network Policy를 함께 사용합니다.

코드 예제

# 1. 안전한 개발자 권한 예시 (위험한 기능 제외)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: safe-developer
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "configmaps"]
  verbs: ["get", "list", "watch", "create", "delete"]
  # 주의: update, patch는 의도적으로 제외 (실행 중인 Pod 수정 방지)
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "create", "delete"]
  # replicas 조정은 별도 권한으로 분리
- apiGroups: ["apps"]
  resources: ["deployments/scale"]
  verbs: ["update"]
# 주의: 다음 권한은 절대 주지 말 것
# - secrets에 대한 create/update (imagePullSecret 조작 가능)
# - nodes에 대한 어떤 권한 (노드 접근)
# - roles/rolebindings에 대한 create/update (권한 상승)
---
# 2. 감사용 읽기 전용 역할
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: audit-viewer
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["get", "list"]  # watch도 제외하여 부하 방지
- apiGroups: [""]
  resources: ["secrets"]
  verbs: []  # Secret은 메타데이터만 볼 수 있도록 추가 제한 가능
---
# 3. Pod Security Standards와 함께 사용
# PodSecurity admission을 활성화하여 RBAC 우회 방지
# (이것은 API 서버 설정이지만, RBAC과 함께 필수)
# --admission-control-config-file에 다음 내용 포함:
# apiVersion: apiserver.config.k8s.io/v1
# kind: AdmissionConfiguration
# plugins:
# - name: PodSecurity
#   configuration:
#     defaults:
#       enforce: "baseline"
#       enforce-version: "latest"

설명

이것이 하는 일: 위 예제는 보안을 고려한 RBAC 설정과 피해야 할 위험한 패턴을 보여줍니다. 첫 번째 단계로, safe-developer Role을 살펴봅시다.

이것은 개발자에게 필요한 기본 권한을 주되, 보안 위험이 있는 권한은 의도적으로 제외한 것입니다. Pod에 대해 create와 delete 권한은 있지만 update와 patch는 없습니다.

그 이유는 update/patch로 실행 중인 Pod의 스펙을 변경하면 예기치 않은 동작이 발생할 수 있고, 특히 privileged: true 같은 위험한 설정을 추가할 수 있기 때문입니다(물론 Pod는 immutable이라 대부분 수정이 불가능하지만, 일부 필드는 가능합니다). Secret에 대한 create/update 권한을 주지 않은 것이 특히 중요한데, 이 권한이 있으면 imagePullSecret을 만들어서 악의적인 컨테이너 이미지를 실행할 수 있고, Secret을 Pod에 마운트하여 민감한 정보에 접근할 수 있습니다.

코멘트로 "절대 주지 말 것" 리스트를 명시한 것은, 다른 관리자가 나중에 권한을 추가할 때 경고 역할을 합니다. 그 다음으로, audit-viewer ClusterRole은 감사나 읽기 전용 접근이 필요한 경우를 위한 것입니다.

모든 리소스에 대해 get과 list만 허용하고, watch는 제외했습니다. watch는 변경사항을 실시간으로 스트리밍하므로 API 서버에 부하를 줄 수 있고, 감사 목적에는 불필요하기 때문입니다.

Secret의 경우 추가로 제한할 수 있는데, Secret의 메타데이터(이름, 레이블)는 볼 수 있지만 실제 데이터(data 필드)는 볼 수 없도록 하는 것이 이상적입니다. 하지만 쿠버네티스 RBAC만으로는 필드 수준 제어가 불가능하므로, Admission Webhook이나 OPA(Open Policy Agent) 같은 추가 도구가 필요합니다.

마지막으로, Pod Security Standards와의 통합이 매우 중요합니다. RBAC으로 Pod 생성 권한을 주더라도, Pod Security Standards를 baseline 또는 restricted로 설정하면 privileged 컨테이너, hostPath 볼륨, hostNetwork 같은 위험한 설정을 사용하는 Pod는 생성이 거부됩니다.

이것이 다층 방어(defense in depth)의 핵심입니다. RBAC은 "누가 무엇을 할 수 있는가"를 제어하고, Pod Security는 "어떻게 하는가"를 제어하며, Network Policy는 "누구와 통신할 수 있는가"를 제어합니다.

이 세 계층을 함께 사용해야 비로소 안전한 쿠버네티스 환경이 완성됩니다. 여러분이 이러한 모범 사례를 따르면 보안 사고의 위험을 크게 줄일 수 있습니다.

권한 상승 공격(한 사용자가 자신의 권한을 스스로 늘리는 것)을 방지할 수 있고, 컨테이너 탈출이나 노드 침해 같은 심각한 공격의 가능성을 최소화할 수 있습니다. 또한 규정 준수(compliance) 요구사항도 충족할 수 있는데, 대부분의 보안 표준(CIS Kubernetes Benchmark, PCI-DSS 등)은 최소 권한 원칙과 역할 분리를 요구하기 때문입니다.

정기적인 권한 검토를 통해 더 이상 필요하지 않은 권한을 제거하고, 새로운 위협에 대응할 수 있습니다.

실전 팁

💡 escalate, bind, impersonate 권한은 매우 위험합니다. escalate 권한이 있으면 자신보다 높은 권한을 가진 Role을 만들 수 있고, bind 권한으로 그것을 자신에게 부여할 수 있으며, impersonate 권한으로 다른 사용자 행세를 할 수 있습니다. 이 권한들은 클러스터 관리자에게만 주세요.

💡 roles와 rolebindings 리소스에 대한 권한을 함부로 주지 마세요. 이 권한이 있으면 사용자가 스스로 권한을 상승시킬 수 있습니다. 정말 필요하다면 resourceNames를 사용하여 특정 Role만 관리할 수 있도록 제한하세요.

💡 CIS Kubernetes Benchmark를 참고하세요. Center for Internet Security에서 제공하는 이 벤치마크는 RBAC을 포함한 쿠버네티스 보안의 모범 사례를 제시합니다. kube-bench 도구로 자동으로 검사할 수 있습니다.

💡 정기적으로 unused 권한을 제거하세요. audit2rbac 같은 도구를 사용하면 실제 사용된 API 호출을 분석하여, 사용되지 않는 권한을 찾아낼 수 있습니다.

💡 쿠버네티스 1.25 이상에서는 Pod Security Standards를 사용하고, 1.25 미만이라면 OPA Gatekeeper나 Kyverno 같은 Policy Engine을 도입하세요. RBAC만으로는 불충분한 보안 제어를 이들이 보완해줍니다.


#Kubernetes#RBAC#ServiceAccount#Role#ClusterRole