🎼

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
pod-demo.yaml
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 オブジェクトです。

まず、トークン文字列を埋め込んだマニフェストを用意します。

tokenreview.yaml
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-uidtest-pod の情報が含まれており、このトークンが特定の Pod に紐づけられていることが確認できます。また、node-namenode-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