この記事は、「EKSを使わずにIRSAを使う」試みの3回目の記事です。
これまでの記事の内容と課題
以下の2つの記事で、kubeadmで構築したKubernetesクラスターにおいて、ServiceAccountを使ってIAMロールを引き受けられる(AssumeRoleできる)状態、つまりIRSAが使える状態になっています。
しかしながら、Podのマニフェストに以下を毎回書く必要があります。
-
AWS_ROLE_ARN/AWS_WEB_IDENTITY_TOKEN_FILEのenv -
projectedのserviceAccountTokenボリューム定義とvolumeMount
これは動作確認としては分かりやすいのですが、「Podのマニフェストが冗長」「コピペが増える」「書き間違いが起きる」などのつらさが出ます。
そこで今回は、EKSでも使われている amazon-eks-pod-identity-webhook をインストールし、Mutating WebhookによってPod作成時に必要な定義を自動注入させます。結果として、PodマニフェストからRoleArnやprojected volumeの記述を消し、シンプルに書けることを目標にします。
この記事でやること
- Mutating Webhook(Admission Webhook)が何を解決するかを整理する
- amazon-eks-pod-identity-webhook をHelm(Helmfile)でインストールする
- ServiceAccountにロールを紐付け、Pod側は最小限のマニフェストでIRSAを使えることを確認する
参考情報
本記事の記載内容を実現するための環境は、以下の k8s-irsa-without-eks で構築可能です。
Mutating Webhook とは(今回の文脈)
Kubernetesでは、リソースの作成・更新などのリクエストがkube-apiserverに到達した時点でAdmission Controllerが介入し、リクエストの許可/拒否や、リソース内容の書き換え(ミューテーション)を行えます。例えば、ポリシーに違反するPodを拒否したり、運用ルールに沿うようにPodの定義を自動で補正できます。
このうちMutating Webhookは、kube-apiserverが受け取ったPodの作成リクエストに対してフィールドを追加・変更するパッチを適用し、その結果を「実体として作られるPod」の定義に反映できます。
今回インストールする amazon-eks-pod-identity-webhook は、ざっくり以下を行います。
- Podが参照しているServiceAccountに、IRSA用の注釈(例:
eks.amazonaws.com/role-arn)が付いているかを見る - 条件に合えば、Podに以下を注入する
-
AWS_ROLE_ARNなどのenv - Web Identityトークンのファイルを置くための
projectedボリュームとvolumeMount
-
つまり、前回記事でPodマニフェストに手書きしていた部分を、Webhookが自動で差し込んでくれるイメージです。
amazon-eks-pod-identity-webhook のインストール
以下のHelmfileを使ってインストールします。
repositories:
- name: jkroepke
url: https://jkroepke.github.io/helm-charts/
releases:
- chart: jkroepke/amazon-eks-pod-identity-webhook
version: 2.6.0
createNamespace: false
name: amazon-eks-pod-identity-webhook
namespace: kube-system
values: # 環境に応じて適宜変更ください
- config:
defaultAwsRegion: ap-northeast-1
以下はインストールコマンドです。
helmfile apply -f amazon-eks-pod-identity-webhook.yaml
各リソースがデプロイされているのを確認します。
$ kubectl -n kube-system get svc,deploy,po -l app.kubernetes.io/name=amazon-eks-pod-identity-webhook
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/amazon-eks-pod-identity-webhook ClusterIP 10.106.84.229 <none> 8443/TCP,9999/TCP 94s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/amazon-eks-pod-identity-webhook 1/1 1 1 94s
NAME READY STATUS RESTARTS AGE
pod/amazon-eks-pod-identity-webhook-5d584bc69d-92jp4 1/1 Running 0 93s
以下のように、MutatingWebhookConfigurationリソースもデプロイされていることを確認できます。
$ kubectl -n kube-system get mutatingwebhookconfigurations | rg -i 'pod-identity'
amazon-eks-pod-identity-webhook 1 3m38s
IAMロールに紐付けるServiceAccountの作成
前回記事と同様に、IAMロールを引き受けるServiceAccountを作成します。
基本は、対象Podが使うServiceAccountにRoleArnのannotationを付与します。
例(前回と同じ default/my-app を使う想定):
AWS_ACCOUNT_ID=012345678901
ROLE_NAME='default/my-app'
kubectl -n default create sa my-app
kubectl -n default annotate sa my-app "eks.amazonaws.com/role-arn=arn:aws:iam::${AWS_ACCOUNT_ID}:role/${ROLE_NAME}"
以下は、上記コマンドをマニフェストで表現したものです。RoleArnのannotationが追加されている点がポイントです。
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: default
annotations: # ポイント
eks.amazonaws.com/role-arn: "arn:aws:iam::012345678901:role/default/my-app"
ここで紐付けるIAMロールの信頼ポリシー(sts:AssumeRoleWithWebIdentity)は、前回記事の内容と同様に sub=system:serviceaccount:default:my-app と aud=sts.amazonaws.com を満たすようにしておく必要があります。
ServiceAccountを使うPodの作成
以下のように、作成したServiceAccountを使うPodのマニフェストを用意します。
apiVersion: v1
kind: Pod
metadata:
name: irsa-test
namespace: default
spec:
serviceAccountName: my-app
containers:
- name: app
image: public.ecr.aws/aws-cli/aws-cli:latest
command: ["sh","-c"]
args:
- |
tail -f /dev/null
マニフェストをもとに、Podをデプロイします。
kubectl apply -f irsa-test.pod.yaml
Podがデプロイされたことを確認します。
$ kubectl get po -n default irsa-test
NAME READY STATUS RESTARTS AGE
irsa-test 1/1 Running 0 25s
前回記事と同様に、PodがIAMロールを引き受けられている(AssumeRoleできている)のを確認できます。
$ kubectl exec -n default -it irsa-test -- aws sts get-caller-identity
{
"UserId": "AROAXK6M****:botocore-session-012345678901",
"Account": "012345678901",
"Arn": "arn:aws:sts::012345678901:assumed-role/my-app/botocore-session-012345678901"
}
$ kubectl exec -n default -it irsa-test -- aws configure list
NAME : VALUE : TYPE : LOCATION
profile : <not set> : None : None
access_key : ****************4HRP : assume-role-with-web-identity :
secret_key : ****************pBSf : assume-role-with-web-identity :
region : ap-northeast-1 : env : ['AWS_REGION', 'AWS_DEFAULT_REGION']
Podのマニフェストがどれだけ簡単になったかの確認
前回記事のPodのマニフェストではAWS_ROLE_ARNなどの環境変数やprojected volumeの設定が必要でしたが、今回はserviceAccountNameの指定だけで済み、非常にシンプルになっています。
前回記事のPodのマニフェストとの差分は以下です。
apiVersion: v1
kind: Pod
metadata:
name: irsa-test
namespace: default
spec:
serviceAccountName: my-app
containers:
- name: app
image: public.ecr.aws/aws-cli/aws-cli:latest
- env:
- - name: AWS_ROLE_ARN
- value: arn:aws:iam::012345678901:role/default/my-app
- - name: AWS_WEB_IDENTITY_TOKEN_FILE
- value: /var/run/secrets/tokens/aws-token
command: ["sh","-c"]
args:
- |
tail -f /dev/null
- volumeMounts:
- - name: aws-token
- mountPath: /var/run/secrets/tokens
- readOnly: true
- volumes:
- - name: aws-token
- projected:
- sources:
- - serviceAccountToken:
- path: aws-token
- audience: sts.amazonaws.com
- expirationSeconds: 3600
amazon-eks-pod-identity-webhookによって変更された箇所の確認
作成されたPodのマニフェストを、以下のコマンドで確認してみましょう。
kubectl get po irsa-test -oyaml
上記の出力とPodのデプロイに使ったマニフェストを比較すると、次のような差分があることがわかりました。
※ 実際のマニフェストでは他の差分もありますが、ここでは関係する差分だけを出力しています。
apiVersion: v1
kind: Pod
metadata:
name: irsa-test
namespace: default
spec:
serviceAccountName: my-app
containers:
- name: app
args:
- |
tail -f /dev/null
command:
- sh
- -c
+ env:
+ - name: AWS_STS_REGIONAL_ENDPOINTS
+ value: regional
+ - name: AWS_DEFAULT_REGION
+ value: ap-northeast-1
+ - name: AWS_REGION
+ value: ap-northeast-1
+ - name: AWS_ROLE_ARN
+ value: arn:aws:iam::012345678901:role/default/my-app
+ - name: AWS_WEB_IDENTITY_TOKEN_FILE
+ value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
image: public.ecr.aws/aws-cli/aws-cli
+ volumeMounts:
+ - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
+ name: aws-iam-token
+ readOnly: true
+ volumes:
+ - name: aws-iam-token
+ projected:
+ defaultMode: 420
+ sources:
+ - serviceAccountToken:
+ audience: sts.amazonaws.com
+ expirationSeconds: 86400
+ path: token
AWS CLIに関する環境変数とprojected volumeの設定が追加されていますね。これは、amazon-eks-pod-identity-webhookがPod作成時にMutating Webhookによって自動注入したものです。
トリガーは my-app のServiceAccountリソース作成時に追加した以下のannotationです。
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::012345678901:role/default/my-app"
ServiceAccountを作成する際に、うっかりこのannotationが抜ける(または内容が間違っている)とAWSに認証できないので、使用時はお気をつけください。
おわりに
PodからIRSAでAWSのリソースにアクセスする際に、前回記事ではAWSにアクセスするための設定を書く必要がありましたが、amazon-eks-pod-identity-webhookを使うことで、それらを書かずに済むことを確認できました。Mutating WebhookによってPodの内容が書き換えられる様子も確認できたので、私自身もKubernetesに関する理解が一つ進んだ気がします。
IRSAの使い勝手を改善したKubernetesクラスターに、次回記事ではaws-ebs-csi-driverをインストールした後に、PVCリソースを作成してAWS EBSのボリュームが調達できることを確認する予定です。