【実務・中級編】 コンテナ環境におけるIAMロールの割り当て(EKS IRSA/GKE Workload Identity) – インフラ・ネットワーク & クラウドセキュリティ防御ガイド

なぜ「ノード単位の権限付与」が、あなたのクラウド環境を崩壊させるのか

エンジニアの諸君、お疲れ様。今日も「動けばいい」という甘い誘惑と戦っていることだろう。だが、クラウドセキュリティの現場で長年インシデントを見てきた私から言わせれば、「ノード(EC2やノードプール)にIAMロールを直付けする」のは、鍵のかかっていない家の玄関に全財産を置いておくのと同じだ。

Kubernetes(EKSやGKE)を使っているなら、Podごとに権限を絞る「IRSA (IAM Roles for Service Accounts)」や「Workload Identity」は、もはやオプションではなく必須の教養だ。なぜなら、攻撃者は常に「最も権限の強いPod」を起点にラテラルムーブメント(横展開)を狙っているからだ。

攻撃者の視点:Podが「ノードの特権」を悪用する瞬間

もし、あるPodが脆弱性(例えば、最近流行りのOSSライブラリのRCEなど)を突かれて侵入されたとしよう。ノードにIAMロールが付与されていると、そのPodは「ノードが持つ権限」をそのまま継承する。

攻撃者は、メタデータサービス(169.254.169.254)を叩くだけで、ノードのクレデンシャルを盗み出し、S3バケットを全公開したり、他のインフラを破壊したりする。これはもはや、「ただのWebアプリの脆弱性」では済まない。クラウド全体を乗っ取られる「致命的なインシデント」への切符だ。

実装:Pod単位で最小権限を割り当てる(AWS EKS IRSAの例)

「Pod単位の分離」とは、OIDCプロバイダーを経由して、KubernetesのServiceAccountにIAMロールを紐付ける仕組みだ。これにより、Podは「その業務に必要なS3バケットだけを操作できる」といった制限が可能になる。

1. IAMロールの作成(信頼関係の設定)

IAMロールの信頼ポリシーには、KubernetesのServiceAccountを指定する必要がある。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.region.amazonaws.com/id/EXAMPLED..."
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.region.amazonaws.com/id/EXAMPLED...:sub": "system:serviceaccount:default:my-app-sa"
        }
      }
    }
  ]
}

*※ここで sub に system:serviceaccount:<namespace>:<serviceaccount-name> を指定するのが肝だ。これで、特定のNamespaceの特定のSA以外はこのロールを使えなくなる。*

2. Kubernetes側のマニフェスト

ServiceAccountにアノテーションを付与するだけで、AWS SDKが自動的に一時的なクレデンシャルを取得してくれる。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-app-sa
  namespace: default
  annotations:
    # ここで先ほど作成したIAMロールのARNを指定する
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-app-s3-access-role
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  template:
    spec:
      serviceAccountName: my-app-sa # 忘れずに指定すること
      containers:
      - name: app
        image: my-app:latest

アプリケーションコードでの確認(Python/Boto3)

SDKは、この設定を自動で検知する。コード側で aws_access_key_id などをハードコードする必要は一切ない。

import boto3
import os

# IRSAが正しく設定されていれば、環境変数 AWS_WEB_IDENTITY_TOKEN_FILE が自動注入される
# Boto3は自動的にそのトークンを使い、一時的なロールへスイッチする
s3 = boto3.client('s3')

def list_my_bucket():
    try:
        # このPodに許された権限でのみアクセス可能
        response = s3.list_objects_v2(Bucket='my-secure-data-bucket')
        print(response.get('Contents'))
    except Exception as e:
        print(f"権限エラーまたは接続失敗: {e}")

if __name__ == "__main__":
    list_my_bucket()

現場のセキュリティ担当者が教える「守りの鉄則」

最後に、現場で泣きを見ないためのチェックリストを置いておく。

1. ノードロールの剥奪: ノード(Worker Node)に付与されているIAMロールを極限まで削れ。基本は AmazonEKSWorkerNodePolicy など必要最低限のものだけにし、S3やDynamoDBへのアクセス権限はノードから外せ。
2. IMDSv2の強制: AWSでは、メタデータサービスへのアクセスにセッションベースのトークンを必須にする IMDSv2 を強制すること。これにより、SSRF脆弱性を突いたクレデンシャル抽出の難易度を大幅に上げられる。
3. 監査ログの監視: CloudTrail で AssumeRoleWithWebIdentity の呼び出しを監視せよ。予期せぬPodからのアクセスがあれば、即座にアラートが飛ぶようにしておくのがプロの仕事だ。

セキュリティは「魔法の杖」を振って完了するものではない。こうした地味な設定の積み重ねが、攻撃者のモチベーションを削ぎ、あなたのシステムを守る防波堤となる。

さあ、明日からのデプロイでは、全てのPodに「必要最小限の権限」が与えられているか、もう一度見直してほしい。それができるエンジニアだけが、自信を持って「安全だ」と言えるのだから。

コメント

タイトルとURLをコピーしました