Kubernetes v1.7 で導入された Node Authorization について概要と kubeadm で構築して試してみた結果をまとめました。確認は Kubernetes v1.7.0 で行っています。
概要
Node Authorization とは Node (Kubelet) の権限管理をより厳密に行う機能です。この機能を有効にすることで、Node はその Node が関連するオブジェクトにのみ権限が制限されるようになります。例えば Node は割り当てられた Pod が参照する Secret 以外にはアクセスできなくなります。これにより Node のクレデンシャルが漏洩したときのセキュリティリスクを最小限にすることができます。
制限されるリソース
Node Authorization を有効にすると Node がアクセスする必要があるリソースをその Node に関連あるものだけに自動的に絞られます。権限は以下のように制御されます。実装上の都合で認可フェーズと Admission Control のフェーズ、の2フェーズで権限の制御が行われています。
- 認可 (Node Authorizer)による機能
- その Node に紐づく Pod が参照している Secret, ConfigMap, PersistentVolume, PersistentVolumeClaim のみ参照できる
- Admission Control (NodeRestriction)による機能
- その Node に紐づく Node オブジェクトのみを変更できる
- その Node に紐づく Pod オブジェクトのみステータスを変更できる
- その Node に紐づく Static な Pod オブジェクト (mirror pod)のみを作成・更新できる
- mirror pod は Secret などの他のオブジェクトの参照はできないようになっている
その他の Kubelet が参照するリソースに関しては、RBAC の system:node
の権限が参考になります。kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy/policy.go
補足: 実装上の都合
認可フェーズでは、リクエストの body 部分は見ることができず、また Admission Control では読み込みにはかからないという制限があるため、このような 2 つを合わせた実装になっているようです。
有効にするための設定
Node Authorization を有効にするためには下記の3点の設定が必要になります。
Node 側のクレデンシャル情報
Node のクレデンシャルには以下の情報が含まれている必要があります
- Group が
system:nodes
であること - User 名が
system:node:<nodeName>
であること
例えばクライアント証明書による認証を使っている場合は、下記のような Subject になっている必要があります。
Subject: O=system:nodes, CN=system:node:<nodeName>
認可 (Node Authorizer) の設定
API Server の認可の設定にNode
を追加する必要があります。
-
--authorization-mode=Node,...
- 必要に応じてカンマ区切りで複数かけます。例)
Node,RBAC
- 必要に応じてカンマ区切りで複数かけます。例)
Admission Control (NodeRestriction) の設定
API Server の Admission Control の設定にNodeRestriction
を追加する必要があります。
--admission-control=NodeRestriction,...
kubeadm で Node Authorization を試してみる
kubeadm を使って Node Authorization の機能の効果を試してみます。v1.7.0 の時点で kubeadm のデフォルトで Node Authorization の機能が有効になっているようです。
kubeadm による構築は Using kubeadm to Create a Cluster のドキュメントどおりに行いました。Pod Network には Calico を用いています。
構成
以下のようにMaster 1台、Node 2台の計3台で構成されています。
$ kubectl get nodes
NAME STATUS AGE VERSION
master Ready 4h v1.7.0
worker-1 Ready 4h v1.7.0
worker-2 Ready 4h v1.7.0
kubeadm によって worker-1, 2 のクライアント証明書の Group 名、Node 名が仕様どおり設定されています。
# worker-1
$ cat /etc/kubernetes/kubelet.conf | grep client-certificate-data | awk '{print $2;}' | base64 -d | openssl x509 -text | grep Subject:
Subject: O=system:nodes, CN=system:node:worker-1
^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^
Group 名 Node 名
# worker-2
$ cat /etc/kubernetes/kubelet.conf | grep client-certificate-data | awk '{print $2;}' | base64 -d | openssl x509 -text | grep Subject:
Subject: O=system:nodes, CN=system:node:worker-2
API サーバーの Node Authorization の設定 (--admission-control=...,NodeRestriction,..
, --authorization-mode=Node,...
の設定)が有効になっていることを確認します。
# master
$ cat /etc/kubernetes/manifests/kube-apiserver.yaml | grep Node
- --admission-control=Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,DefaultTolerationSeconds,NodeRestriction,ResourceQuota
- --authorization-mode=Node,RBAC
アクセス制御の確認
Node Authorization によって Node に割り当てられた Pod のマウントした Secret のみにアクセスできるよう制御されていることを確認してみます。
まずはアクセス制御の対象となる Secret を作成します。
$ kubectl create secret generic mysecret --from-literal=username=myusername --from-literal=password=mypassword
secret "mysecret" created
次にこの Secret (mysecret)をマウントした Deployment を定義します。
$ kubectl apply -f myapp-dep.yaml
deployment "myapp" created
Pod がスケジューリングされた Node を確認します。worker-1 に割り当てられたようです。
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
myapp-1607853247-kmgrp 1/1 Running 0 25s 192.168.226.67 worker-1
^^^^^^^^
worker-1 のクレデンシャル (/etc/kubernetes/kubelet.conf
の接続情報) を使ってこの Secret (mysecret) が読めることを確認します。
# worker-1
$ KUBECONFIG=/etc/kubernetes/kubelet.conf kubectl get secrets mysecret
NAME TYPE DATA AGE
mysecret Opaque 2 28m
# read できている
worker-1 でPod がマウントしていない他の Secret (othersecret) は読めないことを確認します。
# worker-1
$ KUBECONFIG=/etc/kubernetes/kubelet.conf kubectl get secret othersecret
Error from server (Forbidden): User "system:node:worker-1" cannot get secrets in the namespace "default".: "no path found to object" (get secrets othersecret)
# エラーになった
また Pod が割り当てられていない worker-2 のクレデンシャルを使ってこの Secret が読めないことを確認します。
# worker-2
$ KUBECONFIG=/etc/kubernetes/kubelet.conf kubectl get secrets mysecret
Error from server (Forbidden): User "system:node:worker-2" cannot get secrets in the namespace "default".: "no path found to object" (get secrets mysecret)
Node に関連ある Secret のみにアクセスできるようアクセス制御が正しく動作していることが確認できました
関連ソースコード
- 認可 (Node Authorizer)
- Admission Control (NodeRestriction)