kakakakakku blog

Weekly Tech Blog: Keep on Learning!

kube-apiserver で「匿名リクエスト」を無効化する : --anonymous-auth=false

Kubernetes の kube-apiserver では,デフォルトで「匿名リクエスト」機能が有効になっている(正確な条件は以下のドキュメントに載っている).今回は「匿名リクエスト」機能の動作確認と kube-apiserver のセキュリティ対策として「匿名リクエスト」機能の無効化を試す.検証環境は Kubernetes v1.20.2 とする.

kubernetes.io

「匿名リクエスト」機能

Kubernetes API にリクエストをする場合,通常は HTTP Header の AuthorizationBearer Token を付ける.以下のドキュメントを参考に Kubernetes API(今回の検証環境では https://172.17.0.12:8443/api)にリクエストをすると,うまく実行できる.

kubernetes.io

$ 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 権限を付与する ClusterRoleClusterRoleBinding を作る.ClusterRoleBindingsystem: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 には他にも多くオプションがある.詳しくは以下のドキュメントに載っている.

kubernetes.io

もう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 匿名ユーザの取り扱い」にも載っている.

関連記事

kakakakakku.hatenablog.com