kOps v1.21.0 を使い Amazon EKS Pod Identity webhook をやめて IRSA を実現する

kOps の v1.21.0 が今月の頭にリリースされて、その中の1つに "Service Account Issuer Discovery and AWS IAM Roles for Service Accounts (IRSA)" という変更が入りました。

この変更を使うことで kOps は OIDC ディスカバリ ドキュメント を S3 に公開してそれを IRSA で使えるように設定してくれます。
github.com

IRSA についてはこちらの記事が参考になります。

aws.amazon.com

今まで自分はこの IRSA を実現するために上記の記事でも紹介されている Amazon EKS Pod Identity webhook を使ってきました。
EKS の場合は特に自分で何かを用意する必要はないのですが、 kOps のように自分でクラスタを構築している場合は OIDC ディスカバリ ドキュメント を自分で作成する必要があり鍵つくったりS3にコンテンツをアップロードします。
さらに webhook 用の Pod や MutatingWebhookConfiguration を管理する必要がありメンテナンスがちょっと面倒です。

詳しい導入方法などは以前書いた下記の記事に書いてあります。

blog.hatappi.me

この記事ではこれらを kOps v1.21.0 から入った変更を使ってリプレイスしていきます。

kOps 側の設定

導入手順としては複雑なものはなく下記の公式ドキュメントに従って設定していくだけです。
kops.sigs.k8s.io

ただ Amazon EKS Pod Identity webhook を設定していた時と被る部分があったので Amazon EKS Pod Identity webhook で設定した値は削除しました。

-  fileAssets:
-    # For IAM Role for Service Accounts)
-    - name: service-account-signing-key-file
-      path: /srv/kubernetes/assets/service-account-signing-key
-      isBase64: true
-      content: {{.service_account_private_key}}
-    - name: service-account-key-file
-      path: /srv/kubernetes/assets/service-account-key
-      isBase64: true
-      content: {{.service_account_key}}
-  kubeAPIServer:
-    serviceAccountKeyFile:
-      - "/srv/kubernetes/server.key"
-      - "/srv/kubernetes/assets/service-account-key"
-    serviceAccountSigningKeyFile: /srv/kubernetes/assets/service-account-signing-key
-    apiAudiences:
-      - oidc-aaaaa-bbbbb-cccccc.s3.amazonaws.com
-    serviceAccountIssuer: https://oidc-aaaaa-bbbbb-cccccc.s3.amazonaws.com
+  serviceAccountIssuerDiscovery:
+    discoveryStore: s3://[public な bucket名]
+    enableAWSOIDCProvider: true

discoveryStore に設定した S3 バケットはドキュメントに書かれているようにパブリックにアクセスできる必要があります。
Terraform で作成する場合の最低限の設定は下記になります。

resource "aws_s3_bucket" "oidc" {
  bucket = "[public な bucket名]"
  acl    = "public-read"
}

後はドキュメントに書かれているように Kubernetes のサービスアカウントと AWS IAM Policy を紐付ける設定を下記のように行い update を完了したら kOps 側の作業は終わりです。

spec:
  iam:
    serviceAccountExternalPermissions:
      - name: [指定したnamespace内の任意のserviceAccount]
        namespace: [任意namespace名]
        aws:
          policyARNs:
            - arn:aws:iam::000000000000:policy/somePolicy

IRSAを使う

Amazon EKS Pod Identity webhook の時は webhook によって Pod 起動時に AWS のクレデンシャル情報が Inject されていました。
そのため Pod 作成時は紐付ける ServiceAccount だけを気にしました。

ただ今回の kOps で設定した時は自動的に Inject されないので Pod の定義に必要な情報を自分で設定する必要があります。
(これ間違っていたら教えてほしいです。)

具体的には今回下記の設定を Pod に追加しました。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test
spec:
  template:
      spec:
        serviceAccountName: test
        containers:
            ~~~~
            - name: AWS_REGION
              value: "ap-northeast-1"
            - name: AWS_ROLE_ARN
              value: "arn:aws:iam::000000000:role/test.default.sa.cluster"
            - name: AWS_WEB_IDENTITY_TOKEN_FILE
              value: "/var/run/secrets/amazonaws.com/serviceaccount/token"
          volumeMounts:
            - mountPath: "/var/run/secrets/amazonaws.com/serviceaccount/"
              name: aws-token
        volumes:
        - name: aws-token
          projected:
            sources:
            - serviceAccountToken:
                audience: "amazonaws.com"
                expirationSeconds: 86400
                path: token

導入してみて

導入自体は Amazon EKS Pod Identity webhook よりも楽になりました。
IRSA の使用時の YAML の記述量は少し増えましたが個人的にはそこまで気にならないのとwebhook がなくなった分構成もシンプルになったので良かったです。

ただ1つ気になったのは ServiceAccount と IAM Policy の紐付けを kOps の YAML ファイルに記載するので追加したり編集するたびに kOps での update が必要になる部分です。
ただ実際の処理を見てみると IAM Role の StringEquals や Federated に OIDC 周りの設定をしているだけなので自分で Terraform とか使って作れそうな感じでした。
このあたりは今後の kOps のアップデートで何か別の設定方法がでてくるのを楽しみにしたいと思います。