こんにちは、技術本部研究開発部 ML Platformチームの神林です。前回は技術とは関係ないULパッキングの記事を書きました。あまりにも関係なさすぎたので、今回は技術の方に振り戻そうと思います。
AWS re:Invent 2023も後半戦となりました。毎日6時前後起きで20000歩くらい歩いています。私はEKSやKubernetesのBreakout Session、Workshop、Chalk Talkを中心に参加しています。初日は「The future of Amazon EKS」というBreakout Sessionがあったので見に行きました。Breakout Sessionは基本的に後でアーカイブが見られるようになるので、話半分で見ていたら半分以上忘れてしまいました。一つ、スライドの中で気になるワードが出てきたので、そこに絞って詳しく見ていこうと思います。
Centralized IAM roles mapping
スライドを見ていたらJust launched!の機能としてこの見出しのワードが目に入りました。Apply IRSA role to service account mapping via an EKS API. No need to annotate YAML files とも書いてあります。IRSA*1を作成時にKubernetesのService Accountのannotationに書いていたIAM roleとのマッピング設定が不要になるのでしょうか。とても気になります。 タイムリーにAWSから関連しそうな記事が出ていました。
この機能はPod Identityと呼べばいいんでしょうか。機能自体は既に使えるようになっているので、この記事を追いながら試してみましょう。
S3にアクセスするIAM roleを作成
PodからAWSのなんらかのサービスにアクセスするためのIAM roleを作ります。ここではS3のオブジェクトを取得できるようなインラインポリシーを持ったroleをterraformで作ってみます。
resource "aws_iam_role" "simple_pod_identity_role" { name = "simple-pod-identity-role" assume_role_policy = data.aws_iam_policy_document.simple_pod_identity_assume_role_policy.json } data "aws_iam_policy_document" "simple_pod_identity_assume_role_policy" { statement { actions = [ "sts:AssumeRole", "sts:TagSession" ] principals { type = "Service" identifiers = ["pods.eks.amazonaws.com"] } } } resource "aws_iam_role_policy" "simple_pod_identity_inline_policy" { name = "simple-pod-identity-inline-policy" role = aws_iam_role.simple_pod_identity_role.id policy = data.aws_iam_policy_document.s3_policy_document.json } data "aws_iam_policy_document" "s3_policy_document" { statement { actions = [ "s3:GetObject", "s3:ListBucket" ] resources = [ "arn:aws:s3:::*", ] } }
ロールに設定する信頼関係のPrincipalsが pods.eks.amazonaws.com
になっているのがポイントです。
Amazon EKS Pod Identity Agent アドオンのインストール
次にEKSアドオンの Amazon EKS Pod Identity Agent をインストールします。ドキュメントによるとplatform versionが新しいものだけ使えるようなので、既存のクラスターには2023年11月28日現在、まだ適用されていないと思います。早く試したい場合は新しいクラスターを立てる必要があります。クラスター作成作業は省略します。
アドオンもterraformでインストールします。
resource "aws_eks_addon" "addons" { cluster_name = "your-cluster-name" addon_name = "eks-pod-identity-agent" addon_version = "v1.0.0-eksbuild.1" }
失敗するケースを確認
ここまでで一旦podからS3にアクセスできないことを確認しておきます。最初AWS CLIを使って試そうとしていたのですが、AWS CLI v2はまだPod Identityを使ったリソースアクセスに対応していないようで、下記のようなエラーになってしまいました。
Unsupported host '169.254.170.23'. Can only retrieve metadata from these hosts: 169.254.170.2, localhost, 127.0.0.1
169.254.170.23
はPod Identityで使用されるIPアドレスのようです。仕方がないので対応されているAWS SDKを使います。boto3の最新イメージを使って確認してみます。
$ cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: boto3 --- apiVersion: v1 kind: Pod metadata: name: boto3 spec: serviceAccountName: boto3 containers: - name: boto3 image: demisto/boto3py3:1.0.0.81604 command: ["sleep", "infinity"] EOF
このpod内でboto3を使用してS3にアクセスします。
$ kubectl exec pod/boto3 -- python -c "import boto3 s3 = boto3.resource('s3') bucket = s3.Bucket('sample') print([obj.key for obj in bucket.objects.all()])"
すると
An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
というエラーログがでてきます。想定通りの挙動です。
Pod Identity associations
IAM roleをKubernetesのService Accountに紐付けます。terraformは今のところまだ対応していないので、AWS CLIを使用します。AWS CLIはPod Identityを使ったリソースアクセスは対応してないのですが、IAM roleとService Accountの紐付けだけは対応しているようです。AWS CLIも前もって最新にしておきます。
aws eks create-pod-identity-association \ --cluster-name your-cluster-name \ --namespace default \ --service-account boto3 \ --role-arn arn:aws:iam::123456789012:role/simple-pod-identity-role
これでIAM roleとService Accountが紐付きました。
もう一度S3へのアクセスを試してみます。
$ kubectl exec pod/boto3 -- python -c "import boto3 s3 = boto3.resource('s3') bucket = s3.Bucket('sample') print([obj.key for obj in bucket.objects.all()])" ['a.png', 'b/c.txt']
無事にアクセスできることを確認できました。
AWSコンソールをみると、EKSのクラスターページのアクセスタブでPod Identity associationsの情報を見ることができます。ここに全てのassociationsが集約されそうですね。Centralizeとはこのことを指しているようです。
何が嬉しいのか
IAM roleとService AccountのマッピングがCentralizeされるとどのようなメリットがあるのでしょうか。詳しくは下記に記載があります。
この中のReusabilityについて取り上げます。複数のクラスターでIAM roleを共有するようなケース(例えばblue-greenクラスターアップデート)では、IRSAのroleの信頼ポリシーを下記のように設定する方法があります。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/XXXXXXX" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.region-code.amazonaws.com/id/XXXXXXX:sub": "system:serviceaccount:default:your-service-account", "oidc.eks.region-code.amazonaws.com/id/XXXXXXX:aud": "sts.amazonaws.com" } } }, { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.ap-northeast-1.amazonaws.com/id/YYYYYYY" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "oidc.eks.region-code.amazonaws.com/id/YYYYYYY:sub": "system:serviceaccount:default:your-service-account", "oidc.eks.region-code.amazonaws.com/id/YYYYYYY:aud": "sts.amazonaws.com" } } } ] }
EKSクラスターはそれぞれが異なるOIDC Providerを持っているため、クラスターが増えたときに既存のroleの信頼ポリシーを更新する必要がありました。一方、Pod Identityを使うと、
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "pods.eks.amazonaws.com" }, "Action": [ "sts:TagSession", "sts:AssumeRole" ] } ] }
信頼ポリシーはこのようになり、クラスターが増えても固定です。既存のIAM roleを編集しなくてよくなるので、サービスへの影響を考える必要がなくなります。結構嬉しいですね。
ただし、現在Pod Identityには下記のような制約があります。
- Linuxインスタンスのみ
- Fargateでは使えない
- セルフマネージドなアドオンを除くEKSアドオン(VPC CNI、AWS Load Balancer Controller等)は従来通りIRSAを使用する必要がある
まとめ
まだ各種ツールの対応が追いついていないのでProductionで使うには厳しそうですが、運用が楽になるので今後に期待したいと思います。この記事を書いているときにDatadogがさらにDeep Diveした記事を出していて先を越さた感がありますが気にしないことにします。とても参考になりました。
追記: Breakout Sessionのアーカイブが早くも公開されていました。
研究開発部ではEKSの未来について語り明かしたいMLOps/DevOpsエンジニアを募集しています。 open.talentio.com
*1:IAM roles for service accounts