フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【図解化】KubernetesのRBACについてわかりやすく整理します

こちらの本で紹介されているRBACについてkubernetes-dashboardの例を交えながら紹介します。

RBACとは

Role Based Access Controlの略で最近流行ってきてる権限周りの単語です。

を許可するのか?という意味です。

この図のように、それぞれのユーザー(人)と役割を紐づけて管理するのがRBACです。(一番右の社長っぽい人には全ての役割が紐づいていますね)

f:id:lirlia:20200413185334p:plain

KubernetesにおけるRBAC

Kubernetesには様々なリソースが存在します。これらに対してユーザごとに権限を与えたり、お互いのリソース間でやりとりをさせるためにRBACは利用されています。

ちなみにKubernetesではユーザーと役割を紐づけるためにRoleBindingというものを使って管理しています。

f:id:lirlia:20200413192650p:plain

kubernetesのユーザーについて

kuberneteには2種類のUserAccountServiceAccountが存在します。

それぞれの違いは以下の通り

  • UserAccount → 外部のアカウントからkuberneteクラスタを制御する場合のユーザー(AWSのIAMなど)
  • ServiceAccount → kubernetesの中で利用するユーザー

そのため基本的にはServiceAccountを知っておく必要があります。

ServiceAccountのデフォルト値を確認する

httpdのpodを起動して見ましょう。

[root@master k8s-role]# kubectl run httpd-test -o yaml --image httpd                 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: "2020-04-13T16:11:11Z"
  labels:
    run: httpd-test
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:metadata:
        f:labels:
          .: {}
          f:run: {}
      f:spec:
        f:containers:
          k:{"name":"httpd-test"}:
            .: {}
            f:image: {}
            f:imagePullPolicy: {}
            f:name: {}
            f:resources: {}
            f:terminationMessagePath: {}
            f:terminationMessagePolicy: {}
        f:dnsPolicy: {}
        f:enableServiceLinks: {}
        f:restartPolicy: {}
        f:schedulerName: {}
        f:securityContext: {}
        f:terminationGracePeriodSeconds: {}
    manager: kubectl
    operation: Update
    time: "2020-04-13T16:11:11Z"
  name: httpd-test
  namespace: default
  resourceVersion: "139719"
  selfLink: /api/v1/namespaces/default/pods/httpd-test
  uid: 176c17d6-d73c-46f4-8db2-e936ff4dfac3
spec:
  containers:
  - image: httpd
    imagePullPolicy: Always
    name: httpd-test
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: default-token-8b6g2
      readOnly: true
  dnsPolicy: ClusterFirst
  enableServiceLinks: true
  priority: 0
  restartPolicy: Always
  schedulerName: default-scheduler
  securityContext: {}
  **serviceAccount: default**
  serviceAccountName: default
  terminationGracePeriodSeconds: 30
  tolerations:
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  volumes:
  - name: default-token-8b6g2
    secret:
      defaultMode: 420
      secretName: default-token-8b6g2
status:
  phase: Pending
  qosClass: BestEffort

するとserviceAccount: defaultとかかれています。これはnamespaceに初めから存在するdefaultのユーザです。

実際にServiceAccountを作ってみる

root@master k8s-role]# kubectl create serviceaccount sample-account
serviceaccount/sample-account created
  
[root@master k8s-role]# kubectl get serviceaccount sample-account
NAME   SECRETS   AGE
sample-account   1         10s

このように作成できます。そして作成したアカウントを見てみるとsecretsというものが増えています。

[root@master k8s-role]# kubectl get serviceaccount sample-account -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2020-04-13T15:48:52Z"
  name: test
  namespace: default
  resourceVersion: "136799"
  selfLink: /api/v1/namespaces/default/serviceaccounts/sample-account
  uid: f62a0897-e232-4989-ba16-28bf245dd7bf
**secrets:**
**- name: sample-account-token-lhbsd**

これはkubernetesが勝手に作成したものでトークン証明書です。

[root@master k8s-role]# kubectl get secrets sample-account-token-lhbsd -o yaml
apiVersion: v1
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUN5RENDQWJDZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwcmRXSmwKY201bGRHVnpNQjRYRFRJd01EUXhNakV3TXpRME4xb1hEVE13TURReE1ERXdNelEwTjFvd0ZURVRNQkVHQTFVRQpBeE1LYTNWaVpYSnVaWFJsY3pDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBT214CmdaL0JFY0dWellQaGRuSTBwZlJyamRxdkVoU2c3S0RtTEFNMzc3SXpoT2Jvb1VMU2p2TEZLQU5oOEJGMDJYREEKZ3NaMFBXSmIyTmk1bUI0cXBCYXROWjNkeGdSNjlhbVJ1N3Zibi9USFg0T3lhcHVqNG1KcWFqc0tRQjRQQ3FxYgpYVXladFRKU1cwNXpQWjVrdWNISk93TkF5M1EwdGtJRlkraFRLeTBnL01OS3NHN1RmcDZDNHV4ZG9TRmZ3YmQ1CitmN1J0OHFRVUcwNkJsYmVzcUYvQk5zL2pobTY2SmZLU0Q3c2dDS215VWEvSkhBV09JM09xMURpUS8ybktJMXYKV1VZdjJ3QWE5bTRYVlpMY212dGpBRE4va3FCTlo4R2kyYXhSOTF4cDlkd3l5VkZ5LzdieFZhUUNwcVFqSkFkOApKT3RTaEtvaUNzZ0Vld3pMdTRNQ0F3RUFBYU1qTUNFd0RnWURWUjBQQVFIL0JBUURBZ0trTUE4R0ExVWRFd0VCCi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFMaHF0VnVtYkpTOGthYWlCMW5oZGtHWXZNQkIKWWVPUFdRdW95b2w0NkppWUM5b3Q4V0p4S0tmNGU0UVFOUzlPVkI2Umc1M0RWSm9SVXp4NTlqdytOMm84bjJKTwoxQmxZdjd1SlhMWFBrM3FMUnRxaEtDV3g3RHFiU0t5SVJxZ0M4b0JUNnN4eUVManFySGpOL0J4eTE5b0RvYkhMCitBWnZ4NDBwUFB5WHU5b1QyTEFxSE0wZHorM0lBU2E4d1p5bVUrZ0xKQnVPQlZNY2lCc3FvYldUTTVEd1dOeFAKV3kzTHFPdVR4T0ZvTG5RWDg3Rm0vQjhXSVV0bkEwSUxVTWsrc0RoUjRhMDVranFvdWx2Ujd5Rk5EM2ZPdzM2Twp4eGpsNVZxNHpFTVhnam5MUTNmc2pVSnY5bjNqNllDSFlLdjFVQWo2OVI3UlFoMmE3NzNQRWhqRUxhVT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
  namespace: ZGVmYXVsdA==
  token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklrc3diVE5KUmpGSFgxSkljbUZRV2tkMFJrVmlZV3hUTVMxdmNUaGFhM0JIWVVObloxUmFjM2xvVFVraWZRLmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJblJsYzNRdGRHOXJaVzR0YkdoaWMyUWlMQ0pyZFdKbGNtNWxkR1Z6TG1sdkwzTmxjblpwWTJWaFkyTnZkVzUwTDNObGNuWnBZMlV0WVdOamIzVnVkQzV1WVcxbElqb2lkR1Z6ZENJc0ltdDFZbVZ5Ym1WMFpYTXVhVzh2YzJWeWRtbGpaV0ZqWTI5MWJuUXZjMlZ5ZG1salpTMWhZMk52ZFc1MExuVnBaQ0k2SW1ZMk1tRXdPRGszTFdVeU16SXRORGs0T1MxaVlURTJMVEk0WW1ZeU5EVmtaRGRpWmlJc0luTjFZaUk2SW5ONWMzUmxiVHB6WlhKMmFXTmxZV05qYjNWdWREcGtaV1poZFd4ME9uUmxjM1FpZlEuTWZGUERYaXMxZFpjVWtmRV9fczI1NkpKLTNuN3Rfd21qVUdueHY1dHdKTEc5UF9LQVJtTjMyZmRFXzM1QTJRaUh1YUFSRjhfMktzTXhqSXdWbk9KZHlrOXFnblRxbjdfd0xZVFVGNHlNNlNNbUFCLUVKVmdpRWV3YmtqZW1BT3VBUzlfZFY4amxWTzV1ZzN5NkJmY003QTBLT2ZhN3lBdElhTF9GbVhxMkpOaTVDa0NNRUFKbDAxakZkTFJaQ25BNjVjTkFIMjlXZmNaUXpWTkx3ZnVnbVoySXhfQVhjWHVyTHJHNzNKVU5WNE9DdUItOFFfcVozeUNTZldOQ0taUGJJczRxbjMxQmkwb21IdGFMX0c3ZmU3S05qWEZMb18yd2pJZkxxTXFPdWtzYlNLVDRiLWRHaUxqNU1LVk9UbVlBWENPMmh5SzQ5Z1RNZERNVFc1ZXlR
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: sample-account
    kubernetes.io/service-account.uid: f62a0897-e232-4989-ba16-28bf245dd7bf
  creationTimestamp: "2020-04-13T15:48:52Z"
  managedFields:
  - apiVersion: v1
    fieldsType: FieldsV1
    fieldsV1:
      f:data:
        .: {}
        f:ca.crt: {}
        f:namespace: {}
        f:token: {}
      f:metadata:
        f:annotations:
          .: {}
          f:kubernetes.io/service-account.name: {}
          f:kubernetes.io/service-account.uid: {}
      f:type: {}
    manager: kube-controller-manager
    operation: Update
    time: "2020-04-13T15:48:52Z"
  name: sample-account-token-lhbsd
  namespace: default
  resourceVersion: "136798"
  selfLink: /api/v1/namespaces/default/secrets/sample-account-token-lhbsd
  uid: 757becf9-c427-4b2f-bab8-e2b039348ee8
type: kubernetes.io/service-account-token

ServiceAccountが割り当てられたリソース(podなど)はこの権限を使ってAPIを叩いたりしています。

つづいて作ったユーザのtokenを見てみましょう。

[root@master k8s-role]# kubectl get secret | grep sample-account
sample-account-token-lhbsd             kubernetes.io/service-account-token   3      35m
  
[root@master k8s-role]# kubectl describe secret sample-account-token-lhbsd
Name:         sample-account-token-lhbsd
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: sample-account
              kubernetes.io/service-account.uid: f62a0897-e232-4989-ba16-28bf245dd7bf

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1025 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6IkswbTNJRjFHX1JIcmFQWkd0RkViYWxTMS1vcThaa3BHYUNnZ1Rac3loTUkifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRlc3QtdG9rZW4tbGhic2QiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoidGVzdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImY2MmEwODk3LWUyMzItNDk4OS1iYTE2LTI4YmYyNDVkZDdiZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OnRlc3QifQ.MfFPDXis1dZcUkfE__s256JJ-3n7t_wmjUGnxv5twJLG9P_KARmN32fdE_35A2QiHuaARF8_2KsMxjIwVnOJdyk9qgnTqn7_wLYTUF4yM6SMmAB-EJVgiEewbkjemAOuAS9_dV8jlVO5ug3y6BfcM7A0KOfa7yAtIaL_FmXq2JNi5CkCMEAJl01jFdLRZCnA65cNAH29WfcZQzVNLwfugmZ2Ix_AXcXurLrG73JUNV4OCuB-8Q_qZ3yCSfWNCKZPbIs4qn31Bi0omHtaL_G7fe7KNjXFLo_2wjIfLqMqOuksbSKT4b-dGiLj5MKVOTmYAXCO2hyK49gTMdDMTW5eyQ

この長いのがtokenです。

kubernetes-dashboardでためしてみよう

こちらの記事を参考にkubernetes-dashboardを入れてみましょう。

blog.framinal.life

そして先ほどのtokenでログインしてみます。すると何も表示されないことがわかります。

f:id:lirlia:20200414013223p:plain

なぜでしょうか?

これはServiceAccountに各種リソースをみる権限がないからです。では権限をつけるにはどうすれば良いのか?そこで大事なのがRoleとなります。

kubernetesのroleとRoleBindingについて

kubernetesには2種類のRoleRoleBindingが存在します。

f:id:lirlia:20200413221158p:plain

それぞれの違いは範囲です。

  • RoleRoleBinding → NameSpace単位で存在
  • Cluster RoleCluster RoleBinding → クラスター単位で存在

Roleの確認方法

[root@master ~]# kubectl get role  -n kube-system
NAME                                             CREATED AT
extension-apiserver-authentication-reader        2020-04-12T10:35:10Z
kube-proxy                                       2020-04-12T10:35:12Z
kubeadm:kubelet-config-1.18                      2020-04-12T10:35:10Z
kubeadm:nodes-kubeadm-config                     2020-04-12T10:35:10Z
system::leader-locking-kube-controller-manager   2020-04-12T10:35:10Z
system::leader-locking-kube-scheduler            2020-04-12T10:35:10Z
system:controller:bootstrap-signer               2020-04-12T10:35:10Z
system:controller:cloud-provider                 2020-04-12T10:35:10Z
system:controller:token-cleaner                  2020-04-12T10:35:10Z

ClusterRoleの確認方法

[root@master ~]# kubectl get clusterrole 
NAME                                                                   CREATED AT
admin                                                                  2020-04-12T10:35:09Z
calico-kube-controllers                                                2020-04-12T10:51:45Z
calico-node                                                            2020-04-12T10:51:46Z
cluster-admin                                                          2020-04-12T10:35:09Z
edit                                                                   2020-04-12T10:35:09Z
kubeadm:get-nodes                                                      2020-04-12T10:35:11Z
kubernetes-dashboard                                                   2020-04-13T08:47:51Z
system:aggregate-to-admin                                              2020-04-12T10:35:09Z
system:aggregate-to-edit                                               2020-04-12T10:35:09Z
system:aggregate-to-view                                               2020-04-12T10:35:09Z

RoleやClusterRoleの作成について

ClusterRoleには初めからプリセットと呼ばれるものが存在します

名前 内容
cluster-admin 全てのリソース操作可能
admin ClusterRoleの編集とNameSpaceレベルのRBAC
view Clusterに対するRead/Write権限
edit Clusterに対するReadOnly権限

Roleを作ってみる

  
# ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sample-account
  namespace: default
  
---
  
# Role
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: sample-role
  namespace: default
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs:
  - get
  - list
  - watch
  - create
  - delete
  - update
  
---
  
# RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: sample-rolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: sample-role
subjects:
- kind: ServiceAccount
  name: sample-account
  namespace: default
  
---

# Pod
apiVersion: v1
kind: Pod
metadata:
  name: sample-kubectl
spec:
  serviceAccount: sample-account
  containers:
    - name: kubectl-container
      image: lachlanevenson/k8s-kubectl:latest
      command: ["sleep", "86400"]

kubernetes-dashboardでためしてみよう

こちらの記事を参考にkubernetes-dashboardを入れてみましょう。

blog.framinal.life

そして先ほどのtokenでログインしてみます。すると今度はdefault namespaceの情報が表示されていることがわかります。

f:id:lirlia:20200414013419p:plain

割り当てたroleがきちんと効いていることがわかりますね。

つづいてroleをpodsのみ許可するようにかえてみます。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: sample-role
  namespace: default
rules:
- apiGroups: ["*"]
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
  - create
  - delete
  - update

変更したらkubectl apply -fしてあげてください。

すると、このようにpodしか表示されなくなります。

f:id:lirlia:20200414013640p:plain

これは先ほど見えていたリソースには権限がないからですね。

ということで「何を誰に許可するのか?」がRBACということでした。