TT Lab
はじめる
学ぶ 学習パス コース

Kubernetes運用実務

ServiceAccount — ワークロードのアイデンティティ

TT Labで続きを見る

一言でいうと

人は外部の認証システムでアイデンティティを証明しますが、PodはServiceAccountで証明します。その証明書がトークンであり、最近のトークンは有効期限が切れます。

なぜ必要なのか

クラスターの中で動くプログラムも、APIを呼び出します。Operator、コントローラー、モニタリングエージェント、CIランナーが、すべてそうです。これらに人間のアカウントを発行することはできないため、Kubernetesはワークロード専用のアイデンティティであるServiceAccountを用意しています。Podは自分のSAのトークンをファイルとしてマウントされ、apiserverはそのトークンでサブジェクトを識別します。その後の判定は、前のモジュールで学んだRBACが行います。認証(誰なのか)と認可(何ができるのか)は別物という構造が、ここで鮮明に見えます。

問題は、以前の方式でした。1.24より前は、SAを作成するとトークンを含むSecretが自動的に1つ作られ、そのトークンには有効期限がありませんでした。一度漏れると永遠に有効な認証情報が、クラスターごとに何十個も転がっていたということです。ログに出力されても、イメージレイヤーに残っても、コピーを追跡する方法もありませんでした。

どう動くのか

1.24からデフォルトが変わりました。SAを作成してもSecretが自動的には作られず、Podには有効期間が決められたprojectedトークンがマウントされます。kubeletが期限切れの前に自動で更新するので、アプリケーションはファイルを読み直すだけで済みます。

トークンを手動で取得するときは、TokenRequest APIを使います。

kubectl create token payments -n sa-lab --duration=3600s --audience=vault

このトークンのペイロードを開くと、3つのことが見えます。subはサブジェクト(system:serviceaccount:<네임스페이스>:<이름>)、audはこのトークンをどこで使うのか、expとiatは有効期間です。audが重要なのは、再利用攻撃を防ぐからです。Vaultに渡すために発行したトークンがapiserverにも通用すると、1か所が突破されたときにほかの場所まで開いてしまいます。対象が埋め込まれたトークンは、その対象でのみ有効です。

Podの仕様に直接書くと、次のようになります。

volumes:
  - name: vault-token
    projected:
      sources:
        - serviceAccountToken:
            audience: vault
            expirationSeconds: 3600
            path: vault-token

この仕組みが、クラウドのワークロードアイデンティティの基盤です。Podが受け取ったこの短命のトークンをクラウドのSTSに提示すると、一時的な認証情報に交換してくれます。保存すべき静的なキーそのものがなくなります。

逆方向の制御もあります。トークンが不要なPodには、そもそも渡さないことです。

spec:
  automountServiceAccountToken: false

このフィールドは、PodにもServiceAccountにも設定できます。アカウント側に設定すると、そのアカウントを使うすべてのPodにデフォルトで適用されます。Webサーバーのように、APIをまったく呼び出さないワークロードは、トークンを持っている理由がなく、コンテナが突破されたときに攻撃者が持ち去れるものが1つ減ります。

レガシーな方式も、今でも作成できます。kubernetes.io/service-account-tokenタイプのSecretにkubernetes.io/service-account.nameアノテーションを付けると、有効期限のないトークンができます。クラスター外のツールがTokenRequestに対応していないときの最後の手段ですが、有効期限がないということは、取り消しの手続きを人が100%責任を持つということなので、推奨されません。

現場での姿

1つ目は、defaultサービスアカウントの乱用です。SAを指定しないPodは、ネームスペースのdefaultを使います。その結果、1つのネームスペースのすべてのPodが同じアイデンティティを共有することになり、権限を少しでも与えた瞬間に、その権限が全員に広がります。Podごとに専用のSAを与えるのが基本です。

2つ目は、権限は依然としてRBACが決めることです。SAを作成しただけでは、権限は何も生じません。逆に、便宜上設定しておいたバインディング1つが、ワークロードに過剰な権限を与えてしまうこともあります。--asで問い合わせる習慣は、ここでも有効です。

3つ目は、トークンファイルのパスです。デフォルトのマウントパスは/var/run/secrets/kubernetes.io/serviceaccountです。コンテナ乗っ取り事故の分析で、攻撃者が最初に確認するパスでもあります。サイドカーやデバッグコンテナも同じものを見られるという点を、覚えておく必要があります。

次のラボですること

専用のSAを作成してPodに付け、自動マウントされたトークンボリュームを確認します。トークンをオフにする2つの方法を、Podとアカウントの両方で適用してみて、TokenRequestで取得したトークンのペイロードをデコードし、サブジェクト・対象・有効期間を自分で読み取ります。対象が指定されたprojectedトークンを仕様に書き、レガシーの長期トークンSecretを作成してそのリスクを整理したあと、最後に使用状況の監査レポートを作成します。