2020/10/15

EKSでServiceAccount毎にIAMロールを作成してpod毎に権限を変更する

awseksterraform

概要

EKSで運用しているwebアプリケーションの中で、特定のS3バケットにアクセスしたいという要件があり対応しました。
IAMユーザーを作成して、ACCESS_KEY_IDやSECRETなどを作成し、それを利用してもよかったのですが
IAMロールを作るやり方が推奨される(ACCESS_KEY_IDやSECRETを作ると、定期的な更新が煩雑なのが理由)ため、やり方を調査して対応しました。

基本的にはサービスアカウントの IAM ロール - Amazon EKSの記事のやり方に沿って対応しました。

簡単に説明すると以下のような感じでした

  1. EKSクラスターがOpenID ConnectプロバイダーURLを保有しているか確認する
  2. IAMのオープンIDコネクトプロバイダーを作成する
  3. サービスアカウントに付与したい権限(IAMポリシー)を作成する
  4. サービスアカウントに紐付けるIAMロールを作成して、作成したIAMポリシーをアタッチする
  5. kubectlでservice accountのリソースを作成する
  6. kubectlでdeployment(pod)にservice accountを使うように変更する

2 ~ 4については、terraform を使って作成しましたが、もちろん手動(コンソール画面)からも作成できます。

実施事項

OpenID ConnectプロバイダーURLの確認

クラスターでのサービスアカウントの IAM ロールの有効化 - Amazon EKS

「サービスアカウントの IAM ロール機能は、新しい Amazon EKS Kubernetes バージョン 1.14 以降のおクラスター、および 2019 年 9 月 3 日以降にバージョン 1.13 に更新されたクラスターで利用できます。」

とのこと。現在は 1.16 を使っているので有効化はされていました。

念のため、以下のコマンドを実行して確認できました。

% aws eks describe-cluster --name your-eks-cluster-name --query "cluster.identity.oidc.issuer" --output text
https://oidc.eks.your-region.amazonaws.com/id/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

追加のIAMの作成

以下の部分です。

  1. IAMのオープンIDコネクトプロバイダーを作成する
  2. サービスアカウントに付与したい権限(IAMポリシー)を作成する
  3. サービスアカウントに紐付けるIAMロールを作成して、作成したIAMポリシーをアタッチする

terraformで一括で作成しました。以下のような感じになります。

resource "aws_iam_openid_connect_provider" "your-openid-connect-provider" {
  url = aws_eks_cluster.your-eks-cluster.identity.0.oidc.0.issuer
  client_id_list = [
    "sts.amazonaws.com"
  ]
  thumbprint_list = [
    # see https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_create_oidc_verify-thumbprint.html
    var.eks.eks-oidc-thumbprint
  ]
}
resource "aws_iam_policy" "your-eks-app-service-account-policy" {
  name        = "your-eks-app-service-account-policy"
  policy      = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": [
          "arn:aws:s3:::your-s3-bucket-name",
          "arn:aws:s3:::your-s3-bucket-name/*"
      ]
    }
  ]
}
EOF
}

# StringEqualsの箇所に、k8sで使っているnamespaceとserviceaccount名を使います。
resource "aws_iam_role" "your-eks-app-service-account-role" {
  name = "your-eks-app-service-account-role"
  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "${aws_iam_openid_connect_provider.your-eks-cluster-openid-connect-provider.arn}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${aws_iam_openid_connect_provider.your-eks-cluster-openid-connect-provider.url}:sub": "system:serviceaccount:your-namespace:your-app"
        }
      }
    }
  ]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "your-eks-app-service-account" {
  policy_arn = aws_iam_policy.your-eks-app-service-account-policy.arn
  role       = aws_iam_role.your-eks-app-service-account-role.name
}

service accountの作成

  • aws_iam_roleの信頼関係に使用したnamespaceとserviceaccount名を一致させる必要があります
  • 作成したroleのarnを指定する必要があります
apiVersion: v1
kind: ServiceAccount
metadata:
  name: your-app
  namespace: your-namespace
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::467831915280:role/your-eks-app-service-account-role

service accountの利用

  • S3の権限を付与したbucketのobjectのリストを表示させるだけの簡単なjobを作ってtestできます。
  • 先ほどのstepで作成したserviceaccount名を指定します。
apiVersion: batch/v1
kind: Job
metadata:
  name: s3-listonly
  namespace: your-namespace
spec:
  template:
    spec:
      serviceAccountName: your-app # ここ
      containers:
        - name: s3-listonly
          image: amazon/aws-cli
          command: ["aws", "s3api" , "list-objects", "--bucket", "your-s3-bucket-name"]
      restartPolicy: Never
  backoffLimit: 0

参考になった記事

少し複雑な内容で、公式documentだけだと多少混乱してしまいましたが、こういう細かい権限の制御ができるのはAWSの素晴らしい点だと思います。

以上になります。