쿠버네티스 RBAC: 역할 기반 접근 제어 완벽 가이드

RBAC 소개

쿠버네티스에서는 ABAC(특성 기반 접근 제어), RBAC(역할 기반 접근 제어), Webhook, Node, AlwaysDeny(항상 거부) 및 AlwaysAllow(항상 허용)의 6가지 모드로 인증이 구현됩니다.

1.6 버전부터 쿠버네티스는 기본적으로 RBAC 접근 제어 정책을 활성화합니다. 1.8 버전부터 RBAC은 안정적인 기능으로 자리 잡았습니다. –authorization-mode=RBAC 옵션을 설정하여 RBAC을 활성화할 수 있습니다.

RBAC API에서 인증은 다음 단계로 진행됩니다:

  1. 역할 정의: 역할을 정의할 때 해당 역할이 리소스에 대한 접근 제어 규칙을 지정합니다.
  2. 역할 바인딩: 주체(주로 사용자)와 역할을 바인딩하여 사용자에게 접근 권한을 부여합니다.

역할과 클러스터 역할

RBAC API에서 역할은 권한 집합을 나타내는 규칙을 포함합니다. 여기서는 권한이 부여되는 방식만 있으며 거부되는 설정은 없습니다. 쿠버네티스에는 일반 역할과 클러스터 역할의 두 가지 유형이 있습니다.

Role을 사용하여 특정 네임스페이스 내에서 역할을 정의하거나, ClusterRole을 사용하여 클러스터 전체 범위의 역할을 정의할 수 있습니다. 하나의 역할은 단일 네임스페이스의 리소스에 대한 접근 권한만 부여할 수 있습니다.

클러스터 역할(ClusterRole)은 다음과 같은 리소스에 대한 권한을 부여받을 수 있습니다:

  • 클러스터 범위 리소스 (예: Node)
  • 비 리소스 엔드포인트 (예: "/healthz")
  • 클러스터의 모든 네임스페이스에 있는 리소스 (예: Pod)

역할 바인딩과 클러스터 역할 바인딩

역할 바인딩은 하나 이상의 사용자와 역할을 바인딩하여 사용자에게 권한을 부여하는 데 사용됩니다. 주체는 사용자, 그룹 또는 서비스 계정으로 구분됩니다. 역할 바인딩도 일반 역할 바인딩과 클러스터 역할 바인딩으로 나뉩니다. 역할 바인딩은 동일한 네임스페이스에 있는 역할만 참조할 수 있습니다.

역할 바인딩은 클러스터 역할을 참조하여 접근 권한을 부여할 수도 있습니다. 이 경우 주체가 리소스에 대한 접근이 현재 네임스페이스로 제한됩니다. 이를 통해 관리자는 클러스터 전체의 공통 역할 집합을 정의한 후 여러 네임스페이스에서 재사용할 수 있습니다.

클러스터 역할은 클러스터 수준 및 전체 네임스페이스에서 권한 부여에 사용될 수 있습니다.

리소스

쿠버네티스의 주요 리소스에는 Pods, Nodes, Services, Deployment, Replicasets, Statefulsets, Namespace, Persistents, Secrets 및 ConfigMaps 등이 포함됩니다. 또한 일부 리소스에는 하위 리소스가 존재하며, 예를 들어 Pod에는 log 하위 리소스가 있습니다.

주체

RBAC 인증의 주체는 그룹, 사용자 또는 서비스 계정일 수 있습니다. 사용자는 "alice", "bob@example.com" 등 문자열로 표시되며, 구체적인 형식은 관리자가 인증 모듈에서 구성한 사용자 이름에 따라 다릅니다. system:은 쿠버네티스 시스템 사용을 위해 예약되어 있으므로 사용자 접두사로 사용할 수 없습니다. 그룹도 인증 모듈에서 제공되며 사용자와 유사한 형식을 가집니다.

기본 예제

1. RoleBinding을 사용하여 사용자를 Role에 바인딩하기

명령어 도움말 및 형식 확인

[root@k8s-master01 ~]# kubectl create role -h  # role 생성 명령어 도움말 및 간단한 예제 확인
[root@k8s-master01 RBAC]# kubectl create role pod-reader --verb=get,list,watch --resource=pods --dry-run -o yaml  # -o 매개변수로 yaml 형식 내보내기
[root@k8s-master01 RBAC]# cat role-demo.yaml  # 완성된 yaml 파일
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: default  # 네임스페이스 이름
rules:
- apiGroups:        # 포함할 API 그룹, 비작성 시 모든 그룹 포함
  - ""
  resources:  # 포함할 리소스
  - pods
  verbs:      # 위 리소스에 허용할 작업
  - get
  - list
  - watch

role 생성

[root@k8s-master01 RBAC]# kubectl apply -f role-demo.yaml 
role.rbac.authorization.k8s.io "pod-reader" created
[root@k8s-master01 RBAC]# kubectl get role   # role 정보 확인
NAME          AGE
pod-reader   8s
[root@k8s-master01 RBAC]# kubectl describe role pod-reader  # pod-reader 상세 정보 확인
Name:         pod-reader
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"rbac.authorization.k8s.io/v1","kind":"Role","metadata":{"annotations":{},"name":"pod-reader","namespace":"default"},"rules":[{"apiGroup...
PolicyRule:
  Resources  Non-Resource URLs  Resource Names  Verbs
  ---------     -----------------         --------------          -----
  pods          []                            []                         [get list watch]

RoleBinding 생성하여 사용자 testuser(이전 장서비스 계정에서 생성된 사용자)를 pod-reader 역할에 바인딩

[root@k8s-master01 ~]# kubectl create rolebinding -h  # 명령어 도움말 확인
kubectl create rolebinding testuser-read-pods --role=pod-reader --user=testuser  --dry-run -o yaml  # testuser-read-pods라는 이름의 rolebinding 생성
[root@k8s-master01 RBAC]# cat rolebinding-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: testuser-read-pods
roleRef:   # role 참조, 어떤 role을 참조할지 지정
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: pod-reader
subjects:  # 작업을 실행하는 주체
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: testuser
[root@k8s-master01 RBAC]# kubectl describe rolebinding testuser-read-pods 
Name:         testuser-read-pods
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"rbac.authorization.k8s.io/v1","kind":"RoleBinding","metadata":{"annotations":{},"name":"testuser-read-pods","namespace":"default"},"ro...
Role:
  Kind:  Role
  Name:  pod-reader
Subjects:
  Kind  Name        Namespace
  ----  ----        ---------
  User  testuser

작업 확인

[root@k8s-master01 RBAC]# kubectl config use-context testuser@kubernetes # testuser 사용자로 컨텍스트 전환
Switched to context "testuser@kubernetes".
[root@k8s-master01 RBAC]# kubectl get pods    # 현재 네임스페이스의 pod 정보 확인
NAME                             READY     STATUS    RESTARTS   AGE
myapp-deploy-5cfd895984-262kz    1/1       Running   0          3d
myapp-deploy-5cfd895984-7whdn    1/1       Running   0          3d
myapp-deploy-5cfd895984-lg8sh    1/1       Running   0          3d
myapp-deploy-5cfd895984-m7h5j    1/1       Running   0          3d
myapp-deploy-5cfd895984-zd9cm    1/1       Running   0          3d
[root@k8s-master01 RBAC]# kubectl get pods -n kube-system    # 다른 네임스페이스 pod 정보 확인 시 권한 없음 확인
Error from server (Forbidden): pods is forbidden: User "testuser" cannot list pods in the namespace "kube-system"

2. ClusterRoleBinding을 사용하여 사용자를 ClusterRole에 바인딩하기

ClusterRole 생성

[root@k8s-master01 RBAC]# kubectl config use-context kubernetes-admin@kubernetes # 컨텍스트 전환
Switched to context "kubernetes-admin@kubernetes".
[root@k8s-master01 RBAC]# kubectl create clusterrole -h
[root@k8s-master01 RBAC]# kubectl create clusterrole cluster-reader --verb=get,list,watch --resource=pods -o yaml --dry-run
[root@k8s-master01 RBAC]# cat clusterrole-cluster.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: cluster-reader  # ClusterRole은 클러스터 수준이므로 namespace 정의 불가
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
[root@k8s-master01 RBAC]# kubectl apply -f clusterrole-cluster.yaml 
[root@k8s-master01 RBAC]# useradd admin
[root@k8s-master01 RBAC]# cp -rp ~/.kube/ /home/admin
[root@k8s-master01 RBAC]# chown -R admin:admin /home/admin
[root@k8s-master01 RBAC]# su - admin
[admin@k8s-master01 ~]$ kubectl config use-context testuser@kubernetes
[admin@k8s-master01 ~]$ kubectl config view

ClusterRoleBinding 생성하여 사용자 testuser를 cluster-reader ClusterRole에 바인딩

[root@k8s-master01 RBAC]# kubectl delete rolebinding testuser-read-pods   # root 사용자
[admin@k8s-master01 ~]$ kubectl get pods   # admin 사용자로 확인
Error from server (Forbidden): pods is forbidden: User "testuser" cannot list pods in the namespace "default"
[root@k8s-master01 RBAC]# kubectl create clusterrolebinding -h
[root@k8s-master01 RBAC]# kubectl create clusterrolebinding testuser-read-all-pods --clusterrole=cluster-reader --user=testuser --dry-run -o yaml # testuser-read-all-pods라는 clusterrolebinding 생성
[root@k8s-master01 RBAC]# cat clusterrolebinding-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  creationTimestamp: null
  name: testuser-read-all-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: testuser
[root@k8s-master01 RBAC]# kubectl apply -f clusterrolebinding-demo.yaml 
[root@k8s-master01 RBAC]# kubectl describe clusterrolebinding testuser-read-all-pods

확인

# admin 사용자 터미널에서
[admin@k8s-master01 ~]$ kubectl get pods  # 현재 네임스페이스 pod 정보 확인 가능
NAME                             READY     STATUS    RESTARTS   AGE
myapp-deploy-5cfd895984-262kz    1/1       Running   0          3d
myapp-deploy-5cfd895984-7whdn    1/1       Running   0          3d
myapp-deploy-5cfd895984-lg8sh    1/1       Running   0          3d
myapp-deploy-5cfd895984-m7h5j    1/1       Running   0          3d
myapp-deploy-5cfd895984-zd9cm    1/1       Running   0          3d
[admin@k8s-master01 ~]$ kubectl get pods -n ingress-nginx  # 다른 네임스페이스 pod 정보 확인 가능
NAME                                        READY     STATUS    RESTARTS   AGE
default-http-backend-66c4fbf5b4-m8d6j       1/1       Running   0          24d
nginx-ingress-controller-64bcff8657-6j4tq   1/1       Running   0          24d
[admin@k8s-master01 ~]$ kubectl delete pod myapp-deploy-5cfd895984-262kz  # pod 삭제 불가
Error from server (Forbidden): pods "myapp-deploy-5cfd895984-262kz" is forbidden: User "testuser" cannot delete pods in the namespace "default"

3. RoleBinding을 사용하여 ClusterRole 바인딩

RoleBinding(ClusterRole 사용 및 존재) 생성하여 사용자를 ClusterRole에 바인딩

[root@k8s-master01 RBAC]# kubectl delete clusterrolebinding testuser-read-all-pods # 충돌 방지를 위해 이전 clusterrolebinding 삭제
clusterrolebinding.rbac.authorization.k8s.io "testuser-read-all-pods" deleted
[root@k8s-master01 RBAC]# kubectl create rolebinding testuser-read-pods --clusterrole=cluster-reader --user=testuser --dry-run -o yaml
[root@k8s-master01 RBAC]# cat rolebinding-cluster-demo.yaml 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: testuser-read-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-reader
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: testuser
[root@k8s-master01 RBAC]# kubectl apply -f rolebinding-cluster-demo.yaml 
rolebinding.rbac.authorization.k8s.io "testuser-read-pods" created
[root@k8s-master01 RBAC]# kubectl describe rolebinding testuser-read-pods

확인:

# admin 사용자 터미널에서
[admin@k8s-master01 ~]$ kubectl get pods  # 현재 네임스페이스 pod 정보 확인 가능
NAME                             READY     STATUS    RESTARTS   AGE
myapp-deploy-5cfd895984-262kz    1/1       Running   0          3d
myapp-deploy-5cfd895984-7whdn    1/1       Running   0          3d
myapp-deploy-5cfd895984-lg8sh    1/1       Running   0          3d
myapp-deploy-5cfd895984-m7h5j    1/1       Running   0          3d
myapp-deploy-5cfd895984-zd9cm    1/1       Running   0          3d
[admin@k8s-master01 ~]$ kubectl get pods -n ingress-nginx   # 다른 네임스페이스 정보 확인 불가
Error from server (Forbidden): pods is forbidden: User "testuser" cannot list pods in the namespace "ingress-nginx"

4. RoleBinding을 사용하여 시스템 기본 ClusterRole 바인딩

[root@k8s-master01 RBAC]# kubectl get clusterrole  # 현재 클러스터의 clusterrole 확인
[root@k8s-master01 RBAC]# kubectl create rolebinding default-ns-admin --clusterrole=admin --user=testuser  --dry-run -o yaml # admin clusterrole에 testuser 사용자 바인딩
[root@k8s-master01 RBAC]# cat rolebinding-cluster-admin-demo.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: default-ns-admin
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: User
  name: testuser
[root@k8s-master01 RBAC]# kubectl apply -f rolebinding-cluster-admin-demo.yaml
[root@k8s-master01 RBAC]# kubectl describe rolebinding default-ns-admin

확인

# admin 사용자 터미널에서
[admin@k8s-master01 ~]$ kubectl get pods  # 현재 네임스페이스 pod 정보 확인 가능
NAME                             READY     STATUS    RESTARTS   AGE
myapp-deploy-5cfd895984-262kz    1/1       Running   0          3d
myapp-deploy-5cfd895984-7whdn    1/1       Running   0          3d
myapp-deploy-5cfd895984-lg8sh    1/1       Running   0          3d
myapp-deploy-5cfd895984-m7h5j    1/1       Running   0          3d
myapp-deploy-5cfd895984-zd9cm    1/1       Running   0          3d
......
[admin@k8s-master01 ~]$ kubectl delete pod myapp-deploy-5cfd895984-262kz   # 현재 네임스페이스 pod 삭제 가능
pod "myapp-deploy-5cfd895984-262kz" deleted
[admin@k8s-master01 ~]$ kubectl get deploy  # 네임스페이스의 다른 리소스 확인 가능
NAME              DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deploy    5               5              5                   5                 3d
[admin@k8s-master01 ~]$ kubectl delete deployment nginx-deploy  # 현재 네임스페이스의 다른 리소스 삭제 가능
deployment.extensions "nginx-deploy" deleted
[admin@k8s-master01 ~]$ kubectl get pods -n kube-system  # 다른 네임스페이스에는 권한 없음
Error from server (Forbidden): pods is forbidden: User "testuser" cannot list pods in the namespace "kube-system"

Role, ClusterRole, RoleBinding, ClusterRoleBinding의 시스템 관계

[root@k8s-master01 RBAC]# kubectl get clusterrolebinding # 클러스터의 clusterrolebinding 확인
NAME                                                   AGE
cluster-admin                                          31d
......
[root@k8s-master01 RBAC]# kubectl get clusterrolebinding cluster-admin -o yaml  # cluster-admin clusterrolebinding 정보 확인
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  creationTimestamp: 2018-10-30T02:32:22Z
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: cluster-admin
  resourceVersion: "103"
  selfLink: /apis/rbac.authorization.k8s.io/v1/clusterrolebindings/cluster-admin
  uid: 07b1d436-dbec-11e8-8969-5254001b07db
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group   # 타입은 그룹
  name: system:masters   # 이 그룹에는 kubernetes-admin 사용자가 포함되어 있으며, 이는 기본 현재 사용자
[root@k8s-master01 RBAC]# kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: https://172.16.150.212:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin # 기본 현재 사용자
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: testuser
  name: testuser@kubernetes
current-context: kubernetes-admin@kubernetes  # 현재 사용하는 sa
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: testuser
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
[root@k8s-master01 RBAC]# cd /etc/kubernetes/pki/
[root@k8s-master01 pki]# openssl x509  -in ./apiserver-kubelet-client.crt -text -noout # 인서트 내용 확인
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 3187679453637891293 (0x2c3ce992f3e5d4dd)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=kubernetes
        Validity
            Not Before: Oct 30 02:32:03 2018 GMT
            Not After : Oct 30 02:32:03 2019 GMT
        Subject: O=system:masters, CN=kube-apiserver-kubelet-client  # kubernetes-admin 사용자가 system:master 그룹에 속한 이유는 인서트에 정의되어 있음, O는 그룹을 의미
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
              .....

RoleBinding 또는 ClusterRoleBinding의 객체가 서비스 계정인 경우, pod(spec.serviceAccountName에 정의)가 이 서비스 계정 이름으로 시작되면 해당 pod의 애플리케이션도 해당 서비스 계정의 권한을 가집니다. 즉, 해당 서비스 계정에 바인딩된 Role 또는 ClusterRole의 권한을 갖게 됩니다. 시스템의 특수 pod는 이러한 설정이 필요할 수 있습니다. 예를 들어, 클러스터 생성 시 사용된 flannel 네트워크 플러그인을 예로 설명합니다.

flannel 구성 확인

[root@k8s-master01 kubernetes]# cat kube-flannel.yml   # flannel 구성 파일
---
kind: ClusterRole   # ClusterRole 정의
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
rules:
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - get
  - apiGroups:
      - ""
    resources:
      - nodes
    verbs:
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - nodes/status
    verbs:
      - patch
---
kind: ClusterRoleBinding  # ClusterRoleBinding 정의
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-system
---
apiVersion: v1 
kind: ServiceAccount  # ServiceAccount 정의
metadata:
  name: flannel
  namespace: kube-system
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
---
......(이하 생략)

flannel 생성 pod 정보 확인

[root@k8s-master01 kubernetes]# kubectl get pod -n kube-system 
NAME                                   READY     STATUS    RESTARTS   AGE
etcd-k8s-master01                      1/1       Running   0          32d
kube-apiserver-k8s-master01            1/1       Running   0          32d
kube-controller-manager-k8s-master01   1/1       Running   0          7d
kube-dns-86f4d74b45-72kdh              3/3       Running   0          32d
kube-flannel-ds-amd64-847wt            1/1       Running   0          32d
kube-flannel-ds-amd64-9v9t6            1/1       Running   0          32d
kube-flannel-ds-amd64-k4blq            1/1       Running   0          32d
kube-proxy-8l9tf                       1/1       Running   0          32d
kube-proxy-m6pqm                       1/1       Running   0          32d
kube-proxy-scj8n                       1/1       Running   0          32d
kube-scheduler-k8s-master01            1/1       Running   0          32d
[root@k8s-master01 kubernetes]# kubectl get pod kube-flannel-ds-amd64-847wt -n kube-system -o yaml
......(생략)
  serviceAccount: flannel
  serviceAccountName: flannel  # 현재 pod가 시작될 때 컨테이너 프로세스는 API서버와 통신할 때 serviceAccountName의 계정으로 연결되어 해당 서비스 계정의 권한을 얻음
.....(생략)

다음은 사용자가 다른 Role 및 Binding에 바인딩될 때 가지는 권한 경계를 나타내는 표입니다

사용자 바인딩 타입 역할 타입 권한 범위
RoleBinding Role 네임스페이스
ClusterRoleBinding ClusterRole 클러스터
RoleBinding ClusterRole 네임스페이스

태그: 쿠버네티스 RBAC 역할기반접근제어

6월 14일 01:09에 게시됨