Chapter 17

인가와 RBAC

  • 17.1 API 그룹
  • 17.2 인가 메커니즘
  • 17.3 RBAC
  • 17.4 ClusterRole

인증이 "누구인가"를 확인하는 거였다면, 인가는 "뭘 할 수 있는가"를 정하는 거야. Kubernetes는 API를 그룹 단위로 나누고, RBAC으로 역할 기반 접근 제어를 구현해. 이번 장에서는 API 그룹 구조부터 Role, ClusterRole까지 권한 부여의 전체 흐름을 살펴보자.

권한 부여를 이해하려면 먼저 Kubernetes의 API 그룹을 알아야 해. Kubernetes API는 목적에 따라 여러 그룹으로 분류돼. /version은 클러스터 버전 확인용, /metrics/healthz는 상태 모니터링용, /logs는 타사 로깅 통합용이야. 그리고 클러스터 기능을 담당하는 핵심 API들은 Core 그룹과 Named 그룹으로 나뉘어.

Core 그룹(/api/v1)에는 Kubernetes의 핵심 기능이 모여 있어. Namespaces, Pods, ReplicationControllers, Events, Endpoints, Nodes, PersistentVolumes, PersistentVolumeClaims, ConfigMaps, Secrets, Services 같은 것들이지.

Named 그룹(/apis)은 더 체계적으로 정리되어 있고, 앞으로 모든 새로운 기능은 이 Named 그룹을 통해 제공될 예정이야. apps 그룹 아래에는 Deployments, ReplicaSets, StatefulSets가 있고, networking.k8s.io에는 NetworkPolicies, certificates.k8s.io에는 CertificateSigningRequests가 있어. 이 외에도 storage, authentication, authorization 등을 위한 그룹들이 있지.

각 리소스에는 수행 가능한 동작(Verbs)이 있어. list, get, create, delete, update, watch 같은 것들이야. 이 API 그룹과 Verbs가 권한 부여에서 사용자의 접근을 허용하거나 거부하는 데 쓰이는 거야. RBAC에서 역할을 정의할 때 어떤 API 그룹의 어떤 리소스에 대해 어떤 Verbs를 허용할지를 지정하거든.

각 오브젝트의 API 그룹이 뭔지는 Kubernetes API 참조 문서에서 확인할 수 있고, kubectl api-resources 명령으로도 볼 수 있어. 클러스터에 직접 접근해서 확인할 수도 있는데, 포트 6443으로 kube API 서버에 접속하면 사용 가능한 API 그룹이 나열돼.

curl로 API에 직접 접근할 때는 인증 메커니즘을 지정해야 해. 인증서 파일을 명령줄에 전달하거나, **kubectl proxy**를 시작해서 로컬 프록시를 쓰는 방법이 있어. kubectl proxy는 포트 8001에서 로컬로 프록시 서비스를 시작하고 kubeconfig 파일의 자격 증명을 자동으로 사용해서 클러스터에 접근해. 그러면 curl에서 인증서를 지정할 필요가 없어져.

한 가지 주의할 건, kube-proxykubectl proxy는 완전히 다른 거야. kube-proxy는 클러스터의 여러 노드에서 파드와 서비스 간 네트워크 연결을 활성화하는 거고, kubectl proxy는 API 서버에 접근하기 위해 로컬에서 실행하는 HTTP 프록시 서비스야. 이름이 비슷해서 헷갈릴 수 있으니까 구분해서 기억해.

API 그룹과 Verbs가 권한 부여의 재료라면, 이제 그걸 실제로 적용하는 메커니즘을 볼 차례야. 인증(Authentication)은 "누가 접근할 수 있는가"를 다뤘고, 권한 부여(Authorization)는 "접근한 다음에 뭘 할 수 있는가"를 정하는 거야.

클러스터 관리자는 파드, 노드, 배포를 보고, 만들고, 삭제하는 등 모든 작업을 할 수 있어. 하지만 곧 개발자, 테스터, 모니터링 앱, CI/CD 도구 같은 다른 주체들도 클러스터에 접근하게 되잖아. 개발자한테 노드 삭제 권한이나 스토리지 구성 변경 권한을 주면 위험하지. 외부 애플리케이션에는 필요한 최소한의 권한만 줘야 하고. 네임스페이스로 여러 팀이 클러스터를 나눠 쓸 때도 사용자 접근을 해당 네임스페이스로만 제한하고 싶을 거야.

Kubernetes에서 지원하는 권한 부여 메커니즘은 여러 가지야. Node Authorizer는 kubelet이 API 서버에 접근할 때 쓰는 특수 인가자야. 인증서에서 다뤘던 것처럼 kubelet은 system:nodes 그룹에 속하고 이름이 system:node: 접두사로 시작해야 해. 이 조건을 만족하는 요청만 Node Authorizer가 처리하고, kubelet에 필요한 권한(서비스, 엔드포인트, 노드, 파드 정보 읽기, 노드 상태 보고 등)을 부여해. 이건 클러스터 내부 접근 전용이야.

ABAC(속성 기반 액세스 제어)은 사용자나 그룹을 권한 세트에 직접 연결하는 방식이야. JSON으로 정책 파일을 만들어서 API 서버에 전달하는데, 보안을 변경할 때마다 정책 파일을 수동으로 편집하고 API 서버를 재시작해야 해서 관리하기가 어려워.

RBAC(역할 기반 액세스 제어)은 이걸 훨씬 쉽게 만들어줘. 사용자를 권한에 직접 연결하는 대신 역할(Role)을 정의하고, 사용자를 그 역할에 연결하는 거야. 예를 들어 개발자 역할에 필요한 권한을 정의하고 모든 개발자를 그 역할에 연결해. 나중에 권한을 변경해야 하면 역할만 수정하면 모든 개발자에게 즉시 반영돼. 대부분의 Kubernetes 클러스터에서 쓰는 표준적인 접근 방식이야.

Webhook은 권한 부여를 외부로 아웃소싱하는 거야. Open Policy Agent 같은 타사 도구를 써서 Kubernetes가 사용자 정보와 접근 요청을 외부 서비스에 API 호출로 보내고, 외부 서비스가 허용/거부를 결정하는 방식이야.

그 외에 AlwaysAllowAlwaysDeny 모드가 있어. AlwaysAllow는 권한 확인 없이 모든 요청을 허용하는 거고 AlwaysDeny는 전부 거부해.

인가 모드는 kube API 서버의 --authorization-mode 옵션으로 설정해. 지정하지 않으면 기본값은 AlwaysAllow야. 여러 모드를 쉼표로 구분해서 지정할 수도 있어. 예를 들어 --authorization-mode=Node,RBAC,Webhook처럼. 여러 모드를 설정하면 요청은 지정된 순서대로 각 모듈을 거치는데, 한 모듈이 요청을 거부하면 다음 모듈로 넘어가고, 모듈이 요청을 승인하면 즉시 권한이 부여되고 더 이상 확인하지 않아. 체인 방식이라고 생각하면 돼.

인가 메커니즘 중 가장 많이 쓰이는 RBAC을 구체적으로 살펴보자. RBAC은 두 단계로 동작해. 먼저 Role을 만들어서 어떤 리소스에 어떤 동작을 허용할지 정의하고, 그 다음 RoleBinding으로 사용자를 그 Role에 연결하는 거야.

Role을 만들려면 Role 정의 파일을 작성해. apiVersion은 rbac.authorization.k8s.io/v1, kind는 Role이야. 개발자를 위해 만든다면 이름을 developer로 지정하고, rules 섹션에서 규칙을 정의해. 각 규칙에는 apiGroups, resources, verbs 세 가지가 있어. Core 그룹의 경우 apiGroups를 빈 문자열("")로 두면 되고, 다른 그룹이면 그룹 이름을 지정해. 예를 들어 개발자에게 파드에 대한 list, get, create, delete 권한과 configmap에 대한 create 권한을 주려면 규칙을 두 개 추가하면 돼. 단일 Role에 여러 규칙을 넣을 수 있어.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list", "get", "create", "delete"]
- apiGroups: [""]
  resources: ["configmaps"]
  verbs: ["create"]

다음 단계는 사용자를 이 Role에 연결하는 RoleBinding을 만드는 거야. subjects에 사용자 세부 정보를 지정하고, roleRef에 연결할 Role의 세부 정보를 제공해.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: dev-user-to-developer-binding
subjects:
- kind: User
  name: dev-user
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer
  apiGroup: rbac.authorization.k8s.io

Role과 RoleBinding은 네임스페이스 범위에 속해. 기본 네임스페이스에 만들면 기본 네임스페이스 안에서만 적용돼. 다른 네임스페이스에서 접근을 제어하려면 정의 파일의 metadata에 namespace를 지정해야 해.

생성된 Role과 RoleBinding을 확인하려면 kubectl get roles, kubectl get rolebindings 명령을 쓰면 되고, kubectl describe role developer로 각 리소스에 대한 권한 상세 정보를 볼 수 있어.

사용자가 특정 리소스에 대한 접근 권한이 있는지 확인하려면 kubectl auth can-i 명령을 쓸 수 있어. kubectl auth can-i create deploymentskubectl auth can-i delete nodes 같은 식으로. 관리자라면 다른 사용자를 사칭해서 권한을 테스트할 수도 있어. --as 옵션을 쓰면 돼. kubectl auth can-i create pods --as dev-user 이렇게. 네임스페이스를 지정할 수도 있어. kubectl auth can-i create pods --as dev-user --namespace test.

한 가지 더, 네임스페이스 내의 모든 파드가 아니라 특정 파드에만 접근을 허용할 수도 있어. 규칙에 resourceNames 필드를 추가해서 허용할 파드 이름을 지정하면 돼. 예를 들어 blue와 orange 파드에만 접근을 제한할 수 있지.

Role과 RoleBinding이 네임스페이스 안에서만 동작한다면, 노드나 PersistentVolume 같은 클러스터 범위 리소스는 어떻게 할까? 바로 ClusterRoleClusterRoleBinding으로 관리해야 해.

Kubernetes 리소스는 네임스페이스 범위와 클러스터 범위로 나뉘어. 네임스페이스 리소스는 Pods, ReplicaSets, Deployments, Services, Secrets, ConfigMaps, Roles, RoleBindings 같은 것들이야. 생성할 때 네임스페이스를 지정하면 그 안에 만들어지고, 지정하지 않으면 기본 네임스페이스에 생성돼. 클러스터 범위 리소스는 Nodes, PersistentVolumes, ClusterRoles, ClusterRoleBindings, CertificateSigningRequests, 그리고 Namespaces 자체야. 이 리소스들은 특정 네임스페이스에 연결할 수 없어. 전체 목록은 kubectl api-resources --namespaced=truekubectl api-resources --namespaced=false로 확인할 수 있어.

ClusterRole 만드는 건 Role이랑 거의 같아. kind만 ClusterRole로 바꾸면 돼. 예를 들어 클러스터 관리자에게 노드를 보고, 만들고, 삭제할 수 있는 권한을 주는 ClusterRole을 만들 수 있어.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-administrator
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["list", "get", "create", "delete"]

그 다음 ClusterRoleBinding으로 사용자를 연결해.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: cluster-admin-role-binding
subjects:
- kind: User
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-administrator
  apiGroup: rbac.authorization.k8s.io

한 가지 알아둘 점은, ClusterRole이 반드시 클러스터 범위 리소스에만 쓰이는 건 아니라는 거야. 네임스페이스 리소스에 대한 ClusterRole을 만들 수도 있어. 이렇게 하면 사용자가 모든 네임스페이스에서 해당 리소스에 접근할 수 있게 돼. 일반 Role로 파드 접근 권한을 주면 특정 네임스페이스의 파드에만 접근할 수 있지만, ClusterRole로 파드 접근 권한을 주면 클러스터 전체의 모든 파드에 접근할 수 있는 거지.

Kubernetes는 클러스터를 처음 설정할 때 기본적으로 여러 ClusterRole을 자동 생성해. kubectl get clusterroles로 확인할 수 있어.


정리

17장 읽고 기억할 거 세 가지:

  1. Kubernetes API는 Core 그룹(/api/v1)과 Named 그룹(/apis)으로 나뉘고, 각 리소스의 apiGroup과 Verbs가 RBAC 규칙을 정의하는 기본 단위가 된다.
  2. RBAC은 Role로 권한을 정의하고 RoleBinding으로 사용자를 연결하는 2단계 구조이며, 네임스페이스 범위로 동작한다. kubectl auth can-i --as로 권한을 검증할 수 있다.
  3. ClusterRole은 노드 같은 클러스터 범위 리소스뿐 아니라 네임스페이스 리소스에도 쓸 수 있는데, 이 경우 모든 네임스페이스에서 해당 리소스에 접근 가능해진다.