Kubernetes

RBAC 과 Service Accounts 를 사용하여 사용자 권한 제어하기 (Kubernetes v1.24 이상)

seungkyua@gmail.com 2023. 8. 17. 15:59
반응형

Kubernetes 에서 ServiceAccount 를 생성하면 1.22 버전까지는 자동으로 token 을 생성하였다. 그러나 1.23 부터는 토큰을 자동으로 생성해 주지 않기 때문에 수동으로 생성해야 한다.

이 바뀐 기능은 ServiceAcount 와 RBAC 을 연동하여 권한을 제어하고자 할 때 문제가 되므로 수동으로 만드는 방법을 살펴본다.

1. 네임스페이스 - SA 생성

먼저 테스트할 네임스페이스를 만든다.

$ kubectl create ns ask

ask 네임스페이스에 서비스 어카운트를 생성한다.

$ kubectl create sa ask-sa -n ask

1.24 버전부터는 sa 를 생성해도 token 이 자동으로 생성되지 않는다.

참고: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md#no-really-you-must-read-this-before-you-upgrade

token 은 Secret 타입이므로 Secret 을 조회해 보면 token이 자동 생성되지 않았음을 알 수 있다.

참고: https://kubernetes.io/docs/concepts/configuration/secret/#service-account-token-secrets

2. Token 생성

ask-sa 에 해당하는 token 을 수동으로 생성한다.

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
  name: ask-sa
  namespace: ask
  annotations:
    kubernetes.io/service-account.name: ask-sa
type: kubernetes.io/service-account-token
EOF

token 을 생성할 때 어노테이션으로 연결될 서비스 어카운트를 지정한다.

$ kubectl get secret -n ask
NAME     TYPE                                  DATA   AGE
ask-sa   kubernetes.io/service-account-token   3      7s 

조회를 하면 service-account-toke 타입으로 secret 이 생성되었음을 알 수 있다.

혹은 token 을 수동으로 생성하는 방법도 있다.

$ kubectl create token ask-sa --bound-object-kind Secret --bound-object-name ask-sa --duration=999999h  -n ask

------- output -----------
xxxxxxxxxxxxxxxxxxxxxxx

base64 로 변환하여 secret 에 data.token 값으로 저장한다.

$ kubectl create token ask-sa --bound-object-kind Secret --bound-object-name ask-sa --duration=999999h  -n ask | base64 -w 0

------- output -----------
xxxxxxxxxxxxxxxxxxxxxxx
$ kubectl edit secret ask-sa -n ask
...
data:
  token: xxxxxxxxxxxxxxxxxxxx
...

3. Role 과 RoleBinding 생성

Role 과 RoleBinding 은 네임스페이스 별로 연결된다. 그러므로 생성한 권한은 해당 네임스페이스에만 권한이 주어진다.

먼저 Role 을 생성한다.

 $ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: ask-role
  namespace: ask
rules:
- apiGroups: ["", "*"]
  resources: ["*"]
  verbs: ["*"]
EOF

apiGroup 에서 ""core API group 으로 다음의 출력으로 확인할 수 있다.

APIVERSION 이 v1 인 리소스들이 core API group 이 되면 이들에 대해서 권한을 사용하겠다는 뜻이다.

$ kubectl api-resources -o wide
NAME                              SHORTNAMES       APIVERSION      NAMESPACED   KIND                             VERBS
bindings                                           v1              true         Binding                          [create]
componentstatuses                 cs               v1              false        ComponentStatus                  [get list]
configmaps                        cm               v1              true         ConfigMap                        [create delete deletecollection get list patch update watch]
endpoints                         ep               v1              true         Endpoints                        [create delete deletecollection get list patch update watch]
events                            ev               v1              true         Event                            [create delete deletecollection get list patch update watch]
limitranges                       limits           v1              true         LimitRange                       [create delete deletecollection get list patch update watch]
namespaces                        ns               v1              false        Namespace                        [create delete get list patch update watch]
nodes                             no               v1              false        Node                             [create delete deletecollection get list patch update watch]
persistentvolumeclaims            pvc              v1              true         PersistentVolumeClaim            [create delete deletecollection get list patch update watch]
persistentvolumes                 pv               v1              false        PersistentVolume                 [create delete deletecollection get list patch update watch]
pods                              po               v1              true         Pod                              [create delete deletecollection get list patch update watch]
podtemplates                                       v1              true         PodTemplate                      [create delete deletecollection get list patch update watch]
replicationcontrollers            rc               v1              true         ReplicationController            [create delete deletecollection get list patch update watch]
resourcequotas                    quota            v1              true         ResourceQuota                    [create delete deletecollection get list patch update watch]
secrets                                            v1              true         Secret                           [create delete deletecollection get list patch update watch]
serviceaccounts                   sa               v1              true         ServiceAccount                   [create delete deletecollection get list patch update watch]
services                          svc              v1              true         Service                          [create delete deletecollection get list patch update watch]

다음은 Rolebinding을 생성한다.

$ cat <<EOF | kubectl apply -f - 
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ask-role-binding
  namespace: ask
subjects:
- kind: ServiceAccount
  name: ask-sa
  namespace: ask
roleRef:
  kind: Role
  name: ask-role
  apiGroup: rbac.authorization.k8s.io
EOF

ServiceAcount 인 ask-saask-role Role 을 서로 연결 시킨 다는 의미이다.

이렇게 되면 이제 ask-sa sa 는 ask-role role 에 대한 권한만을 사용할 수 있다.

4. kubeconfig 생성

sa 를 만들었으니 이를 연동할 kubeconfig 를 만들어 본다.

token 을 조회해 보자.

$ kubectl get secret -n ask ask-sa -ojsonpath={.data.token} | base64 -d

----- output -----
xxxxxxxxxxxxxxxxxxxxxxxxx

token 값으로 kubeconfig 의 user 접속 token 에 넣는다.


apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxxxxxxxxxxxxxxxxxxxxxxx
server: https://xxxxxxxxxx.ap-northeast-2.eks.amazonaws.com
  name: mycluster
contexts:
- context:
    cluster: mycluster
    user: ask-sa
    namespace: ask
  name: mycluster
current-context: mycluster
kind: Config
users:
- name: ask-sa
  user:
    token: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

위의 kubeconfig 로 접속하면 ask 네임스페이스에 대해서 kubectl 명령어를 실행할 수 있다.

$ kubectl --kubeconfig ask.kubeconfig get pods
Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:ask:ask-sa" cannot list resource "pods" in API group "" in the namespace "default"

default 네임스페이스에는 권한이 없으므로 권한 없음 에러가 리턴된다.

$ kubectl --kubeconfig ask.kubeconfig get pods -n ask
No resources found in ask namespace.

ask 네임스페이스의 파드는 정상적으로 조회된다.

반응형