[Kubernetes] マイ・ポッドの身分証が変わった? Service AccountとProjected Volumeを徹底解剖 🆔

こんにちは!今日は、Kubernetesセキュリティの基本であり核心であるService Account(サービスアカウント)について深く掘り下げていきたいと思います。

単に「Podに権限を与えるときに使うものじゃないの?」と思っていた方は、今日の投稿を通じて、より深い内容を持ち帰ることができるでしょう。特に、最近のKubernetesバージョンで標準となったProjected VolumeBound Tokenの概念は、セキュリティの観点から非常に重要なので、必ず理解しておきましょう。

10分だけ投資して、Kubernetes認証構造の核心をマスターしてください! 🚀

image


1. Service Account (SA): Podのための身分証 🪪

私たちが会社の建物に入る際に社員証をかざすように、Kubernetesクラスター内部でPod内のアプリケーションがAPIサーバーと通信するには身分証が必要です。これがService Accountです。

👤 User Account vs. 🤖 Service Account

  • User Account: 人間(Human)のためのアカウントです。(管理者、開発者など)。主にグローバルに管理され、AWS IAMやGoogleアカウントなどの外部システムと連携します。
  • Service Account: プロセス(Bot)のためのアカウントです。Namespaceに依存する点が最も大きな特徴です。

Podを作成する際に別途指定しない場合、Kubernetesは自動的にそのNamespaceのdefaultサービスアカウントを割り当てます。


2. 過去の方法: 「永遠に腐らない鍵」(Legacy) 🗝️

以前(Legacy)の方法では、サービスアカウントを作成すると自動的にSecret(シークレット)リソースが作成されました。そして、このシークレットの中には有効期限のない(No Expiration)トークンが入っていました。

この方法には致命的な欠点がありました。

  1. セキュリティ脆弱性: トークンが一度盗まれると、管理者が手動で失効させるまでハッカーが永遠に使用できてしまいます。
  2. 管理の不便さ: トークンを交換(Rotation)するには、シークレットを削除して再作成するという面倒な作業が必要でした。

そのため、KubernetesコミュニティはProjected Volumeという新しい技術を導入しました。


3. 現在の標準: Projected Volumeと「生きているトークン」 ✨

最新のKubernetesでは、トークンは静的なSecretに保存されません。代わりにProjected Volumeを利用して、Podが作成されるその瞬間にAPIサーバーから「一時トークン」を発行してもらい、Podに注入します。

📽️ なぜ「Projected(投影された)」という名前なのですか?

一般的なボリュームマウントが単一のストレージを接続するのに対し、Projected Volume複数のソース(Source)を一つのディレクトリに集めて(投影して)見せる技術だからです。

通常、次の3つの情報が1つのフォルダ(/var/run/secrets/kubernetes.io/serviceaccount)に混在して表示されます。

  1. serviceAccountToken: 認証のためのJWTトークン
  2. configMap (kube-root-ca.crt): APIサーバー信頼のための証明書
  3. downwardAPI: PodのNamespace情報

4. コア技術: Bound Service Account Token 🔗

Projected Volumeを通じて注入されるトークンはBound Tokenと呼ばれます。どこかに強力に「묶여(Bound)」いるからです。この概念がセキュリティの核心です。

① Time Bound(時間制限) ⏳

このトークンには有効期間があります(デフォルトは1時間)。

  • Legacy: 有効期限なし。
  • Modern: expirationSecondsが設定されています。

② Object Bound(Podへの依存) 📦

このトークンは、発行された特定のPod(Pod UID)と運命を共にします。

  • Podが削除されると、トークンも即座に無効化されます。
  • 攻撃者がトークンをコピーして別のPodで使おうとしても、トークン内部の情報と実行環境が一致しない場合、拒否される可能性があります。

③ Audience Bound(使用目的の制限) 🎯

トークンに aud(Audience)フィールドを設定できます。

  • 「このトークンはAWS認証用だ」として発行された場合、このトークンでKubernetes APIサーバーをハッキングしようとしても、「あれ?君はAWS用じゃないか?」と拒否されます。
  • Istioのようなサービスメッシュは、この機能を積極的に活用してサービス間の認証を行います。

5. YAMLファイルを覗いてみよう 📝

皆さんのPod YAMLファイルの一番下を見ると、kubeletが自動的に追加した次のような設定が見られます。

YAML

volumes:
  - name: kube-api-access-xxxxx
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          expirationSeconds: 3607  # 👈 1時間後に失効!
          path: token
      - configMap:
          items:
          - key: ca.crt
            path: ca.crt
          name: kube-root-ca.crt
      - downwardAPI:
          items:
          - fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
            path: namespace

この設定のおかげで、Pod内部のアプリケーションは /var/run/secrets/kubernetes.io/serviceaccount/token ファイルを読み込んで、安全に通信できるのです。


6. トークンが期限切れになったらアプリは死ぬの?(Token Rotation) 🔄

「1時間後に期限切れになるなら、私のサービスも1時間後に停止するの?」

いいえ!心配しないでください。

Kubeletが非常に勤勉に動いています。

  1. トークンの有効期限が近づくと、Kubeletは自動的にAPIサーバーに新しいトークンをリクエストします。
  2. そして、Pod内部にマウントされたtokenファイルを新しいトークン値で上書き(Update)します。
  3. アプリケーション(ほとんどのK8sクライアントライブラリ)は、定期的にファイルを再読み込みしてトークンを更新します。

⚠️ 注意点: アプリケーションを直接開発する場合、トークンファイルを最初に読み込んだら終わりではなく、定期的に再読み込みするロジック(Reload)を実装する必要があります。(Goクライアントなど標準ライブラリは既に実装されています。)


7. まとめ 🎁

今日の内容を3行で要約してみましょう。

  1. Service Accountは、PodがKubernetes APIと対話するための身分証です。
  2. セキュリティのため、Projected Volume方式を使用し、寿命が短く自動更新されるトークン(Bound Token)を使用します。
  3. このトークンはPodと運命を共にし、特定のPodに묶られて(Bound)いるため、盗まれてもリスクが低いです。

これで、kubectl get pod -o yaml を実行したときに出てくる複雑なprojected構文も怖くないですよね?これは、皆さんのクラスターを安全に守るためのKubernetesの細やかな配慮なのです。 🛡️

今日も安全で楽しいKubernetesライフをお過ごしください!



Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です