Kubernetes の kube-apiserver では,デフォルトで「匿名リクエスト」機能が有効になっている(正確な条件は以下のドキュメントに載っている).今回は「匿名リクエスト」機能の動作確認と kube-apiserver のセキュリティ対策として「匿名リクエスト」機能の無効化を試す.検証環境は Kubernetes v1.20.2 とする.
「匿名リクエスト」機能
Kubernetes API にリクエストをする場合,通常は HTTP Header の Authorization
に Bearer
Token を付ける.以下のドキュメントを参考に Kubernetes API(今回の検証環境では https://172.17.0.12:8443/api
)にリクエストをすると,うまく実行できる.
$ TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}" | base64 --decode) $ curl -s -k https://172.17.0.12:8443/api --header "Authorization: Bearer ${TOKEN}" { "kind": "APIVersions", "versions": [ "v1" ], "serverAddressByClientCIDRs": [ { "clientCIDR": "0.0.0.0/0", "serverAddress": "172.17.0.12:8443" } ] }
今度は Bearer
Token を付けずに Kubernetes API にリクエストをすると HTTP 403 Forbidden
となる.これを「匿名リクエスト」と言う.エラーメッセージに載っている通り,RBAC としては「匿名リクエスト」を system:anonymous
User として権限を確認する.もしくは system:unauthenticated
Group として権限を確認する.
$ curl -s -k https://172.17.0.12:8443/api { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "forbidden: User \"system:anonymous\" cannot get path \"/api\"", "reason": "Forbidden", "details": { }, "code": 403 } $ curl -s -k https://172.17.0.12:8443/api/v1/namespaces { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "namespaces is forbidden: User \"system:anonymous\" cannot list resource \"namespaces\" in API group \"\" at the cluster scope", "reason": "Forbidden", "details": { "kind": "namespaces" }, "code": 403 }
system:anonymous
User に権限を付与する
「匿名リクエスト」機能の動作確認をするために system:anonymous
User に権限を付与する.以下のように Namespace に Read 権限を付与する ClusterRole と ClusterRoleBinding を作る.ClusterRoleBinding で system:anonymous
User と紐付けている.
ClusterRole
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: my-cluster-role rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "list"]
ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: my-cluster-role-binding roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: my-cluster-role subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: system:anonymous
もう1度 Bearer
Token を付けずに Kubernetes API にリクエストをすると,今度は Namespace を確認できるようになった.ここまでで「匿名リクエスト」機能の動作確認ができた.
$ curl -s -k https://172.17.0.12:8443/api/v1/namespaces | jq .items[].metadata.name "default" "kube-node-lease" "kube-public" "kube-system"
「匿名リクエスト」機能を無効化する
とは言え,基本的には「匿名リクエスト」に権限を付与する必要はなく,kube-apiserver に --anonymous-auth=false
オプションを追加すれば「匿名リクエスト」機能を無効化できる.なお「匿名リクエスト」機能の無効化は以下のように CIS Kubernetes V1.20 Benchmark でも推奨されている.
1.2.1 Ensure that the --anonymous-auth argument is set to false (Manual)
さっそく /etc/kubernetes/manifests/kube-apiserver.yaml
を修正して --anonymous-auth=false
を追加する.すると Static Pod によってすぐに反映される.以下には差分を抜粋して載せておく.
(中略)
spec:
containers:
- command:
- kube-apiserver
+ - --anonymous-auth=false
- --advertise-address=172.17.0.80
- --allow-privileged=true
- --authorization-mode=Node,RBAC
(中略)
なお,kube-apiserver には他にも多くオプションがある.詳しくは以下のドキュメントに載っている.
もう1度 Bearer
Token を付けずに Kubernetes API にリクエストをすると,今度は HTTP 401 Unauthorized
となる.「匿名リクエスト」は拒否されるようになった.なるほど!
$ curl -s -k https://172.17.0.12:8443/api { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "Unauthorized", "reason": "Unauthorized", "code": 401 }
まとめ
Kubernetes の kube-apiserver では,デフォルトで「匿名リクエスト」機能が有効になっている.今回は「匿名リクエスト」機能の動作確認と kube-apiserver のセキュリティ対策として「匿名リクエスト」機能の無効化を試した.kube-apiserver の --anonymous-auth
オプションは「Docker/Kubernetes開発・運用のためのセキュリティ実践ガイド」の「5.3.7 匿名ユーザの取り扱い」にも載っている.