[アップデート] EKS Pod Identity で簡単にクロスアカウントの権限付与ができるようになりました

[アップデート] EKS Pod Identity で簡単にクロスアカウントの権限付与ができるようになりました

こんにちは。クラウド事業本部の枡川です。
1 ヶ月前の話題ですが、EKS で Pod Identity を利用して権限付与を行う際、簡単にクロスアカウントアクセスを付与できるようになりました。

https://aws.amazon.com/jp/about-aws/whats-new/2025/06/amazon-eks-pod-identity-cross-account-access/

https://docs.aws.amazon.com/eks/latest/userguide/pod-id-assign-target-role.html

ここで 「エクスペリエンスが簡素化された」 と言っているのは、アプリケーション側で AssumeRole のことを意識せず、EKS 側の設定だけでクロスアカウントアクセスを扱えるということのようです。
どれだけ簡単になったのか、実際に構築して試してみようと思います。

リソース作成

今回は Terraform で下記構成を構築して、試してみます。

arch.png

v6.2.0 以上の AWS Provider を利用していれば、Pod Identity を作成する際にクロスアカウントアクセスを設定できます。

https://github.com/hashicorp/terraform-provider-aws/releases/tag/v6.2.0

role_arn と合わせて、target_role_arn を指定すれば良い形ですね!

target_role_arn - (Optional) The Amazon Resource Name (ARN) of the IAM role to be chained to the the IAM role specified as role_arn.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_pod_identity_association

ただ、AWS EKS Terraform module を利用する条件として、aws provider が < 6.0.0 である必要があったので、今回は Pod Identity 周りのみマネジメントコンソールから設定することとします。
aws_eks_cluster などを使って、普通に定義しても良いんですけどね...
少し面倒だったのと、初めてその機能を触る際はマネジメントコンソールの方がわかりやすいって話もあるので!

https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/20.37.1

ターゲットアカウント (DynamoDB が存在するアカウント) のリソース作成

まず、ターゲットアカウントに DynamoDB と IAM ロールを作成します。
もっと細かくアクセスを制限するべきかもしれませんが、ソースアカウント側で厳しく制限する前提で緩めのポリシーとしています。

resource "aws_dynamodb_table" "test-table" {
  provider     = aws.account-b
  name         = "test-dynamodb"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "UserId"

  attribute {
    name = "UserId"
    type = "S"
  }
}

data "aws_iam_policy_document" "pod_identity_assume_role_policy" {
  statement {
    effect = "Allow"

    principals {
      type        = "AWS"
      identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
    }

    actions = ["sts:AssumeRole", "sts:TagSession"]
  }
}

resource "aws_iam_role" "dynamodb_access" {
  provider           = aws.account-b
  name               = "dynamo-db-access-role"
  assume_role_policy = data.aws_iam_policy_document.pod_identity_assume_role_policy.json
}

resource "aws_iam_role_policy_attachment" "dynamodb_access" {
  provider   = aws.account-b
  role       = aws_iam_role.dynamodb_access.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess"
}

sts:AssumeRole だけではなく、sts:TagSession も付与することがポイントです。
※ 恐らく、Pod Identity 作成時にセッションタグを無効にするオプションを選択すれば不要ですが、基本権限を付与しつつ有効化で良いと思います。
DynamoDB には適当なデータを突っ込んでおきます。

data.png

ソースアカウント (EKS が存在するアカウント) のリソース作成

VPC を作成します。

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.17.0"

  name = "eks-vpc"

  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  public_subnets  = ["10.0.0.0/24", "10.0.1.0/24", "10.0.2.0/24"]
  private_subnets = ["10.0.100.0/24", "10.0.101.0/24", "10.0.102.0/24"]

  enable_nat_gateway = true
  single_nat_gateway = true
  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }

}

EKS (Auto Mode) と Pod Identity で指定する IAM ロールを作成します。

locals {
  cluster_name                  = "test-cluster"
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.37.1"

  cluster_name                    = local.cluster_name
  cluster_version                 = "1.33"
  cluster_endpoint_public_access  = true
  cluster_endpoint_private_access = true

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  enable_cluster_creator_admin_permissions = true

  cluster_compute_config = {
    enabled    = true
    node_pools = ["general-purpose"]
  }

  bootstrap_self_managed_addons = false
}

data "aws_iam_policy_document" "allow_pod_identity" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }

    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]
  }
}

resource "aws_iam_role" "app" {
  name               = "app-sa-role"
  assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}

resource "aws_iam_role_policy_attachment" "app" {
  role       = aws_iam_role.app.name
  policy_arn = aws_iam_policy.assume_role_policy.arn
}

data "aws_iam_policy_document" "assume_role_policy" {
  statement {
    effect = "Allow"
    actions = ["sts:AssumeRole", "sts:TagSession"]
    resources = [aws_iam_role.dynamodb_access.arn]
  }
}

resource "aws_iam_policy" "assume_role_policy" {
  name   = "assume-role-policy"
  policy = data.aws_iam_policy_document.assume_role_policy.json
}

Pod Identity の関連付け

関連付けの前に Kubernetes 側の権限を取得して、Service Account を作成します。
Pod Identity は Service Account と IAM ロールを関連付けて使うためです。

aws eks update-kubeconfig --name test-cluster

名前空間を作ります。

% kubectl create ns app
namespace/app created

Service Account も作成します。

% kubectl create sa app-sa -n app
serviceaccount/app-sa created

マネジメントコンソールから、Pod Identity の設定を行います。

pod-identity.png

Assume Role 可能な権限を付与した IAM ロールと、Assume Role 先の IAM ロールを指定します。
コンソールにも、クロスアカウントアクセスに関する記述がありますね!

続いて、下記のように DynamoDB アクセスを行う Python アプリケーションのコンテナを作成します。
この際、Assume Role に関する記述は一切書いておりません。

from fastapi import FastAPI
import boto3

app = FastAPI()

@app.get("/")
def read_root():
    dynamodb = boto3.client("dynamodb", region_name="ap-northeast-1")
    response = dynamodb.scan(
        TableName="test-dynamodb",
    )
    return response["Items"]

Boto3 のassume_role を使えば同じことを実現できますが、アプリケーションがシンプルであることに越したことはないので嬉しいですね。
ではマニフェストファイルを用意して、アプリケーションコンテナを作成していきます。

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: app
  name: fast-api
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: fast-api
  replicas: 1
  template:
    metadata:
      labels:
        app.kubernetes.io/name: fast-api
    spec:
      serviceAccountName: app-sa
      containers:
        - image: xxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/fast-api-app:v3
          imagePullPolicy: Always
          name: fast-api
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: "0.5"

Service を作成します。

apiVersion: v1
kind: Service
metadata:
  namespace: app
  name: fast-api
spec:
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
  type: NodePort
  selector:
    app.kubernetes.io/name: fast-api

IngressClass を作成します。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  namespace: app
  labels:
    app.kubernetes.io/name: LoadBalancerController
  name: alb
spec:
  controller: eks.amazonaws.com/alb

Ingress を作成します。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: app
  name: fast-api-ingress
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: fast-api
                port:
                  number: 80

払い出された DNS 名にアクセスすると、無事クロスアカウントで DynamoDB 内のデータを取得できました!

% curl http://k8s-app-fastapii-821882c6be-1557614806.ap-northeast-1.elb.amazonaws.com
[{"UserId":{"S":"1"},"Name":{"S":"Taro"}}]

最後に

EKS 側の設定だけで、簡単に Pod に対してクロスアカウントの権限を付与することができました!
aws-for-fluent-bit の Pod Identity 対応や Auto Mode への Pod Identity Agent 組み込みなどもあり、いよいよ新規構築時は Pod Identity を選ばない理由が無くなってきた感じがあります。

https://dev.classmethod.jp/articles/aws-for-fluent-bit-eks-pod-identity/

皆さんも是非、便利にセキュアに便利に EKS を使っていきましょう!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.