EKSのIngressでALBを作成するときのIAM Roles for Service Accounts (IRSA) の設定
はじめに
AWSのマネージドKubernetesサービスであるElastic Kubernetes Service (EKS) では、AWS Load Balancer Controllerを使うことで、Kubernetes側からAWSのApplication Load Balaner (ALB) を作成することができます。本記事では、AWS Load Balancer Controllerを使ったALBの作成と、その際に使うIAM Roles for Sercice Accounts (IRSA) について書きます。
公式ドキュメントではCLIやAWS Management Consoleを使った説明がされているので、TerraformやKubernetesのマニフェストによる設定を紹介します。
KubernetesのServiceとIngress
Kubernetesでは、コンテナ化されたアプリケーションへの通信を管理するために「Service」というリソースが用いられます。Serviceは特定の単位でまとめた複数のPodへのアクセスポイントを提供します。言い換えると、Serviceを作ることで、Podへのトラフィックをルーティングできるようになります。例えば同じ機能のWebサーバーのPodを3台起動している場合、Serviceを入り口にしてそれらの3つのPodへリクエストが振り分けられるようなイメージです。Serviceにはいくつか種類があり、クラスター内部の通信に用いられるもの、外部からの通信を受け付けるために用いられるものなどがあります。
公式ドキュメントはこちら (日本語ページは情報が古い場合があります)
次に、今回扱う「Ingress」リソースです。Ingressは、外部からのトラフィックをKubernetesクラスター内の特定のサービスにルーティングするために使用されます。ここまでだと同じような役割のServiceも存在しますが、それらとの違いは、IngressがHTTP/HTTPS通信のルートを公開する点です。IngressはURLベースのルーティング、SSL/TLS Termination、ロードバランシングなどの機能を提供します。
公式ドキュメントはこちら (日本語ページは情報が古い場合があります)
AWS Load Balancer Controllerの役割
次に、AWS Load Balancer Controllerの話です。Ingressの実体は、Kubernetesがホストされている環境やクラスターにデプロイされているControllerによって異なります。
Controllerとは、クラスターの状態を監視し、システムが予め定義された状態と異なる状態になった際に、自動的に調整してくれるコンポーネントのことです。例えば、Deployment Controllerは特定の数のPodが常に実行されていることを保証するために、もしPodが削除された場合には新しいPodを起動します (正確にはReplicaSetが) 。
AWS Load Balancer ControllerがデプロイされたElastic Kubernetes Service (EKS) クラスターでは、Ingressリソースで、Application Load Balancer (ALB) を作成することができます。ALBはアプリケーション層 (L7) のロードバランシングを提供してくれるAWSのリソースです。
AWS Load Balancer Controllerのデプロイ方法は以下の公式ドキュメントに書いてあります。
なんでこの記事を書いているのか
やりたかったことはここまでに示した公式ドキュメントで全て達成されるのですが、AWS Load Balancer Controllerをデプロイするための設定が初見ではそこそこ複雑だったのでこの記事を書いています。
ひとことで言うと、「IngressでALBを作成するためにAWS Load Balancer Controlerを使うために、IAM Roles for Service Accountsを設定するためにOpenID Connectを設定する必要がある」です。これだけ読んで理解できた場合、あなたは本記事の想定読者よりも経験値が高い方です。ありがとうございました。
(もっと言うと、もともと当時の自分がやりたかったことはArgo CDの導入で、Argo CDを導入した結果、作成されたWeb UIにアクセスしたいというニーズが生まれ、それを実現するためにIngressを使うことになり、IngressでALBを作成するためにAWS Load Balancer Controllerを使うために (以下略))
それではいってみましょう。
ALBを作成するためのIAM Roles for Service Accounts
概要
上記のドキュメントでは、最初のステップでIAMポリシー/ロールの作成があります。ALBはAWSのリソースなので、ALBを作成するには、ALBの作成が許可されたIAM権限が必要です。そのためにIAMポリシー/ロールを作成します。
しかし、Kubernetes上で直接IAMを扱うことはできません。そこでIAM Roles for Service Accounts (IRSA) の出番です。
これを使うことで、KubernetesのServiceAccountとAWSのIAMロールを紐づけることができ、AWS Load Balancer ControllerにLBを作成する権限を付与できます。
OpenID Connect
IRSAを設定するためにOpenID Connect (OIDC) を使います。
OIDC自体の説明は省略しますが、以下のようなTerraformのコードで、EKSクラスターにIAM用のOIDCプロバイダーを作成できます。
data "tls_certificate" "my-oidc-issuer" {
url = aws_eks_cluster.my-cluster.identity[0].oidc[0].issuer
}
resource "aws_iam_openid_connect_provider" "my-provider" {
client_id_list = ["sts.amazonaws.com"]
thumbprint_list = data.tls_certificate.my-oidc-issuer.certificates[*].sha1_fingerprint
url = data.tls_certificate.my-oidc-issuer.url
tags = {
eks_cluster = aws_eks_cluster.my-cluster.name
}
}
- my-cluster: Terraformで作成したaws_eks_clusterの名前 (任意)
- my-oidc-issuer: 任意の名前
- my-provider: 任意の名前
これができたら、IRSAを設定することができます。
AWS Load Balancer ConrtollerのためのIRSA
まず以下のように、専用のIAMポリシーをattachしたIAMロールを用意します。service_account_namespaceとservice_account_nameは、このあとに作成するKubernetesのServiceAccountのものと一致させてください。
locals {
account_id = "000000000000" # TODO: 自分のAWSアカウントのIDに置き換える
oidc_provider = trimprefix (data.tls_certificate.my-oidc-issuer.url, "https://")
service_account_namespace = "my-namespace" # あとで重要
service_account_name = "aws-load-balancer-controller" # あとで重要
}
# IAMロール
resource "aws_iam_role" "aws-load-balancer-controller" {
name = "AwsLoadBalancerController" # あとで重要
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${local.account_id}:oidc-provider/${local.oidc_provider}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${local.oidc_provider}:aud": "sts.amazonaws.com",
"${local.oidc_provider}:sub": "system:serviceaccount:${local.service_account_namespace}:${local.service_account_name}"
}
}
}
]
}
EOF
}
# AWS Load Balancer Controller用のポリシー
# 以下からダウンロードしたもの
# https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.5.4/docs/install/iam_policy.json
# バージョンは変わっていくので、公式ドキュメントを参照して現在の最新に読み替えてください
resource "aws_iam_policy" "aws-load-balancer-controller" {
name = "AwsLoadBalancerController"
policy = file("./iam_policy.json") # TODO: ファイルのパスはよしなに書き換えてください
}
# ロールにポリシーをattach
resource "aws_iam_role_policy_attachment" "aws-load-balancer-controller" {
role = aws_iam_role.aws-load-balancer-controller.name
policy_arn = aws_iam_policy.aws-load-balancer-controller.arn
}
ここから先はKubernetes側の設定です。以下のようなServiceAccountを作ると、上記のIAMロールと紐づけることができます。
apiVersion: v1
kind: ServiceAccount
metadata:
name: aws-load-balancer-controller # IAM側に同じ値を書く
namespace: my-namespace # IAM側に同じ値を書く
annotations:
eks.amazonaws.com/role-arn: "arn:aws:iam::{local.account_id}:role/AwsLoadBalancerController" # 上で作成したIAMロール
- metadata.name: 先ほどIAMロールのassume_role_policyの中に書いたものと同じ値
- metadata.namespace: 先ほどIAMロールのassume_role_policyの中に書いたものと同じ値
- metadata.annorations."eks.amazonaws.com/role-arn": 上で作成したIAMロールのARN
以上で、IRSAの設定が完了しました。
依存関係のおさらい
先ほどの依存関係を振り返ると、「IngressでALBを作成するためにAWS Load Balancer Controlerを使うために、IAM Roles for Service Accountsを設定するためにOpenID Connectを設定する必要がある」の後半部分の、「IAM Roles for Service Accountsを設定する」とそのための「OpenID Connectを設定する」が終わりました。
あとは、AWS Load Balancer Controllerをデプロイする → Ingressリソースを作るとALBができる、で目的を達成できます。これ以降の手順は割とすんなりできたので、公式ドキュメントにしたがうことをおすすめします。
最後に
AWS Load Balancer Controllerをデプロイする方法は、Helmを使う方法とKubernetesマニフェストを使う方法があり、どちらも試しましたがどちらもそんなにとても苦労することはありませんでした。以下、公式ドキュメントの再掲です。
これができたら、Ingressのマニフェストを書いて、クラスターに適用してみてください。
もし動かない場合、自分はIRSAの設定で失敗していることが多かったです。シンプルながら、ServiceAccountのmetadataに書いたIAMロールの名前が間違っていたなどです。間違っていてもその段階では何もエラーが出ず、ただ連携されていない状態になるだけなので、最終的にALBを作成しようとする段階になるまでミスしていることに気づけないのがつらかったです。また、そのときに何かがおかしいことは分かっても、どこがおかしいかが分かりづらかったのもつらかったです。
本記事は以上です。公式ドキュメントを読み解くのに苦労した方の参考になれば幸いです。
Discussion
この記事は、Voicy Advent Calendar 2023の3日目に掲載しました