GKE 用 Identity Service を使用して Cloud Build プライベート プールから限定公開 Google Kubernetes Engine クラスタにアクセスする


このチュートリアルでは、Cloud Build プライベート プールを使用して限定公開の Google Kubernetes Engine(GKE)クラスタのコントロール プレーンにアクセスする方法について説明します。このアクセス権により、Cloud Build を使用して限定公開 GKE クラスタにアプリケーションをデプロイし、リソースを管理できるようになります。このチュートリアルは、プラットフォーム管理者、クラスタ管理者、デベロッパーを対象としています。対象読者は、GKE、Cloud Build、OpenID Connectgcloud コマンドライン ツールに精通していることを前提としています。

Cloud Build のプライベート プールと GKE クラスタ コントロール プレーンは、どちらも Google が所有する Virtual Private Cloud(VPC)ネットワークで実行されます。これらの VPC ネットワークは、Google Cloud 上の独自の VPC ネットワークにピアリングされます。ただし、VPC ネットワーク ピアリングでは推移的なピアリングがサポートされていないため、Cloud Build のプライベート プールを使用する場合は制限となる可能性があります。このチュートリアルでは、Identity Service for GKE を使用して、Cloud Build プライベート プールのワーカーが限定公開 GKE クラスタのコントロール プレーンにアクセスできるようにするソリューションを紹介します。

アーキテクチャの概要

Identity Service for GKE は、GKE クラスタ コントロール プレーンの認証プロキシです。API サーバーにリクエストをプロキシし、OpenID Connect(OIDC) ID プロバイダによって発行された ID トークンを検証します。プロキシで ID トークンが正常に検証されると、プロキシはユーザーなりすましの HTTP ヘッダーを元のリクエストに追加し、API サーバーに転送します。プロキシは、ユーザーとグループの権限を借用する権限を持つ Kubernetes サービス アカウントとして実行されます。

Identity Service for GKE プロキシはクラスタノードで Pod として動作します。LoadBalancer タイプの Kubernetes Service は、クラスタ外部にプロキシを公開します。限定公開クラスタで Identity Service for GKE が有効になっている場合、インストーラが Kubernetes Service にアノテーションを追加して、内部パススルー ネットワーク ロードバランサをプロビジョニングします。プロキシは、VPC ネットワーク ピアリング接続(Cloud Build プライベート プールなど)上でロードバランサを通じてアクセスできます。これは、プロキシが、VPC ネットワークのクラスタノードで実行されているためです。

Google の OAuth 2.0 認証システムは OpenID Connect 仕様に準拠しているため、Identity Service for GKE で OpenID Connect ID プロバイダとして Google を構成できます。Google サービス アカウントの ID トークンを取得するには、Service Account Credentials API APIgenerateIdToken メソッドを使用できます。ID トークンは、Google によって発行され、署名されます。

すべてをまとめると、このソリューションでは、Identity Service for GKE プロキシを使用して、限定公開 GKE クラスタ コントロール プレーンへのアクセスが可能です。Cloud Build プライベート プールで実行されるビルドは、VPC ネットワーク ピアリング接続上でプロキシに接続します。Cloud Build プライベート プールで実行されているビルドは、Google サービス アカウントとして実行されます。この Google サービス アカウントは、Service Account Credentials API からプロキシを認証するための ID トークンを取得できます。

次の図は、前述のテキストで説明したアーキテクチャを示しています。

Identity Service for GKE を使用して限定公開 GKE クラスタにアクセスする

このソリューションのすべての通信は、内部 IP アドレス空間上で行われます。プライベート プール内のワーカーは、公共のインターネット接続を必要としません。

ユーザー アカウントと Google サービス アカウントに付与されている Identity and Access Management(IAM)権限は、Identity Service for GKE を使用して認証する場合には適用されません。代わりに、Kubernetes ロールベースのアクセス制御(RBAC)を使用して、これらのアカウントのクラスタ権限を管理します。

準備

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Google Cloud CLI をインストールします。
  3. gcloud CLI を初期化するには:

    gcloud init
  4. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  5. Google Cloud プロジェクトで課金が有効になっていることを確認します

  6. Cloud Build, GKE, Identity-Aware Proxy (IAP), and Service Networking APIs API を有効にします。

    gcloud services enable cloudbuild.googleapis.comcontainer.googleapis.comiap.googleapis.comservicenetworking.googleapis.com
  7. Google Cloud CLI をインストールします。
  8. gcloud CLI を初期化するには:

    gcloud init
  9. Google Cloud プロジェクトを作成または選択します

    • Google Cloud プロジェクトを作成します。

      gcloud projects create PROJECT_ID

      PROJECT_ID は、作成する Google Cloud プロジェクトの名前に置き換えます。

    • 作成した Google Cloud プロジェクトを選択します。

      gcloud config set project PROJECT_ID

      PROJECT_ID は、実際の Google Cloud プロジェクト名に置き換えます。

  10. Google Cloud プロジェクトで課金が有効になっていることを確認します

  11. Cloud Build, GKE, Identity-Aware Proxy (IAP), and Service Networking APIs API を有効にします。

    gcloud services enable cloudbuild.googleapis.comcontainer.googleapis.comiap.googleapis.comservicenetworking.googleapis.com

限定公開 GKE クラスタの作成

  1. Cloud Shell で、コントロール プレーンのパブリック エンドポイントへのクライアント アクセス権がなく、Identity Service for GKE がインストールされている GKE クラスタを作成します。

    gcloud container clusters create CLUSTER  \
      --enable-identity-service \
      --enable-ip-alias \
      --enable-master-authorized-networks \
      --enable-private-endpoint \
      --enable-private-nodes \
      --master-ipv4-cidr CONTROL_PANE_CIDR \
      --network NETWORK\
      --release-channel regular \
      --scopes cloud-platform \
      --subnetwork SUBNET \
      --tags NODE_TAGS \
      --workload-pool PROJECT_ID.svc.id.goog \
      --zone ZONE
    

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

    • CLUSTER: クラスタの名前。 このチュートリアルでは、private-cluster を使用します。
    • CONTROL_PANE_CIDR: コントロール プレーンの IP アドレス範囲。/28 接頭辞が必要です。このチュートリアルでは、172.16.0.32/28 を使用できます。
    • NETWORK: コントロール プレーンが接続する VPC ネットワーク。このチュートリアルでは、default を使用します。
    • SUBNET: GKE クラスタ コントロール プレーンが接続するサブネット。サブネットは、NETWORK で指定された VPC ネットワークに属している必要があります。このチュートリアルでは、default を使用します。
    • NODE_TAGS: ノードに適用するネットワーク タグのカンマ区切りのリスト。このチュートリアルでは、private-cluster-node を使用します。
    • PROJECT_ID: Google Cloud プロジェクト ID。
    • ZONE: GKE クラスタのゾーン。このチュートリアルでは、us-central1-f を使用します。

    コマンドについて、次の点に注意してください。

    • --enable-identity-service フラグによって、クラスタで Identity Service for GKE が有効になります。独自の環境では、既存のクラスタで Identity Service for GKE を有効にできます。

    • --enable-private-endpoint フラグは、内部 IP アドレスを使用することによってのみアクセスできるようにコントロール プレーンを構成します。

    • --enable-private-nodes フラグは、内部 IP アドレスのみを持つようにクラスタノードを構成します。

    • --enable-master-authorized-networks フラグと --enable-private-nodes フラグによって、--network フラグで指定されたプライベート ネットワークからのみ API サーバーにアクセスできます。

    • オプションの --workload-pool フラグによって、Workload Identity が有効になります。それはこのチュートリアルでは必須ではありません。

  2. GKE クラスタ コントロール プレーンが ClientConfig リソースの検証用アドミッション Webhook に接続できるようにファイアウォール ルールを追加します。

    gcloud compute firewall-rules create allow-control-plane-clientconfig-webhook \
      --allow tcp:15000 \
      --network NETWORK\
      --source-ranges CONTROL_PANE_CIDR\
      --target-tags NODE_TAGS
    

    ClientConfig は、Identity Service for GKE が使用して ID プロバイダとやり取りする方法を構成する Kubernetes カスタム リソースタイプ(CRD)です。

Identity Service for GKE を OAuth 2.0 クライアント アプリケーションとして登録する

このセクションでは、Google の OAuth 2.0 認証システムを使用して、Identity Service for GKE をクライアント アプリケーションとして登録します。

  1. Google Cloud コンソールの認証情報ページを開きます。

    [認証情報] ページを開く

  2. [認証情報を作成] をクリックします。

  3. [OAuth クライアント ID] を選択します。

    Google Cloud プロジェクトに対して同意画面がまだ構成されていない場合は、[同意画面を構成] をクリックします。同意画面を構成に関するドキュメントに従います。このチュートリアルでは、次の値を設定します。

    • [User Type] には、[Internal] または [External] のいずれかを使用できます。このチュートリアルでは、[Internal] を選択できます。
    • [アプリ名]、[ユーザー サポートメール]、[デベロッパーの連絡先情報] の値は必須で、任意の値を設定できます。
    • このチュートリアルでは、スコープを追加する必要はありません。

    同意画面の構成が完了したら、[ダッシュボードに戻る] をクリックし、現在の手順のステップ 1 からやり直します。

  4. [アプリケーションの種類] リストで、[ウェブ アプリケーション] を選択します。

  5. [名前] フィールドに、クライアント ID の名前を入力します。このチュートリアルでは、Identity Service for GKE を使用します。

  6. [作成] をクリックします。

    ダイアログが表示されます。 [クライアント ID] の値をコピーします。この手順で後で必要になります。

  7. [OK] をクリックしてダイアログ ボックスを閉じます。

  8. Cloud Shell で、cloud-build-private-pools-gke-tutorial というホーム ディレクトリの下にディレクトリを作成し、そのディレクトリに移動します。

    mkdir -p ~/cloud-build-private-pools-gke-tutorial cd ~/cloud-build-private-pools-gke-tutorial

  9. 新しいディレクトリに、client-config-patch.yaml という名前の YAML ファイルを作成します。これには、後で Identity Service for GKE ClientConfig リソースにパッチを適用するのに必要な値があります。

    cat << EOF > client-config-patch.yaml
    spec:
      authentication:
      - name: google-oidc
        oidc:
          clientID: CLIENT_ID
          cloudConsoleRedirectURI: https://console.cloud.google.com/kubernetes/oidc
          extraParams: prompt=consent,access_type=offline
          issuerURI: https://accounts.google.com
          kubectlRedirectURI: http://localhost:10000/callback
          scopes: email
          userClaim: email
          userPrefix: '-'
    EOF
    

    CLIENT_ID は、前の手順からの OAuth クライアント ID で置き換えます。

    パッチに関する次の点に注意してください。

    • Google の OAuth 2.0 認証システムが発行する ID トークンには、サブ(サブジェクト)クレームに一意の数値識別子が含まれています。この不透明な ID をロール バインディングで使用すると、ロール バインディングのサブジェクトを特定するのが難しくなります。そのため、このパッチにより、デフォルトのサブクレームを使用する代わりに、ID トークンのメール クレームを使用してユーザーを識別するように Identity Service for GKE を構成します。

    • メールのスコープが追加され、発行された ID トークンにメール クレームが含まれるようになります。

    • cloudConsoleRedirectURIextraParamskubectlRedirectURI、スコープのフィールドは、デベロッパーが Identity Service for GKE を使用してクラスタに対する認証を行う場合に使用されます。Google サービス アカウントがクラスタを認証するときには使用されません。kubectlRedirectURI フィールドが必須です。

    • userPrefix フィールドは、構成された ID プロバイダを使用して認証するユーザーの接頭辞です。値 '-' は接頭辞がないことを意味します。

    • spec.authentication フィールドは配列です。Identity Service for GKE では、複数の OpenID Connect ID プロバイダを使用できます。たとえば、Google サービス アカウントを認証するための ID プロバイダとして、そしてデベロッパーを認証する別の ID プロバイダとして、Google を使用できます。

    この構成のフィールドの詳細については、外部 ID プロバイダを使用して GKE に認証するをご覧ください。

Google サービス アカウントを作成して Identity Service for GKE を構成する

  1. Cloud Shell で、Google サービス アカウントを作成します。

    gcloud iam service-accounts create ISG_GSA \
      --display-name "Configure Identity Service for GKE"
    

    ISG_GSA は、Google サービス アカウントに使用する名前に置き換えます。このチュートリアルでは、identity-service-for-gke を使用します。

    Identity Service for GKE を構成し、クラスタで Kubernetes のロールベース アクセス制御を構成するには、Compute Engine VM インスタンスにこの Google サービス アカウントを割り当てます。

  2. プロジェクトの Kubernetes Engine 管理者ロールを Google サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/container.admin
    

    このロールは、このチュートリアルで次のタスクを行うために必要な権限を提供します。

    • プロジェクト内のクラスタで Identity Service for GKE の設定を構成します。
    • クラスタにロール バインディングとクラスタ ロール バインディングを作成します。

GKE 用 Identity Service を構成する

Identity Service for GKE を構成するには、クラスタ コントロール プレーンへのアクセス権が必要です。このチュートリアルでは、コントロール プレーンにアクセスするための Compute Engine VM インスタンスを作成します。

VM インスタンスへの SSH アクセスが必要です。VPC ネットワークの外側から VM インスタンスへの SSH アクセスの認証と認可を有効にするには、Identity-Aware Proxy(IAP)で TCP 転送を使用します。この機能により、VM インスタンスにパブリック IP アドレスがなくても SSH アクセスが可能になります。

  1. Cloud Shell で、ssh-iap ネットワーク タグを持つ任意の VM インスタンスへの IAP TCP 転送を使用して SSH アクセスを許可するファイアウォール ルールを作成します。

    gcloud compute firewall-rules create allow-ssh-ingress-from-iap \
      --allow tcp:22 \
      --description "Allow SSH tunneling using Identity-Aware Proxy" \
      --network NETWORK \
      --source-ranges 35.235.240.0/20 \
      --target-tags ssh-iap
    

    ソース範囲には、IAP が TCP 転送に使用する IP アドレスが含まれています。

  2. GKE クラスタと同じ VPC ネットワーク内に Compute Engine VM インスタンスを作成します。

    gcloud compute instances create VM \
      --metadata enable-oslogin=TRUE \
      --network NETWORK \
      --no-address \
      --scopes cloud-platform,userinfo-email \
      --service-account ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --subnet SUBNET  \
      --tags ssh-iap \
      --zone ZONE
    

    VM は、VM インスタンスに使用する名前に置き換えます。このチュートリアルでは、identity-service-for-gke-configuration を使用します。

    上記のコマンドについて、次の点に注意してください。

    • --service-account フラグは、Google サービス アカウントを VM インスタンスに接続します。

    • Service Account Credentials API にアクセスするには cloud-platform スコープが必要です。

    • userinfo-email スコープは、Kubernetes ロールベースのアクセス制御を管理する VM インスタンスを作成するときに役立ちます。このチュートリアルでは省略できます。

    • --no-address フラグは、VM インスタンスが外部 IP アドレスなしで作成されていることを意味します。

    • オプションの enable-oslogin インスタンス メタデータ値によって、VM インスタンスで OS Login が有効になります。OS Login は、IAM を使用して VM インスタンスへの SSH アクセスの管理を有効にします。

  3. ClientConfig パッチファイルを VM インスタンスにコピーします。

    gcloud compute scp client-config-patch.yaml VM:~ --tunnel-through-iap --zone ZONE
    

    --tunnel-through-iap フラグを指定すると、gcloud は IAP を介して接続をトンネリングします。

  4. SSH を使用して VM インスタンスに接続します。

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    このセクションの残りのコマンドは、SSH セッションから実行します。

  5. VM インスタンスに kubectl コマンドライン ツールと gke-gcloud-auth-plugin バイナリをインストールします。

    sudo apt-get install -y kubectl google-cloud-sdk-gke-gcloud-auth-plugin
    
  6. GKE クラスタの認証情報を取得します。

    export USE_GKE_GCLOUD_AUTH_PLUGIN=True
    gcloud container clusters get-credentials CLUSTER --zone ZONE
    
  7. デフォルトの ClientConfig リソースにパッチを適用します。

    kubectl patch clientconfig default \
        --namespace kube-public \
        --patch-file client-config-patch.yaml \
        --type merge
    
  8. パッチされたデフォルトの ClientConfig リソースから certificateAuthorityData フィールドを抽出し、それを certificateAuthorityData.pem というファイルに保存します。

    kubectl get clientconfig default \
         --namespace kube-public \
         --output jsonpath='{.spec.certificateAuthorityData}' \
         | base64 --decode > certificateAuthorityData.pem
    
  9. パッチされたデフォルトの ClientConfig リソースからサーバー フィールドを抽出し、それを server.txt というファイルに保存します。

    kubectl get clientconfig default \
         --namespace kube-public \
         --output jsonpath='{.spec.server}' > server.txt
    
  10. SSH セッションを終了します。

    exit
    

(省略可)クラスタ構成を確認する

続行する前に、Identity Service for GKE がクラスタで正しく設定されていることを確認できます。設定を確認するには、VM インスタンスに接続された Google サービス アカウントを使用して、Identity Service for GKE を使用するクラスタに対して認証を行います。

  1. Cloud Shell で、Google サービス アカウントのサービス アカウントの OpenID Connect ID トークン作成者をサービス アカウント自体に付与します。

    gcloud iam service-accounts add-iam-policy-binding \
      ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
      --role roles/iam.serviceAccountOpenIdTokenCreator
    

    このロールは、Service Account Credentials API からサービス アカウントの ID トークンをリクエストするために必要な iam.serviceAccounts.getOpenIdToken 権限を提供します。

  2. SSH を使用して VM インスタンスに接続します。

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    このセクションの残りのコマンドは、SSH セッションから実行します。

  3. VM インスタンスに接続されている Google サービス アカウントのメタデータ サーバーから、リクエストされた aud(audience)クレームとして OAuth クライアント ID を使用して、OAuth 2.0 アクセス トークンをリクエストします。

    ACCESS_TOKEN=$(curl --silent --header "Metadata-Flavor: Google" \
    http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token \
           | python3 -c 'import json, sys; print(json.load(sys.stdin).get("access_token"))')
    

    メタデータ サーバーからのレスポンス本文は JSON ドキュメントです。このコマンドは、インライン Python スクリプトを使用して、レスポンス本文から access_token フィールドを抽出します。

  4. VM インスタンスに接続された Google サービス アカウントの Service Account Credentials API から ID トークンをリクエストします。

    ID_TOKEN=$(curl --silent --request POST \
        --data '{"audience": "CLIENT_ID", "includeEmail": true}' \
        --header "Authorization: Bearer $ACCESS_TOKEN" \
        --header "Content-Type: application/json; charset=utf-8" \
    "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/ISG_GSA@PROJECT_ID.iam.gserviceaccount.com:generateIdToken" \
           | python3 -c 'import json, sys; print(json.load(sys.stdin).get("token"))')
    

    上記のコマンドについて、次の点に注意してください。

    • リクエスト本文の JSON の audience フィールドには、ID トークンのリクエストされた aud(audience)クレームを指定します。
    • 前のステップからのアクセス トークンを使用して API の認証を行います。
  5. ID トークンでクレームを表示します。

    echo $ID_TOKEN \
        | cut -d. -f2 \
        | base64 --decode --ignore-garbage 2> /dev/null \
        | python3 -m json.tool
    

    email クレームに Google サービス アカウントのメールアドレスが含まれていることを確認します。

  6. Identity Service for GKE で ID トークンを使用して、コントロール プレーンを認証します。

    kubectl get namespaces \
        --certificate-authority certificateAuthorityData.pem \
        --server $(cat server.txt) \
        --token $ID_TOKEN
    

    出力は次のようになります。

      Error from server (Forbidden): namespaces is forbidden: User "ISG_GSA@PROJECT_ID.iam.gserviceaccount.com" cannot list resource "namespaces" in API group "" at the cluster scope
    

    これは予想されるエラーです。Google サービス アカウントにはプロジェクトの GKE クラスタに対する IAM 権限が付与されていますが、Identity Service for GKE を使用して認証する場合は IAM の権限は適用されません。代わりに、Kubernetes ロールベースのアクセス制御(RBAC)を使用してアクセス権を構成します。

  7. サービス アカウントが Google の OpenID Connect プロバイダを使用してクラスタに対する認証を行うときに、Google サービス アカウントに view クラスタロールを付与するクラスタロール バインディングを作成します。

    kubectl create clusterrolebinding ISG_GSA-cluster-view \
        --clusterrole view \
        --user ISG_GSA@PROJECT_ID.iam.gserviceaccount.com
    

    独自の環境で ClientConfig で - 以外の userPrefix 値を設定している場合は、このコマンドで --user フラグの値に接頭辞を追加します。

  8. Identity Service for GKE を使用して GKE クラスタにアクセスします。

    kubectl get namespaces \
        --certificate-authority certificateAuthorityData.pem \
        --server $(cat server.txt) \
        --token $ID_TOKEN
    

    出力は次のようになります。

    NAME                      STATUS   AGE
    anthos-identity-service   Active   1h
    default                   Active   1h
    kube-node-lease           Active   1h
    kube-public               Active   1h
    kube-system               Active   1h
    
  9. SSH セッションを終了します。

    exit
    

kubectl ツールのコンテキストを作成する

kubectl コマンドでは、kubeconfig ファイルを使用してクラスタへのアクセス権を構成できます。kubeconfig ファイルには、1 つ以上のコンテキストが含まれています。各コンテキストには名前があり、必要に応じてクラスタの接続情報、クラスタの認証に使用される認証情報、デフォルトの名前空間が含まれます。

このセクションでは、コンテキストを持つ kubeconfig ファイルを作成します。コンテキストには、クラスタの Identity Service for GKE プロキシの接続の詳細が含まれます。kubeconfig ファイルには、ユーザー認証情報は追加しません。

  1. Cloud Shell で、認証局データとサーバー URL を含むファイルを VM インスタンスから現在のディレクトリにコピーします。

    gcloud compute scp VM:~/certificateAuthorityData.pem VM:~/server.txt . \
        --tunnel-through-iap --zone ZONE
    
  2. 後で、Cloud Build から GKE クラスタに接続する際に使用するコンテキストとクラスタ構成を作成します。

    kubectl config set-context private-cluster \
        --cluster private-cluster \
        --kubeconfig kubeconfig
    

    --kubeconfig フラグをによって、現在のディレクトリに kubeconfig という新しいファイル内にコンテキストとクラスタ構成が作成されます。

    このコマンドは、GKE クラスタ名をコンテキストのクラスタ構成名として使用します。独自の環境では、コンテキストで別のクラスタ構成名を使用できます。

  3. クラスタ構成に certificateAuthorityData フィールドを設定します。

    kubectl config set-cluster private-cluster \
        --certificate-authority certificateAuthorityData.pem \
        --embed-certs \
        --kubeconfig kubeconfig
    
  4. クラスタ構成に server フィールドを設定します。

    kubectl config set-cluster private-cluster \
        --kubeconfig kubeconfig \
        --server $(cat server.txt)
    

Cloud Build 用の Google サービス アカウントを作成する

  1. Cloud Shell で、Cloud Build プライベート プールでビルドを実行する Google サービス アカウントを作成します。

    gcloud iam service-accounts create CB_GSA \
      --description "Runs builds on Cloud Build private pools" \
      --display-name "Cloud Build private pool"
    

    CB_GSA は、Google サービス アカウントに使用する名前に置き換えます。このチュートリアルでは、cloud-build-private-pool を使用します。

  2. プロジェクトの Cloud Build サービス アカウント ロールを Google サービス アカウントに付与します。

    gcloud projects add-iam-policy-binding PROJECT_ID \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/cloudbuild.builds.builder
    

    このロールは、Google が管理する Cloud Build サービス アカウントのデフォルトの権限を提供します。

  3. Google サービス アカウントの サービス アカウントの OpenID Connect ID トークン作成者をサービス アカウント自体に付与します。

    gcloud iam service-accounts add-iam-policy-binding \
        CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    

    このロールは、Service Account Credentials API からサービス アカウントの ID トークンをリクエストするために必要な iam.serviceAccounts.getOpenIdToken 権限を提供します。

  4. SSH を使用して VM インスタンスに接続します。

    gcloud compute ssh VM --tunnel-through-iap --zone ZONE
    

    このセクションの残りのコマンドは、SSH セッションから実行します。

  5. SSH セッションで、サービス アカウントが Google の OpenID Connect プロバイダを使用してクラスタを認証するときに、Google サービス アカウントに cluster-admin クラスタロールを付与する Kubernetes クラスタのロール バインディングを作成します。

    kubectl create clusterrolebinding CB_GSA-cluster-admin \
        --clusterrole cluster-admin \
        --user CB_GSA@PROJECT_ID.iam.gserviceaccount.com
    

    cluster-admin クラスタロールは、クラスタ全体にわたる広範な権限を付与します。独自の環境では、Cloud Build が実行するタスクに必要な権限のみを提供するクラスタロールを使用できます。ロール バインディングを使用して、特定の名前空間にのみ権限を付与することもできます。

    独自の環境の ClientConfig で userPrefix を設定する場合は、このコマンドで --user フラグの値にその接頭辞を追加する必要があります。

  6. SSH セッションを終了します。

    exit
    

Cloud Build プライベート プールを作成します。

  1. Cloud Shell で、プライベート プールとの接続用に VPC ネットワーク内の IP アドレス範囲を割り当てます。

    gcloud compute addresses create RESERVED_RANGE_NAME \
    --addresses RESERVED_RANGE_START_IP\
        --description "Cloud Build private pool reserved range" \
        --global \
        --network NETWORK \
        --prefix-length RESERVED_RANGE_PREFIX_LENGTH \
        --purpose VPC_PEERING
    

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

    • RESERVED_RANGE_NAME: Cloud Build プライベート プールをホストする割り当てられた IP アドレス範囲の名前。このチュートリアルでは、cloud-build-private-pool を使用します。
    • RESERVED_RANGE_START_IP: 割り当てられた IP アドレス範囲の最初の IP アドレス。このチュートリアルでは、192.168.12.0 を使用します。
    • RESERVED_RANGE_PREFIX_LENGTH: 割り当てられた IP アドレス範囲の接頭辞長(サブネット マスク)。接頭辞長は /23 以下(たとえば、/22/21)である必要があります。より小さい数が、より大きいアドレス範囲を意味します。このチュートリアルでは、23 を使用し、先頭の /(スラッシュ)は入力しないでください。
  2. ファイアウォール ルールを作成して、予約済み IP アドレス範囲から VPC ネットワーク内の他のリソースへの受信トラフィックを許可します。

    gcloud compute firewall-rules create allow-private-pools-ingress \
        --allow all \
        --network NETWORK \
        --source-ranges RESERVED_RANGE_START_IP/RESERVED_RANGE_PREFIX_LENGTH
    
  3. プライベート サービス接続を作成して、VPC ネットワークをサービス ネットワーキング サービスに接続します。

    gcloud services vpc-peerings connect \
        --network NETWORK \
        --ranges RESERVED_RANGE_NAME \
        --service servicenetworking.googleapis.com
    

    Cloud Build のプライベート プールは、Service Networking を使用してワーカーを実行します。プライベート サービス接続によって、VPC ネットワーク ピアリング接続を使用して、VPC ネットワークが内部 IP アドレスの割り当てられた範囲のプライベート プールと通信できるようになります。

    プライベート サービス接続の作成には数分かかる可能性があります。

    独自の環境で共有 VPC を使用している場合、プライベート サービス接続を作成する追加の手順については、環境を設定するをご覧ください。

  4. VPC ネットワークに VPC ピアリングされる Google 所有の VPC ネットワークに Cloud Build プライベート プールを作成します。

    gcloud builds worker-pools create PRIVATE_POOL_NAME \
       --no-public-egress \
       --peered-network projects/PROJECT_ID/global/networks/NETWORK \
       --region REGION
    

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

    • PRIVATE_POOL_NAME: プライベート プールの名前。このチュートリアルでは、private-pool を使用します。
    • REGION: プライベート プールに使用するリージョン。このチュートリアルでは、us-central1 を使用します。

    --no-public-egress フラグは、プライベート プール内のワーカーにパブリック IP アドレスがないことを意味します。独自の環境では、プライベート プール内のワーカーがパブリック IP アドレスを使用してインターネットに接続できるようにする場合は、このフラグを削除します。

    プライベート プール内のワーカーのマシンタイプやディスクサイズなどの追加の構成オプションについては、プライベート プールの作成と管理をご覧ください。

問題の解決を確認する

このセクションでは、Cloud Build プライベート プールでビルドを実行してソリューションを確認します。ビルドが限定公開 GKE クラスタにアクセスします。

  1. Cloud Shell で、Cloud Build のビルドログを保存する Cloud Storage バケットを作成します。

    gsutil mb -l REGION gs://PROJECT_ID-build-logs
    
  2. Cloud Build のビルド構成ファイルを作成します。

    cat << "EOF" > cloudbuild.yaml
    steps:
    - id: list-services
      name: gcr.io/google.com/cloudsdktool/google-cloud-cli
      entrypoint: bash
      args:
      - -eEuo
      - pipefail
      - -c
      - |-
        kubectl config use-context $_KUBECTL_CONTEXT
    
        ACCESS_TOKEN=$$(curl --silent \
            --header "Metadata-Flavor: Google" \
            http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token \
            | python3 -c 'import json, sys; print(json.load(sys.stdin).get("access_token"))')
    
        ID_TOKEN=$$(curl --silent --request POST \
            --data '{"audience": "CLIENT_ID", "includeEmail": true}' \
            --header "Authorization: Bearer $$ACCESS_TOKEN" \
            --header "Content-Type: application/json; charset=utf-8" \
            "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$_SERVICE_ACCOUNT:generateIdToken" \
            | python3 -c 'import json, sys; print(json.load(sys.stdin).get("token"))')
    
        kubectl get services --namespace $_NAMESPACE --token $$ID_TOKEN
    
    logsBucket: gs://PROJECT_ID-build-logs
    
    options:
      env:
      - KUBECONFIG=/workspace/$_KUBECONFIG
    
    substitutions:
      _KUBECONFIG: kubeconfig
      _KUBECTL_CONTEXT: private-cluster
      _NAMESPACE: default
    
    serviceAccount: projects/$PROJECT_ID/serviceAccounts/$_SERVICE_ACCOUNT
    EOF
    

    ビルド構成ファイルの手順では、次のようにします。

    1. _KUBECTL_CONTEXT 置換で指定された kubectl コンテキストに切り替わります。デフォルトの置換値は private-cluster です。

    2. メタデータ サーバーのアクセス トークンを取得します。アクセス トークンは、ビルドを実行する Google サービス アカウントに発行されます。

    3. Service Account Credentials API を使用して ID トークンを生成します。ID トークンを生成するリクエストは、アクセス トークンを使用して認証されます。ID トークンのリクエストされた _CLIENT_ID(audience)クレームが、aud 置換で指定された OAuth 2.0 クライアント ID です。

    4. _NAMESPACE 置換で指定された名前空間内の Kubernetes サービスを一覧表示します。デフォルトの置換値は default です。リクエストは、前のコマンドで生成された ID トークンを使用して認証されます。

    ビルド構成ファイルについて次の点に注意してください。

    • $ 文字は置換の接頭辞です。$$ は、bash パラメータの拡張とコマンドの置換に使用されます。

    • 置換 _KUBECONFIG_KUBECTL_CONTEXT によって、ビルドの実行時に異なる kubeconfig ファイルと異なるコンテキストを指定できます。これらの置換によって、複数のコンテキストを含む単一の kubeconfig ファイルと複数の kubeconfig ファイルのいずれかを使用して、複数のクラスタ構成を管理できます。

    • 置換 _SERVICE_ACCOUNT にはデフォルト値がありません。ビルドを実行するときは、この置換の値を指定する必要があります。

    • options ブロックはビルドのすべての手順に KUBECONFIG 環境変数を設定します。

    • ビルド手順では、gcr.io/google.com/cloudsdktool/google-cloud-cli ビルダー イメージを使用します。これは大きなコンテナ イメージであり、レジストリからプライベート プールワーカーにそれを pull するにはいくらかの時間がかかります。ビルダー イメージを pull する時間を短縮するには、curlkubectl、Python などのビルド手順に必要なツールのみを含むカスタム ビルダー イメージを作成します。

    ビルド構成ファイルのインライン シェル スクリプトの詳細については、bash スクリプトの実行をご覧ください。

  3. ビルド構成ファイルと現在のディレクトリ内のファイルを使用してビルドを実行します。

    gcloud builds submit \
        --config cloudbuild.yaml \
        --region REGION \
        --substitutions _SERVICE_ACCOUNT=CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --worker-pool projects/PROJECT_ID/locations/REGION/workerPools/PRIVATE_POOL_NAME
    

    コマンドは、現在のディレクトリ内のすべてのファイルを、Cloud Build による使用のために Cloud Storage にアップロードします。ビルド手順では、kubeconfig ファイルを使用して GKE クラスタに接続します。

    出力の終わり付近に、次のような行が表示されます。

    NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   2h
    

    この出力は、プライベート プール ワーカーが Identity Service for GKE 認証プロキシを使用してクラスタ コントロール プレーンに接続していることを示しています。

トラブルシューティング

SSH を使用して VM インスタンスに接続できない場合は、--troubleshoot フラグを追加して接続の問題の原因の究明に役立てます。

gcloud compute ssh VM --tunnel-through-iap --zone ZONE --troubleshoot

GKE クラスタでデフォルトの ClientConfig にパッチを適用したときにメッセージ Error from server (NotFound): clientconfigs.authentication.gke.io "default" not found が表示された場合、限定公開 GKE クラスタの作成セクションの説明のとおりに、ファイアウォール ルールが作成されていることを確認してください。そのファイアウォール ルールが存在することを確認します。

gcloud compute firewall-rules describe allow-control-plane-clientconfig-webhook

Identity Service for GKE プロキシで認証できない場合は、gke-oidc-service deployment の Pod のログでエラーを探します。

gcloud compute ssh VM --tunnel-through-iap --zone ZONE --command \
    'kubectl logs deployment/gke-oidc-service \
         --namespace anthos-identity-service --all-containers'

このチュートリアルで他の問題が発生した場合は、次のドキュメントを確認することをおすすめします。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

プロジェクトの削除

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

リソースを削除する

このチュートリアルで使用したプロジェクトを残しておく場合は、個々のリソースを削除します。

  1. Cloud Shell で、Cloud Build プライベート プールを削除します。

    gcloud builds worker-pools delete PRIVATE_POOL_NAME --region REGION --quiet
    
  2. サービス ネットワーキングへのプライベート サービス接続を削除します。

    gcloud services vpc-peerings delete --network NETWORK \
      --service servicenetworking.googleapis.com --quiet --async
    
  3. Cloud Build プライベート プールに割り当てられた IP アドレス範囲を削除します。

    gcloud compute addresses delete RESERVED_RANGE_NAME --global --quiet
    
  4. Cloud Storage バケットとそのすべての内容を削除します。

    gsutil rm -r gs://PROJECT_ID-build-logs
    
  5. GKE クラスタを削除します。

    gcloud container clusters delete CLUSTER --zone ZONE --quiet --async
    
  6. Compute Engine VM インスタンスを削除します。

    gcloud compute instances delete VM --zone ZONE --quiet
    
  7. ファイアウォール ルールを削除します。

    gcloud compute firewall-rules delete allow-private-pools-ingress --quiet
    
    gcloud compute firewall-rules delete allow-ssh-ingress-from-iap --quiet
    
    gcloud compute firewall-rules delete allow-control-plane-clientconfig-webhook --quiet
    
  8. IAM ロール バインディングを削除します。

    gcloud projects remove-iam-policy-binding PROJECT_ID \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/cloudbuild.builds.builder
    
    gcloud projects remove-iam-policy-binding PROJECT_ID \
        --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/container.admin
    
    gcloud iam service-accounts remove-iam-policy-binding \
        CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    
    gcloud iam service-accounts remove-iam-policy-binding \
        ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --member serviceAccount:ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
        --role roles/iam.serviceAccountOpenIdTokenCreator
    
  9. Google サービス アカウントを削除します。

    gcloud iam service-accounts delete CB_GSA@PROJECT_ID.iam.gserviceaccount.com \
       --quiet
    
    gcloud iam service-accounts delete ISG_GSA@PROJECT_ID.iam.gserviceaccount.com \
       --quiet
    

OAuth 2.0 クライアント ID を削除する

  1. Google Cloud コンソールの [認証情報] ページに移動します。

    [認証情報] ページを開く

  2. プロジェクト セレクタのリストからプロジェクトを選択します。

  3. [OAuth 2.0 クライアント ID] の表で、Identity Service for GKE の行を見つけて、[OAuth クライアントを削除] アイコンをクリックします。

  4. ダイアログで [削除] をクリックします。

次のステップ