AWS での Workload Identity の使用

このトピックでは、GKE on AWS ワークロードの Workload Identity を有効にして AWS リソースへのアクセスを制御する方法について説明します。

Google Cloud Identity and Access Management(IAM)アカウントで Workload Identity を使用して GCP リソースへのアクセスを制御する方法については、Google Cloud での Workload Identity の使用 をご覧ください。

概要

Workload Identity は、AWS IAM 権限を使用して、クラウド リソースへのアクセスを制御します。ワークロード ID を使用すると、各ワークロードに異なる IAM のロールを割り当てることができます。権限をきめ細かく制御することで、最小権限の原則に準拠できます。ワークロード ID を使用しない場合は、GKE on AWS ノードに AWS IAM ロールを割り当て、ノード上のすべてのワークロードにノード自体と同じ権限を付与する必要があります。

クラスタのワークロード ID を有効にするには次の操作を行います。以下の手順は、操作を行う管理者のロールごとにグループ化されます。

クラスタ管理者

  1. OIDC 検出データを格納する Cloud Storage バケットを作成します。
  2. そのバケットから読み取るための Identity and Access Management ロールを作成します。
  3. ワークロード ID を有効にしてユーザー クラスタを作成します。
  4. 作成時に Pod にワークロード ID 認証情報を適用する Webhook をクラスタに作成します。Webhook を使用しない場合は、Pod に環境変数を手動で設定できます。
  5. AWS OIDC プロバイダを構成します。
  6. AWS IAM のロールとポリシーを作成します。
クラスタ管理者またはデベロッパー
  1. Kubernetes サービス アカウントを作成し、AWS ポリシーをバインドします。
デベロッパー
  1. Pod に認証情報を適用します

前提条件

このドキュメントの手順を完了するには、以下の設定が必要です。

  • GKE on AWS 管理サービス
  • 1.17.9 以降の Kubernetes バージョンを実行しているユーザー クラスタ。

  • 以下の権限とツール。

権限

ワークロード ID を有効にしてクラスタを作成するには、次の権限が必要です。

Google Cloud

  • 均一なバケットレベルのアクセスを有効にして、一般公開可能な Cloud Storage バケットを作成します。
  • management-sa@PROJECT_NAME.iam.gserviceaccount.com の読み取り / 書き込み権限をバケットに付与します。

AWS

  • AWS OIDC プロバイダを作成します。
  • AWS IAM のロールを作成します。

ツール

ローカルマシンに jq ツールをインストールすることをおすすめします。

OIDC ディスカバリ バケットを作成する

このセクションは、クラスタ管理者を対象としています。

ユーザー クラスタは、一般公開されている Cloud Storage バケットに OIDC ディスカバリ データを保存する必要があります。バケットには OIDC ディスカバリ構成と公開鍵が格納されています。AWS は、コンテンツを使用してユーザー クラスタからのリクエストを認証します。

バケットには次の属性を持たせる必要があります。

上記の属性を持つバケットがない場合は、次の gsutil コマンドを使用してバケットを作成します。

BUCKET=BUCKET_NAME
gsutil mb -b on gs://${BUCKET}
gsutil iam ch allUsers:objectViewer gs://${BUCKET}

BUCKET_NAME は、新しいバケット名に置き換えます。

管理サービス アカウントに権限を付与する

GKE on AWS 管理サービス用の Identity and Access Management サービス アカウントには、オブジェクトの読み取りとこのバケットへのオブジェクト書き込みを行うための権限が必要です。

  1. 次の gsutil コマンドを使用して、管理サービス アカウントに権限を付与します。

    MANAGEMENT_SA=management-sa@PROJECT_NAME.iam.gserviceaccount.com
    gsutil iam ch serviceAccount:${MANAGEMENT_SA}:admin gs://${BUCKET}
    

    PROJECT_NAME は、Google Cloud プロジェクトに置き換えます。

  2. このバケットの管理権限を含む新しい IAM ロールを作成します。ロールを作成するには、まず、ロール定義をファイルに保存し、ロールを作成して管理サービス アカウントにバインドします。

    これらの手順を完了するには、次のコマンドを実行します。

    cat << EOF >  anthos-oidc-role.yaml
    title: anthosAwsOidcStorageAdmin
    description: permissions to manage the OIDC buckets
    stage: GA
    includedPermissions:
    - storage.buckets.get
    EOF
    
    gcloud iam roles create anthosAwsOidcStorageAdmin --project=PROJECT_NAME \
      --file=anthos-oidc-role.yaml
    
    gcloud projects add-iam-policy-binding \
      PROJECT_NAME \
      --member=serviceAccount:${MANAGEMENT_SA} \
      --role=projects/PROJECT_NAME/roles/anthosAwsOidcStorageAdmin
    

    PROJECT_NAME は、Google Cloud プロジェクトに置き換えます。

    Google Cloud CLI によって、ポリシー バインディングが作成されたことを確認できます。

ユーザー クラスタの作成

このセクションは、クラスタ管理者を対象としています。

ワークロード ID を有効にしてユーザー クラスタを作成する

OIDC 検出バケットの詳細を含むユーザー クラスタを作成します。この情報は、AWSClusterspec.controlPlane.workloadIdentity.oidcDiscoveryGCSBucket フィールドに設定します。

この例では、AWSCluster CRD と AWSNodePool CRD からクラスタを手動で作成します。

  1. GKE on AWS 構成のディレクトリに移動します。このディレクトリは、管理サービスをインストールしたときに作成したものです。

    cd anthos-aws

  2. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  3. テキスト エディタを開き、次の AWSCluster 定義を custom-cluster.yaml という名前のファイルにコピーします。

    apiVersion: multicloud.cluster.gke.io/v1
    kind: AWSCluster
    metadata:
      name: CLUSTER_NAME
    spec:
      region: AWS_REGION
      networking:
        vpcID: VPC_ID
        podAddressCIDRBlocks: POD_ADDRESS_CIDR_BLOCKS
        serviceAddressCIDRBlocks: SERVICE_ADDRESS_CIDR_BLOCKS
        ServiceLoadBalancerSubnetIDs: SERVICE_LOAD_BALANCER_SUBNETS
      controlPlane:
        version:  CLUSTER_VERSION # Latest version is 1.25.5-gke.2100
        instanceType: AWS_INSTANCE_TYPE
        keyName: SSH_KEY_NAME
        subnetIDs:
        - CONTROL_PLANE_SUBNET_IDS
        securityGroupIDs:
        - CONTROL_PLANE_SECURITY_GROUPS
        iamInstanceProfile: CONTROL_PLANE_IAM_ROLE
        rootVolume:
          sizeGiB: ROOT_VOLUME_SIZE
          volumeType: ROOT_VOLUME_TYPE # Optional
          iops: ROOT_VOLUME_IOPS # Optional
          kmsKeyARN: ROOT_VOLUME_KEY # Optional
        etcd:
          mainVolume:
            sizeGiB: ETCD_VOLUME_SIZE
            volumeType: ETCD_VOLUME_TYPE # Optional
            iops: ETCD_VOLUME_IOPS # Optional
            kmsKeyARN: ETCD_VOLUME_KEY # Optional
        databaseEncryption:
          kmsKeyARN: ARN_OF_KMS_KEY
        hub: # Optional
          membershipName: ANTHOS_CONNECT_NAME
        cloudOperations: # Optional
          projectID: YOUR_PROJECT
          location: GCP_REGION
          enableLogging: ENABLE_LOGGING
          enableMonitoring: ENABLE_MONITORING
        workloadIdentity: # Optional
          oidcDiscoveryGCSBucket: WORKLOAD_IDENTITY_BUCKET
    

    以下を置き換えます。

    • CLUSTER_NAME: クラスタの名前。
    • AWS_REGION: クラスタが稼働している AWS リージョン。

    • VPC_ID: クラスタが稼働している VPC の ID。

    • POD_ADDRESS_CIDR_BLOCKS: クラスタの Pod で使用される IPv4 アドレスの CIDR 範囲。現時点では 1 つの範囲のみがサポートされています。この範囲は、ネットワークから到達可能なサブネットと重複してはなりません。複数の異なる AWSCluster オブジェクト間では、同じ範囲を使用できます。例: 10.2.0.0/16

    • SERVICE_ADDRESS_CIDR_BLOCKS: クラスタの Service で使用される IPv4 アドレスの範囲。現時点では 1 つの範囲のみがサポートされています。この範囲は、ネットワークから到達可能なサブネットと重複してはなりません。複数の異なる AWSCluster オブジェクト間では、同じ範囲を使用できます。例: 10.1.0.0/16

    • SERVICE_LOAD_BALANCER_SUBNETS: GKE on AWS がパブリック ロードバランサまたはプライベート ロードバランサを作成できるサブネット ID で置き換えます。

    • CLUSTER_VERSION: GKE on AWS でサポートされている Kubernetes バージョン。最新バージョンは 1.25.5-gke.2100 です。

    • AWS_INSTANCE_TYPE: サポートされている EC2 インスタンス タイプ

    • SSH_KEY_NAME: AWS EC2 鍵ペア

    • CONTROL_PLANE_SUBNET_IDS: コントロール プレーン インスタンスが実行される AZ のサブネット ID。

    • CONTROL_PLANE_SECURITY_GROUPS: 管理サービスのインストール中に作成された securityGroupID。これをカスタマイズするには、コントロール プレーンへの接続に必要な securityGroupID を追加します。

    • CONTROL_PLANE_IAM_PROFILE: コントロール プレーンのレプリカに割り当てられた AWS EC2 インスタンス プロファイルの名前。

    • ROOT_VOLUME_SIZE: コントロール プレーン ルート ボリュームのサイズ(GiB)。

    • ROOT_VOLUME_TYPEEBS ボリューム タイプに置き換えます。例: gp3

    • ROOT_VOLUME_IOPS は、ボリューム用にプロビジョニングされた IO オペレーション/秒(IOPS)の量に置き換えます。volumeTypeGP3 の場合のみ有効です。詳細については、汎用 SSD ボリューム(gp3)をご覧ください。

    • ROOT_VOLUME_KEY は、コントロール プレーン インスタンスのルート ボリュームを暗号化する AWS KMS 鍵の Amazon Resource Name に置き換えます。

    • ETCD_VOLUME_SIZE: etcd が使用するボリュームのサイズ。

    • ETCD_VOLUME_TYPEEBS ボリューム タイプに置き換えます。例: gp3

    • ETCD_VOLUME_IOPS は、ボリューム用にプロビジョニングされた IO オペレーション/秒(IOPS)の量に置き換えます。volumeTypegp3 の場合のみ有効です。詳細については、汎用 SSD ボリューム(gp3)をご覧ください。

    • ETCD_VOLUME_KEY は、コントロール プレーン etcd のデータ ボリュームを暗号化する AWS KMS 鍵の Amazon Resource Name に置き換えます。

    • ARN_OF_KMS_KEY: クラスタ Secret の暗号化に使用される AWS KMS 鍵。

    • ANTHOS_CONNECT_NAME: クラスタの登録に使用する Connect メンバーシップ名。メンバーシップ名は一意である必要があります。たとえば、projects/YOUR_PROJECT/locations/global/memberships/CLUSTER_NAME の場合、YOUR_PROJECT は Google Cloud プロジェクト、CLUSTER_NAME はプロジェクト内の一意の名前です。このフィールドは省略可能です。

    • YOUR_PROJECT: プロジェクト ID。

    • GCP_REGION: ログを保存する Google Cloud リージョン。AWS リージョンに近接したリージョンを選択します。詳細については、グローバル ロケーション - リージョンとゾーンをご覧ください。例: us-central1

    • ENABLE_LOGGING: true または false。コントロール プレーン ノードで Cloud Logging が有効かどうか。

    • ENABLE_MONITORING: true または false。コントロール プレーン ノードで Cloud Monitoring が有効かどうか。

    • WORKLOAD_IDENTITY_BUCKET: ワークロード ID ディスカバリ情報を含む Cloud Storage バケット名。このフィールドは省略可能です。

  4. クラスタに 1 つ以上の AWSNodePools を作成します。テキスト エディタを開き、次の AWSCluster 定義を custom-nodepools.yaml という名前のファイルにコピーします。

    apiVersion: multicloud.cluster.gke.io/v1
    kind: AWSNodePool
    metadata:
      name: NODE_POOL_NAME
    spec:
      clusterName: AWSCLUSTER_NAME
      version:  CLUSTER_VERSION # latest version is 1.25.5-gke.2100
      region: AWS_REGION
      subnetID: AWS_SUBNET_ID
      minNodeCount: MINIMUM_NODE_COUNT
      maxNodeCount: MAXIMUM_NODE_COUNT
      maxPodsPerNode: MAXIMUM_PODS_PER_NODE_COUNT
      instanceType: AWS_NODE_TYPE
      keyName: KMS_KEY_PAIR_NAME
      iamInstanceProfile: NODE_IAM_PROFILE
      proxySecretName: PROXY_SECRET_NAME
      rootVolume:
        sizeGiB: ROOT_VOLUME_SIZE
        volumeType: VOLUME_TYPE # Optional
        iops: IOPS # Optional
        kmsKeyARN: NODE_VOLUME_KEY # Optional 
    

    以下を置き換えます。

    • NODE_POOL_NAME: AWSNodePool の一意の名前。
    • AWSCLUSTER_NAME: AWSCluster の名前。例: staging-cluster
    • CLUSTER_VERSION: サポートされている GKE on AWS Kubernetes のバージョン
    • AWS_REGION: AWSCluster と同じ AWS リージョン。
    • AWS_SUBNET_ID: AWSCluster と同じリージョン内の AWS サブネット。
    • MINIMUM_NODE_COUNT: ノードプール内のノードの最小数。詳しくは、ユーザー クラスタのスケーリングをご覧ください。
    • MAXIMUM_NODE_COUNT: ノードプール内のノードの最大数。
    • MAXIMUM_PODS_PER_NODE_COUNT: GKE on AWS がノードに割り当てることができる Pod の最大数。
    • AWS_NODE_TYPE: AWS EC2 インスタンス タイプ
    • KMS_KEY_PAIR_NAME: 各ノードプールのワーカーに割り当てられる AWS KMS 鍵ペア。
    • NODE_IAM_PROFILE: プール内のノードに割り当てられる AWS EC2 インスタンス プロファイルの名前。
    • ROOT_VOLUME_SIZE: コントロール プレーン ルート ボリュームのサイズ(GiB)。
    • VOLUME_TYPE: ノードの AWS EBS ボリューム タイプ。例: gp3
    • IOPS: ボリュームに対してプロビジョニングされた IO オペレーション/秒(IOPS)の量。volumeTypegp3 の場合のみ有効です。
    • NODE_VOLUME_KEY: ボリュームの暗号化に使用される AWS KMS 鍵の ARN。詳細については、顧客管理の CMK を使用したボリュームの暗号化をご覧ください。
  5. マニフェストを管理サービスに適用します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f custom-cluster.yaml
    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f custom-nodepools.yaml
    

kubeconfig を作成する

ユーザー クラスタが起動している間、新しいユーザー クラスタの kubeconfig コンテキストを作成できます。このコンテキストを使用して、ユーザー クラスタまたは管理クラスタに対する認証を行います。

  1. anthos-gke aws clusters get-credentials を使用して、~/.kube/config にユーザー クラスタの kubeconfig を生成します。

    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials CLUSTER_NAME
    

    CLUSTER_NAME をクラスタ名に置き換えます。例: cluster-0

  2. kubectl を使用して、新しいユーザー クラスタに対する認証を行います。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl cluster-info
    

    クラスタの準備が整っている場合は、出力にクラスタ内の Kubernetes コンポーネントの URL が含まれます。

クラスタのステータスの表示

管理サービスは、AWSCluster または AWSNodePool を適用するとき、AWS リソースをプロビジョニングします。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. クラスタをリストするために、kubectl get AWSClusters を使用します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get AWSClusters
    

    出力には、各クラスタの名前、状態、経過時間、バージョン、エンドポイントが含まれます。

    たとえば、次の出力には cluster-0 という名前の AWSCluster が 1 つだけ含まれています。

    NAME        STATE          AGE     VERSION         ENDPOINT
    cluster-0   Provisioning   2m41s   1.25.5-gke.2100   gke-xyz.elb.us-east-1.amazonaws.com
    

クラスタのイベントを表示する

ユーザー クラスタの最近の Kubernetes イベントを表示するには、kubectl get events を使用します。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. kubectl get events を実行します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get events
    

出力には、管理サービスからの情報、警告、関連エラーが含まれます。

Workload Identity Webhook の作成

このセクションは、クラスタ管理者を対象としています。

追加構成なしで Workload Identity の認証情報をワークロードに提供するために、ユーザー クラスタ上に Webhook を作成することもできます。この Webhook は、Pod の作成リクエストをインターセプトし、Pod で環境変数として次の AWS IAM 情報を使用できるようにします。

  • AWS_ROLE_ARN: IAM のロールの Amazon Resource Name(ARN)
  • aws-iam-token: AWS IAM 認証情報と交換されるトークン
  • AWS_WEB_IDENTITY_TOKEN_FILE: トークンが保存されるパス

これらの変数を使用すると、ワークロードで AWS コマンドライン ツールを呼び出すか、SDK で AWS ロールに付与されたリソースにアクセスできます。

Webhook の作成は省略可能です。Webhook を作成しない場合は、以前に Pod に一覧表示した環境変数を設定する必要があります。Webhook を使用しない方法については、Webhook を使用せず認証情報を適用するをご覧ください。

Webhook の YAML ファイルを作成する

Webhook をデプロイするには、次の操作を行います。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. kubectl でユーザー クラスタ名を取得します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster
    

    kubectl は、すべてのユーザー クラスタを一覧表示します。Workload Identity が有効な状態で作成したユーザー クラスタを選択します。

  3. 環境変数にクラスタの名前を設定します。

    CLUSTER_NAME=CLUSTER_NAME
    

    CLUSTER_NAME は、使用するクラスタの名前に置き換えます。例: cluster-0

  4. Workload Identity の Pod イメージと Namespace の環境変数を設定します。

    IDENTITY_IMAGE=amazon/amazon-eks-pod-identity-webhook:ed8c41f
    
    WEBHOOK_NAMESPACE=workload-identity-webhook
    
  5. 次の手順に沿って、aws-webhook.yaml という名前のファイルに Webhook YAML マニフェストを生成します。

    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials ${CLUSTER_NAME}
    
    CLUSTER_CA=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl config view --raw -o json  | jq -r '.clusters[] | select(.name == "'$(kubectl config current-context)'") | .cluster."certificate-authority-data"')
    
    cat << EOF > aws-webhook.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    rules:
      - apiGroups: ['']
        resources: ['secrets']
        verbs: ['create']
      - apiGroups: ['']
        resources: ['secrets']
        verbs: ['get', 'update', 'patch']
        resourceNames:
          - pod-identity-webhook
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: Role
      name: pod-identity-webhook
    subjects:
      - kind: ServiceAccount
        name: pod-identity-webhook
        namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: pod-identity-webhook
    rules:
      - apiGroups: ['']
        resources: ['serviceaccounts']
        verbs: ['get', 'watch',  'list']
      - apiGroups:  ['certificates.k8s.io']
        resources: ['certificatesigningrequests']
        verbs:  ['create', 'get', 'list', 'watch']
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: pod-identity-webhook
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: pod-identity-webhook
    subjects:
      - kind: ServiceAccount
        name: pod-identity-webhook
        namespace: ${WEBHOOK_NAMESPACE}
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: pod-identity-webhook
      template:
        metadata:
          labels:
            app: pod-identity-webhook
        spec:
          serviceAccountName: pod-identity-webhook
          containers:
            - name: pod-identity-webhook
              image: ${IDENTITY_IMAGE}
              imagePullPolicy: Always
              command:
                - /webhook
                - --in-cluster
                - --namespace=${WEBHOOK_NAMESPACE}
                - --service-name=pod-identity-webhook
                - --tls-secret=pod-identity-webhook
                - --annotation-prefix=eks.amazonaws.com
                - --token-audience=sts.amazonaws.com
                - --logtostderr
              volumeMounts:
                - name: webhook-certs
                  mountPath: /var/run/app/certs
                  readOnly: false
          volumes:
            - name: webhook-certs
              emptyDir: {}
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
      annotations:
        prometheus.io/port: '443'
        prometheus.io/scheme: https
        prometheus.io/scrape: 'true'
    spec:
      ports:
        - port: 443
          targetPort: 443
      selector:
        app: pod-identity-webhook
    ---
    apiVersion: admissionregistration.k8s.io/v1
    kind: MutatingWebhookConfiguration
    metadata:
      name: pod-identity-webhook
      namespace: ${WEBHOOK_NAMESPACE}
    webhooks:
      - name: pod-identity-webhook.amazonaws.com
        failurePolicy: Ignore
        sideEffects: 'None'
        admissionReviewVersions: ['v1beta1']
        clientConfig:
          service:
            name: pod-identity-webhook
            namespace: ${WEBHOOK_NAMESPACE}
            path: /mutate
          caBundle: ${CLUSTER_CA}
        rules:
          - operations: ['CREATE']
            apiGroups: ['']
            apiVersions: ['v1']
            resources: ['pods']
    EOF
    

    aws-webhook.yaml のコンテンツをクラスタに適用する準備ができました。

Webhook をユーザー クラスタに適用する

Webhook をユーザー クラスタに適用するには、次の手順を行います。

  1. aws-webhook.yaml ファイルをユーザー クラスタに適用します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f aws-webhook.yaml
    
  2. マニフェストを適用すると、Webhook Pod によって Kubernetes 証明書署名リクエスト(CSR)が生成されます。system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook からのリクエストをすべて kubectl certificate approve で承認します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl certificate approve $(env HTTPS_PROXY=http://localhost:8118 \ &&\
      kubectl get csr -o \
        jsonpath="{.items[?(@.spec.username==\"system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook\")].metadata.name}")
    
  3. 承認されていない CSR が残っていないかを確認します。

    kubectl get csr を使用して、リクエスト元の system:serviceaccount:${WEBHOOK_NAMESPACE}:pod-identity-webhook のすべての CSR が承認されているかを確認します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get csr
    

    レスポンス:

    NAME        AGE   REQUESTOR                                            CONDITION
    csr-mxrt8   10s   system:serviceaccount:default:pod-identity-webhook   Approved,Issued
    

AWS OIDC プロバイダを構成する

このセクションは、クラスタ管理者を対象としています。

AWS で OIDC プロバイダを作成するには、AWS で中間認証局(CA)またはサーバー証明書のサムプリントが必要です。OIDC ディスカバリ認証情報は、GTS CA 1C3 という名前の中間 CA によって署名された証明書とともに storage.googleapis.com に保存されます。中間 CA GTS CA 1C3 の SHA-1 サムプリントは 08745487E891C19E3078C1F2A07E452950EF36F6 です。

AWS で OIDC ディスカバリ バケットを OIDC プロバイダとして登録するには、次の操作を行います。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. OIDC 発行者 URL、発行者のホストパス、Cloud Storage サムプリントを環境変数に保存します。

    ISSUER_URL=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.workloadIdentityInfo.issuerURL}')
    ISSUER_HOSTPATH=${ISSUER_URL#"https://"}
    CA_THUMBPRINT=08745487E891C19E3078C1F2A07E452950EF36F6
    
  3. aws コマンドライン ツールを使用して、AWS で OIDC プロバイダを作成します。

    aws iam create-open-id-connect-provider \
      --url ${ISSUER_URL} \
      --thumbprint-list ${CA_THUMBPRINT} \
      --client-id-list sts.amazonaws.com
    

サムプリントを更新する

Google が storage.googleapis.com の CA をローテーションする場合は、次のコマンドを実行します。

  1. 更新された証明書のサムプリント 08745487E891C19E3078C1F2A07E452950EF36F6 をコピーします。

  2. aws iam update-open-id-connect-provider-thumbprint コマンドの手順に沿って操作します。ターゲット ホスト名として storage.googleapis.com を使用し、サムプリントとして 08745487E891C19E3078C1F2A07E452950EF36F6 を使用します。

AWS IAM のロールとポリシーを作成する

このセクションは、クラスタ管理者を対象としています。

Kubernetes サービス アカウントにバインドする AWS IAM ロールを作成します。IAM ロールには、sts:AssumeRoleWithWebIdentity の権限が付与されています。

ロールを作成する手順は次のとおりです。

  1. ワークロードに必要な権限を付与する AWS IAM ポリシーを検索するか作成します。

    ポリシーの Amazon Resource Name(ARN)の AWS IAM ポリシーが必要です。例: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess

  2. 認証情報で環境変数を設定します。

    KSA_NAME=KUBERNETES_SERVICE_ACCOUNT
    WORKLOAD_NAMESPACE=WORKLOAD_IDENTITY_NAMESPACE
    
    AWS_ROLE_NAME=AWS_ROLE_NAME
    AWS_POLICY=EXISTING_AWS_POLICY
    

    次のように置き換えます。

    • KUBERNETES_SERVICE_ACCOUNT: 新しい Kubernetes サービス アカウントの名前
    • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される Namespace の名前
    • AWS_ROLE_NAME: ワークロードに対する新しい AWS ロールの名前
    • EXISTING_AWS_POLICY: 既存の AWS IAM ポリシーの Amazon Resource Name(ARN)。例: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
  3. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  4. ユーザー クラスタが AWS セキュリティ トークン サービスを使用して一時的なセキュリティ認証情報を引き継ぐことができる AWS IAM ポリシーを作成します。

    CLUSTER_ID=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.clusterID}')
    
    # Get the ID Provider ARN
    PROVIDER_ARN=$(aws iam list-open-id-connect-providers  \
    | jq '.OpenIDConnectProviderList' \
    | jq ".[] | select(.Arn |  contains(\"${CLUSTER_ID}\"))"   \
    | jq  '.Arn' | tr -d '"')
    
    # Create AWS role and policy
    cat > irp-trust-policy.json << EOF
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "${PROVIDER_ARN}"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "${ISSUER_HOSTPATH}:sub": "system:serviceaccount:${WORKLOAD_NAMESPACE}:${KSA_NAME}"
            }
          }
        }
      ]
    }
    EOF
    
  5. このポリシーで AWS IAM のロールを作成し、既存のポリシーをロールに接続するには、次のコマンドを実行します。

    aws iam create-role \
      --role-name ${AWS_ROLE_NAME} \
      --assume-role-policy-document file://irp-trust-policy.json
    aws iam update-assume-role-policy \
      --role-name ${AWS_ROLE_NAME} \
      --policy-document file://irp-trust-policy.json
    aws iam attach-role-policy \
      --role-name ${AWS_ROLE_NAME} \
      --policy-arn ${AWS_POLICY}
    

    aws コマンドライン ツールによって、ポリシーがロールに接続されていることを確認できます。

ワークロード用の Kubernetes サービス アカウントを作成する

このセクションは、開発者またはクラスタ管理者を対象としています。

事前に指定された AWS IAM ロールにバインドされた Kubernetes サービス アカウントを作成するには、次の手順を行います。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストをユーザー クラスタに切り替えます。

    cd anthos-aws
    env HTTPS_PROXY=http://localhost:8118 \
      anthos-gke aws clusters get-credentials CLUSTER_NAME
    CLUSTER_NAME は、ユーザー クラスタ名に置き換えます。

  2. 次のコマンドを実行して Kubernetes サービス アカウントを作成します。

    S3_ROLE_ARN=$(aws iam get-role \
      --role-name AWS_ROLE_NAME \
      --query Role.Arn --output text)
    
    cat << EOF  > k8s-service-account.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: ${KSA_NAME}
      namespace: WORKLOAD_IDENTITY_NAMESPACE
    EOF
    
    env HTTPS_PROXY=http://localhost:8118 \
    kubectl apply -f k8s-service-account.yaml
    
    env HTTPS_PROXY=http://localhost:8118 \
    kubectl annotate sa --namespace ${WORKLOAD_NAMESPACE} ${KSA_NAME} eks.amazonaws.com/role-arn=${S3_ROLE_ARN}
    

    以下を置き換えます。

    • AWS_ROLE_NAME: ワークロードに適用する AWS IAM ロールの名前
    • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される名前空間の名前

Pod に認証情報を適用する

このセクションはデベロッパーを対象としています。

このセクションは、ワークロード ID Webhook をデプロイしていることを前提としています。Webhook をデプロイしていない場合は、Webhook を使用せずに認証情報を適用するに進んでください。

Webhook を使用して認証情報を適用する

このセクションでは、Webhook で使用可能な認証情報を読み取るように Pod を構成する方法について説明します。

Pod にサービス アカウントを追加する

ワークロードでワークロード ID を使用するには、次のフィールドに Kubernetes サービス アカウントを追加します。

  • Deployment の場合: spec.template.spec.serviceAccountName
  • Pod の場合: spec.serviceAccount

次の Pod マニフェストは、基本の CentOS イメージを起動し、spec.serviceAccount フィールドを含みます。

apiVersion: v1
kind: Pod
metadata:
  name: sample-centos-pod
  namespace: WORKLOAD_IDENTITY_NAMESPACE
spec:
  containers:
  - command:
    - /bin/bash
    - -ec
    - while :; do echo '.'; sleep 500 ; done
    image: amazon/aws-cli
    name: centos
  serviceAccount: KUBERNETES_SERVICE_ACCOUNT

以下を置き換えます。

  • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される名前空間の名前
  • KUBERNETES_SERVICE_ACCOUNT: 事前に作成した Kubernetes サービス アカウントの名前

Pod に環境変数が設定されているかどうかを確認する

Pod に環境変数が設定されているかどうかを確認するには、次のコマンドを実行して Pod の情報を取得します。

kubectl get pod --namespace WORKLOAD_IDENTITY_NAMESPACE POD_NAME -o yaml

以下を置き換えます。

  • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される名前空間の名前
  • POD_NAME: 確認する Pod の名前

出力には、spec.containers.command.env の環境変数値と、AWS IAM トークンのマウント ポイントが含まれます。Pod マニフェストの例を次に示します。

apiVersion: v1
kind: Pod
metadata:
  ...
spec:
  containers:
  - command:
    - /bin/bash
    - -ec
    - while :; do echo '.'; sleep 500 ; done
    env:
    - name: AWS_ROLE_ARN
      value: arn:aws:iam::1234567890:role/my-example-workload-role-1
    - name: AWS_WEB_IDENTITY_TOKEN_FILE
      value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
    image: amazon/aws-cli
    imagePullPolicy: IfNotPresent
    name: centos
    resources: {}
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    volumeMounts:
    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
      name: my-k8s-serviceaccount-token-d4nz4
      readOnly: true
    - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
      name: aws-iam-token
      readOnly: true
  serviceAccount: my-k8s-serviceaccount
  serviceAccountName: my-k8s-serviceaccount
  volumes:
  - name: aws-iam-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: sts.amazonaws.com
          expirationSeconds: 86400
          path: token
  - name: my-k8s-serviceaccount-token-d4nz4
    secret:
      defaultMode: 420
      secretName: my-k8s-serviceaccount-token-d4nz4
   ...
status:
  ...

Webhook なしで認証情報を適用する

ワークロード ID の Webhook をデプロイしない場合は、次のことを行う必要があります。

Workload Identity の認証情報を持つ Pod を作成する

ワークロード ID に必要な認証情報を含む Pod を作成するには、以下の手順を行います。

  1. 次の Pod マニフェストを sample-pod-no-webhook.yaml という名前のファイルにコピーします。この構成により、必要な認証情報を含む基本の CentOS イメージが起動されます。

    apiVersion: v1
    kind: Pod
    metadata:
      name: sample-centos-pod-no-webhook
      namespace: WORKLOAD_IDENTITY_NAMESPACE
    spec:
      containers:
      - command:
        - /bin/bash
        - -ec
        - while :; do echo '.'; sleep 500 ; done
        image: centos:7
        name: centos
        env:
        - name: AWS_ROLE_ARN
          value: IAM_ROLE_ARN
        - name: AWS_WEB_IDENTITY_TOKEN_FILE
          value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
        volumeMounts:
        - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount
          name: aws-iam-token
          readOnly: true
      volumes:
      - name: aws-iam-token
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              audience: sts.amazonaws.com
              expirationSeconds: 86400
              path: token
      serviceAccount: KUBERNETES_SERVICE_ACCOUNT
    

    以下を置き換えます。

    • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される名前空間の名前。
    • IAM_ROLE_ARN: Pod に付与された IAM ロールの ARN。例: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess
    • KUBERNETES_SERVICE_ACCOUNT: 事前に作成した Kubernetes サービス アカウントの名前。
  2. kubectl を使用して、Pod マニフェストをクラスタに適用します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl apply -f sample-pod-no-webhook.yaml
    

Pod が AWS リソースにアクセスできるかどうかを確認する

以下の手順では、ワークロード ID が機能するために必要な認証情報を Pod が受信したかどうかを確認する方法について説明します。

手順を完了するには、以下が必要です。

  • コンテナに対する bash シェルアクセス。ほとんどの本番環境イメージには利用可能なシェルがありません。次の例は、前のセクションで指定されている Pod を使用して AWS S3 にアクセスする方法を示しています。

  • AWS コマンドライン インターフェースをダウンロードするには、Pod にインターネットへの送信アクセス権を設定する必要があります。

Pod が S3 バケットにアクセスできるかどうかを確認する手順は次のとおりです。

  1. kubectl exec を使用して、Pod sample-centos-pod-no-webhook でインタラクティブ bash シェルを起動します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl exec -it --namespace ${WORKLOAD_NAMESPACE} sample-centos-pod-no-webhook -- bash
    

    ターミナルが Pod の bash シェルを開きます。

  2. aws ツールを使用して、AWS IAM の権限と認証情報を確認します。

    aws sts assume-role-with-web-identity \
     --role-arn ${AWS_ROLE_ARN} \
     --role-session-name mh9test \
     --web-identity-token file:///var/run/secrets/eks.amazonaws.com/serviceaccount/token \
     --duration-seconds 1000
    

    aws ツールによって、次のような認証情報が出力されます。

    {
        "AssumedRoleUser": {
            "AssumedRoleId": "AROAR2ZZZLEXVSDCDJ37N:mh9test",
            "Arn": "arn:aws:sts::126285863215:assumed-role/my-example-workload-role-1/mh9test"
        },
        "Audience": "sts.amazonaws.com",
        "Provider": "arn:aws:iam::126285863215:oidc-provider/storage.googleapis.com/gke-issuer-cec6c353",
        "SubjectFromWebIdentityToken": "system:serviceaccount:default:my-s3-reader-ksa",
        "Credentials": {
            "SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
            "SessionToken": "MY_TOKEN",
            "Expiration": "2020-08-14T22:46:36Z",
            "AccessKeyId": "AKIAIOSFODNN7EXAMPLE"
        }
    }
    

    An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: Couldn't retrieve verification key from your identity provider, please reference AssumeRoleWithWebIdentity documentation for requirements」というメッセージが表示されたら、バケットが一般公開されていることを確認します。

Webhook のアップグレード

Workload Identity を有効にして Kubernetes 1.18 以前のクラスタと Workload Identity の Webhook バージョン release-0.2.2-gke.0 を作成した場合は、Kubernetes 1.19 にアップグレードする前に Webhook をアップグレードする必要があります。

Webhook をアップグレードするには、次の操作を行います。

  1. 次のコマンドを実行して、Webhook がインストールされていることを確認します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get MutatingWebhookConfiguration
    

    クラスタに Webhook がデプロイされている場合、出力には次のものが含まれます。

    NAME                   WEBHOOKS   AGE
    pod-identity-webhook   1          11m
    

    Webhook がクラスタにデプロイされていない場合は、次の手順をスキップできます。

  2. aws-webhook.yaml ファイルを保存した場合は、マニフェストを削除できます。このファイルを使用できない場合は、Webhook のコンポーネントを手動で削除できます。以下のファイルまたはコンポーネントから選択します。

    ファイル

    aws-webhook.yaml ファイルを引き続き保持している場合は、次のコマンドを実行して Webhook を削除します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete -f aws-webhook.yaml
    

    コンポーネント

    Webhook のコンポーネントを手動で削除するには、次のコマンドを実行します。

    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete namespace WEBHOOK_NAMESPACE
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete clusterrole pod-identity-webhook
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete clusterrolebinding pod-identity-webhook
    env HTTPS_PROXY=http://localhost:8118 \
       kubectl delete mutatingwebhookconfiguration pod-identity-webhook
    

    WEBHOOK_NAMESPACE は、Workload Identity Webhook をインストールした Namespace に置き換えます。例: workload-identity-webhook

  3. 次のコマンドを実行して、残りの証明書署名リクエスト(CSR)があるかどうかを確認します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl get csr |grep pod-identity-webhook
    

    出力が空白の場合は、次の手順に進みます。CSR がまだ存在する場合は、kubectl コマンドによって既存の CSR が一覧表示されます。CSR を削除するには、次のコマンドを実行します。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete csr $(kubectl get csr -o \
      jsonpath="{.items[?(@.spec.username==\"system:serviceaccount:WEBHOOK_NAMESPACE:pod-identity-webhook\")].metadata.name}")
    

    WEBHOOK_NAMESPACE は、Workload Identity Webhook をインストールした Namespace に置き換えます。例: workload-identity-webhook

  4. Webhook を作成するの手順に沿って、新しいバージョンの Webhook をデプロイします。

    新しいバージョンの Webhook をデプロイした後、その Webhook を使用する Pod を再起動する必要があります。ユーザー クラスタをアップグレードすることで、Pod を再起動できます。

クリーンアップ

このセクションでは、このドキュメントの前の部分で作成したリソースを削除する方法を説明します。

サービス アカウントとそれに関連する IAM のロールをクリーンアップする

サービス アカウントとそれに関連する IAM ロールを削除するには、次の手順を行います。

  1. サービス アカウントをクリーンアップします。

    env HTTPS_PROXY=http://localhost:8118 \
      kubectl delete sa KUBERNETES_SERVICE_ACCOUNT --namespace WORKLOAD_IDENTITY_NAMESPACE
    

    以下を置き換えます。

    • KUBERNETES_SERVICE_ACCOUNT: 新しい Kubernetes サービス アカウントの名前
    • WORKLOAD_IDENTITY_NAMESPACE: ワークロードが実行される名前空間の名前
  2. AWS IAM ロールをクリーンアップします。次のいずれかの方法を選択します。

    • AWS コンソールで AWS の IAM ロールを削除する。

    • 次のコマンドを使用して、AWS コマンドライン ツールでロールを削除する。

      aws iam  detach-role-policy \
        --role-name=${AWS_ROLE_NAME} \
        --policy-arn=${AWS_POLICY}
      aws iam delete-role --role-name=${AWS_ROLE_NAME}
      

ユーザー クラスタを削除する

ユーザー クラスタを削除するには、GKE on AWS のアンインストール手順に沿って操作します。

AWS OIDC プロバイダをクリーンアップする

ユーザー クラスタを削除したら、次の bash シェルコマンドまたは AWS コンソールを使用して、AWS で OIDC プロバイダの登録を解除して削除します。

  1. anthos-aws ディレクトリから anthos-gke を使用して、コンテキストを管理サービスに切り替えます。

    cd anthos-aws
    anthos-gke aws management get-credentials

  2. 次のコマンドを使用して、AWS コマンドライン ツールでロールを削除します。

    CLUSTER_ID=$(env HTTPS_PROXY=http://localhost:8118 \
      kubectl get awscluster ${CLUSTER_NAME} -o jsonpath='{.status.clusterID}')
    
    PROVIDER_ARN=$(aws iam list-open-id-connect-providers  \
    | jq '.OpenIDConnectProviderList' \
    | jq ".[] | select(.Arn |  contains(\"${CLUSTER_ID}\"))"   \
    | jq  '.Arn' | tr -d '"')
    
    aws iam delete-open-id-connect-provider \
      --open-id-connect-provider-arn=${PROVIDER_ARN}
    

    AWS OIDC プロバイダが削除されたことを示す確認メッセージが表示されます。

次のステップ