概要
KubernetesではRBACという、各種リソースへのアクセス権限を管理する仕組みが用意されてます。
たとえばPrometheusのようにKubernetesのAPIを叩く場合、各リソースへアクセスするための権限が必要になります。
今回はそれの基本的な仕組みや設定方法を説明します。
環境
- minikube 1.2.0
- Kubernetes 1.15.0
Service Account
KubernetesにはUserAccountとServiceAccountがあります。大きな違いとしては以下です。
UserAccount | ServiceAccount | |
---|---|---|
対象 | 人 | プロセス |
権限範囲 | グローバル。 GCPのアカウントや AWSのIAMとリンクする。 |
namespace区切り。 Kubernetesの世界で完結する。 |
ref: Managing Service Accounts - Kubernetes
Pod起動時には必ずServiceAccountを1つ割り当てる必要があります。
指定しない場合はdefault
ServiceAccountが割り当てられます。
RBAC
RBAC(Role-based Access Control)はロール型のリソースへのアクセス権限管理の仕組みです。
リソースへアクセスするために必要な権限をRoleとして用意し、それをUserやServiceAccountに付与することでアクセスを可能にします。
以前はABAC(Attribute-based Access Control)という仕組みを使っていましたが、今のバージョンではこちらを使っています。
検証
ServiceAccountの作成
apiVersion: v1 kind: ServiceAccount metadata: name: sample-serviceaccount namespace: default
反映すると以下のように作成されます。
$ kubectl get sa NAME SECRETS AGE default 1 14d sample-serviceaccount 1 9h
Secretsが紐付いていることが分かります。
詳細を見てみましょう。
$ kubectl get sa sample-serviceaccount -o yaml apiVersion: v1 kind: ServiceAccount metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"sample-serviceaccount","namespace":"default"}} creationTimestamp: "2019-08-05T15:35:23Z" name: sample-serviceaccount namespace: default resourceVersion: "129319" selfLink: /api/v1/namespaces/default/serviceaccounts/sample-serviceaccount uid: 4dd63807-c7ee-44ce-8b77-223270d9dd5c secrets: - name: sample-serviceaccount-token-t6s9p
Secretsの詳細も確認します。
$ kubectl get secret sample-serviceaccount-token-t6s9p -o yaml apiVersion: v1 data: ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tL...== namespace: ZGVmYXVsdA== token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbX...== kind: Secret metadata: annotations: kubernetes.io/service-account.name: sample-serviceaccount kubernetes.io/service-account.uid: 4dd63807-c7ee-44ce-8b77-223270d9dd5c creationTimestamp: "2019-08-05T15:35:23Z" name: sample-serviceaccount-token-t6s9p namespace: default resourceVersion: "129318" selfLink: /api/v1/namespaces/default/secrets/sample-serviceaccount-token-t6s9p uid: b3429905-ebe3-48a3-8387-7b0fa32d4657 type: kubernetes.io/service-account-token
ServiceAccountはこのトークンをKubernetesAPIへの認証情報として利用します。
Podに紐づけて起動
Podに先程のServiceAccountを紐付けて起動します。
apiVersion: v1 kind: Pod metadata: name: sample-kubectl spec: serviceAccountName: sample-serviceaccount containers: - name: kubectl-container image: lachlanevenson/k8s-kubectl:v1.10.4 command: ["sleep", "86400"]
詳細を見ると以下のように紐付いてることが分かります。
また先程のSecretもマウントされてます。
$ kubectl get po sample-kubectl -o yaml ... securityContext: {} serviceAccount: sample-serviceaccount serviceAccountName: sample-serviceaccount terminationGracePeriodSeconds: 30 ... volumes: - name: sample-serviceaccount-token-t6s9p secret: defaultMode: 420 secretName: sample-serviceaccount-token-t6s9p ...
権限がない状態での検証
ServiceAccountを紐付けたPodの内部からkubectlを使ってAPIアクセスしてみます。
$ kubectl exec -it sample-kubectl -- kubectl get pods Error from server (Forbidden): pods is forbidden: User "system:serviceaccount:default:sample-serviceaccount" cannot list resource "pods" in API group "" in the namespace "default" command terminated with exit code 1
権限がないので予想通り怒られました。
ClusterRoleをバインド
ClusterRoleを独自で作るのもいいですし、既存のClusterRoleをバインドするのも1つです。
今回は既存のものを使います。
以下ClusterRole一覧
$ kubectl get clusterrole NAME AGE admin 14d cluster-admin 14d edit 14d system:aggregate-to-admin 14d system:aggregate-to-edit 14d system:aggregate-to-view 14d system:auth-delegator 14d system:basic-user 14d system:certificates.k8s.io:certificatesigningrequests:nodeclient 14d system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 14d system:controller:attachdetach-controller 14d system:controller:certificate-controller 14d ... system:node 14d system:node-bootstrapper 14d system:node-problem-detector 14d system:node-proxier 14d system:persistent-volume-provisioner 14d system:public-info-viewer 14d system:volume-scheduler 14d view 14d
使いやすいのは以下の4つです。
cluster role | 説明 |
---|---|
cluster-admin | 全権限 |
admin | リソース割当、Namespace操作以外の全権限 |
edit | 基本的なリソースのread/write権限。 ただしrole系のread/write権限はない |
view | 基本的なリソースのread権限。 ただしsecretsリソースは見れない |
先程のコマンドはPodの取得権限が必要なので、view
をバインドします。
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: sample-clusterrolebinding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: view subjects: - kind: ServiceAccount name: sample-serviceaccount namespace: default
roleRef
に付与する権限をsubjects
に付与対象を
設定します。
権限がある状態での検証
ServiceAccountを紐付けたPodの中から、あらためてkubectlを使ってAPIアクセスしてみます。
$ kubectl exec -it sample-kubectl -- kubectl get pods NAME READY STATUS RESTARTS AGE sample-kubectl 1/1 Running 0 29m
今度はAPIへの認証/認可が成功して取得できました。
サンプルコード
今回検証したコードは以下です。
その他
検証する上で気になった事をまとめます。
RBACを有効にするには?
Kubernetes 1.6から使えるようになったRBACですが、Kubernetes 1.8以降ではデフォルトでONになっています。
RBACが有効になってるか確認したい場合は
$ kubectl api-versions
をした時にrbac.authorization.k8s.io/v1
が表示されます。
ref: kubernetes - how to check whether RBAC is enabled, using kubectl - Stack Overflow
ABACが有効か無効かを確認したい
GKEの場合はクラスタの編集で確認できます。
有効の場合はlegacy-authorization
がまだ使われてます。
上記で無効にすれば完全にRBAC移行できます。
GKEでない場合は--no-enable-legacy-authorization
フラグを使ってクラスタの作成をしたり・api-serverを起動する必要があります。
ref: How to enable RBAC on existing Kubernetes Cluster - Stack Overflow
ABACからRBACへ移行した場合の確認方法は?
両方のauthorization-modeが有効の場合、最初にRBACでアクセス権限をチェックし、失敗するとABACにfallbackします。
なのでapi-serverのログにはRBAC DENY:
というログが出ます。
ref: Using RBAC Authorization - Kubernetes
ログの出し方は以下です。
$ kubectl proxy
でプロキシを立て、ログを取得します。
$ curl -s http://localhost:8001/logs/kube-apiserver.log
ref: How to debug ABAC to RBAC transition in a GKE kubernetes cluster? - Stack Overflow
ServiceAccountに紐付くRoleを確認したい
kubectl get clusterrolebinding
で-o wide
をつけるとUser, Group, ServiceAccountが表示されるので確認できます。
$ kubectl get clusterrolebinding -o wide
NAME AGE ROLE USERS GROUPS SERVICEACCOUNTS
cluster-admin 14d ClusterRole/cluster-admin system:masters
kubeadm:kubelet-bootstrap 14d ClusterRole/system:node-bootstrapper system:bootstrappers:kubeadm:default-node-token
kubeadm:node-autoapprove-bootstrap 14d ClusterRole/system:certificates.k8s.io:certificatesigningrequests:nodeclient system:bootstrappers:kubeadm:default-node-token
kubeadm:node-autoapprove-certificate-rotation 14d ClusterRole/system:certificates.k8s.io:certificatesigningrequests:selfnodeclient system:nodes
kubeadm:node-proxier 14d ClusterRole/system:node-proxier kube-system/kube-proxy
minikube-rbac 14d ClusterRole/cluster-admin kube-system/default
storage-provisioner 14d ClusterRole/system:persistent-volume-provisioner kube-system/storage-provisioner
system:basic-user 14d ClusterRole/system:basic-user system:authenticated
system:controller:attachdetach-controller 14d ClusterRole/system:controller:attachdetach-controller kube-system/attachdetach-controller
system:controller:certificate-controller 14d ClusterRole/system:controller:certificate-controller kube-system/certificate-controller
system:controller:clusterrole-aggregation-controller 14d ClusterRole/system:controller:clusterrole-aggregation-controller kube-system/clusterrole-aggregation-controller
system:controller:cronjob-controller 14d ClusterRole/system:controller:cronjob-controller kube-system/cronjob-controller
system:controller:daemon-set-controller 14d ClusterRole/system:controller:daemon-set-controller kube-system/daemon-set-controller
system:controller:deployment-controller 14d ClusterRole/system:controller:deployment-controller kube-system/deployment-controller
system:controller:disruption-controller 14d ClusterRole/system:controller:disruption-controller kube-system/disruption-controller
system:controller:endpoint-controller 14d ClusterRole/system:controller:endpoint-controller kube-system/endpoint-controller
system:controller:expand-controller 14d ClusterRole/system:controller:expand-controller kube-system/expand-controller
system:controller:generic-garbage-collector 14d ClusterRole/system:controller:generic-garbage-collector kube-system/generic-garbage-collector
system:controller:horizontal-pod-autoscaler 14d ClusterRole/system:controller:horizontal-pod-autoscaler kube-system/horizontal-pod-autoscaler
...
ServiceAccountが持ってる権限確認したい
can-i
で確認できます。
kubectl auth can-i <verb> <resource> \ --as=system:serviceaccount:<namespace>:<serviceaccountname> \ [-n <namespace>]
例えばdefaultのServiceAccountにpodの読み込み権限があるか、だと
$ kubectl auth can-i get pod --as=system:serviceaccount:default:default no
となります。
ref: Securing your Cluster with RBAC and PSP – Giant Swarm Documentation
Docker for MacはデフォルトだとRBACの検証ができない
ここにあるようにデフォルトだと全てのservice accountにcluster-admin
のcluster roleがbindされるため検証ができません。
なのでdocker-for-desktop-binding
を消すか今回のようにminikubeなど別環境で検証する必要があります。