본문 바로가기
Container/Kubernetes

[k8s] 쿠버네티스 RBAC을 사용한 API 서버 접근 제어 실습

by wrynn 2022. 5. 18.

 학습용 환경이 아닌 실제 엔터프라이즈 환경에서는 1명의 클러스터 관리자가 아닌 다양한 이해관계자가 쿠버네티스 클러스터에 접근합니다. 클러스터에 접근하는 각각의 사용자들에게는 최소 권한의 원칙에 따라 필요한 만큼의 권한만 부여해야 합니다. 여기서는 kubectl을 사용하여 쿠버네티스 컨트롤 플레인의 API 서버에 요청을 보낼 때 접근 제어가 이루어지는 방식에 대해 간단히 알아보고, 직접 클러스터에 사용자별로 접근 권한을 부여해 보겠습니다.

 


쿠버네티스의 사용자

 본격적인 접근 제어 방식을 논하기에 앞서, 쿠버네티스는 사용자를 어떻게 구분하는지부터 살펴보겠습니다. 모든 쿠버네티스 클러스터에는 쿠버네티스에 의해 관리되는 Service AccountUser Account 두가지 종류의 사용자가 있습니다. 주로 사람이 API 서버에 접근하는 경우에는 User Account를, 시스템이 접근할 때에는 Service Account를 사용합니다. 두 사용자의 차이점은 여기에서 확인할 수 있습니다.

 일반 사용자(User Account)는 쿠버네티스 클러스터와는 독립적으로 관리되는 계정입니다. 쿠버네티스는 이런 일반 사용자를 표현할 수 있는 오브젝트를 포함하고 있지 않으며 계정 관리를 AWS, Google 계정 혹은 자체 구축 LDAP 등의 계정 관리 시스템에 위임합니다. 그 대신 쿠버네티스는 인증서, 토큰, 웹훅 등 인증을 위한 다양한 방법을 제공합니다. 일반 사용자가 직접 API를 인증하고 호출할 수 있게 하려면 쿠버네티스 클러스터에서 발급한 인증서를 API 서버에 제시해야 합니다. 

 반면 Service Account는 쿠버네티스에 의해 관리되는 사용자입니다. Pod에 Service Account 정보를 마운트하여 Pod 내 컨테이너에서 실행되는 프로세스가 API 서버 호출이 가능하도록 구성할 수 있습니다. Pod 생성 시 별도의 Service Account를 지정하지 않더라도, 네임스페이스 생성 시 기본적으로 생성되는 default라는 이름의 Service Account를 사용합니다. 

 


쿠버네티스 API 접근 제어 개요

 사용자가 API 서버에 접근했을 때, API 서버 내에서 이루어지는 절차는 크게 다음과 같은 3가지로 구분됩니다. 

  1. Authentication (인증)
  2. Authorization (인가)
  3. Admission Control

 인증은 사용자가 누구인지 식별하는 단계이고, 인가는 사용자가 권한이 있는지를 확인하는 단계입니다. 마지막 Admission Control은 사용자 요청을 검증하고 변형시킬 수 있는 단계입니다. 이 세가지 단계를 모두 통과하고 나서야 비로소 요청이 수행됩니다. 여기서 저희가 다를 부분은 인가 단계입니다. 쿠버네티스에서는 4가지 인가 모드를 지원하며 그 중 가장 널리 사용되는 RBAC을 사용하여 실습해보겠습니다.

 


쿠버네티스 RBAC (Role Based Access Control)

 RBAC은 각 사용자의 역할에 따라 권한을 부여하는 방식입니다. 쿠버네티스는 권한을 Role 혹은 ClusterRole이라는 리소스로 정의하고, 이것을 각 Account에 연결시키는 RoleBinding, ClusterRoleBinding을 정의하는 방식으로 RBAC을 구현합니다. 본격적인 실습에 앞서 먼저 테스트용 네임스페이스 testns를 하나 생성해 두겠습니다. 예제에서는 testuser라는 사용자에게 권한을 부여하는 상황을 가정하겠습니다.

$ kubectl create ns testns
namespace/testns created

 

Role과 ClusterRole

 쿠버네티스의 RBAC에서 사용하는 리소스를 살펴보겠습니다. 먼저 Role과 ClusterRole 입니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: testns
  name: pod-reader
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

 Role은 권한의 집합을 나타내는 쿠버네티스 리소스입니다. Role은 규칙(Rule)이라고 부르는 권한 집합을 포함하고 있습니다. 규칙에는 허용할 권한을 추가하는 것만 가능하며 거부하는 규칙은 추가할 수 없습니다. 또한 Role은 항상 특정 네임스페이스 내의 권한을 설정합니다. 그러므로 Role을 생성할 때 반드시 어느 네임스페이스에 생성될 지 지정해야 합니다. (여기서 verbs에 명시된 get, list, watch의 차이가 궁금하신 분은 stackoverflow를 참고하세요.)

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

 ClusterRole은 Role과 유사하지만, 네임스페이스 범위를 벗어난 클러스터 범위의 리소스입니다. 따라서 Role과는 달리 네임스페이스를 지정하지 않고 생성하며, 특정 네임스페이스에 속하지 않는 리소스에 대한 역할을 정의하거나 전체 네임스페이스에 대한 접근 권한을 정의할 때 사용합니다. 네임스페이스에 속하는 리소스와 그렇지 않은 리소스는 아래와 같이 확인할 수 있습니다. 이것은 상호 배타적인 특성으로 네임스페이스에 속하지 않는 리소스이면서 네임스페이스에 속하는 리소스는 존재하지 않습니다. 

# 네임스페이스에 속하는 리소스
$ kubectl api-resources --namespaced=true

# 네임스페이스에 속하지 않는 리소스
$ kubectl api-resources --namespaced=false

 Role과 ClusterRole은 위에서 살펴본 manifest 파일을 사용하여 생성하는 것 외에도 kubectl 명령을 사용하여 생성할 수 있습니다. 다음은 manifest 파일에서 살펴본 것과 동일한 내용으로 Role과 ClusterRole을 생성하는 명령어를 나타냅니다.

# Create Role
$ kubectl create role pod-reader --verb=get --verb=watch --verb=list --resource=pods -n testns
role.rbac.authorization.k8s.io/pod-reader created

# Create ClusterRole
$ kubectl create clusterrole secret-reader --verb=get --verb=watch --verb=list --resource=secrets
clusterrole.rbac.authorization.k8s.io/secret-reader created

 

RoleBinding과 ClusterRoleBinding

 이렇게 생성한 Role과 ClusterRole은 RoleBindingClusterRoleBinding으로 특정 사용자에게 부여할 수 있습니다. 아래 RoleBinding은 testuser에게 testns 네임스페이스의 pod-reader Role을 부여합니다. 

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: testns
subjects:
- kind: User
  name: testuser
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

 RoleBinding 역시 kubectl 명령어를 사용해서 생성할 수 있습니다. RoleBinding을 생성한 후에 kubectl auth can-i 명령으로 사용자가 특정 네임스페이스의 리소스에 대한 권한이 있는지 확인해 봅시다. testuser는 pod에 대한 list는 가능하지만, delete 권한은 pod-reader Role에 추가되지 않은 권한이기 때문에 no로 표시되는것을 알 수 있습니다.

$ kubectl create rolebinding read-pods --role=pod-reader --user=testuser -n testns
rolebinding.rbac.authorization.k8s.io/read-pods created

$ kubectl auth can-i list pods -n testns --as testuser
yes

$ kubectl auth can-i delete pods -n testns --as testuser
no

 RoleBinding을 생성할 때 유의해야할 사항은 다음과 같습니다.

  • User 및 Role이 생성되어 있어야 합니다.
  • User 및 Role의 name 필드는 대소문자를 구분합니다.
  • subject 필드에는 하나 이상의 사용자, 사용자 그룹, Service Account가 올 수 있습니다.
  • RoleBinding을 생성한 이후에는 roleRef에서 Role 혹은 ClusterRole을 변경할 수 없습니다. 변경이 필요한 경우 RoleBinding을 제거한 다음 새로 만들어야 합니다.
  • RoleBinding의 roleRef에는 Role이 아니라 ClusterRole이 올 수도 있습니다. 이런 경우 ClusterRole에 명시된 권한이 RoleBinding이 속한 네임스페이스의 리소스에만 적용됩니다. 

 여기서 마지막 항목을 주목해서 볼 필요가 있습니다. 여러 네임스페이스에 공통으로 사용되는 Role은 각 네임스페이스별로 중복해서 생성하지 않고 이렇게 ClusterRole 하나를 생성한 다음, 각 네임스페이스에서 RoleBinding을 생성하여 부여할 수 있습니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-secrets
  namespace: testns
subjects:
- kind: User
  name: testuser
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

 아래는 ClusterRole을 사용한 RoleBinding 예시입니다. RoleBinding을 생성한 직후에는 secret에 대한 list가 가능하지만, RoleBinding을 삭제한 이후에는 list가 불가능합니다.  

$ kubectl create rolebinding read-secrets --clusterrole=secret-reader --user=testuser -n testns
rolebinding.rbac.authorization.k8s.io/read-pods created

$ kubectl auth can-i list secrets -n testns --as testuser
yes

$ k delete rolebinding read-secrets -n testns
rolebinding.rbac.authorization.k8s.io "read-secrets" deleted

$ kubectl auth can-i list secrets -n testns --as testuser
no

 

 이와 유사하게, 전체 클러스터에 대한 접근 권한을 부여할 때에는 ClusterRoleBinding을 사용합니다. 

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: read-secrets-global
subjects:
- kind: User
  name: testuser
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

 testns 뿐만 아니라 다른 네임스페이스의 secret도 list가 가능한 것을 확인할 수 있습니다.

$ kubectl create clusterrolebinding read-secrets-global --clusterrole=secret-reader --user=testuser -n testns
rolebinding.rbac.authorization.k8s.io/read-pods created

$ kubectl auth can-i list secrets -n testns --as testuser
yes

$ kubectl auth can-i list secrets -n default --as testuser
yes

 

요약

 여기까지 쿠버네티스의 RBAC에 관한 기본 내용을 살펴보았습니다. 권한을 Role과 ClusterRole의 형태로 정의하고 이를 RoleBinding과 ClusterRoleBinding으로 사용자나 사용자 그룹 혹은 Service Account에 부여하였습니다. 하지만 이 외에도 쿠버네티스는 접근 제어와 관련된 다양한 기능을 추가적으로 제공합니다. 이러한 기능은 다음 글에서 이어서 살펴보겠습니다.

 


References

[1] https://kubernetes.io/docs/concepts/security/controlling-access/

 

Controlling Access to the Kubernetes API

This page provides an overview of controlling access to the Kubernetes API. Users access the Kubernetes API using kubectl, client libraries, or by making REST requests. Both human users and Kubernetes service accounts can be authorized for API access. When

kubernetes.io

[2] https://kubernetes.io/docs/reference/access-authn-authz/authentication/

 

Authenticating

This page provides an overview of authenticating. Users in Kubernetes All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users. It is assumed that a cluster-independent service manages normal users in t

kubernetes.io

[3] https://kubernetes.io/docs/reference/access-authn-authz/authorization/

 

Authorization Overview

Learn more about Kubernetes authorization, including details about creating policies using the supported authorization modules. In Kubernetes, you must be authenticated (logged in) before your request can be authorized (granted permission to access). For i

kubernetes.io

[4] https://kubernetes.io/docs/reference/access-authn-authz/rbac/

 

Using RBAC Authorization

Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within your organization. RBAC authorization uses the rbac.authorization.k8s.io API group to drive authorization decis

kubernetes.io

 

댓글