Kubernetes のセキュリティ対策として,Service Account と Pod に設定できる automountServiceAccountToken
フィールド(Secret の自動マウントをオプトアウトするかどうか)の動作確認をした.とは言え,Service Account と Secret の関係性なども整理する必要があるため,一歩一歩進めていく.今回は Kubernetes v1.20 を検証環境とした.
Pod と Service Account
まず,Service Account を指定せずに Pod を作ると default
Service Account と紐付く.確認をするために nginx:1.21
イメージを指定した以下のマニフェストを検証用に適用する.
apiVersion: v1 kind: Pod metadata: name: my-nginx spec: containers: - name: my-nginx image: nginx:1.21
以下に kubectl get pods my-nginx -o yaml
コマンドの結果を抜粋して載せる.serviceAccountName: default
になっている通り,デフォルトでは Pod と default
Service Account が紐付いている.
apiVersion: v1 kind: Pod metadata: name: my-nginx namespace: default spec: containers: - image: nginx:1.21 name: my-nginx volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-5qnst readOnly: true serviceAccountName: default volumes: - name: default-token-5qnst secret: defaultMode: 420 secretName: default-token-5qnst
Service Account と Secret
もう1点重要なのは,上記 YAML の volumes
と volumeMounts
で,default-token-5qnst
Secret を Pod のボリュームとしてファイルシステムにマウントしている.この default-token-5qnst
Secret は default
Service Account に紐付いている.以下に kubectl get serviceaccounts default -o yaml
コマンドの結果を抜粋して載せる.
apiVersion: v1 kind: ServiceAccount metadata: name: default namespace: default secrets: - name: default-token-5qnst
そして kubectl get secrets default-token-5qnst -o yaml
コマンドで default-token-5qnst
Secret の値を確認すると,Base64 でエンコードされた token
を確認できる(以下は xxxxxxxxxx
としてマスキングをした).
apiVersion: v1 data: token: xxxxxxxxxx kind: Secret metadata: name: default-token-5qnst namespace: default type: kubernetes.io/service-account-token
Kubernetes API にリクエストを送る
実際に kubectl exec
コマンドを使って Pod に接続をすると,ファイルシステムにマウントされた /var/run/secrets/kubernetes.io/serviceaccount/token
ファイルを確認できる.token
ファイルは Base64 でデコードされた値となる(以下は yyyyyyyyyy
としてマスキングをした).この token
を HTTP Header に乗せると Kubernetes API にリクエストを送れるようになる.今回 default
Service Account には権限を付与していないため Forbidden
になっているのは期待通りと言える.
$ kubectl exec -it my-nginx -- /bin/sh # cat /var/run/secrets/kubernetes.io/serviceaccount/token yyyyyyyyyy # TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) # curl -s -k https://kubernetes/api/v1/namespaces/default/ --header "Authorization: Bearer ${TOKEN}" { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "namespaces \"default\" is forbidden: User \"system:serviceaccount:default:default\" cannot get resource \"namespaces\" in API group \"\" in the namespace \"default\"", "reason": "Forbidden", "details": { "name": "default", "kind": "namespaces" }, "code": 403 }
Kubernetes API にリクエストを送る手順は以下のドキュメントを参考にした.
Pod : automountServiceAccountToken
フィールド
一般的には Pod から Kubernetes API にリクエストを送る場面は少なく,不要なら automountServiceAccountToken
フィールドを false
にして Secret の自動マウントをオプトアウトする.例えば EKS Best Practices Guides にもベストプラクティスとして載っている.
まず,Pod に automountServiceAccountToken: false
を指定すると,Pod レベルで Secret の自動マウントをオプトアウトできる.以下のようにマニフェストに1行追加して,Pod を作り直す.
apiVersion: v1 kind: Pod metadata: name: my-nginx spec: containers: - name: my-nginx image: nginx:1.21 automountServiceAccountToken: false
すると volumes
と volumeMounts
の設定はなくなり,Secret の自動マウントはされなくなった.
$ kubectl get pod my-nginx -o yaml apiVersion: v1 kind: Pod metadata: name: my-nginx namespace: default spec: automountServiceAccountToken: false containers: - image: nginx:1.21 name: my-nginx serviceAccountName: default
念のため /var/run/secrets/kubernetes.io/serviceaccount/token
ファイルを確認したところ,存在しなかった.
$ kubectl exec -it my-nginx -- /bin/sh # cat /var/run/secrets/kubernetes.io/serviceaccount/token cat: /var/run/secrets/kubernetes.io/serviceaccount/token: No such file or directory
Service Account : automountServiceAccountToken
フィールド
Pod レベルではなく,Service Account レベルで automountServiceAccountToken
フィールドを false
にすることもできる.以下のマニフェストで新しく auto-mount-off
Service Account を作る.
$ cat serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: auto-mount-off automountServiceAccountToken: false
次に serviceAccountName: auto-mount-off
を指定した Pod を作る.今回は Pod には automountServiceAccountToken: false
を指定していない.
$ cat pod.yaml apiVersion: v1 kind: Pod metadata: name: my-nginx spec: serviceAccountName: auto-mount-off containers: - name: my-nginx image: nginx:1.21
以下に kubectl get pods my-nginx -o yaml
コマンドの結果を抜粋して載せる.同じく volumes
と volumeMounts
の設定はなくなり,Secret の自動マウントはされなくなった.
apiVersion: v1 kind: Pod metadata: name: my-nginx namespace: default spec: containers: - image: nginx:1.21 name: my-nginx serviceAccountName: auto-mount-off
なお,Service Account と Secret は紐付いているため,以下のように確認できる.
$ kubectl get serviceaccounts NAME SECRETS AGE auto-mount-off 1 3m10s default 1 50m $ kubectl get secrets NAME TYPE DATA AGE auto-mount-off-token-7mhnv kubernetes.io/service-account-token 3 3m10s default-token-5qnst kubernetes.io/service-account-token 3 50m
まとめ
Kubernetes のセキュリティ対策として,Service Account と Pod に設定できる automountServiceAccountToken
フィールド(Secret の自動マウントをオプトアウトするかどうか)の動作確認をした.CKS (Certified Kubernetes Security Specialist) の出題範囲にも関連するトピックが含まれているし,最近読んでいる「Docker/Kubernetes開発・運用のためのセキュリティ実践ガイド」にも automountServiceAccountToken
フィールドの解説が載っていたので,気になっていた!引き続き試していくぞー!