15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Bound Service Account Tokenへの切り替えにあたり確認しておくこと

Last updated at Posted at 2021-05-10

はじめに

Kubernetes v1.21.0からはBoundServiceAccountVolumeの機能がデフォルトで有効になり、PodにマウントされるService Account TokenがこれまでのSecretベースのService Account TokenからBound Service Account Tokenへ切り替わります。

参考: Bound Service Account Tokenとは何か

このエントリでは、Bound Service Account Tokenへの切り替えが進むにあたり、Service Account Tokenの利用パターン毎にそれぞれ確認しておくべきことをまとめたいと思います。

利用パターンと確認事項

利用パターンとしては、大きく送信側と受信側のワークロードに分けることができます。
それに加えて、対象のWorkloadがKubernetesクラスタの中に配置されているのか、外に配置されているのかも関係してきます。

Kubernetesクラスタ内からService Account Tokenを利用する

これはKubenretesのPodがSerivce Account Tokenを扱う場合に該当します。

この場合、ワークロードはService Account Tokenをどのように扱っているかがポイントになります。SDKを経由してService Account Tokenを扱う場合、そのSDKがBound Service Account Tokenに対応していることを確認します。例えば、client-goの場合、v11.0.0+またはv0.15.0+となっているかを確認します。

read-token-via-sdk.png

SDKなどを使わずワークロードがfilesystemから直接読み込んでいるような場合、ワークロード自身でService Account Tokenのリロードが必要になります。Bound Service Account Tokenはkubeletによって自動的にローテーションされてPodに反映されるので、ワークロードは有効期限が切れる前にfilesystemから再読込するような対応が必要です。

directly-read-token.png

正しくBound Service Account Tokenへの切り替えができているかどうかは、serviceaccount_legacy_tokens_totalserviceaccount_stale_tokens_totalのメトリクスで確認することができます。

Kubernetsクラスタ外からService Account Tokenを利用する

これはCI/CD、自動化のためのワークロードなどが該当しそうです。

このパターンでは、SecretベースのService Account Tokenを外部に持ち出し、クラスタ内のKubernetes APIサーバやクラスタ内外のワークロードに対する通信でクレデンシャルとして利用していると思います。

BoundServiceAccountVolume自体はPodにマウントされるService Account TokenがBound Service Account Tokenになるという話であるため、このパターンに直接的な影響はありません。現状ではBoundServiceAccountVolumeが有効化されても、SecretベースのService Account Tokenが無効化されたり、新規発行が停止されるようなことはないため、そのまま使い続けることは可能です。(セキュリティ的な面としてSecretベースのService Account Tokenは無効化が難しいなどの問題はあります)
ただしSecretベースのService Account Tokenを発行しているToken Controllerの削除も検討されているようであり、将来的には代替手段の検討が必要になってくると思われます。

参考:
- https://github.com/kubernetes/kubernetes/issues/77599
- https://github.com/kubernetes/kubernetes/issues/77600

現時点で別の手段を検討するのであれば、CSR APIを使ったTLSクライアント証明書への移行や、Secretにバインドしたlong-livedなBound Service Account Token(--service-account-max-token-expirationが設定されている場合にはその値が最大となる)、クラウド基盤のクレデンシャル(AWS IAM Keypairのような)などが候補になりそうです。

external-workload.png

補足

Service Account Tokenをクラスタの外で扱うことの是非については、kubernetesコミュニティ内でも明確な結論は出ていないようです。

広義にはクラスタ外のワークロードも含まれると思いますが、
https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#user-accounts-versus-service-accounts では

User accounts are for humans. Service accounts are for processes, which run in pods.

のような記述もあり、クラスタ外のワークロードに対する位置づけは微妙なところです。

e.g. Secretに紐付けたBound Service Account Token

$ curl \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Content-Type: application/json" \
  -d @token-req.json  \
  https://127.0.0.1:61399/api/v1/namespaces/default/serviceaccounts/default/token
{
  "kind": "TokenRequest",
  "apiVersion": "authentication.k8s.io/v1",
  "spec": {
     "audience": [
     "https://kubernetes.default.svc"
    ],
    "expirationSeconds": 157680000, 
    "boundObjectRef": {
      "kind": "Secret",
      "apiVersion": "v1",
      "name": "default-token-xxx"
    }
  }
}

これで得たTokenは紐づくSecretを削除すると無効化されます。

Kubernetesクラスタ内でSerivce Account Tokenを受け取る

送信元の認証のためにBearer Tokenとして送られてきたService Account Tokenを検証する場合などのパターンです。

Bound Service Account Tokenの検証にはKubernetesのTokenReview APIを使った方法や、v1.21.0でGAに昇格したServiceAccountIssuerDiscoveryの機能を使ってAPIサーバからJWKsを取得し、署名を検証する方法があります。どちらの方法を使っても問題は無さそうですが、JWKsエンドポイントから取得する場合には、Service Account Tokenの検証フローがOIDCでいうID Tokenの検証に近いものとなるためOIDCのエコシステムの恩恵を受けやすくなったり、APIサーバの負荷軽減に繋がるなどの利点があります。

TokenReview APIまたはOIDC Configuration/JWKsエンドポイントに対してアクセス制御が設定されており、クレデンシャルとしてService Account Tokenを利用する場合には、先述のKubernetesクラスタ内からService Account Tokenを利用するの内容を確認してください。

verify-token).png

Kubernetesクラスタ外でService Account Tokenを受け取る

基本的にクラスタ内で受け取る場合と同様で、どちらの機能も利用できますがTokenReview APIまたはOIDC Configuration/JWKsエンドポイントに対してアクセス制御が設定されている場合には、Kubernetesクラスタ外からService Account Tokenを利用するの内容を確認してください。

クラスタ外からのアクセスになるため、JWKsをキャッシュしておける分ServiceAccountIssuerDiscoveryの機能を使ったほうが可用性は高そうです。また、ServiceAccountIssuerDiscoveryの機能ではsystem:service-account-issuer-discoveryのClusterRoleに対してsystem:unauthenticatedを紐付けることで認証なしにJWKsエンドポイントから検証鍵が取得できるため、外部のワークロードにクレデンシャルを渡さなくてすむようなことも可能です。ただし外部から認証なしにアクセスできてしまうことになるのでセキュリティ要件等、注意は必要です。

external-verify-token.png

15
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?