ISID テックブログ

ISIDが運営する技術ブログ

Amazon EKSのクラスター認証・認可を理解する

こんにちは、電通国際情報サービス デジタルイノベーション部の加世です。

昨今は、コンテナアプリケーション開発が主流であり、コンテナオーケストレーションを理解することは非常に重要であると考えています。
そこで、コンテナオーケストレーションツールである「Kubernetes」をマネージド・サービス化した「Amazon EKS」を題材として、Amazon EKSのクラスター認証・認可について理解します。

Kubernetesは、カスタマイズ性の高いコンテナオーケストレーションツールです。
正しく設計すれば「マイクロサービス化」「リソース最適化」「リリース最適化」「耐障害性に関わる制御の最適化」などを1つの統合された仕組みで実現できます。
これは、非常に魅力的です。
また、アプリケーション開発者が主体となって、サービス構成変更・運用を進められる点も素晴らしいです。

下記のガートナープレスリリースのとおり、コンテナー化の増加とともにコンテナー管理の需要が高まると考えています。
Kubernetesのようなコンテナオーケストレーションツールを始めるなら「今」です。

■ガートナー プレスリリース
https://www.gartner.com/en/newsroom/press-releases/2020-06-25-gartner-forecasts-strong-revenue-growth-for-global-co
https://www.gartner.co.jp/ja/newsroom/press-releases/pr-20211118

はじめに

Amazon EKSクラスター認証には「IAMによる認証(本記事では便宜上この方式を aws-auth 方式と呼びます)」「OIDCプロバイダーによる認証」の2つの方式があります。
本記事は、このうち以下の内容を記載します。

  1. Amazon EKSのクラスター認証・認可の概要を説明します。
  2. Amazon EKSの「OpenID Connect(OIDC)」認証の検証環境を構築します。
  3. 「OIDC」認証後にKubernetesAPI操作ができることを確認します。

Amazon EKSのクラスター認証・認可の概要について

Amazon EKSのクラスター認証・認可の概要を説明します。
Kubernetesコンポーネントと認証・認可の基礎は、下記リンク先を参照してください。

Kubernetesコンポーネント
https://kubernetes.io/ja/docs/concepts/overview/components/
■認証
https://kubernetes.io/ja/docs/reference/access-authn-authz/authentication
■RBAC認可を使用する
https://kubernetes.io/ja/docs/reference/access-authn-authz/rbac

認証

Amazon EKSクラスター認証は、「aws-auth」「OIDC」の2つの方式があります。

  1. IAMによる認証(aws-auth)

    クラスターのユーザーまたは IAM ロールの管理
    https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/add-user-role.html

    Amazon EKSは、デフォルト設定でIAMユーザー/IAMロールに基づく認証機能が組み込まれています。

    機能仕様は、aws eks get-tokenコマンドで取得したトークンを「kube-apiserver」に渡して認証します。
    ※Auditログを確認した限りでは、ブラックボックス化されたコントロールプレーン内の「kubernetes-aws-authenticator」プロセスがトークンを検証しているものと推察しています。なお、AWSマニュアルに詳細な仕様は公開されていません。

  2. OIDCプロバイダーによる認証

    OpenID Connect ID プロバイダーからクラスターのユーザーを認証する
    https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/authenticate-oidc-identity-provider.html

    OIDCプロバイダーを用意して、「kube-apiserver」自体のOIDC認証機能(標準機能)を利用します。
    複数AWSアカウントでAmazon EKSを含めたサービスを運用する場合は、一元的なID統制・管理を目指すことによるメリットが大きくなるためこちらを検討します。
    Kubernetes専用のOIDCプロバイダーになってしまう場合は、今後のID統合方針や運用コストなどを考慮して採用を検討します。

認可

認証が完了したら、「kube-apiserver」は次にKubernetesAPI操作を許可するかをRBACで判断します。
その際に使用されるのが「Role/ClusterRole」「RoleBinding/ClusterRoleBinding」です。

なお、Amazon EKSの認可は「Kubernetesの認可」と同様です。
そのため、本記事では説明を省きます。

検証環境の準備

では、ここからOIDCを利用したAmazon EKSクラスター認証を実際に試してみたいと思います。

検証環境は、下記のAWS Blogを参考に構築します。
なお、AWSサービス(東京リージョン内)のみで検証を完了できるように構成しています。

AWS Blog
https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks

  • 検証環境の構成

    ※最低限のコンポーネントのみを示しています。

  • AWSサービス

    • Amazon VPC
      事前に、任意のVPCネットワークを作成した状態を前提とします。

    • AWS IAM
      事前に、EKSを初期作成するためのユーザー作成と権限付与をした状態を前提とします。

    • Amazon Cognito (User Pool)
      補足情報を後述します。

    • Amazon EKS (ver 1.21)
      補足情報を後述します。
      ※ワーカーノードは不要です。

    • CloudShell (EKS API操作用)
      補足情報を後述します。
      ※最近AWS管理コンソールのホーム画面のインタフェースアップデートがあり、ホーム画面の右上のアイコンからすぐに起動できます。

Cognito構築

  1. AWSのマネジメントコンソールから、OIDCプロバイダーとなるCognitoユーザープールを作成します。
    ※「Cognitoフェデレーティッド IDプール」の整備は不要です。

    • サインインエクスペリエンスを設定
      • 「Cognito ユーザープールのサインインオプション」は「Eメール」のみを指定します。
    • セキュリティ要件を設定
      • 検証のため、「パスワードポリシー」「多要素認証」は任意設定で問題ありません。
      • 検証のため、「ユーザーアカウントの復旧」は、デフォルト設定で問題ありません。
    • サインアップエクスペリエンスを設定
      • 検証のため、「自己登録」は無効化します。
      • 検証のため「Cognito が検証と確認のためにメッセージを自動的に送信することを許可」の設定は無効化します。
      • 必須の属性は自動的に「email」が設定されるため、追加の必須属性・カスタム属性は設定不要です。
    • メッセージ配信を設定
      • 「Cognito で E メールを送信」を設定して、デフォルト設定で問題ありません。
    • アプリケーションを統合
      • 「ユーザープール名」は、任意設定で問題ありません。
      • 「ホストされた認証ページ」は、「Cognito のホストされた UI を使用」「Cognito ドメインを使用する」を有効化しつつ、任意のドメイン名を登録します。
      • 「最初のアプリケーションクライアント」は、検証のため「パブリッククライアント(クライアントシークレットなし)」を設定します。
        ※「秘密クライアント(クライアントシークレットあり)」を選択した場合は、OIDC認証時にクライアントシークレット情報が必要となり、後述する手順では情報不足になりますが本記事では割愛します。
      • 「アプリケーションクライアント名」は、任意設定で問題ありません。
      • 「許可されているコールバックURL」は、検証のため「http://localhost」を設定します。
      • 「高度なアプリケーションクライアントの設定」は、検証のため以下の「認証フロー」「OpenID 接続スコープ」を設定します。
        • 認証フロー
          • ALLOW_REFRESH_TOKEN_AUTH(自動設定)
          • ALLOW_ADMIN_USER_PASSWORD_AUTH
          • ALLOW_USER_PASSWORD_AUTH
        • OpenID 接続スコープ
          • E メール(email)
          • OpenIDopenid
          • プロファイル(profile)
            ※それ以外は、検証のためデフォルト設定で問題ありません。
  2. Cognito管理コンソールから作成された「ユーザープールID」「クライアントID」を控えます。

     プールID : ap-northeast-1_XXXXXXXXX
     クライアントID : 1abc7efgh6xxxxxxxxxxx11ab1
    
  3. CognitoユーザープールのOpen IDプロバイダー設定情報(OpenID Provider Configuration Information)を確認します。
    ※本記事ではCognitoの「issuer」の情報のみ利用しますが、すぐに特定できるため確認はスキップ可能です。
    ※Cognito以外のOpen IDプロバイダーを利用する場合は、Open IDプロバイダー設定情報を確認することが多いです。

       https://cognito-idp.ap-northeast-1.amazonaws.com/<ユーザープールID>/.well-known/openid-configuration
    
    • issuer

      https://cognito-idp.ap-northeast-1.amazonaws.com/<ユーザープールID>/
      
  4. Cognitoグループ
    Cognito管理コンソールから「admin」グループを作成します。
    ※cognitoグループに対して、IAMロールの設定は不要です。

  5. Cognitoユーザ
    Eメールを受信可能なメールアドレスを利用して、ユーザーを登録します。
    その際に、「E メールで招待を送信」を選択した場合は、登録したEメールにメッセージが送信されます。

  6. Cognitoグループにユーザーを追加
    [4.]の手順で作成したCognitoグループに[5.]で作成したユーザーを追加します。

  7. Cognito管理コンソール上から「アプリケーションクライアント」の設定を表示し、「ホストされた UI」から「ホストされた UIを表示」ボタンを押下してCognito専用のログイン画面を表示します。

  8. Cognito専用ログイン画面が表示されるため、作成したCognitoユーザーでログインして初期パスワードを変更します。
    認証後はCallBack URLで指定した「locahost」のURLが表示され、「Not Found」になります。
    検証はこの結果で問題なく、パスワード変更と認証完了を確認したことになります。

CloudShellの事前準備

CloudShellは、Amazon Linux2ベースのクライアントとして利用可能です。
いくつか利用上の注意点はあります。

  • 最低限の条件

    • IAMユーザー(または、スイッチ先のIAMロール)にcloudshellの操作権限が必要です。
    • セッション数に制限はありますが、無料です。
    • 「/home/<ユーザ>」配下が永続データ領域となり、1GB制限があります。
  • 必要なモジュールのインストール

    ■kubectl
    https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/install-kubectl.html

    こちらのマニュアルを参照して「/home/<ユーザ>」配下にkubectlを導入します。
    AWS CLI含めて、いくつか必要なモジュールはデフォルトで使用可能です。

  • AWS CLI経由でCognitoのユーザー認証&トークン取得
    OIDCプロバイダーとなるCognitoで認証しつつ、リフレッシュトークン・IDトークンを取得します。
    このトークンは、Kubernetesの「kube-apiserver」に連携するものです。

    また、IDトークン(ヘッダー、ペイロード、署名がBase64化されたもの)のペイロードからユーザーの属性情報を確認することがポイントです。
    特に、本記事では所属グループとなるcognito:groupsの「admin」に属していることを確認します。

    • OIDCに関する情報

      ACCOUNT_ID="123456789123"
      REGION="ap-northeast-1"
      USERPOOL_ID="ap-northeast-1_XXXXXXXXX"
      ISSUER_URL="https://cognito-idp.${REGION}.amazonaws.com/${USERPOOL_ID}"
      CLIENT_ID="5abc7ufem9hpagvidrafo11ce1"
      USERNAME="kase.teruyoshi@isid.co.jp"
      PASSWORD="InitPassword"
      
    • OIDC認証でリフレッシュトークン、IDトークンを取得

      tokenInfo=`aws cognito-idp --region ${REGION} admin-initiate-auth --auth-flow ADMIN_USER_PASSWORD_AUTH  --client-id ${CLIENT_ID} --user-pool-id ${USERPOOL_ID} --auth-parameters USERNAME=${USERNAME},PASSWORD=${PASSWORD} --query 'AuthenticationResult.{RefreshToken:RefreshToken, IdToken:IdToken}'`
      refreshToken=`echo ${tokenInfo} | jq -r .RefreshToken`
      idToken=`echo ${tokenInfo} | jq -r .IdToken`
      
      echo $refreshToken
      echo $idToken
      
    • IDトークンからペイロードを確認

      • コマンド

        idTokenHeader=`echo $idToken | cut -f 1 -d. | base64 --decode`
        idTokenPayload=`echo $idToken | cut -f 2 -d. | base64 --decode`
        
        echo $idTokenHeader | jq
        echo $idTokenPayload | jq
        
    • 実行結果

      [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenHeader | jq
      {
        "kid": "lxZZOgtZffh16NGpS8a6IM9J5zu3KmkcbLnkDQ9/MCY=",
        "alg": "RS256"
      }
      
      [cloudshell-user@ip-10-0-107-185 ~]$ echo $idTokenPayload | jq
      {
        "sub": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6",
        "cognito:groups": [
          "admin"
        ],
        "email_verified": true,
        "iss": "https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX",
        "cognito:username": "abc4d541-e6f1-45g0-h6c1-184b36f52cf6",
        "origin_jti": "5abc2d90-e3f4-455g-94h8-6cd7909f2059",
        "aud": "5abc7ufem9hpagvidrafo11ce1",
        "event_id": "8765f9f9-999c-10e5-8a13-c44a68c8ed33",
        "token_use": "id",
        "auth_time": 1637655335,
        "name": "kase.teruyoshi@isid.co.jp",
        "exp": 1637658935,
        "iat": 1637655335,
        "jti": "568d2c50-544c-4fa8-92d0-9dc9cac2d2cb",
        "email": "kase.teruyoshi@isid.co.jp"
      }
      

EKS構築

  1. EKSクラスター「poc-eks-cluster-dev」を作成します。

    • 検証環境のため、パブリックAPIエンドポイントは作成します。
    • Cloudshellを使用する都合で、パブリックAPIエンドポイントに対するアクセス元の制限はしません。
    • EKSを作成したIAMユーザー(またはIAMロール)で「aws-auth」認証が登録されます。
  2. 今まで得た情報を元にOIDCプロバイダーをAmazon EKSのクラスターに関連付けます。

    AWS Blog
    https://aws.amazon.com/jp/blogs/containers/introducing-oidc-identity-provider-authentication-amazon-eks

    こちらを参考に設定します。
    なお、追加設定で20~40分程度かかることと、変更は再作成となるためおよそ2倍の時間が必要になります。

    これにより、Amazon EKS内の「kube-apiserver」にOIDCプロバイダー情報が登録されます。
    これで、「kube-apiserver」側でトークン検証できる準備が整います。

「ClusterRoleBinding」によるRBAC認可の設定

CloudShell上でkubectlコマンドを実行して、ClusterRoleBinding「admin-role-binding」を作成します。
この段階では、「aws-auth」認証を使用します。

AWS Blogでは「secret-reader」に対応するClusterRoleを作成しています。
本記事は、簡略化のため既にデフォルトで作成されているClusterRole「cluster-admin」を利用します。
※「cluster-admin」は、操作権限の範囲が大きいため運用時は注意してください。

また、subjectセクションは、Cognitoユーザーが属するグループ「admin」を設定します。
この際、「kube-apiserver」にOIDCプロバイダーを登録したGroup Prefix「gid:」を考慮して「gid:admin」とします。

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-role-binding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: "gid:admin"

OIDC認証で取得したトークンを利用したAPI操作

「CloudShellの事前準備」の章の「OIDC認証でリフレッシュトークン、IDトークンを取得」を実施して、再度トークンを取得します。
その後、以下のとおりkubectl側で「kube-apiserver」にトークンを渡す準備をしたあと、自由にkubectlコマンドを実行してみてください。
※今回、RBAC認可に使用した「cluster-admin」は強力な権限のため、ほとんどの操作ができます。

  • kube-config初期設定

    aws eks --region ap-northeast-1 update-kubeconfig --name poc-eks-cluster-dev
    kubectl config get-contexts
    
  • kubectlトークン設定

    • credentials設定

      kubectl config set-credentials cognito-user --auth-provider=oidc --auth-provider-arg=idp-issuer-url=${ISSUER_URL} --auth-provider-arg=client-id=${CLIENT_ID} --auth-provider-arg=refresh-token=${refreshToken} --auth-provider-arg=id-token=${idToken}
      
    • context設定

      kubectl config set-context cognito-user-login --cluster arn:aws:eks:ap-northeast-1:${ACCOUNT_ID}:cluster/poc-eks-cluster-dev --user cognito-user
      
    • context切替

      kubectl config use-context cognito-user-login
      kubectl config get-contexts
      
  • kubectlコマンドでAPI実行結果
    Amazon EKSにデフォルトで設定されている「ConfigMap」の情報をAPIで取得します。

    [cloudshell-user@ip-10-0-107-185 ~]$ kubectl get configmap -n kube-system
    NAME                                 DATA   AGE
    aws-auth                             1      6d6h       
    

まとめ

本記事では、Amazon EKSのOIDC認証をAWSサービスのみで検証しました。

OIDCプロバイダーは、一般的にはSaaSサービス(Google、Azure AD、Okta...etc)でID統合することになります。
本記事では触れていませんが、様々なクライアントツールを活用してログイン認証画面(本記事では「Cognito のホストされた UI 」)を経由して認証をさせることもできます。

また、本日使用した「cluster-admin」はデフォルトのClusterRoleであり、API操作の許可範囲が大きいものになります。
そのため、操作可能な名前空間・リソース・アクションなどを正しく設計して、ID管理されたユーザー(または、ユーザー属性情報)に対して適切に付与することが重要になります。

執筆:@kase.teruyoshi、レビュー:@shibata.takaoShodoで執筆されました