AKS で Bound Service Account Tokens を試す
Kubernetes v1.32 では、サービスアカウントトークンのセキュリティ強化として「Bound Service Account Tokens」の機能が改良されました。
従来、Pod にマウントされるサービスアカウントトークンは、該当の Pod の削除後も有効期間内なら使用可能で、トークンが流出した場合に悪用されるリスクがありました。v1.32 ではトークンを特定のオブジェクト (例: Pod) に紐付けて発行でき、トークン内部に対象オブジェクトの名前や UID 等の情報が含まれます。API サーバーはトークン使用時にそれらクレームを検証し、もし紐付けられたオブジェクトが存在しなかったり UID が変わっていれば、そのトークンでの認証を無効とします。この仕組みにより、サービスアカウントトークンが特定の Pod や Node のライフサイクルに限定され、不要に長く使われ続けることを防ぎます。結果として、Pod 終了後のトークン不正利用リスクや、ノード経由の権限昇格リスクを低減し、クラスター全体のセキュリティが向上します。
上記について、AKS 上で試してみました!
お試し手順
AKS の準備
下記のクイックスタートを参考に、新しい AKS クラスターを作成しておきます。バージョンは v1.32 以降となるようにしてください。
また、以降の環境では kubectl の実行環境として WSL2 上の Ubuntu (22.04) を利用しています。
下準備
作業用ネームスペースの作成
他のリソースと干渉しないように、本機能を試すための Namespace を作成します。ここでは例として token-demo という名前にします。
kubectl create namespace token-demo
kubectl config set-context --current --namespace=token-demo
サービスアカウントとテスト用 Pod の用意
トークンを発行・検証するため、サービスアカウントと、それを使用する Pod を作成します。サービスアカウント名は demo-sa、Pod名は test-pod とします。
kubectl create serviceaccount demo-sa
apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: token-demo
spec:
serviceAccountName: demo-sa
containers:
- name: demo-container
image: nginx:stable-alpine3.21-perl # 任意の軽量イメージ
command: ["sleep", "3600"]
下記のコマンドで Pod をデプロイしておきます。
kubectl apply -f pod-demo.yaml
検証
トークンの発行
kubectl create token コマンドで、サービスアカウント demo-sa に対し、特定の Pod に紐づけされたトークンを発行します。--bound-object-kind と --bound-object-name により紐づけ先オブジェクトを指定できます。ここでは Pod/test-pod とします。
TOKEN=$(kubectl create token demo-sa \
--bound-object-kind=Pod \
--bound-object-name=test-pod)
echo "$TOKEN"
コマンド実行により、環境変数 TOKEN に JWT 形式のトークン文字列が格納されます。発行されたトークンには test-pod およびその UID (さらに Pod が動作するノード名 / UID) がプライベートクレームとして埋め込まれています。
TokenReview APIを使ったトークン内容の確認
Kubernetes の TokenReview API を利用して、先ほど発行したトークンの認証情報を検証します。TokenReview は任意のトークンを受け取り、その認証結果 (ユーザー名やクレーム情報) を返す API オブジェクトです。
まず、トークン文字列を埋め込んだマニフェストを用意します。
apiVersion: authentication.k8s.io/v1
kind: TokenReview
metadata:
name: demo-tokenreview
spec:
token: <YOUR_TOKEN_HERE> # 発行したトークン文字列を貼り付け
TokenReview オブジェクトを作成して確認します。なお、TokenReview は揮発性オブジェクトであり kubectl get 等での事後確認ができません。このため create 時点で出力するようにしています。
kubectl create -f tokenreview.yaml -o yaml
正常に認証されていれば、出力の status 項目に以下のような情報が含まれます。
status:
authenticated: true
user:
username: system:serviceaccount:token-demo:demo-sa
uid: ...
extra:
authentication.kubernetes.io/credential-id:
- JTI=<トークン ID の GUID>
authentication.kubernetes.io/pod-name:
- test-pod
authentication.kubernetes.io/pod-uid:
- e87dbbd6-3d7e-45db-aafb-72b24627dff5
authentication.kubernetes.io/node-name:
- <現在のノード名>
authentication.kubernetes.io/node-uid:
- <現在のノード UID>
user.extra フィールドに、トークンに埋め込まれたクレーム情報が列挙されています。pod-name および pod-uid に test-pod の情報が含まれており、このトークンが特定の Pod に紐づけられていることが確認できます。また、node-name と node-uid も記録されており、トークン発行時の Pod 配置ノードがトレース可能になっています。
トークンの無効化確認
次に、当該 Pod を削除し、トークンが無効化されることを確認します。
kubectl delete pod test-pod
Pod が削除されると、demo-sa サービスアカウントに紐付いた先のトークンはもはや有効ではなくなるはずです。
再度 TokenReview を実行して動作を確認します。
kubectl create -f tokenreview.yaml -o yaml
status:
error: '[invalid bearer token, service account token has been invalidated]'
user: {}
今回の出力では status.error にエラーが記録され、user 情報も空になっています。Pod の削除によりトークンが無効化され、認証に失敗していることがわかります。これは、このトークンが既に存在しない Pod にバウンドされていたため無効化されたことを意味します。
おわりに
ということで Kubernetes v1.32 での「Bound Service Account Tokens」を試してみました。
引き続き、新機能のお試しなどを通じて Kubernetes の知識アップデートに勤しんでいきたいと思います!
Discussion