1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【EKS】Pod Identityの流れと仕組みを理解する

Last updated at Posted at 2025-03-29

Proxy環境で Pod Identityを利用するにあたって、Pod Identityの流れや通信を詳しく調べる必要があったので、調査結果を残しておきます。

■ 結論

Pod Identity を利用する場合、以下にアクセスできる必要があります。

  • ロールを引き受けるPod
    • 169.254.170.23 (pod-identity-agentのエンドポイント)
      Pod Identityで関連付けを作成したIAMロールの認証情報を取得するのに必要
  • pod-identity-agent
    • 169.254.169.254 (インスタンスメタデータサービスのエンドポイント)
      ノードロールの認証情報を取得するのに必要
    • eks-auth.ap-northeast-1.api.aws (EKS Authエンドポイント)
      AssumeRoleForPodIdentity APIを呼び出すために必要
      EKSサービスエンドポイント

■ Pod Identityの処理の流れ

pod-identity.drawio.png

1. Podに適用するIAM Roleの作成

Podに適用するIAM RoleにはEKS Pod Identityによる使用を許可する信頼ポリシーを設定します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowEksAuthToAssumeRoleForPodIdentity",
            "Effect": "Allow",
            "Principal": {
                "Service": "pods.eks.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}

2. Pod Identityの関連付けを作成

作成したIAMロールでPod Identityの関連付けを作成します。
Pod Identityの関連付けでは、どのNamespaceのどのServiceAccountがIAM Roleを使用できるかを設定します。

aws eks create-pod-identity-association \
  --cluster-name my-cluster \
  --role-arn arn:aws:iam::111122223333:role/my-role \
  --namespace pod-identity-test \
  --service-account my-service-account

3. Podの作成

Pod Identityの関連付けで指定した Namespace と ServiceAccount でPodを起動します。

app.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: pod-identity-test
---
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: pod-identity-test
  name: my-service-account
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: pod-identity-test
  name: awscli
spec:
  selector:
    matchLabels:
      app: awscli
  replicas: 2
  template:
    metadata:
      labels:
        app: awscli
    spec:
      serviceAccountName: my-service-account
      containers:
      - name: aws-cli
        image: public.ecr.aws/aws-cli/aws-cli:2.17.37
        command: ["sleep", "infinity"]
kubectl apply -f app.yaml

4~6. EKS Pod Identity Webhookでマニフェストを変更

マニフェストがapplyされるとEKS Pod Identity Webhookが処理をインターセプトします。

aws/amazon-eks-pod-identity-webhook | GitHub
※ EKS Pod Identity WebhookはEKSのマネージドです。

EKS Pod Identity WebhookはPod Identityの関連付けにマニフェストで指定されたNamespaceとServiceAccountのが存在するかをチェックします。
Pod Identity の関連付けが存在する場合、Podのマニフェストに以下を追加します。

    env:
    - name: AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE
      value: "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/eks-pod-identity-token"
    - name: AWS_CONTAINER_CREDENTIALS_FULL_URI
      value: "http://169.254.170.23/v1/credentials"
    volumeMounts:
    - mountPath: "/var/run/secrets/pods.eks.amazonaws.com/serviceaccount/"
      name: eks-pod-identity-token
  volumes:
  - name: eks-pod-identity-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: pods.eks.amazonaws.com
          expirationSeconds: 86400 # 24 hours
          path: eks-pod-identity-token

7~8. Podを起動

変換されたマニフェストでkubeletがPodを起動します。

9. Podからpod-identity-agentの認証エンドポイントにIAM認証情報を要求

Pod内でAWS SDKを実行すると、SDKは一時的なIAM認証情報を取得するため 、Authorizationヘッダにサービスアカウントトークンを含めて AWS_CONTAINER_CREDENTIALS_FULL_URI にリクエストを送信します。

Curlで再現するとこんな感じです。

# セッショントークンを変数に格納
SERVICE_ACCOUNT_TOKEN=$(cat $AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE)

# pod-identity-agentのエンドポイントにアクセスしてAWSの認証情報を取得
curl -H "Authorization: $SERVICE_ACCOUNT_TOKEN" "$AWS_CONTAINER_CREDENTIALS_FULL_URI" | jq .
# {
#   "AccessKeyId": "XXXXXXXXXXXXXXXXXXXX",
#   "SecretAccessKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
#   "Token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
#   "AccountId": "xxxxxxxxxxxxxx",
#   "Expiration": "2025-03-28T13:12:52Z"
# }

10~11. pod-identity-agentがIMDSにノードロールのIAM認証情報を要求

EKS AuthのAssumeRoleForPodIdentity APIを実行してAWSの認証情報を取得するには、IAMの eks-auth:AssumeRoleForPodIdentity 権限が必要となるため、pod-identity-agentはインスタンスメタデータサービス( IMDS)( 169.254.169.25 ) にアクセスしてノードロールの認証情報を取得します。

ノード上でインスタンスメタデータサービス( IMDS)( 169.254.169.25 ) への通信をtcpdumpでキャプチャすると以下のリクエストを確認できます。

tcpdump -tnlA -i any "tcp and dst port 80 and dst 169.254.169.254"
  • PUT /latest/api/token HTTP/1.1
    IMDSv2 のトークン取得リクエスト
    IMDSv2 では最初に PUT リクエストでトークンを取得し、それ以降のメタデータ取得にこのトークンを使う仕組みです。
  • GET /latest/meta-data/iam/security-credentials/
    IAM ロール名の一覧を取得しています
  • GET /latest/meta-data/iam/security-credentials/KarpenterNodeRole
    指定された IAM ロール (KarpenterNodeRole) のクレデンシャル情報を取得しています。
    これには一時的なアクセスキー、シークレットキー、セッショントークンなどが含まれます。
IP 10.32.1.37.34244 > 169.254.169.254.http: Flags [P.], seq 0:277, ack 1, win 491, options [nop,nop,TS val 2945826404 ecr 3130553910], length 277: HTTP: PUT /latest/api/token HTTP/1.1
E..I.|@...x.
 .%.......P^,.....a....`}.....
...d..v6PUT /latest/api/token HTTP/1.1
Host: 169.254.169.254
User-Agent: aws-sdk-go-v2/1.26.1 os/linux lang/go#1.22.5 md/GOOS#linux md/GOARCH#amd64 ft/ec2-imds
Content-Length: 0
Amz-Sdk-Request: attempt=1; max=3
X-Aws-Ec2-Metadata-Token-Ttl-Seconds: 300
Accept-Encoding: gzip

................

IP 10.32.1.37.oracleas-https > 169.254.169.254.http: Flags [P.], seq 0:325, ack 1, win 491, options [nop,nop,TS val 2945826405 ecr 3130553911], length 325: HTTP: GET /latest/meta-data/iam/security-credentials/ HTTP/1.1
E..y.M@...j.
 .%.......P$..\........`......
...e..v7GET /latest/meta-data/iam/security-credentials/ HTTP/1.1
Host: 169.254.169.254
User-Agent: aws-sdk-go-v2/1.26.1 os/linux lang/go#1.22.5 md/GOOS#linux md/GOARCH#amd64 ft/ec2-imds
Amz-Sdk-Request: attempt=1; max=3
X-Aws-Ec2-Metadata-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Accept-Encoding: gzip

................
IP 10.32.1.37.49431 > 169.254.169.254.http: Flags [P.], seq 0:355, ack 1, win 491, options [nop,nop,TS val 2945826406 ecr 3130553912], length 355: HTTP: GET /latest/meta-data/iam/security-credentials/KarpenterNodeRole HTTP/1.1
E...X.@.....
 .%.......P..:..*......`......
...f..v8GET /latest/meta-data/iam/security-credentials/KarpenterNodeRole HTTP/1.1
Host: 169.254.169.254
User-Agent: aws-sdk-go-v2/1.26.1 os/linux lang/go#1.22.5 md/GOOS#linux md/GOARCH#amd64 ft/ec2-imds
Amz-Sdk-Request: attempt=1; max=3
X-Aws-Ec2-Metadata-Token: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Accept-Encoding: gzip

................

※ 補足: インスタンスメタデータサービス(IMDS)について

12~14. pod-identity-agentがEKS Auth APIエンドポイントにPodのIAM認証情報を要求

pod-identity-agentがノードロールの認証情報を取得できたら、EKS Auth ( eks-auth.ap-northeast-1.api.aws ) の AssumeRoleForPodIdentity API にサービスアカウントトークンとクラスタ名を指定してリクエストを送信し、Pod Identityでサービスアカウントに関連付けられたIAMロールの認証情報を取得します。

pod-identity-agentのソースコードだとこの辺りです
internal/cloud/eksauth/service.go#L46 - aws/eks-pod-identity-agent | GitHub

※ 補足1: EKS Authのエンドポイントの一覧
※ 補足2: AssumeRoleForPodIdentity API (boto3)

15. PodがPod Identityに関連付けたIAMロールの認証情報を取得

Pod Identityに関連付けられたIAMロールの認証情報をレスポンスとして受け取ります。

{
  "AccessKeyId": "XXXXXXXXXXXXXXXXXXXX",
  "SecretAccessKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "Token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "AccountId": "xxxxxxxxxxxxxx",
  "Expiration": "2025-03-28T13:12:52Z"
}

■ さらに調査

pod-identity-agentのエンドポイント( 169.254.170.23 )について

エンドポイントの存在確認

pod-identity-agentのDaemonsetは hostNetwork: true で起動しているため、エンドポイントはkubernetes上から確認できません。

まずはこのエンドポイントがホスト上に存在していて、pod-identity-agentプロセスがそのエンドポイントをListenしているかを確認します。

ノードにログインして下記コマンドを実行します。

# ノードが169.254.170.23:80 をListenしていることを確認します。
netstat -tuln | grep 169.254.170.23:80
# tcp        0      0 169.254.170.23:80       0.0.0.0:*               LISTEN

# どのプロセスがポート80を利用しているかを確かめる
lsof -i :80 
# COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
# eks-pod-i 2699 root    6u  IPv6  18423      0t0  TCP [fd00:ec2::23]:http (LISTEN)
# eks-pod-i 2699 root    7u  IPv4  19305      0t0  TCP ip-10-32-1-37.ap-northeast-1.compute.internal:http (LISTEN)

# プロセスツリーでpod-identity-agentがポートを利用しているプロセスであることを確認
pstree -pa
#  |-containerd-shim,1568 -namespace k8s.io -id5a5f80457fd7f9323a63824372c9182f8fb6ca 
#  |   |-go-runner,2676 /eks-pod-identity-agent server --port 80 --cluster-name baseport-prd --probe-port 2703
#  |   |   |-eks-pod-identit,2699 server --port 80 --cluster-name baseport-prd --probe-port 2703

ipコマンドで pod-id-link0 インターフェースに 169.254.170.23 が設定されているかを確認します。

ip a | grep -B 2 -A 5  169.254.170.23
# 3: pod-id-link0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000
#     link/ether 4e:a0:b6:ea:bf:2e brd ff:ff:ff:ff:ff:ff
#     inet 169.254.170.23/32 scope global pod-id-link0
#        valid_lft forever preferred_lft forever
#     inet6 fd00:ec2::23/128 scope global
#        valid_lft forever preferred_lft forever
#     inet6 fe80::4ca0:b6ff:feea:bf2e/64 scope link
#        valid_lft forever preferred_lft forever

pod-identity-agentのエンドポイントへのリクエストをtcpdump

ノード上で169.254.170.23 へのリクエストをtcpdumpして、pod側でaws sts get-caller-identity を実行すると、AWS_CONTAINER_CREDENTIALS_FULL_URI へのリクエストが確認できます。

tcpdump -tnlA -i any "tcp and port 80 and dst 169.254.170.23"
IP 10.32.1.213.53620 > 169.254.170.23.http: Flags [P.], seq 0:1385, ack 1, win 491, options [nop,nop,TS val 1679748253 ecr 1911346896], length 1385: HTTP: GET /v1/credentials HTTP/1.1
E....H@.....
 .......t.P'VRB..M.....e......
d...q...GET /v1/credentials HTTP/1.1
Host: 169.254.170.23
Accept-Encoding: identity
Accept: application/json
Authorization: [サービスアカウントトークン(JWT)]
User-Agent: python-urllib3/1.26.19
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?