はじめに
こんにちは。satyamです。
Amazon EKS 上で動作するアプリケーションでは、Amazon S3 などの AWS サービスへアクセスする必要があります。ポッド内に AWS アクセスキーを保存する方法でも動作しますが、不要なセキュリティリスクや管理負荷が発生します。
Pod Identity を利用すると、固定のアクセスキーをポッド内に保存せず、IAM ロールを通じて一時的な AWS 認証情報を使用できます。
本記事では、Pod Identity を使用して、Kubernetes ワークロードから Amazon S3 へ安全かつ制御されたアクセスを実現する方法を紹介します。
- はじめに
- Pod Identity の概要
- 前提条件
- 環境変数の設定
- 既存環境の確認
- IAM ポリシーと Pod Identity 用 IAM ロールの作成
- Namespace と ServiceAccount の作成
- Pod Identity の関連付けの作成
- アクセスを許可するテストポッドのデプロイ
- IAM ロールと S3 アクセスの確認
- Pod Identity の関連付けがない場合のアクセス確認
- まとめ
Pod Identity の概要
Pod Identity を使用すると、特定の Kubernetes ワークロードに AWS の権限を割り当てることができます。
この構成では、主に次の 3 つの要素を使用します。
Kubernetes ServiceAccount
EKS クラスター内で動作するワークロードを識別します。IAM ロール
アタッチされた IAM ポリシーにより、ワークロードが実行できる AWS サービスの操作を定義します。Pod Identity の関連付け
Kubernetes ServiceAccount と IAM ロールを関連付けます。
Amazon EKS Pod Identity Agent は、関連付けられた ServiceAccount を使用するポッドに、IAM ロールの一時的な認証情報を提供します。
これにより、ワーカーノード上のすべてのポッドに同じ AWS 権限を付与するのではなく、必要なワークロードだけに権限を限定できます。
前提条件
作業を開始する前に、以下のリソースとツールが利用できることを確認します。
- 既存の Amazon EKS クラスター
- Ready 状態のワーカーノードが 1 台あるノードグループ
- EKS アドオンとしてインストール済みの Amazon EKS Pod Identity Agent
- 既存の Amazon S3 バケット(パブリックアクセスはブロックしておくことを推奨)
- S3 バケットに保存された sample.txt
- インストールおよび設定済みの AWS CLI
- 対象の EKS クラスターに接続できるよう設定済みの kubectl
- AWS CLI を実行するサーバーに設定された、以下の EKS 読み取り権限を持つ IAM ロール
eks:DescribeCluster eks:DescribeNodegroup eks:DescribeAddon eks:ListPodIdentityAssociations
sample.txt の内容は任意の固定テキストで問題ありません。
たとえば、以下のような内容を使用できます。
Testing...... こんにちは、Pod Identity。
環境変数の設定
本記事で使用するリソース名をまとめて管理するため、環境変数ファイルを作成します。
cat > eks-pod-identity-env.sh <<'EOF' # 既存のリソース export AWS_REGION="<AWS_REGION>" export CLUSTER_NAME="<EKS_CLUSTER_NAME>" export NODEGROUP_NAME="<NODEGROUP_NAME>" export BUCKET_NAME="<S3_BUCKET_NAME>" # 本記事で作成するリソース export NAMESPACE="pod-identity-demo" export SERVICE_ACCOUNT="s3-access-sa" export IAM_POLICY_NAME="EKS-Pod-Identity-S3-Policy" export POD_IDENTITY_ROLE="EKS-Pod-Identity-S3-Role" export AUTHORIZED_POD="s3-access-test" export UNAUTHORIZED_POD="s3-access-denied-test" EOF
プレースホルダー部分は、利用する環境の既存リソース情報に置き換えてください。
その他のリソース名は変更しても問題ありませんが、後続のコマンド、マニフェスト、AWS コンソールの設定でも同じ名前を使用してください。
環境変数を現在のシェルセッションに読み込みます。
source eks-pod-identity-env.sh
※ 注意点
サーバーへ再接続した場合や、新しいシェルセッションを開始した場合は、同じコマンドを再度実行してください。
設定した値を確認します。
printf 'AWS_REGION=%s\nCLUSTER_NAME=%s\nNODEGROUP_NAME=%s\nBUCKET_NAME=%s\nNAMESPACE=%s\nSERVICE_ACCOUNT=%s\nIAM_POLICY_NAME=%s\nPOD_IDENTITY_ROLE=%s\nAUTHORIZED_POD=%s\nUNAUTHORIZED_POD=%s\n' \ "$AWS_REGION" \ "$CLUSTER_NAME" \ "$NODEGROUP_NAME" \ "$BUCKET_NAME" \ "$NAMESPACE" \ "$SERVICE_ACCOUNT" \ "$IAM_POLICY_NAME" \ "$POD_IDENTITY_ROLE" \ "$AUTHORIZED_POD" \ "$UNAUTHORIZED_POD"
実行結果:
AWS_REGION=<AWS_REGION> CLUSTER_NAME=<EKS_CLUSTER_NAME> NODEGROUP_NAME=<NODEGROUP_NAME> BUCKET_NAME=<S3_BUCKET_NAME> NAMESPACE=pod-identity-demo SERVICE_ACCOUNT=s3-access-sa IAM_POLICY_NAME=EKS-Pod-Identity-S3-Policy POD_IDENTITY_ROLE=EKS-Pod-Identity-S3-Role AUTHORIZED_POD=s3-access-test UNAUTHORIZED_POD=s3-access-denied-test
既存環境の確認
AWS CLI と kubectl が設定されているサーバーから、以下の確認を行います。
1. AWS の実行ユーザーを確認する
aws sts get-caller-identity \
--query '{Account:Account,Arn:Arn}' \
--output yaml
実行結果:
Account: '<AWS_ACCOUNT_ID>' Arn: arn:aws:sts::<AWS_ACCOUNT_ID>:assumed-role/<IAM_ROLE_NAME>/<SESSION_NAME>
AWS CLI が使用している AWS アカウントと、EC2 インスタンスプロファイルに設定された IAM ロールを確認します。
2. EKS クラスターを確認する
aws eks describe-cluster \
--name "$CLUSTER_NAME" \
--region "$AWS_REGION" \
--query 'cluster.{Name:name,Status:status,Version:version}' \
--output yaml
実行結果:
Name: <EKS_CLUSTER_NAME> Status: ACTIVE Version: <EKS_KUBERNETES_VERSION>
3. ノードグループを確認する
aws eks describe-nodegroup \
--cluster-name "$CLUSTER_NAME" \
--nodegroup-name "$NODEGROUP_NAME" \
--region "$AWS_REGION" \
--query 'nodegroup.{Name:nodegroupName,Status:status}' \
--output yaml
実行結果:
Name: <NODEGROUP_NAME> Status: ACTIVE
4. ワーカーノードを確認する
kubectl get nodes
実行結果:
NAME STATUS ROLES AGE VERSION <WORKER_NODE_NAME> Ready <none> ... <KUBERNETES_VERSION>
1 台のワーカーノードが Ready 状態であることを確認します。
5. kubectl のインストールと接続を確認する
kubectl version
実行結果:
Client Version: v<KUBECTL_VERSION> Kustomize Version: v<KUSTOMIZE_VERSION> Server Version: v<EKS_KUBERNETES_VERSION>
Client Version と Server Version が表示されれば、kubectl が対象の EKS クラスターへ接続できていることを確認できます。
6. Amazon EKS Pod Identity Agent のアドオンを確認する
aws eks describe-addon \
--cluster-name "$CLUSTER_NAME" \
--addon-name eks-pod-identity-agent \
--region "$AWS_REGION" \
--query 'addon.{Name:addonName,Status:status,Version:addonVersion}' \
--output yaml
実行結果:
Name: eks-pod-identity-agent Status: ACTIVE Version: <ADDON_VERSION>
7. Amazon EKS Pod Identity Agent のポッドを確認する
kubectl get pods -n kube-system | grep pod-identity
実行結果:
eks-pod-identity-agent-xxxxx 1/1 Running 0 ...
Amazon EKS Pod Identity Agent のポッドが Running 状態であることを確認します。
IAM ポリシーと Pod Identity 用 IAM ロールの作成
1. IAM ポリシーを作成する
IAM コンソールの「ポリシー」→「ポリシーの作成」から作成します。
「JSON」を選択し、以下のポリシーを入力します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListTargetBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::<S3_BUCKET_NAME>"
},
{
"Sid": "ReadObjectsFromTargetBucket",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<S3_BUCKET_NAME>/*"
}
]
}
<S3_BUCKET_NAME> を、使用する既存の S3 バケット名に置き換えます。
ポリシー名には、以下を入力します。
EKS-Pod-Identity-S3-Policy
設定内容を確認し、[ポリシーの作成] を選択します。

2. IAM ロールを作成する
IAM コンソールの「ロール」→「ロールを作成」から作成します。
「信頼されたエンティティタイプ」→「カスタム信頼ポリシー」を選択し、以下の信頼ポリシーを入力します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
「許可ポリシー」で、前の手順で作成した以下のポリシーを選択します。
EKS-Pod-Identity-S3-Policy
ロール名には、以下を入力します。
EKS-Pod-Identity-S3-Role
設定内容を確認し、[ロールを作成] を選択します。

Namespace と ServiceAccount の作成
Namespace と ServiceAccount を定義するマニフェストファイルを作成します。
cat > service-account.yaml <<'EOF' apiVersion: v1 kind: Namespace metadata: name: pod-identity-demo --- apiVersion: v1 kind: ServiceAccount metadata: # Pod Identity の関連付けに使用する ServiceAccount name: s3-access-sa namespace: pod-identity-demo EOF
作成したマニフェストを適用します。
kubectl apply -f service-account.yaml
実行結果:
namespace/pod-identity-demo created serviceaccount/s3-access-sa created
Namespace を確認します。
kubectl get namespace "$NAMESPACE"
実行結果:
NAME STATUS AGE pod-identity-demo Active ...
Namespace のステータスが Active であることを確認します。
ServiceAccount を確認します。
kubectl get serviceaccount "$SERVICE_ACCOUNT" -n "$NAMESPACE"
実行結果:
NAME AGE s3-access-sa ...
指定した Namespace 内に ServiceAccount が作成されていることを確認します。
Pod Identity の関連付けの作成
Amazon EKS コンソールの「クラスター」→「対象の EKS クラスター名」→「アクセス」から設定します。
「Pod Identity の関連付け」で、[作成] を選択します。
以下の値を入力します。
IAM ロール:EKS-Pod-Identity-S3-Role Kubernetes 名前空間:pod-identity-demo Kubernetes サービスアカウント:s3-access-sa

その他の設定はデフォルトのままとし、設定内容を確認して [作成] を選択します。

サーバーから作成結果を確認します。
aws eks list-pod-identity-associations \ --cluster-name "$CLUSTER_NAME" \ --region "$AWS_REGION"
実行結果:
{
"associations": [
{
"clusterName": "<EKS_CLUSTER_NAME>",
"namespace": "pod-identity-demo",
"serviceAccount": "s3-access-sa",
"associationArn": "arn:aws:eks:<AWS_REGION>:<AWS_ACCOUNT_ID>:podidentityassociation/<EKS_CLUSTER_NAME>/<ASSOCIATION_ID>",
"associationId": "<ASSOCIATION_ID>"
}
]
}
対象の Namespace と ServiceAccount の関連付けが作成されていることを確認します。
アクセスを許可するテストポッドのデプロイ
アクセスを許可するテストポッドのマニフェストファイルを作成します。
cat > s3-access-test.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: s3-access-test
namespace: pod-identity-demo
spec:
# Pod Identity の関連付けに設定した ServiceAccount を使用
serviceAccountName: s3-access-sa
containers:
- name: aws-cli
image: public.ecr.aws/aws-cli/aws-cli:latest
command:
- /bin/sh
- -c
- sleep 3600
restartPolicy: Never
EOF
※ 注意点
本マニフェストでは、検証用ポッド内で AWS CLI コマンドを実行するために、公開コンテナイメージを使用しています。コンテナイメージ自体は、本検証の対象外です。
作成したマニフェストを適用します。
kubectl apply -f s3-access-test.yaml
実行結果:
pod/s3-access-test created
ポッドのステータスを確認します。
kubectl get pod "$AUTHORIZED_POD" -n "$NAMESPACE"
実行結果:
NAME READY STATUS RESTARTS AGE s3-access-test 1/1 Running 0 ...
ポッドのステータスが Running であることを確認します。
ポッドが使用している ServiceAccount を確認します。
kubectl get pod "$AUTHORIZED_POD" \
-n "$NAMESPACE" \
-o jsonpath='{.spec.serviceAccountName}{"\n"}'
実行結果:
s3-access-sa
Pod Identity の関連付けに設定した ServiceAccount を、ポッドが使用していることを確認します。
IAM ロールと S3 アクセスの確認
1. ポッドが使用している IAM ロールを確認する
kubectl exec -n "$NAMESPACE" "$AUTHORIZED_POD" -- \ aws sts get-caller-identity
実行結果:
{
"UserId": "<USER_ID>",
"Account": "<AWS_ACCOUNT_ID>",
"Arn": "arn:aws:sts::<AWS_ACCOUNT_ID>:assumed-role/EKS-Pod-Identity-S3-Role/<SESSION_NAME>"
}
ARN に以下の文字列が含まれていることを確認します。
assumed-role/EKS-Pod-Identity-S3-Role
ポッドが Pod Identity を通じて、以下の ServiceAccount に関連付けられた IAM ロールを使用していることを確認します。
- s3-access-sa
2. Pod Identity の認証情報用環境変数を確認する
kubectl exec -n "$NAMESPACE" "$AUTHORIZED_POD" -- \ env | grep AWS_CONTAINER
実行結果:
AWS_CONTAINER_CREDENTIALS_FULL_URI=<CREDENTIALS_URI> AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE=/var/run/secrets/pods.eks.amazonaws.com/<TOKEN_FILE>
Pod Identity の認証情報エンドポイントと認証トークンが、ポッド内で利用できることを確認します。
3. 固定の AWS 認証情報に関する環境変数が設定されていないことを確認する
kubectl exec -n "$NAMESPACE" "$AUTHORIZED_POD" -- \ /bin/sh -c 'env | grep -E "^AWS_(ACCESS_KEY_ID|SECRET_ACCESS_KEY|SESSION_TOKEN)=" || true'
実行結果:
出力なし
固定の AWS 認証情報に関する環境変数が、ポッド内に設定されていないことを確認します。
4. S3 バケット内のオブジェクトを一覧表示する
kubectl exec -n "$NAMESPACE" "$AUTHORIZED_POD" -- \
aws s3 ls "s3://${BUCKET_NAME}"
実行結果:
<DATE> <TIME> <SIZE> sample.txt
ポッドから対象の S3 バケット内のオブジェクトを一覧表示できることを確認します。
5. テストオブジェクトを読み取る
kubectl exec -n "$NAMESPACE" "$AUTHORIZED_POD" -- \
aws s3 cp "s3://${BUCKET_NAME}/sample.txt" -
実行結果:
Testing...... こんにちは、Pod Identity。
ポッドから対象の S3 バケット内のテストオブジェクトを読み取れることを確認します。
Pod Identity の関連付けがない場合のアクセス確認
デフォルトの ServiceAccount を使用するポッドを作成します。
cat > s3-access-denied-test.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: s3-access-denied-test
namespace: pod-identity-demo
spec:
# serviceAccountName を指定せず、デフォルトの ServiceAccount を使用
containers:
- name: aws-cli
image: public.ecr.aws/aws-cli/aws-cli:latest
command:
- /bin/sh
- -c
- sleep 3600
restartPolicy: Never
EOF
※ 注意点
本マニフェストでは、検証用ポッド内で AWS CLI コマンドを実行するために、公開コンテナイメージを使用しています。コンテナイメージ自体は、本検証の対象外です。
マニフェストを適用します。
kubectl apply -f s3-access-denied-test.yaml
実行結果:
pod/s3-access-denied-test created
ポッドのステータスを確認します。
kubectl get pod "$UNAUTHORIZED_POD" -n "$NAMESPACE"
実行結果:
NAME READY STATUS RESTARTS AGE s3-access-denied-test 1/1 Running 0 ...
ポッドが Running 状態であることを確認します。
使用している ServiceAccount を確認します。
kubectl get pod "$UNAUTHORIZED_POD" \
-n "$NAMESPACE" \
-o jsonpath='{.spec.serviceAccountName}{"\n"}'
実行結果:
default
Pod Identity の関連付けがないデフォルトの ServiceAccount を使用していることを確認します。
AWS の IAM アイデンティティを取得できないことを確認します。
kubectl exec -n "$NAMESPACE" "$UNAUTHORIZED_POD" -- \ aws sts get-caller-identity
実行結果:
aws: [ERROR]: An error occurred (NoCredentials): Unable to locate credentials. You can configure credentials by running "aws login". command terminated with exit code 253
デフォルトの ServiceAccount を使用するポッドが、AWS の認証情報を取得できないことを確認します。
S3 へのアクセスを確認します。
kubectl exec -n "$NAMESPACE" "$UNAUTHORIZED_POD" -- \
aws s3 ls "s3://${BUCKET_NAME}"
実行結果:
aws: [ERROR]: An error occurred (NoCredentials): Unable to locate credentials. You can configure credentials by running "aws login". command terminated with exit code 253
この環境では、Pod Identity の関連付けがないポッドが、対象の S3 バケットへアクセスできないことを確認します。
まとめ
本記事では、Pod Identity を使用し、ポッド内に固定の AWS 認証情報を保存せずに、EKS 上のワークロードから特定の S3 バケットへアクセスする構成を作成しました。
IAM ポリシーと Pod Identity 用の IAM ロールを作成し、Kubernetes の ServiceAccount と関連付けたうえで、その ServiceAccount を使用するテストポッドをデプロイしました。テストポッドは一時的な AWS 認証情報を取得し、対象の S3 バケットへアクセスできました。
また、デフォルトの ServiceAccount を使用するポッドでは、AWS 認証情報を取得できず、S3 バケットへもアクセスできないことを確認しました。
この結果から、Pod Identity を利用することで、必要なワークロードだけに AWS サービスへのアクセス権限を付与できることが確認できました。同じ仕組みは、DynamoDB、SQS、Secrets Manager などにも活用できます。




