EKSの認証・認可の仕組み解説

公開:2021/02/05
更新:2021/02/08
6 min読了の目安(約5600字TECH技術記事

EKS の認証・認可では AWS の IAM 認証Kubernetes の認証という2つの要素が登場するため
少し分かりづらいものになっています。

この記事ではEKSの認証・認可について解説します。

EKSで認証・認可では次の2つの仕組みが存在します。

  • ConfigMap aws-auth
  • IAM Roles for Service Accounts (IRSA)

それでは見ていきましょう。

aws-auth

最初はaws-authです。
aws-authはIAMエンティティに対して, Kubernetesの権限を付与するための設定(ConfigMap)です。

次のような場合に利用します。

  • 管理者や開発者がkubectlを使ってEKSクラスタにアクセスする
  • Code Build等のCIサービスからEKSクラスタにデプロイする
  • EKSのコンソールにpod等のKubernetesワークロードを表示する

大まかな流れ

  1. aws eks update-kubeconfigを実行
  2. aws eks describe-clusterが実行され、クラスタのエンドポイント等を取得
  3. ~/.kube/configにクラスタエンドポイントや5のトークン取得コマンドが書き込まれる
  4. kubectlを実行
  5. aws eks get-tokenが実行されクラスタにアクセスするためのトークンを取得
  6. トークンを使ってクラスタにアクセス
  7. aws-authのConfigMapのマッピング情報を元にk8sの認証・認可を処理

update-kubeconfig

aws eks update-kubeconfigはEKSクラスタに接続するためのkubectlの設定(=kubeconfig)を生成してくれる便利コマンドです。

実際にEKSクラスタに接続するための情報、手順はkubeconfigに書き込まれますので1度だけ実行すればよいです。

kubeconfigには次のような内容が書き込まれます。
server, exec等の接続に必要な情報が書き込まれていることがわかるかと思います。

apiVersion: v1
kind: Config
clusters:
- cluster:
    certificate-authority-data: XXXXXXXXXXXXXXXXXXXXXXXXX
    server: https://XXXXXXXXXXXXXXXXXXXXXXXXX.sk1.ap-northeast-1.eks.amazonaws.com
  name: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
contexts:
- context:
    cluster: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
    user: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
  name: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
current-context: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
preferences: {}
users:
- name: arn:aws:eks:ap-northeast-1:375137234141:cluster/cluster-name
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1alpha1
      args:
      - --region
      - ap-northeast-1
      - eks
      - get-token
      - --cluster-name
      - cluster-name
      command: aws
      env:
      - name: AWS_PROFILE
        value: my-aws-profile

aws-auth

EKSではクラスタ作成時にkube-systemnamespaceにaws-authというConfigMapが作成されます.

aws-authは次のようになっています.

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - groups:
      - system:masters
      rolearn: arn:aws:iam::123456789012:role/my-role
      username: my-k8s-role
  mapUsers: |
    - userarn: arn:aws:iam::123456789012:user/my-user
      username: my-k8s-user
      groups:
      - system:masters

aws-authにはIAM RoleまたはIAM Userに対して、kubernetes上でどのようなgroupに割り当てるかを指定します.

先程の例で言うと

  • arn:aws:iam::123456789012:role/my-roleというIAM Roleに対して
    • k8sのusernameはmy-k8s-role
    • k8sのgroupはsystem:mastersに所属
  • arn:aws:iam::123456789012:user/my-user
    • k8sのusernameはmy-k8s-user
    • k8sのgroupはsystem:mastersに所属

という設定がされていることになります。

aws-authの詳細はこちらが参考になりました。

IAM Roles for Service Accounts(IRSA)

次にIRSAです。
IAM Roles for Service Accounts(IRSA)はKubernetes上のService Accountに対してIAM Roleを割り当てるための仕組みです。

eksctlではiam service accountとも呼ばれていました。

IRSAは次のような場合に利用します。

  • EKSのpodとして稼働しているアプリケーションからAWSサービスを利用する
  • AWS Load Balancer ControllerのようなAWSサービスを利用するアプリケーションをデプロイする場合

大まかな流れ

  1. EKSにビルトインされているOIDC ID ProviderをIAMに登録
  2. IAM Roleを作成し、OIDC ID Provider経由でログインしたユーザ(=ServiceAccount)に対してRoleの引き受けを許可
  3. IAM Roleにポリシーをアタッチし、パーミッションを付与
  4. Service Accountを作成し、Podに割り当て
  5. PodからSAを通してIAM Roleを引き受け

OIDC ID Provider

EKSクラスタにはOIDC ID Providerがビルトインされています。

またIAMにはOIDC ID Providerと連携してOIDC上のユーザに対してIAM Roleを割り当てる機能(IDフェデレーション)があります。

これらの仕組みでService Account Tokenを利用してIAMのIDフェデレーションを行うことで、
Service AccountをIAMのアイデンティティとして利用出来るようになります

Roleの引き受け

次のようなAssumeRolePolicyDocumentを設定することで、Service Account(でIDフェデレーションされたIAM アイデンティティ)
に対してRoleの引き受けを許可します。

これでService AccountがIAM RoleとしてAWSサービスにアクセス出来るようになりました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${AWS_ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:aud": "sts.amazonaws.com",
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:<my-namespace>:<my-service-account>"
        }
      }
    }
  ]
}

Service Accountの設定

kubernetes側ではService Accountを作成し、Podに割り当てます。

Service Accountに対しては次のような設定が必要になります。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-account
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::<AWS_ACCOUNT_ID>:role/<IAM_ROLE_NAME>

このannotationを設定することで、Podに対して環境変数AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARNが自動的にinjectされるようになります。

Podの中のアプリケーションはこの環境変数を利用してIAM認証を行います。

aws cliやaws-sdkを利用している場合は勝手にやってくれるので、特に環境変数の存在を意識する必要はありません。

おわりに

更に詳しい情報やリファレンス等はドキュメントを参照しましょう。
参考になりそうなリンクを貼っておきます。

この記事が理解の一助になれば幸いです。