Kubernetes サービスアカウント

Pod に割り当てる ID で、RBAC と連携して Pod の API アクセス権限を制御する

Kubernetes認証

Kubernetes サービスアカウントとは

サービスアカウント (ServiceAccount) は、Pod に割り当てる ID である。人間のユーザーアカウントとは異なり、Pod が Kubernetes API や外部サービスにアクセスする際の認証に使用する。RBAC (Role-Based Access Control) と組み合わせて、Pod ごとに最小権限を付与する。

基本的な設定

サービスアカウントを作っただけでは、その Pod にできることは 1 つも増えない。権限は Role (何ができるか) と RoleBinding (誰に許すか) の組で初めて成立するため、実際の設定は ServiceAccount・Role・RoleBinding・それを使う Pod の 4 つで 1 セットになる。Role と RoleBinding は Namespace 単位のオブジェクトなので、この 4 つは同じ Namespace に揃える。また RoleBinding の roleRef は作成後に変更できず、参照先を差し替えたいときは RoleBinding を削除して作り直す。

# 1. サービスアカウントの作成
apiVersion: v1
kind: ServiceAccount
metadata:
  name: order-service
  namespace: production
---
# 2. ロールの定義 (何ができるか)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: order-service-role
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
---
# 3. ロールバインディング (誰に何を許可するか)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: order-service-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: order-service
roleRef:
  kind: Role
  name: order-service-role
  apiGroup: rbac.authorization.k8s.io
---
# 4. Pod にサービスアカウントを割り当て
apiVersion: v1
kind: Pod
metadata:
  name: order-service
  namespace: production
spec:
  serviceAccountName: order-service
  containers:
    - name: app
      image: order-service:1.0

トークンはどのように Pod へ渡るか

サービスアカウントの実体は Kubernetes API に対する ID であり、Pod はそれを表すトークンで API サーバーに認証される。Kubernetes 1.22 以降は、kubelet が TokenRequest API を使って短命のトークンを取得し、投影ボリューム (projected volume) としてコンテナにマウントする。このトークンは期限が来る前に kubelet が入れ替えるため、アプリケーション側は起動時に一度読むのではなく、必要なときにファイルを読み直す実装にしておく。1.22 より前は、Secret に入った長期・静的なトークンが渡されていた。

さらに 1.24 より前は、サービスアカウントを作るたびに期限のないトークンを持つ Secret が自動生成されていた。この自動生成は 1.24 で既定停止となり、1.27 ではその挙動を切り替える機能ゲート自体が削除されて固定された。期限のないトークンを手動で作ることは今でもできるが、失効しない資格情報が残るので、通常は投影トークンに任せる。

投影トークンには結び付いた Pod の名前と UID が埋め込まれ、TokenReview の応答でも Pod 名・Pod UID・ノード名として返る。結び付いた Pod が存在しなくなった場合や UID が一致しない場合、API サーバーはそのトークンでの認証を通さない。ただし自前でトークンの署名だけを検証する実装では、この「今も有効か」の確認までは行われない。そこまで保証が必要なら TokenReview API を使う。トークンに含まれるノード情報は認証時に API サーバーが検証しない仕様なので、認可の判断材料にはしない。

EKS での IAM 連携 (IRSA)

EKS では IAM Roles for Service Accounts (IRSA) を使って、サービスアカウントに IAM ロールを紐づけられる。Pod が S3 や DynamoDB にアクセスする際、ノードの IAM ロールではなく Pod 固有の IAM ロールで認証される。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: order-service
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/order-service-role

IRSA のメリット:

  • Pod ごとに異なる IAM 権限を付与できる (ノード共有の IAM ロールより細かい制御)
  • 一時的な認証情報が自動的にローテーションされる
  • EC2 メタデータサービスへのアクセスが不要 (SSRF 攻撃のリスク軽減)

EKS Pod Identity (IRSA と並ぶもう 1 つの選択肢)

re:Invent 2023 で発表された EKS Pod Identity は、クラスターごとに OIDC プロバイダーを設定しなくても Pod へ IAM の一時認証情報を渡せる方式である。ただし AWS は IRSA を置き換えるものとしてではなく、IRSA と並ぶ選択肢として位置づけている。IRSA は EKS 以外 (EKS Anywhere や EC2 上の自前 Kubernetes など) でも使えるのに対し、Pod Identity は EKS のために作られた仕組みだからである。

適用条件も広くはない (2026 年 8 月時点)。Pod Identity が使えるのは Linux の EC2 ワーカーノード上で動く Pod だけで、Fargate 上の Pod・Windows の EC2 ノード上の Pod・AWS Outposts・EKS Anywhere・EC2 上の自前 Kubernetes は対象外である。前提として各ノードでエージェント (eks-pod-identity-agent アドオン。EKS Auto Mode では組み込み済み) を動かし、ノードの IAM ロールに EKS Auth API を呼ぶ権限を与え、ノードからその API に到達できるようにしておく (プライベートサブネットでは PrivateLink のエンドポイントが必要)。クラスターのバージョンにも下限がある。

つまり OIDC プロバイダーの管理を、ノード常駐エージェントの運用に置き換える取引である。Fargate を併用している場合や、EKS 以外のクラスターも同じ方式で揃えたい場合は IRSA を選ぶことになる。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: order-service
# Pod Identity では annotations 不要。AWS コンソールまたは CLI で関連付け

デフォルトサービスアカウントの危険性

各 Namespace には default サービスアカウントが自動作成される。サービスアカウントを指定しない Pod はすべて default を使う。

問題点:

  • 全 Pod が同じ ID を共有するため、権限の分離ができない
  • default 自体は、RBAC を有効にしたクラスターで認証済みの相手すべてに与えられる API ディスカバリー相当以外の権限を持たない。問題が現実になるのは「動かすために」誰かが default へ権限を足したときで、その 1 回の変更が Namespace 内の全 Pod に効いてしまう
  • 認証の記録からは、投影トークンに入っている情報を通じてどの Pod かを辿れる。しかし ID が同じである限り、「この Pod にはここまで」という権限側の切り分けはできない

対策:

  • Pod ごとに専用のサービスアカウントを作成する
  • default サービスアカウントの自動マウントを無効化する
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
automountServiceAccountToken: false  # トークンの自動マウントを無効化

default は Namespace ごとに存在し、削除してもコントロールプレーンが作り直すので、この設定は Namespace ごとに入れる。さらに同じフィールドは Pod の spec 側にも書けて、両方に値がある場合は Pod 側が優先される。サービスアカウント側で false にしても Pod 側で true と書かれればマウントされてしまうため、Kubernetes API を呼ばない Pod では Pod 側にも明示しておく。

Role と ClusterRole の使い分け

判断は「触りたいリソースが Namespace に属するか」で決まる。ノードや PersistentVolume のように Namespace を持たないリソースは、ClusterRole でしか書けない。

種類スコープ用途
Role + RoleBindingNamespace 内特定 Namespace のリソースへのアクセス
ClusterRole + RoleBindingその RoleBinding がある Namespace 内共通の権限セットを 1 か所で定義し、Namespace 単位で使い回す
ClusterRole + ClusterRoleBindingクラスター全体ノード、PV など Namespace を跨ぐリソース

見落としやすいのは 2 行目で、ClusterRole を RoleBinding から参照した場合、権限が及ぶのはその RoleBinding を置いた Namespace の中だけである。逆に読み取りしか許さない ClusterRole でも ClusterRoleBinding で束ねると全 Namespace の同種リソースが見えてしまう。迷ったら RoleBinding 側から参照する。

サービスアカウント vs IAM ロール

両者は「Kubernetes API に対する ID」と「AWS API に対する ID」であり、どちらかを選ぶ関係にはない。EKS の Pod から AWS を呼ぶ構成は、この 2 つを IRSA か EKS Pod Identity で橋渡ししている。

観点K8s サービスアカウントIAM ロール
割り当てる対象Namespace 内の PodLambda 関数、ECS タスク、EC2 インスタンスなど AWS 側の実行環境
権限が及ぶ範囲Kubernetes API のリソース操作AWS API の操作
資格情報クラスターが署名したトークン (投影ボリュームでマウント)STS が発行する一時認証情報
相互の橋渡しIRSA または EKS Pod Identity で IAM ロールへ結び付けるAWS 側の実行環境には直接付けられる

Kubernetes サービスアカウントの背景や設計思想は関連書籍に詳しい。

この記事は役に立ちましたか?

関連用語

関連する記事