2020/10/15
EKSでServiceAccount毎にIAMロールを作成してpod毎に権限を変更する
概要
EKSで運用しているwebアプリケーションの中で、特定のS3バケットにアクセスしたいという要件があり対応しました。
IAMユーザーを作成して、ACCESS_KEY_IDやSECRETなどを作成し、それを利用してもよかったのですが
IAMロールを作るやり方が推奨される(ACCESS_KEY_IDやSECRETを作ると、定期的な更新が煩雑なのが理由)ため、やり方を調査して対応しました。
基本的にはサービスアカウントの IAM ロール - Amazon EKSの記事のやり方に沿って対応しました。
簡単に説明すると以下のような感じでした
- EKSクラスターがOpenID ConnectプロバイダーURLを保有しているか確認する
- IAMのオープンIDコネクトプロバイダーを作成する
- サービスアカウントに付与したい権限(IAMポリシー)を作成する
- サービスアカウントに紐付けるIAMロールを作成して、作成したIAMポリシーをアタッチする
- kubectlでservice accountのリソースを作成する
- 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の作成
以下の部分です。
- IAMのオープンIDコネクトプロバイダーを作成する
- サービスアカウントに付与したい権限(IAMポリシー)を作成する
- サービスアカウントに紐付ける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の素晴らしい点だと思います。
以上になります。
関連する記事
EKSのロードバランサーでIPアドレスのアクセス制限を設定する
EKSで構築しているネットワークロードバランサータイプのServiceにIP Whitelistを設定しました。
EKSのバージョンをアップグレードする
開発に利用しているEKSのバージョンをアップグレードしました
tfenvでterraformの複数バージョンを管理
tfenvという便利なツールがあったので、それを使ってローカル環境のterraformの複数バージョンの管理をすることにしました
[EKS]NLB+NginxでClientのIPアドレスを取得する
EKS上にdeployしたnginxをNetwork Load Balancerを使って外部公開した時に接続元のIPアドレスを取得する対応をしました