プロキシレス gRPC を使用してサービス セキュリティを設定する

このガイドでは、プロキシレス gRPC サービス メッシュ用にセキュリティ サービスを構成する方法について説明します。

要件

gRPC プロキシレス サービス メッシュのサービス セキュリティを構成する前に、次の要件を満たしていることを確認してください。

Identity and Access Management を構成する

Google Kubernetes Engine を使用するための権限が必要です。その場合、少なくとも次のロールが必要になります。

  • roles/container.clusterAdmin GKE ロール
  • roles/compute.instanceAdmin Compute Engine ロール
  • roles/iam.serviceAccountUser ロール

設定に必要なリソースを作成するには、compute.NetworkAdmin ロールが必要です。このロールには、必要なリソースの作成、更新、削除、一覧表示、使用(他のリソースでの参照)に必要なすべての権限が含まれています。プロジェクトのオーナー編集者には、このロールが自動的に付与されます。

バックエンド サービスのリソースでこれらのリソースを参照する場合、networksecurity.googleapis.com.clientTlsPolicies.usenetworksecurity.googleapis.com.serverTlsPolicies.use は適用されません。

今後これが適用され、compute.NetworkAdmin ロールを使用している場合、このチェックの適用時に問題は検出されません。

カスタムロールを使用していて、今後このチェックが適用される場合は、各 .use 権限を含める必要があります。そうしないと、今後、バックエンド サービスから clientTlsPolicy または serverTlsPolicy を参照するために必要な権限がカスタムロールに含まれなくなる場合があります。

設定を準備する

プロキシレス サービス メッシュ(PSM)セキュリティは、プロキシレス gRPC サービスのドキュメントに従って、ロード バランシング用に設定されたサービス メッシュにセキュリティを追加します。プロキシレス サービス メッシュでは、gRPC クライアントが URI のスキーム xds: を使用してサービスにアクセスし、PSM ロード バランシングとエンドポイント検出機能を有効にします。

gRPC クライアントとサーバーを正しいバージョンに更新する

ご使用の言語でサポートされている gRPC の最小バージョンを使用して、アプリケーションを構築または再構築します。

ブートストラップ ファイルを更新する

gRPC アプリケーションは単一のブートストラップ ファイルを使用します。このファイルには、gRPC のクライアント側コードとサーバー側コードに必要なすべてのフィールドが含まれている必要があります。ブートストラップ ジェネレータは、PSM セキュリティで必要とされるフラグと値を含むブートストラップ ファイルを自動的に生成します。詳細については、ブートストラップ ファイル セクションをご覧ください。ここでは、サンプル ブートストラップ ファイルを使用しています。

設定の概要

この設定プロセスは、GKE とプロキシレス gRPC サービスを使用した Traffic Director の設定の拡張機能です。この設定手順の既存の変更されていないステップは、適用するすべての場所で参照されます。

GKE での Traffic Director の設定の主な機能強化は次のとおりです。

  1. CA Service の設定。プライベート CA プールと必要な認証局を作成します。
  2. GKE Workload Identity とメッシュ証明書の機能、CA Service の統合による GKE クラスタの作成。
  3. クラスタでのメッシュ証明書の発行の構成。
  4. クライアントとサーバー サービス アカウントの作成。
  5. xDS API と xDS サーバー認証情報を使用して Traffic Director からセキュリティ構成を取得するサーバーの例
  6. xDS 認証情報を使用するサンプル クライアントの設定。
  7. セキュリティ構成を含める Traffic Director 構成の更新。

xDS 認証情報を使用するコード例は、次の場所で確認できます。

Google Cloud CLI を更新する

Google Cloud CLI を更新するには、次のコマンドを実行します。

gcloud components update

環境変数を設定する

このガイドでは Cloud Shell コマンドを使用します。コマンド内の繰り返し情報は、さまざまな環境変数で表されます。コマンドを実行する前に、シェル環境で特定の値を次の環境変数に設定します。各コメント行は、関連する環境変数の意味を示しています。

# Your project ID
PROJECT_ID=PROJECT_ID

# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
ZONE=ZONE
gcloud config set compute/zone $ZONE

# GKE cluster URL derived from the above
GKE_CLUSTER_URL="https://container.googleapis.com/v1/projects/${PROJECT_ID}/locations/${ZONE}/clusters/${CLUSTER_NAME}"

# Workload pool to be used with the GKE cluster
WORKLOAD_POOL="${PROJECT_ID}.svc.id.goog"

# Kubernetes namespace to run client and server demo.
K8S_NAMESPACE='default'
DEMO_BACKEND_SERVICE_NAME='grpc-gke-helloworld-service'

# Compute other values
# Project number for your project
PROJNUM=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")

# VERSION is the GKE cluster version. Install and use the most recent version
# from the rapid release channel and substitute its version for
# CLUSTER_VERSION, for example:
# VERSION=latest available version
# Note that the minimum required cluster version is 1.21.4-gke.1801.
VERSION="CLUSTER_VERSION"
SA_GKE=service-${PROJNUM}@container-engine-robot.iam.gserviceaccount.com

必要な API へのアクセスを有効にする

このセクションでは、必要な API へのアクセスを有効にする方法を説明します。

  1. 次のコマンドを実行して、Traffic Director と、プロキシレス gRPC サービス メッシュ セキュリティに必要なその他の API を有効にします。

    gcloud services enable \
        container.googleapis.com \
        cloudresourcemanager.googleapis.com \
        compute.googleapis.com \
        trafficdirector.googleapis.com \
        networkservices.googleapis.com \
        networksecurity.googleapis.com \
        privateca.googleapis.com \
        gkehub.googleapis.com
    
  2. 次のコマンドを実行して、デフォルトのサービス アカウントで Traffic Director のセキュリティ API にアクセスできるようにします。

    GSA_EMAIL=$(gcloud iam service-accounts list --format='value(email)' \
        --filter='displayName:Compute Engine default service account')
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member serviceAccount:${GSA_EMAIL} \
       --role roles/trafficdirector.client
    

GKE クラスタを作成または更新する

Traffic Director サービスのセキュリティは、GKE と CA Service の統合に依存します。GKE クラスタは、設定要件に加えて、次の要件を満たしている必要があります。

  • 1.21.4-gke.1801 の最小クラスタ バージョンを使用します。新しいバージョンの機能が必要な場合は、Rapid リリース チャンネルからそのバージョンを取得できます。
  • 証明書を発行する認証局の作成で説明されているように、GKE クラスタを有効にして、メッシュ証明書で構成する必要があります。
  1. Workload Identity を使用する新しいクラスタを作成します。既存のクラスタを更新する場合は、次のステップに進みます。--tags に指定する値は、Cloud Load Balancing コンポーネントを使用して Traffic Director を構成するのセクションで説明している firewall-rules create コマンドの --target-tags フラグに渡された名前と一致している必要があります。

    # Create a GKE cluster with GKE managed mesh certificates.
    gcloud container clusters create CLUSTER_NAME \
      --release-channel=rapid \
      --scopes=cloud-platform \
      --image-type=cos_containerd \
      --machine-type=e2-standard-2 \
      --zone=ZONE \
      --workload-pool=PROJECT_ID.svc.id.goog \
      --enable-mesh-certificates \
      --cluster-version=CLUSTER_VERSION \
      --enable-ip-alias \
      --tags=allow-health-checks \
      --workload-metadata=GKE_METADATA
    

    クラスタの作成が完了するまでに数分かかることがあります。

  2. 既存のクラスタを使用している場合は、Workload Identity と GKE メッシュ証明書を有効にします。クラスタが --enable-ip-alias フラグで作成されていることを確認してください。このフラグは、update コマンドでは使用できません。

    gcloud container clusters update CLUSTER_NAME \
      --enable-mesh-certificates
    
  3. 次のコマンドを実行して、kubectl コマンドのデフォルト クラスタとして新しいクラスタに切り替えます。

    gcloud container clusters get-credentials CLUSTER_NAME \
      --zone ZONE
    

フリートにクラスタを登録する

GKE クラスタの作成で作成または更新したクラスタをフリートに登録します。クラスタを登録すると、複数のプロジェクトにまたがるクラスタを簡単に構成できるようになります。

各ステップが完了するまでに最大で 10 分かかることがあります。

  1. クラスタをフリートに登録します。

    gcloud container fleet memberships register CLUSTER_NAME \
      --gke-cluster=ZONE/CLUSTER_NAME \
      --enable-workload-identity --install-connect-agent \
      --manifest-output-file=MANIFEST-FILE_NAME
    

    変数を、次のように置き換えます。

    • CLUSTER_NAME: クラスタの名前。
    • ZONE: クラスタのゾーン。
    • MANIFEST-FILE_NAME: これらのコマンドが登録用のマニフェストを生成するファイルパス。

    登録プロセスが成功すると、次のようなメッセージが表示されます。

    Finished registering the cluster CLUSTER_NAME with the fleet.
  2. 生成されたマニフェスト ファイルをクラスタに適用します。

    kubectl apply -f MANIFEST-FILE_NAME
    

    適用プロセスが成功すると、次のようなメッセージが表示されます。

    namespace/gke-connect created
    serviceaccount/connect-agent-sa created
    podsecuritypolicy.policy/gkeconnect-psp created
    role.rbac.authorization.k8s.io/gkeconnect-psp:role created
    rolebinding.rbac.authorization.k8s.io/gkeconnect-psp:rolebinding created
    role.rbac.authorization.k8s.io/agent-updater created
    rolebinding.rbac.authorization.k8s.io/agent-updater created
    role.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created
    clusterrole.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created
    clusterrolebinding.rbac.authorization.k8s.io/gke-connect-impersonation-20210416-01-00 created
    clusterrolebinding.rbac.authorization.k8s.io/gke-connect-feature-authorizer-20210416-01-00 created
    rolebinding.rbac.authorization.k8s.io/gke-connect-agent-20210416-01-00 created
    role.rbac.authorization.k8s.io/gke-connect-namespace-getter created
    rolebinding.rbac.authorization.k8s.io/gke-connect-namespace-getter created
    secret/http-proxy created
    deployment.apps/gke-connect-agent-20210416-01-00 created
    service/gke-connect-monitoring created
    secret/creds-gcp create
    
  3. クラスタからメンバー リソースを取得します。

    kubectl get memberships membership -o yaml
    

    出力には、フリートによって割り当てられた Workoad Identity プールが含まれています。ここで、PROJECT_ID はプロジェクト ID です。

    workload_identity_pool: PROJECT_ID.svc.id.goog
    

    これは、クラスタが正常に登録されたことを意味します。

証明書を発行する認証局を作成する

Pod に対して証明書を発行するには、CA Service プールと次の認証局(CA)を作成します。

  • ルート CA。これは、発行されるすべてのメッシュ証明書のルート オブ トラストです。既存のルート CA が存在する場合はそれを使用できます。ルート CA を enterprise 階層に作成します。ルート CA は有効期間が長く、少量の証明書の発行に適しています。
  • 下位 CA。この CA はワークロード用の証明書を発行します。クラスタがデプロイされるリージョンで下位 CA を作成します。下位 CA を devops 階層に作成します。下位 CA は有効期間が短く、大量の証明書の発行に適しています。

下位 CA の作成は任意ですが、GKE メッシュの証明書を発行するためにルート CA を使用するよりも、下位 CA を作成することを強くおすすめします。ルート CA を使用してメッシュ証明書を発行する場合は、デフォルトの構成ベースの発行モードが引き続き許可されることを確認してください。

下位 CA はクラスタと異なるリージョンに設定できますが、パフォーマンスを最適化するために、クラスタと同じリージョンに作成することをおすすめします。ただし、ルート CA または下位 CA は別々のリージョンに作成でき、それによるパフォーマンスや可用性への影響はありません。

CA Service では、以下のリージョンがサポートされます。

リージョン名 リージョンの説明
asia-east1 台湾
asia-east2 香港
asia-northeast1 東京
asia-northeast2 大阪
asia-northeast3 ソウル
asia-south1 ムンバイ
asia-south2 デリー
asia-southeast1 シンガポール
asia-southeast2 ジャカルタ
australia-southeast1 シドニー
australia-southeast2 メルボルン
europe-central2 ワルシャワ
europe-north1 フィンランド
europe-southwest1 マドリッド
europe-west1 ベルギー
europe-west2 ロンドン
europe-west3 フランクフルト
europe-west4 オランダ
europe-west6 チューリッヒ
europe-west8 ミラノ
europe-west9 パリ
europe-west10 ベルリン
europe-west12 トリノ
me-central1 ドーハ
me-central2 ダンマーム
me-west1 テルアビブ
northamerica-northeast1 モントリオール
northamerica-northeast2 トロント
southamerica-east1 サンパウロ
southamerica-west1 サンティアゴ
us-central1 アイオワ
us-east1 サウスカロライナ
us-east4 北バージニア
us-east5 コロンバス
us-south1 ダラス
us-west1 オレゴン
us-west2 ロサンゼルス
us-west3 ソルトレイクシティ
us-west4 ラスベガス

サポートされているロケーションのリストを確認するには、次のコマンドを実行します。

gcloud privateca locations list
  1. CA プールと CA を作成する個人に IAM roles/privateca.caManager を付与します。MEMBER の正しい形式は user:userid@example.com です。その個人が現在のユーザーであれば、シェルコマンド $(gcloud auth list --filter=status:ACTIVE --format="value(account)") を使用してユーザー ID を取得できます。

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.caManager
    
  2. IAM ポリシーを変更する必要があるユーザーに CA Service のロール role/privateca.admin を付与します。MEMBER は、このアクセスを必要とするユーザーです(特に、privateca.auditor ロールと privateca.certificateManager ロールを付与する次の手順を行うユーザーです)。

    gcloud projects add-iam-policy-binding PROJECT_ID \
      --member=MEMBER \
      --role=roles/privateca.admin
    
  3. ルート CA Service プールを作成します。

    gcloud privateca pools create ROOT_CA_POOL_NAME \
      --location ROOT_CA_POOL_LOCATION \
      --tier enterprise
    
  4. ルート CA を作成します。

    gcloud privateca roots create ROOT_CA_NAME --pool ROOT_CA_POOL_NAME \
      --subject "CN=ROOT_CA_NAME, O=ROOT_CA_ORGANIZATION" \
      --key-algorithm="ec-p256-sha256" \
      --max-chain-length=1 \
      --location ROOT_CA_POOL_LOCATION
    

    このデモ設定では、変数に次の値を使用します。

    • ROOT_CA_POOL_NAME=td_sec_pool
    • ROOT_CA_NAME=pkcs2-ca
    • ROOT_CA_POOL_LOCATION=us-east1
    • ROOT_CA_ORGANIZATION="TestCorpLLC"
  5. 下位プールと下位 CA を作成します。デフォルトの構成ベースの発行モードが許可されることを確認します。

    gcloud privateca pools create SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --tier devops
    
    gcloud privateca subordinates create SUBORDINATE_CA_NAME \
      --pool SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --issuer-pool ROOT_CA_POOL_NAME \
      --issuer-location ROOT_CA_POOL_LOCATION \
      --subject "CN=SUBORDINATE_CA_NAME, O=SUBORDINATE_CA_ORGANIZATION" \
      --key-algorithm "ec-p256-sha256" \
      --use-preset-profile subordinate_mtls_pathlen_0
    

    このデモ設定では、変数に次の値を使用します。

    • SUBORDINATE_CA_POOL_NAME="td-ca-pool"
    • SUBORDINATE_CA_POOL_LOCATION=us-east1
    • SUBORDINATE_CA_NAME="td-ca"
    • SUBORDINATE_CA_ORGANIZATION="TestCorpLLC"
    • ROOT_CA_POOL_NAME=td_sec_pool
    • ROOT_CA_POOL_LOCATION=us-east1
  6. GKE サービス アカウントからのアクセスを許可するために、ルート CA プールの IAM privateca.auditor ロールを付与します。

    gcloud privateca pools add-iam-policy-binding ROOT_CA_POOL_NAME \
     --location ROOT_CA_POOL_LOCATION \
     --role roles/privateca.auditor \
     --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
    
  7. GKE サービス アカウントからのアクセスを許可するために、下位 CA プールの IAM privateca.certificateManager ロールを付与します。

    gcloud privateca pools add-iam-policy-binding SUBORDINATE_CA_POOL_NAME \
      --location SUBORDINATE_CA_POOL_LOCATION \
      --role roles/privateca.certificateManager \
      --member="serviceAccount:service-PROJNUM@container-engine-robot.iam.gserviceaccount.com"
    
  8. 次の WorkloadCertificateConfig YAML 構成を保存して、メッシュ証明書を発行する方法をクラスタに指示します。

    apiVersion: security.cloud.google.com/v1
    kind: WorkloadCertificateConfig
    metadata:
      name: default
    spec:
      # Required. The CA service that issues your certificates.
      certificateAuthorityConfig:
        certificateAuthorityServiceConfig:
          endpointURI: ISSUING_CA_POOL_URI
    
      # Required. The key algorithm to use. Choice of RSA or ECDSA.
      #
      # To maximize compatibility with various TLS stacks, your workloads
      # should use keys of the same family as your root and subordinate CAs.
      #
      # To use RSA, specify configuration such as:
      #   keyAlgorithm:
      #     rsa:
      #       modulusSize: 4096
      #
      # Currently, the only supported ECDSA curves are "P256" and "P384", and the only
      # supported RSA modulus sizes are 2048, 3072 and 4096.
      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
      # Optional. Validity duration of issued certificates, in seconds.
      #
      # Defaults to 86400 (1 day) if not specified.
      validityDurationSeconds: 86400
    
      # Optional. Try to start rotating the certificate once this
      # percentage of validityDurationSeconds is remaining.
      #
      # Defaults to 50 if not specified.
      rotationWindowPercentage: 50
    
    

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

    • クラスタが実行されるプロジェクトのプロジェクト ID:
      PROJECT_ID
    • メッシュ証明書を発行する CA の完全修飾 URI(ISSUING_CA_POOL_URI)。下位 CA(推奨)またはルート CA のいずれかを指定できます。形式は次のとおりです。
      //privateca.googleapis.com/projects/PROJECT_ID/locations/SUBORDINATE_CA_POOL_LOCATION/caPools/SUBORDINATE_CA_POOL_NAME
  9. 次の TrustConfig YAML 構成を保存して、発行済み証明書を信頼する方法をクラスタに指示します。

    apiVersion: security.cloud.google.com/v1
    kind: TrustConfig
    metadata:
      name: default
    spec:
      # You must include a trustStores entry for the trust domain that
      # your cluster is enrolled in.
      trustStores:
      - trustDomain: PROJECT_ID.svc.id.goog
        # Trust identities in this trustDomain if they appear in a certificate
        # that chains up to this root CA.
        trustAnchors:
        - certificateAuthorityServiceURI: ROOT_CA_POOL_URI
    

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

    • クラスタが実行されるプロジェクトのプロジェクト ID:
      PROJECT_ID
    • ルート CA プールの完全修飾 URI(ROOT_CA_POOL_URI)。形式は次のとおりです。
      //privateca.googleapis.com/projects/PROJECT_ID/locations/ROOT_CA_POOL_LOCATION/caPools/ROOT_CA_POOL_NAME
  10. この構成をクラスタに適用します。

    kubectl apply -f WorkloadCertificateConfig.yaml
    kubectl apply -f TrustConfig.yaml
    

NEG を使用してプロキシレス gRPC サービスを作成する

PSM セキュリティには、Traffic Director からセキュリティ構成を取得するための xDS を使用できるプロキシレス gRPC サーバーが必要です。この手順は、PSM ロード バランシング設定ガイドの NEG を使用して GKE サービスを構成すると似ていますが、java-example-hostname イメージではなく grpc-java リポジトリ内の xDS サンプルで xDS 対応の helloworld サーバーを使用します。

このサーバーは、openjdk:8-jdk イメージから構築されたコンテナで構築して実行します。また、名前付きの NEG 機能を使用して、NEG の名前を指定できます。これにより、デプロイでは検索しなくても NEG の名前が把握されているため、後の手順が簡略化されます。

gRPC サーバーの Kubernetes 仕様の完全な例を次に示します。次の点に注意してください。

  • この仕様では、gRPC サーバー Pod で使用される Kubernetes サービス アカウント example-grpc-server を作成します。
  • この仕様では、サービスの cloud.google.com/neg アノテーションで name フィールドを使用して NEG 名 example-grpc-server を指定します。
  • 変数 ${PROJNUM} は、プロジェクトのプロジェクト番号を表します。
  • この仕様では、initContainers セクションを使用してブートストラップ ジェネレータを実行し、プロキシレス gRPC ライブラリが必要とするブートストラップ ファイルに入力します。このブートストラップ ファイルは、example-grpc-server という gRPC サーバー コンテナの /tmp/grpc-xds/td-grpc-bootstrap.json にあります。

次のアノテーションを Pod の仕様に追加します。

 annotations:
   security.cloud.google.com/use-workload-certificates: ""

従う完全な仕様で正しい配置を核にできます。

作成時には、各 Pod が /var/run/secrets/workload-spiffe-credentials で Volume を取得します。この Volume には次のものが含まれます。

  • private_key.pem は、自動生成された秘密鍵です。
  • certificates.pem は、クライアント証明書チェーンとしての別の Pod への提示や、サーバー証明書チェーンとしての使用ができる、PEM 形式の証明書のバンドルです。
  • ca_certificates.pem は、別の Pod によって提示されたクライアント証明書チェーン、または別の Pod に接続したときに受信したサーバー証明書チェーンを検証するときに信頼アンカーとして使用する、PEM 形式の証明書のバンドルです。

ca_certificates.pem には、ワークロードのローカルの信頼ドメインの証明書が含まれていることに注意してください。これはクラスタのワークロード プールです。

certificates.pem のリーフ証明書には、次の書式なしテキストの SPIFFE ID アサーションが含まれています。

spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT

このアサーションでは次のようになります。

  • WORKLOAD_POOL は、クラスタ ワークロード プールの名前です。
  • NAMESPACE は、Kubernetes サービス アカウントの Namespace です。
  • KUBERNETES_SERVICE_ACCOUNT は、Kubernetes サービス アカウントの名前です。

ご使用の言語の手順に沿って、この例で使用する仕様を作成します。

Java

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 仕様を作成します。

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: openjdk:8-jdk
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 800m
               memory: 512Mi
             requests:
               cpu: 100m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

C++

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 仕様を作成します。

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: phusion/baseimage:18.04-1.0.0
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

Python

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 仕様を作成します。

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: phusion/baseimage:18.04-1.0.0
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

Go

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 仕様を作成します。

    cat << EOF > example-grpc-server.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: example-grpc-server
     namespace: default
     annotations:
       iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
     annotations:
       cloud.google.com/neg: '{"exposed_ports":{"8080":{"name": "example-grpc-server"}}}'
    spec:
     ports:
     - name: helloworld
       port: 8080
       protocol: TCP
       targetPort: 50051
     selector:
       k8s-app: example-grpc-server
     type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: example-grpc-server
     namespace: default
     labels:
       k8s-app: example-grpc-server
    spec:
     replicas: 1
     selector:
       matchLabels:
         k8s-app: example-grpc-server
     strategy: {}
     template:
       metadata:
         annotations:
            security.cloud.google.com/use-workload-certificates: ""
         labels:
           k8s-app: example-grpc-server
       spec:
         containers:
         - image: golang:1.16-alpine
           imagePullPolicy: IfNotPresent
           name: example-grpc-server
           command:
           - /bin/sleep
           - inf
           env:
           - name: GRPC_XDS_BOOTSTRAP
             value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
           ports:
           - protocol: TCP
             containerPort: 50051
           resources:
             limits:
               cpu: 8
               memory: 8Gi
             requests:
               cpu: 300m
               memory: 512Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/grpc-xds/
         initContainers:
         - name: grpc-td-init
           image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
           imagePullPolicy: Always
           args:
           - --config-mesh-experimental
           - "grpc-mesh"
           - --output
           - "/tmp/bootstrap/td-grpc-bootstrap.json"
           - --node-metadata=app=helloworld
           resources:
             limits:
               cpu: 100m
               memory: 100Mi
             requests:
               cpu: 10m
               memory: 100Mi
           volumeMounts:
           - name: grpc-td-conf
             mountPath: /tmp/bootstrap/
         serviceAccountName: example-grpc-server
         volumes:
         - name: grpc-td-conf
           emptyDir:
             medium: Memory
    EOF
    

    次のようにプロセスを完了します。

  1. 仕様を適用します。

    kubectl apply -f example-grpc-server.yaml
    
  2. サービス アカウントに必要なロールを付与します。

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \
      ${PROJNUM}-compute@developer.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-server]" \
      --role roles/trafficdirector.client
    
  3. 次のコマンドを実行して、Service と Pod が正しく作成されたことを確認します。

    kubectl get deploy/example-grpc-server
    kubectl get svc/example-grpc-server
    
  4. NEG 名が正しいことを確認します。

    gcloud compute network-endpoint-groups list \
        --filter "name=example-grpc-server" --format "value(name)"
    

    上記のコマンドから NEG 名 example-grpc-server が返されます。

Google Cloud ロード バランシング コンポーネントを使用して Traffic Director を構成する

このセクションの手順は、ロード バランシング コンポーネントによる Traffic Director の構成と似ていますが、後述するように変更点があります。

ヘルスチェック、ファイアウォール ルール、バックエンド サービスを作成する

gRPC サーバーが mTLS を使用するように構成されている場合、ヘルスチェック クライアントはサーバーに有効なクライアント証明書を提示できないため、gRPC ヘルスチェックは機能しません。これには、次のいずれかの方法で対処できます。

最初の方法では、サーバーによってヘルスチェック ポートとして指定された提供ポートが追加で作成されます。これは、そのポートへの書式なしテキストまたは TLS として、特別なヘルスチェック サービスに関連付けられます。

xDS の helloworld サンプル サーバーでは、平文のヘルスチェック ポートとして PORT_NUMBER + 1 を使用します。この例では、50051 が gRPC アプリケーション サーバーポートであるため、ヘルスチェック ポートとして 50052 を使用します。

2 つ目の方法では、ヘルスチェックを構成して、アプリケーション処理ポートへの TCP 接続だけを確認します。これにより、接続のみがチェックされ、TLS handshake の失敗が発生した場合は、サーバーへの不要なトラフィックが生成されます。このため、最初の方法を使用することをおすすめします。

  1. ヘルスチェックを作成します。ヘルスチェックは、サーバーを作成して起動するまで開始されません。

    • ヘルスチェックに使用する専用のサービスポートを作成する場合は、次のコマンドを使用します(これが推奨の方法です)。

      gcloud compute health-checks create grpc grpc-gke-helloworld-hc \
       --enable-logging --port 50052
      
    • TCP ヘルスチェックを作成する場合は、次のコマンドを使用します(この方法は推奨されません)。

      gcloud compute health-checks create tcp grpc-gke-helloworld-hc \
      --use-serving-port
      
  2. ファイアウォールを作成します。--target-tags の値が GKE クラスタを作成または更新するセクションで --tags に指定した値と一致することを確認します。

    gcloud compute firewall-rules create grpc-gke-allow-health-checks \
      --network default --action allow --direction INGRESS \
      --source-ranges 35.191.0.0/16,130.211.0.0/22 \
      --target-tags allow-health-checks \
      --rules tcp:50051-50052
    
  3. バックエンド サービスを作成します。

    gcloud compute backend-services create grpc-gke-helloworld-service \
       --global \
       --load-balancing-scheme=INTERNAL_SELF_MANAGED \
       --protocol=GRPC \
       --health-checks grpc-gke-helloworld-hc
    
  4. NEG をバックエンド サービスに接続します。

    gcloud compute backend-services add-backend grpc-gke-helloworld-service \
       --global \
       --network-endpoint-group example-grpc-server \
       --network-endpoint-group-zone ${ZONE} \
       --balancing-mode RATE \
       --max-rate-per-endpoint 5
    

Mesh リソースと GRPCRoute リソースを作成する

これは、プロキシレス gRPC サービスの設定Mesh リソースと GRPCRoute リソースを設定する方法に似ています。

  1. Mesh 仕様を作成し、mesh.yaml というファイルに保存します。

    name: grpc-mesh
    
  2. 仕様から Mesh リソースをインポートします。

    gcloud network-services meshes import grpc-mesh \
      --source=mesh.yaml \
      --location=global
    
  3. GRPCRoute 仕様を作成し、grpc_route.yaml というファイルに保存します。

    name: helloworld-grpc-route
    hostnames:
    - helloworld-gke:8000
    meshes:
    - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh
    rules:
    - action:
        destinations:
        - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-service
    
  4. grpc_route.yaml 仕様から GRPCRoute リソースをインポートします。

    gcloud network-services grpc-routes import helloworld-grpc-route \
      --source=grpc_route.yaml \
      --location=global
    

プロキシレス gRPC セキュリティで Traffic Director を構成する

この例では、クライアント側とサーバー側に mTLS を構成する方法を示しています。

ポリシー参照の形式

サーバー TLS ポリシーとクライアント TLS ポリシーを参照する場合は、次の形式にする必要があります。

projects/PROJECT_ID/locations/global/[serverTlsPolicies|clientTlsPolicies]/[server-tls-policy|client-mtls-policy]

例:

projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy

サーバー側で mTLS を構成する

まず、サーバー TLS ポリシーを作成します。このポリシーにより、gRPC サーバー側で、serverCertificate の一部である ID 証明書用の google_cloud_private_spiffe という名前で識別される certificateProvicerInstance プラグイン構成を使用することが求められます。mtlsPolicy セクションは mTLS セキュリティを示し、clientValidationCa のプラグイン構成と同じ google_cloud_private_spiffe を使用します。これはルート(検証)証明書の仕様です。

次に、エンドポイント ポリシーを作成します。このポリシーでは、バックエンド(メタデータ ラベルの有無にかかわらずポート 50051 を使用する gRPC サーバーなど)が、server-mtls-policy という名前の接続されたサーバー TLS ポリシーを受信することが指定されます。メタデータ ラベルを指定するには、MATCH_ALL またはサポートされている値を使用します。サポートされているメタデータ ラベルは、NetworkServicesEndpointPolicy ドキュメントのフィールド endpointMatcher.metadataLabelMatcher.metadataLabelMatchCriteria にあります。エンドポイント ポリシー リソースの値を含む一時ファイル ep-mtls-psms.yaml で、定義済みのポリシーを使用してエンドポイント ポリシーを作成します。

  1. サーバー TLS ポリシー リソースの値を使用して、現在のディレクトリに一時ファイル server-mtls-policy.yaml を作成します。

    name: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    mtlsPolicy:
      clientValidationCa:
      - certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
    
  2. 一時ファイル server-mtls-policy.yaml をインポートして、server-mtls-policy という名前のサーバー TLS ポリシー リソースを作成します。

    gcloud network-security server-tls-policies import server-mtls-policy \
      --source=server-mtls-policy.yaml --location=global
    
  3. 一時ファイル ep-mtls-psms.yaml を作成して、エンドポイント ポリシーを作成します。

    name: "ep-mtls-psms"
    type: "GRPC_SERVER"
    serverTlsPolicy: "projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy"
    trafficPortSelector:
      ports:
      - "50051"
    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: "MATCH_ALL"
        metadataLabels:
        - labelName: app
          labelValue: helloworld
    
  4. ep-mtls-psms.yaml ファイルをインポートして、エンドポイント ポリシー リソースを作成します。

    gcloud beta network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

クライアント側で mTLS を構成する

クライアント側のセキュリティ ポリシーがバックエンド サービスに接続されます。クライアントがバックエンド サービスを介してバックエンド(gRPC サーバー)にアクセスすると、接続されたクライアント側のセキュリティ ポリシーがクライアントに送信されます。

  1. 現在のディレクトリにある client-mtls-policy.yaml という一時ファイルにクライアント TLS ポリシー リソースを作成します。

    name: "client-mtls-policy"
    clientCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. 一時ファイル client-mtls-policy.yaml をインポートして、client-mtls-policy という名前のクライアント TLS ポリシー リソースを作成します。

    gcloud network-security client-tls-policies import client-mtls-policy \
      --source=client-mtls-policy.yaml --location=global
    
  3. 次の例に示すように、一時ファイル内にスニペットを作成してこのポリシーを参照し、SecuritySettings メッセージに subjectAltNames の詳細を追加します。${PROJECT_ID} は、プロジェクト ID の値に置き換えます。これは、前述の ${PROJECT_ID} 環境変数の値です。subjectAltNamesexample-grpc-server は、デプロイ仕様の gRPC サーバー Pod で使用される Kubernetes サービス アカウント名です。

    if [ -z "$PROJECT_ID" ] ; then echo Please make sure PROJECT_ID is set. ; fi
    cat << EOF > client-security-settings.yaml
    securitySettings:
      clientTlsPolicy: projects/${PROJECT_ID}/locations/global/clientTlsPolicies/client-mtls-policy
      subjectAltNames:
        - "spiffe://${PROJECT_ID}.svc.id.goog/ns/default/sa/example-grpc-server"
    EOF
    
  4. 作成済みのバックエンド サービスに securitySettings メッセージを追加します。現在のバックエンド サービス コンテンツをエクスポートし、クライアント securitySetting メッセージを追加します。新しいコンテンツを再度インポートし、バックエンド サービスを更新します。

    gcloud compute backend-services export grpc-gke-helloworld-service --global \
      --destination=/tmp/grpc-gke-helloworld-service.yaml
    
    cat /tmp/grpc-gke-helloworld-service.yaml client-security-settings.yaml \
      >/tmp/grpc-gke-helloworld-service1.yaml
    
    gcloud compute backend-services import grpc-gke-helloworld-service --global \
      --source=/tmp/grpc-gke-helloworld-service1.yaml -q
    

構成を確認する

これで、サーバー側とクライアント側のセキュリティを含む Traffic Director の構成が完了しました。次に、サーバーとクライアントのワークロードを準備し、実行します。これでサンプルが完成します。

プロキシレス gRPC クライアントを作成する

この手順は、前述のプロキシレス gRPC サービスの作成の手順と似ています。grpc-java リポジトリの xDS サンプル ディレクトリにある xDS 対応の helloworld クライアントを使用します。このクライアントは、openjdk:8-jdk イメージから構築されたコンテナ内で構築して実行します。gRPC クライアントの Kubernetes 仕様は以下のように機能します。

  • gRPC クライアント Pod で使用される Kubernetes サービス アカウント example-grpc-client を作成します。
  • ${PROJNUM} はプロジェクトのプロジェクト番号を表し、実際の番号に置き換える必要があります。

次のアノテーションを Pod の仕様に追加します。

  annotations:
    security.cloud.google.com/use-workload-certificates: ""

作成時には、各 Pod が /var/run/secrets/workload-spiffe-credentials で Volume を取得します。この Volume には次のものが含まれます。

  • private_key.pem は、自動生成された秘密鍵です。
  • certificates.pem は、クライアント証明書チェーンとしての別の Pod への提示や、サーバー証明書チェーンとしての使用ができる、PEM 形式の証明書のバンドルです。
  • ca_certificates.pem は、別の Pod によって提示されたクライアント証明書チェーン、または別の Pod に接続したときに受信したサーバー証明書チェーンを検証するときに信頼アンカーとして使用する、PEM 形式の証明書のバンドルです。

ca_certificates.pem には、ワークロードのローカル トラスト ドメイン(クラスタのワークロード プール)のルート証明書が含まれています。

certificates.pem のリーフ証明書には、次の書式なしテキストの SPIFFE ID アサーションが含まれています。

spiffe://WORKLOAD_POOL/ns/NAMESPACE/sa/KUBERNETES_SERVICE_ACCOUNT

このアサーションでは次のようになります。

  • WORKLOAD_POOL は、クラスタ ワークロード プールの名前です。
  • NAMESPACE は、Kubernetes サービス アカウントの名前です。
  • KUBERNETES_SERVICE_ACCOUNT は、Kubernetes サービス アカウントの Namespace です。

ご使用の言語の手順に沿って、この例で使用する仕様を作成します。

Java

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 次の仕様を作成します。

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: openjdk:8-jdk
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 800m
                memory: 512Mi
              requests:
                cpu: 100m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - --config-mesh-experimental
            - "grpc-mesh"
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

C++

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 次の仕様を作成します。

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: phusion/baseimage:18.04-1.0.0
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

Python

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 次の仕様を作成します。

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: phusion/baseimage:18.04-1.0.0
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

Go

  1. 次のコマンドを実行して、プロジェクト番号が正しく設定されていることを確認します。

    if [ -z "$PROJNUM" ] ; then export PROJNUM=$(gcloud projects describe $(gcloud info --format='value(config.project)') --format="value(projectNumber)") ; fi ; echo $PROJNUM
    
  2. 次の仕様を作成します。

    cat << EOF > example-grpc-client.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: example-grpc-client
      namespace: default
      annotations:
        iam.gke.io/gcp-service-account: ${PROJNUM}-compute@developer.gserviceaccount.com
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: example-grpc-client
      namespace: default
      labels:
        k8s-app: example-grpc-client
    spec:
      replicas: 1
      selector:
        matchLabels:
          k8s-app: example-grpc-client
      strategy: {}
      template:
        metadata:
          annotations:
            security.cloud.google.com/use-workload-certificates: ""
          labels:
            k8s-app: example-grpc-client
        spec:
          containers:
          - image: golang:1.16-alpine
            imagePullPolicy: IfNotPresent
            name: example-grpc-client
            command:
            - /bin/sleep
            - inf
            env:
            - name: GRPC_XDS_BOOTSTRAP
              value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 8
                memory: 8Gi
              requests:
                cpu: 300m
                memory: 512Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/grpc-xds/
          initContainers:
          - name: grpc-td-init
            image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0
            imagePullPolicy: Always
            args:
            - --config-mesh-experimental
            - "grpc-mesh"
            - --output
            - "/tmp/bootstrap/td-grpc-bootstrap.json"
            resources:
              limits:
                cpu: 100m
                memory: 100Mi
              requests:
                cpu: 10m
                memory: 100Mi
            volumeMounts:
            - name: grpc-td-conf
              mountPath: /tmp/bootstrap/
          serviceAccountName: example-grpc-client
          volumes:
          - name: grpc-td-conf
            emptyDir:
              medium: Memory
    EOF
    

次のようにプロセスを完了します。

  1. 仕様を適用します。

    kubectl apply -f example-grpc-client.yaml
    
  2. サービス アカウントに必要なロールを付与します。

    gcloud iam service-accounts add-iam-policy-binding \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \
      ${PROJNUM}-compute@developer.gserviceaccount.com
    
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
      --member "serviceAccount:${PROJECT_ID}.svc.id.goog[default/example-grpc-client]" \
      --role roles/trafficdirector.client
    
  3. クライアント Pod が動作していることを確認します。

    kubectl get pods
    

    このコマンドでは、次のようなテキストが返されます。

    NAMESPACE   NAME                                    READY   STATUS    RESTARTS   AGE
    default     example-grpc-client-7c969bb997-9fzjv    1/1     Running   0          104s
    [..skip..]
    

サーバーを実行する

前の手順で作成したサーバー Pod で、xDS 対応の helloworld サーバーを構築して実行します。

Java

  1. example-grpc-server サービス用に作成された Pod の名前を取得します。

    kubectl get pods | grep example-grpc-server
    

    次のようなフィードバックが表示されます。

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. サーバー Pod へのシェルを開きます。

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. シェルで、/tmp/grpc-xds/td-grpc-bootstrap.json のブートストラップ ファイルがブートストラップ ファイルセクションで説明されているスキーマと一致していることを確認します。

  4. gRPC Java バージョン 1.42.1 をダウンロードして、xds-hello-world サーバー アプリケーションを構築します。

    curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz
    
    cd grpc-java-1.42.1/examples/example-xds
    
    ../gradlew --no-daemon installDist
    
  5. --xds-creds フラグを指定してサーバーを実行し、50051 をリスニング ポート、xds-server をサーバー ID 名として使用して、xDS 対応のセキュリティを指定します。

    ./build/install/example-xds/bin/xds-hello-world-server --xds-creds 50051 xds-server
    
  6. サーバーが Traffic Director から必要な構成を取得すると、次の出力が表示されます。

    Listening on port 50051
    Plaintext health service listening on port 50052
    

C++

  1. example-grpc-server サービス用に作成された Pod の名前を取得します。

    kubectl get pods | grep example-grpc-server
    

    次のようなフィードバックが表示されます。

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. サーバー Pod へのシェルを開きます。

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. シェルで、/tmp/grpc-xds/td-grpc-bootstrap.json のブートストラップ ファイルがブートストラップ ファイルセクションで説明されているスキーマと一致していることを確認します。

  4. gRPC C++ をダウンロードして xds-hello-world サーバー アプリケーションを構築します。

    apt-get update -y && \
            apt-get install -y \
                build-essential \
                clang \
                python3 \
                python3-dev
    
    curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
    
    cd grpc-master
    
    tools/bazel build examples/cpp/helloworld:xds_greeter_server
    
  5. 50051 をリッスンポートとして、xds_greeter_server をサーバー ID 名として使用して、サーバーを実行します。

    bazel-bin/examples/cpp/helloworld/xds_greeter_server --port=50051 --maintenance_port=50052 --secure
    

    認証情報なしでサーバーを実行するには、次のように指定します。

    bazel-bin/examples/cpp/helloworld/xds_greeter_server --nosecure
    
  6. サーバーが Traffic Director から必要な構成を取得すると、次の出力が表示されます。

    Listening on port 50051
    Plaintext health service listening on port 50052
    

Python

  1. example-grpc-server サービス用に作成された Pod の名前を取得します。

    kubectl get pods | grep example-grpc-server
    

    次のようなフィードバックが表示されます。

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. サーバー Pod へのシェルを開きます。

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/bash
    
  3. シェルで、/tmp/grpc-xds/td-grpc-bootstrap.json のブートストラップ ファイルがブートストラップ ファイルセクションで説明されているスキーマと一致していることを確認します。

  4. gRPC Python バージョン 1.41.0 をダウンロードして、サンプル アプリケーションを構築します。

    apt-get update -y
    
    apt-get install -y python3 python3-pip
    
    curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
    
    cd grpc-1.41.x/examples/python/xds/
    
    python3 -m virtualenv venv
    
    source venv/bin/activate
    
    python3 -m pip install -r requirements.txt
    

  5. --xds-creds フラグを指定してサーバーを実行し、50051 をリスニング ポートとして使用して、xDS 対応のセキュリティを指定します。

    python3 server.py 50051 --xds-creds
    
  6. サーバーが Traffic Director から必要な構成を取得すると、次の出力が表示されます。

    2021-05-06 16:10:34,042: INFO     Running with xDS Server credentials
    2021-05-06 16:10:34,043: INFO     Greeter server listening on port 50051
    2021-05-06 16:10:34,046: INFO     Maintenance server listening on port 50052
    

Go

  1. example-grpc-server サービス用に作成された Pod の名前を取得します。

    kubectl get pods | grep example-grpc-server
    

    次のようなフィードバックが表示されます。

    default    example-grpc-server-77548868d-l9hmf     1/1    Running   0     105s
    
  2. サーバー Pod へのシェルを開きます。

    kubectl exec -it example-grpc-server-77548868d-l9hmf -- /bin/sh
    
  3. シェルで、/tmp/grpc-xds/td-grpc-bootstrap.json のブートストラップ ファイルがブートストラップ ファイルセクションで説明されているスキーマと一致していることを確認します。

  4. gRPC Go バージョン 1.41.0 をダウンロードし、xds-hello-world サーバー アプリケーションがあるディレクトリに移動します。

    apk add curl
    
    curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz
    
    cd grpc-go-1.42.0/examples/features/xds/server
    
    
  5. リスニング ポートとして 50051 を使用します。--xds_creds フラグを指定してサーバーを構築して実行し、xDS 対応のセキュリティを指定します。

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -port 50051
    
  6. サーバーが Traffic Director から必要な構成を取得すると、次の出力が表示されます。

    Using xDS credentials...
    Serving GreeterService on 0.0.0.0:50051 and HealthService on 0.0.0.0:50052
    

サーバーの起動後に、サービスが正常な状態であることを示すために 3~5 分かかります。

クライアントを実行して構成を確認する

前の手順で作成したクライアント Pod で、xDS 対応の helloworld クライアントを構築して実行します。

Java

  1. クライアント Pod の名前を取得します。

    kubectl get pods | grep example-grpc-client
    

    次のようなフィードバックが表示されます。

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. クライアント Pod へのシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. コマンドシェルで gRPC Java バージョン 1.42.1 をダウンロードして、xds-hello-world クライアント アプリケーションを構築します。

    curl -L https://github.com/grpc/grpc-java/archive/v1.42.1.tar.gz | tar -xz
    
    cd grpc-java-1.42.1/examples/example-xds
    
    ../gradlew --no-daemon installDist
    
  4. --xds-creds フラグを指定してクライアントを実行し、xDS 対応のセキュリティ、クライアント名、ターゲット接続文字列を指定します。

    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke:8000
    

    次のような出力が表示されます。

    Greeting: Hello xds-client, from xds-server
    

C++

  1. クライアント Pod の名前を取得します。

    kubectl get pods | grep example-grpc-client
    

    次のようなフィードバックが表示されます。

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. クライアント Pod へのシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. シェルを開いたら、gRPC C++ をダウンロードして xds-hello-world クライアント アプリケーションを構築します。

    apt-get update -y && \
            apt-get install -y \
                build-essential \
                clang \
                python3 \
                python3-dev
    
    curl -L https://github.com/grpc/grpc/archive/master.tar.gz | tar -xz
    
    cd grpc-master
    
    tools/bazel build examples/cpp/helloworld:xds_greeter_client
    
  4. --xds-creds フラグを指定してクライアントを実行し、xDS 対応のセキュリティ、クライアント名、ターゲット接続文字列を指定します。

    bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000
    

    認証情報を使用せずにクライアントを実行するには、次のように記述します。

    bazel-bin/examples/cpp/helloworld/xds_greeter_client --target=xds:///helloworld-gke:8000 --nosecure
    

    次のような出力が表示されます。

    Greeter received: Hello world
    

Python

  1. クライアント Pod の名前を取得します。

    kubectl get pods | grep example-grpc-client
    

    次のようなフィードバックが表示されます。

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. クライアント Pod へのシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  3. シェルで、gRPC Python バージョン 1.41.0 をダウンロードして、サンプル クライアント アプリケーションを構築します。

    apt-get update -y
    apt-get install -y python3 python3-pip
    python3 -m pip install virtualenv
    curl -L https://github.com/grpc/grpc/archive/v1.41.x.tar.gz | tar -xz
    cd grpc-1.41.x/examples/python/xds/
    python3 -m virtualenv venv
    source venv/bin/activate
    python3 -m pip install -r requirements.txt
    
  4. --xds-creds フラグを指定してクライアントを実行し、xDS 対応のセキュリティ、クライアント名、ターゲット接続文字列を指定します。

    python3 client.py xds:///helloworld-gke:8000 --xds-creds
    

    次のような出力が表示されます。

    Greeter client received: Hello you from example-host!
    

Go

  1. クライアント Pod の名前を取得します。

    kubectl get pods | grep example-grpc-client
    

    次のようなフィードバックが表示されます。

    default    example-grpc-client-7c969bb997-9fzjv     1/1    Running   0     105s
    
  2. クライアント Pod へのシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/sh
    
  3. シェルを開いたら、gRPC Go バージョン 1.42.0 をダウンロードし、xds-hello-world クライアント アプリケーションがあるディレクトリに移動します。

    apk add curl
    
    curl -L https://github.com/grpc/grpc-go/archive/v1.42.0.tar.gz | tar -xz
    
    cd grpc-go-1.42.0/examples/features/xds/client
    
  4. --xds_creds フラグを指定してクライアントを構築して実行し、xDS 対応のセキュリティ、クライアント名、ターゲット接続文字列を指定します。

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke:8000
    

    次のような出力が表示されます。

    Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
    

認可ポリシーでサービスレベルのアクセスを構成する

認可ポリシーをサポートするには、gRFC A41 をサポートする必要があります。必要な言語バージョンは、github で確認できます。

次の手順を使用して、認可ポリシーでサービスレベルのアクセスを構成します。認可ポリシーを作成する前に、認可を使用してアクセスを制限するの注意事項を確認してください。

構成を簡単に検証できるように、クライアントで helloworld-gke サービスを参照するために使用できる追加のホスト名を作成します。

  1. 以前に grpc_route.yaml に保存されていた GRPCRoute 仕様を更新します。

    name: helloworld-grpc-route
    hostnames:
    - helloworld-gke:8000
    - helloworld-gke-noaccess:8000
    meshes:
    - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh
    rules:
    - action:
        destinations:
        - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-gke-helloworld-service
    
  2. grpc_route.yaml 仕様から GRPCRoute リソースを再度インポートします。

    gcloud network-services grpc-routes import helloworld-grpc-route \
      --source=grpc_route.yaml \
      --location=global
    

次の手順では、ホスト名が helloworld-gke:8000 でポートが 50051example-grpc-client アカウントによるリクエストの送信を許可する認可ポリシーを作成します。

gcloud

  1. 認可ポリシーは、helloworld-gke-authz-policy.yaml という名前のファイルを作成することによって作成します。

    action: ALLOW
    name: helloworld-gke-authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/default/sa/example-grpc-client
      destinations:
      - hosts:
        - helloworld-gke:8000
        ports:
        - 50051
    
  2. ポリシーをインポートします。

    gcloud network-security authorization-policies import \
      helloworld-gke-authz-policy \
      --source=helloworld-gke-authz-policy.yaml \
      --location=global
    
  3. ep-mtls-psms.yaml ファイルに次の行を追加して、新しい認可ポリシーを参照するようにエンドポイント ポリシーを更新します。

    authorizationPolicy: projects/${PROJECT_ID}/locations/global/authorizationPolicies/helloworld-gke-authz-policy
    

    これにより、エンドポイント ポリシーに、app:helloworld というラベルを含む gRPC ブートストラップ ファイルを持つ Pod への受信リクエストに対して、mTLS と認可ポリシーの両方を適用する必要があることが定められました。

  4. ポリシーをインポートします。

    gcloud network-services endpoint-policies import ep-mtls-psms \
      --source=ep-mtls-psms.yaml --location=global
    

認可ポリシーを検証する

以下の手順を使用して、認可ポリシーが正しく機能することを確認します。

Java

  1. 前に使用したクライアント Pod でシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. コマンドシェルで、次のコマンドを実行して設定を検証します。

    cd grpc-java-1.42.1/examples/example-xds
    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke:8000
    

    次のような出力が表示されます。

    Greeting: Hello xds-client, from xds-server
    
  3. 別のサーバー名でクライアントを再度実行します。なお、これは失敗するケースです。認可ポリシーでは helloworld-gke:8000 ホスト名へのアクセスのみが許可されるため、このリクエストは無効です。

    ./build/install/example-xds/bin/xds-hello-world-client --xds-creds xds-client \
          xds:///helloworld-gke-noaccess:8000
    

    次のような出力が表示されます。

    WARNING: RPC failed: Status{code=PERMISSION_DENIED}
    

    この出力が表示されない場合は、認可ポリシーがまだ使用されていない可能性があります。数分待ってから、確認プロセス全体をもう一度試しくてださい。

Go

  1. 前に使用したクライアント Pod でシェルを開きます。

    kubectl exec -it example-grpc-client-7c969bb997-9fzjv -- /bin/bash
    
  2. コマンドシェルで、次のコマンドを実行して設定を検証します。

    cd grpc-go-1.42.0/examples/features/xds/client
    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke:8000
    

    次のような出力が表示されます。

    Greeting: Hello xds-client, from example-grpc-server-77548868d-l9hmf
    
  3. 別のサーバー名でクライアントを再度実行します。なお、これは失敗するケースです。認可ポリシーでは helloworld-gke:8000 ホスト名へのアクセスのみが許可されるため、このリクエストは無効です。

    GRPC_GO_LOG_VERBOSITY_LEVEL=2 GRPC_GO_LOG_SEVERITY_LEVEL="info" \
      go run main.go \
      -xds_creds \
      -name xds-client \
      -target xds:///helloworld-gke-noaccess:8000
    

    次のような出力が表示されます。

    could not greet: rpc error: code = PermissionDenied desc = Incoming RPC is not allowed: rpc error: code = PermissionDenied desc = incoming RPC did not match an allow policy
    exit status 1
    

    この出力が表示されない場合は、認可ポリシーがまだ使用されていない可能性があります。数分待ってから、確認プロセス全体をもう一度試しくてださい。

mTLS の代わりに TLS を使用する

この例の TLS を少し変更するだけで使用できます。

  1. ServerTlsPolicymtlsPolicy を削除します。

    cat << EOF > server-tls-policy.yaml
    name: "server-tls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    
  2. 代わりに EndpointPolicy でこのポリシーを使用します。

    cat << EOF > ep-tls-psms.yaml
    name: "ep-mtls-psms"
    type: "GRPC_SERVER"
    serverTlsPolicy: "projects/${PROJECT_ID}/locations/global/serverTlsPolicies/server-tls-policy"
    trafficPortSelector:
      ports:
      - "50051"
    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: "MATCH_ALL"
        metadataLabels: []
    EOF
    
  3. TLS の場合、mTLS の ClientTlsPolicy も動作しますが、ポリシーの clientCertificate セクションは TLS では不要なため、削除できます。

    cat << EOF > client-tls-policy.yaml
    name: "client-tls-policy"
    serverValidationCa:
    - certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    EOF
    

Wallet のサンプルでサービスのセキュリティを使用する

このセクションでは、Java、C++、Go 向けにサービス セキュリティを利用して Wallet のサンプルを有効にする方法の概要を説明します。

Java

Java のソースコードの例は github にあります。このコードでは、プロキシレス セキュリティの構成時に XdsChannelXdsServer の認証情報を使用しています。

以下の手順では、Go を使用して Wallet を構成する例について説明します。このプロセスは Java の場合も同様です。この手順では、Google Cloud コンテナ リポジトリから取得した既存の Docker イメージを使用します。

サンプルを作成する手順は次のとおりです。

  1. リポジトリのクローンを作成し、gRPC サンプルのディレクトリにあるファイルを取得します。
  2. 00-common-env.sh ファイルを編集します。WALLET_DOCKER_IMAGE の値を Go Docker イメージに設定する行をコメントアウトし、WALLET_DOCKER_IMAGE の値を Java Docker イメージに設定する行のコメント化を解除します。
  3. Cloud Router インスタンスの作成と構成の手順を行うか、スクリプト 10.apis.sh で関数 create_cloud_router_instances を使用して、Cloud Router インスタンスの作成と構成を行います。
  4. hello world の例の手順を行うか、スクリプト 20-cluster.sh で関数 create_cluster を使用してクラスタを作成します。
  5. CA Service の手順またはスクリプト 30-private-ca-setup.sh を使用して、プライベート認証局を作成します。
  6. スクリプト 40-k8s-resources.sh を使用して、すべてのサービスのサービス アカウント、Namespace、Kubernetes Service、NEG、サーバー側の Deployment(accountstatsstats_premiumwallet_v1wallet_v2)を含む Kubernetes リソースを作成します。
  7. 作成したサービスごとに、スクリプト 50-td-components.shcreate_health_checkcreate_backend_service を使用してヘルスチェックとバックエンド サービスを作成します。
  8. スクリプト 60-routing-components.shcreate_routing_components を使用して、Traffic Director のルーティング コンポーネントを作成します。
  9. スクリプト 70-security-components.shcreate_security_components を使用して、各バックエンド サービスの Traffic Director セキュリティ コンポーネントを作成します。
  10. スクリプト 75-client-deployment.shcreate_client_deployment を使用して、Wallet クライアントの Deployment を作成します。
  11. grpc-wallet クライアントで確認するの説明に沿ってクライアントを起動し、構成を確認します。

C++

C++ のソースコードの例は github にあります。このコードでは、プロキシレス セキュリティの構成時に XdsChannelXdsServer の認証情報を使用しています。

以下の手順では、Go を使用して Wallet を構成する例について説明します。このプロセスは C++ の場合も同様です。この手順では、Google Cloud コンテナ リポジトリから取得した既存の Docker イメージを使用します。

サンプルを作成する手順は次のとおりです。

  1. リポジトリのクローンを作成し、gRPC サンプルのディレクトリにあるファイルを取得します。
  2. 00-common-env.sh ファイルを編集します。WALLET_DOCKER_IMAGE の値を Go Docker イメージに設定する行をコメントアウトし、WALLET_DOCKER_IMAGE の値を C++ Docker イメージに設定する行のコメント化を解除します。
  3. Cloud Router インスタンスの作成と構成の手順を行うか、スクリプト 10.apis.sh で関数 create_cloud_router_instances を使用して、Cloud Router インスタンスの作成と構成を行います。
  4. hello world の例の手順を行うか、スクリプト 20-cluster.sh で関数 create_cluster を使用してクラスタを作成します。
  5. CA Service の手順またはスクリプト 30-private-ca-setup.sh を使用して、プライベート認証局を作成します。
  6. スクリプト 40-k8s-resources.sh を使用して、すべてのサービスのサービス アカウント、Namespace、Kubernetes Service、NEG、サーバー側の Deployment(accountstatsstats_premiumwallet_v1wallet_v2)を含む Kubernetes リソースを作成します。
  7. 作成したサービスごとに、スクリプト 50-td-components.shcreate_health_checkcreate_backend_service を使用してヘルスチェックとバックエンド サービスを作成します。
  8. スクリプト 60-routing-components.shcreate_routing_components を使用して、Traffic Director のルーティング コンポーネントを作成します。
  9. スクリプト 70-security-components.shcreate_security_components を使用して、各バックエンド サービスの Traffic Director セキュリティ コンポーネントを作成します。
  10. スクリプト 75-client-deployment.shcreate_client_deployment を使用して、Wallet クライアントの Deployment を作成します。
  11. grpc-wallet クライアントで確認するの説明に沿ってクライアントを起動し、構成を確認します。

Go

Go のソースコードの例は github にあります。このコードでは、プロキシレス セキュリティの構成時に XdsChannelXdsServer の認証情報を使用しています。

この手順では、Google Cloud コンテナ リポジトリから取得した既存の Docker イメージを使用します。

サンプルを作成する手順は次のとおりです。

  1. リポジトリのクローンを作成し、gRPC サンプルのディレクトリにあるファイルを取得します。
  2. 00-common-env.sh ファイルを編集して、環境変数に正しい値を設定します。
  3. Cloud Router インスタンスの作成と構成の手順を行うか、スクリプト 10.apis.sh で関数 create_cloud_router_instances を使用して、Cloud Router インスタンスの作成と構成を行います。
  4. hello world の例の手順を行うか、スクリプト 20-cluster.sh で関数 create_cluster を使用してクラスタを作成します。
  5. CA Service の手順またはスクリプト 30-private-ca-setup.sh を使用して、プライベート認証局を作成します。
  6. スクリプト 40-k8s-resources.sh を使用して、すべてのサービスのサービス アカウント、Namespace、Kubernetes Service、NEG、サーバー側の Deployment(accountstatsstats_premiumwallet_v1wallet_v2)を含む Kubernetes リソースを作成します。
  7. 作成したサービスごとに、スクリプト 50-td-components.shcreate_health_checkcreate_backend_service を使用してヘルスチェックとバックエンド サービスを作成します。
  8. スクリプト 60-routing-components.shcreate_routing_components を使用して、Traffic Director のルーティング コンポーネントを作成します。
  9. スクリプト 70-security-components.shcreate_security_components を使用して、各バックエンド サービスの Traffic Director セキュリティ コンポーネントを作成します。
  10. スクリプト 75-client-deployment.shcreate_client_deployment を使用して、Wallet クライアントの Deployment を作成します。
  11. grpc-wallet クライアントで確認するの説明に沿ってクライアントを起動し、構成を確認します。

ブートストラップ ファイル

このガイドの設定プロセスでは、ブートストラップ ジェネレータを使用して必要なブートストラップ ファイルを作成します。このセクションでは、ブートストラップ ファイル自体に関するリファレンス情報を提供します。

ブートストラップ ファイルには、プロキシレス gRPC コードに必要な構成情報(xDS サーバーの接続情報など)が含まれています。ブートストラップ ファイルには、プロキシレス gRPC のセキュリティ機能に必要なセキュリティ構成が含まれています。gRPC サーバーには、以下で説明するように、追加フィールドが 1 つ必要になります。ブートストラップ ファイルのサンプルは、次のようになります。

{
  "xds_servers": [
    {
      "server_uri": "trafficdirector.googleapis.com:443",
      "channel_creds": [
        {
          "type": "google_default"
        }
      ],
      "server_features": [
        "xds_v3"
      ]
    }
  ],
  "authorities": {
    "traffic-director-c2p.xds.googleapis.com": {
      "xds_servers": [
        {
          "server_uri": "dns:///directpath-pa.googleapis.com",
          "channel_creds": [
            {
              "type": "google_default"
            }
          ],
          "server_features": [
            "xds_v3",
            "ignore_resource_deletion"
          ]
        }
      ],
      "client_listener_resource_name_template": "xdstp://traffic-director-c2p.xds.googleapis.com/envoy.config.listener.v3.Listener/%s"
    }
  },
  "node": {
    "id": "projects/9876012345/networks/mesh:grpc-mesh/nodes/b59f49cc-d95a-4462-9126-112f794d5dd3",
    "cluster": "cluster",
    "metadata": {
      "INSTANCE_IP": "10.28.2.8",
      "TRAFFICDIRECTOR_DIRECTPATH_C2P_IPV6_CAPABLE": true,
      "TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": "223606568246",
      "TRAFFICDIRECTOR_NETWORK_NAME": "default",
      "app": "helloworld"
    },
    "locality": {
      "zone": "us-central1-c"
    }
  },
  "certificate_providers": {
    "google_cloud_private_spiffe": {
      "plugin_name": "file_watcher",
      "config": {
        "certificate_file": "/var/run/secrets/workload-spiffe-credentials/certificates.pem",
        "private_key_file": "/var/run/secrets/workload-spiffe-credentials/private_key.pem",
        "ca_certificate_file": "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem",
        "refresh_interval": "600s"
      }
    }
  },
  "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s"
}

セキュリティ サービス用のブートストラップ ファイルを更新する

次のフィールドには、セキュリティと xDS v3 の使用に関連する変更が反映されています。

node 内の id フィールドでは、gRPC クライアントの一意の ID を Traffic Director に提供します。次の形式のノード ID を使用して、Google Cloud プロジェクト番号とネットワーク名を指定する必要があります。

projects/{project number}/networks/{network name}/nodes/[UNIQUE_ID]

プロジェクト番号 1234 とデフォルトのネットワークの例は次のとおりです。

projects/1234/networks/default/nodes/client1

INSTANCE_IP フィールドは、Pod の IP アドレス、または INADDR_ANY を示す 0.0.0.0 です。このフィールドは、gRPC サーバーが Traffic Director から Listener リソースを取得するために使用され、サーバー側のセキュリティを確保します。

ブートストラップ ファイルのセキュリティ構成フィールド

JSON キー
server_listener_resource_name_template 文字列 grpc/server?xds.resource.listening_address=%s gRPC サーバーには必須です。gRPC はこの値を使用して、Traffic Director から Listener リソースを取得してリソース名を作成し、サーバー側のセキュリティやその他の構成に使用します。gRPC はこの情報を使用してリソース名の文字列を作成します。
certificate_providers JSON 構造体 google_cloud_private_spiffe 必須。値は、証明書プロバイダ インスタンスに対する名前のマッピングを表す JSON 構造体です。証明書プロバイダ インスタンスは、ID とルート証明書を取得するために使用されます。サンプルのブートストラップ ファイルには、1 つの名前 google_cloud_private_spiffe が含まれ、証明書プロバイダ インスタンスの JSON 構造体が値として含まれています。各証明書プロバイダ インスタンスの JSON 構造体には、次の 2 つのフィールドがあります。
  • plugin_name。証明書プロバイダの gRPC のプラグイン アーキテクチャで必要なために使用される証明書プロバイダ プラグインを識別する必須の値です。gRPC には、この設定で使用されるファイルウォッチャー プラグインのサポートが組み込まれています。plugin_name は file_watcher です。
  • configfile_watcher プラグインの JSON 構成ブログを識別する必須の値です。スキーマとコンテンツはプラグインによって異なります。

file_watcher プラグインの config JSON 構造の内容を以下に示します。

  • certificate_file: 必須の文字列です。この値は ID 証明書のロケーションです。
  • private_key_file: 必須の文字列です。値は秘密鍵ファイルのロケーションで、ID 証明書と一致している必要があります。
  • ca_certificate_file: 必須の文字列です。値はルート証明書のロケーションで、信頼バンドルとも呼ばれます。
  • refresh_interval: オプションの文字列です。この値は、期間の JSON マッピングの文字列表現を使用して指定された更新間隔を示します。デフォルト値は「600s」で、10 分の期間です。

ブートストラップ ジェネレータ

ブートストラップ ジェネレータのコンテナ イメージは gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.15.0 で入手できます。ソースコードは https://github.com/GoogleCloudPlatform/traffic-director-grpc-bootstrap で入手できます。よく使用されるコマンドライン オプションは次のとおりです。

  • --output: このオプションを使用して、出力ブートストラップ ファイルが書き込まれる場所を指定します。たとえば、コマンド --output /tmp/bootstrap/td-grpc-bootstrap.json を実行すると、Pod のファイル システム内の /tmp/bootstrap/td-grpc-bootstrap.json にブートストラップ ファイルが生成されます。
  • --config-mesh-experimental: このオプションを使用して、Mesh リソースに対応するメッシュ名を指定します。
  • --node-metadata: ブートストラップ ファイルでノード メタデータを入力するには、このフラグを使用します。これは、EndpointPolicy でメタデータ ラベル マッチャーを使用する場合に必要となります。{td_name_short}} はブートストラップ ファイルのノード メタデータ セクションで指定されたラベルデータを使用します。引数は、key=value の形式で指定されます。例: --node-metadata version=prod --node-metadata type=grpc

以上により、ブートストラップ ファイルのノード メタデータ セクションに次の内容が追加されます。

{
  "node": {
...
    "metadata": {
      "version": "prod",
      "type": "grpc",
...
    },
...
  },
...
}

デプロイを削除する

必要に応じて、これらのコマンドを実行して、このガイドに従って作成した Deployment を削除できます。

クラスタを削除するには、次のコマンドを実行します。

gcloud container clusters delete CLUSTER_NAME --zone ZONE --quiet

作成したリソースを削除するには、次のコマンドを実行します。

gcloud compute backend-services delete grpc-gke-helloworld-service --global --quiet
gcloud compute network-endpoint-groups delete example-grpc-server --zone ZONE --quiet
gcloud compute firewall-rules delete grpc-gke-allow-health-checks --quiet
gcloud compute health-checks delete grpc-gke-helloworld-hc --quiet
gcloud network-services endpoint-policies delete ep-mtls-psms \
    --location=global --quiet
gcloud network-security authorization-policies delete helloworld-gke-authz-policy \
   --location=global --quiet
gcloud network-security client-tls-policies delete client-mtls-policy \
    --location=global --quiet
gcloud network-security server-tls-policies delete server-tls-policy \
    --location=global --quiet
gcloud network-security server-tls-policies delete server-mtls-policy \
    --location=global --quiet

トラブルシューティング

以降の手順を使用して、セキュリティのデプロイにおける問題を解決します。

ワークロードで Traffic Director から構成を取得できない

次のようなエラーが表示された場合:

PERMISSION_DENIED: Request had insufficient authentication scopes.

以下のことを確認してください。

  • --scopes=cloud-platform 引数を使用して GKE クラスタを作成した。
  • Kuberneters サービス アカウントに roles/trafficdirector.client を割り当てた。
  • roles/trafficdirector.client をデフォルトの Google Cloud サービス アカウント(前述の ${GSA_EMAIL})に割り当てた。
  • trafficdirector.googleapis.com サービス(API)を有効にした。

Traffic Director 構成が正しい場合でも、gRPC サーバーで TLS/mTLS を使用しない

エンドポイント ポリシーの構成で GRPC_SERVER を指定していることを確認してください。SIDECAR_PROXY を指定した場合、gRPC では構成は無視されます。

リクエストされたクラスタ バージョンでは GKE クラスタを作成できない

GKE クラスタの作成コマンドが、次のようなエラーで失敗することがあります。

Node version "1.20.5-gke.2000" is unsupported.

クラスタ作成コマンドに引数 --release-channel rapid を使用していることを確認します。このリリースの正しいバージョンを取得するには、Rapid リリース チャンネルを使用する必要があります。

No usable endpoint エラーが表示される

No usable endpoint エラーによりクライアントがサーバーと通信できない場合、ヘルス チェッカーがサーバーのバックエンドを異常としてマークしていた可能性があります。バックエンドの健全性を確認するには、次の gcloud コマンドを実行します。

gcloud compute backend-services get-health grpc-gke-helloworld-service --global

コマンドからバックエンド ステータスが異常であると返された場合は、次のいずれかの原因が考えられます。

  • ファイアウォールが作成されていないか、正しいソース IP 範囲を含まれていない。
  • ファイアウォールのターゲットタグが、作成したクラスタのタグと一致していない。

ワークロードがセキュリティ設定で通信できない

プロキシレス サービス メッシュのセキュリティを設定してもワークロードが通信できない場合は、次の手順に沿って原因を特定してください。

  1. プロキシレス セキュリティを無効にして、プロキシレス サービス メッシュの負荷分散のユースケースにおける問題を解消します。メッシュ内のセキュリティを無効にするには、次のいずれかの対応をします。
    1. クライアント側とサーバー側で平文の認証情報を使用する。
    2. Traffic Director の構成でバックエンド サービスとエンドポイント ポリシーに対してセキュリティを構成しない。

デプロイにセキュリティが設定されていないため、プロキシレスの Traffic Director のデプロイに関するトラブルシューティングの手順を行います。

  1. フォールバック認証情報としての平文の認証情報または安全でない認証情報とともに xDS 認証情報を使用するようにワークロードを変更します。前述のように、セキュリティを無効にして Traffic Director の構成を維持します。その場合、gRPC は Traffic Director でセキュリティの構成を許可していますが、Traffic Director はセキュリティ情報を送信しません。この場合、gRPC は前述の最初のケースのように機能する平文の(または安全でない)認証情報にフォールバックします。このケースが機能しない場合は、次の操作を行います。

    1. gRPC と Traffic Director の間で交換された xDS メッセージを確認できるように、クライアント側とサーバー側の両方でロギングレベルを上げます。
    2. Traffic Director で、ワークロードに送信される CDS レスポンスおよび LDS レスポンスでセキュリティが有効になっていないことを確認します。
    3. ワークロードがチャネルで TLS モードまたは mTLS モードを使用していないことを確認します。TLS handshake に関連するログメッセージが表示された場合は、アプリケーションのソースコードを確認し、安全でない認証情報または平文の認証情報をフォールバック認証情報として使用していることを確認してください。アプリケーションのソースコードが正しい場合は、gRPC ライブラリのバグである可能性があります。
  2. ユーザーガイドのトラブルシューティング手順に沿って、GKE クラスタに対して CA Service と GKE の統合が正しく機能していることを確認します。その機能で提供される証明書と鍵が、指定されたディレクトリ /var/run/secrets/workload-spiffe-credentials/ で使用可能であることを確認してください。

  3. 前述のように、メッシュ内で(mTLS ではなく)TLS を有効にして、クライアントとサーバーのワークロードを再起動します。

    1. gRPC と Traffic Director の間で交換された xDS メッセージを表示できるように、クライアント側とサーバー側の両方でロギングレベルを上げます。
    2. Traffic Director で、ワークロードに送信される CDS レスポンスおよび LDS レスポンスでセキュリティが有効になっていることを確認します。

クライアントが CertificateException およびメッセージ Peer certificate SAN check failed で失敗する

これは、SecuritySettings メッセージの subjectAltNames 値に問題があることを示しています。なお、これらの値は、バックエンド サービス用に作成した Kubernetes Service に基づきます。作成した Kubernetes Service ごとに、次の形式の SPIFFE ID が関連付けられます。

spiffe://${WORKLOAD_POOL}/ns/${K8S_NAMESPACE}/sa/${SERVICE_ACCOUNT}

該当の値は次のとおりです。

  • WORKLOAD_POOL: クラスタのワークロード プール(${PROJECT_ID}.svc.id.goog
  • K8S_NAMESPACE: サービスのデプロイに使用した Kubernetes Namespace
  • SERVICE_ACCOUNT: サービスのデプロイに使用した Kubernetes サービス アカウント

ネットワーク エンドポイント グループとしてバックエンド サービスに接続したすべての Kubernetes Service について、SPIFFE ID が正しく計算され、その SPIFFE ID が SecuritySettings メッセージの subjectAltNames フィールドに追加されていることを確認してください。

アプリケーションが gRPC ライブラリで mTLS 証明書を使用できない

アプリケーションが gRPC ライブラリで mTLS 証明書を使用できない場合は、次の手順を行います。

  1. Pod 仕様に、NEG を使用したプロキシレス gRPC サービスの作成で説明されている security.cloud.google.com/use-workload-certificates アノテーションが含まれていることを確認します。

  2. 証明書チェーン、リーフ証明書、秘密鍵、信頼できる CA 証明書が含まれるファイルが、Pod 内から次のパスでアクセス可能であることを確認します。

    1. 証明書チェーンとリーフ証明書: "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
    2. 秘密鍵: "/var/run/secrets/workload-spiffe-credentials/private_key.pem"
    3. CA バンドル: "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem"
  3. 前の手順で指定した証明書を使用できない場合は、次の手順を行います。

      gcloud privateca subordinates describe SUBORDINATE_CA_POOL_NAME 
    --location=LOCATION

    1. GKE のコントロール プレーンに正しい IAM ロールバインディングが付与されていることを確認し、CA Service へのアクセスを許可します。

      # Get the IAM policy for the CA
      gcloud privateca roots get-iam-policy ROOT_CA_POOL_NAME
      
      # Verify that there is an IAM binding granting access in the following format
      - members:
      - serviceAccount:service-projnumber@container-engine-robot.iam.gserviceaccount.com
      role: roles/privateca.certificateManager
      
      # Where projnumber is the project number (e.g. 2915810291) for the GKE cluster.
      
    2. 証明書の有効期限が切れていないことを確認します。これは、/var/run/secrets/workload-spiffe-credentials/certificates.pem の証明書チェーンとリーフ証明書です。確認するには、次のコマンドを実行します。

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
      

    3. 次のコマンドを実行して、アプリケーションでサポートされている鍵タイプを確認します。

      cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
      

    4. gRPC Java アプリケーションの WorkloadCertificateConfig YAML ファイルに、次の keyAlgorithm が含まれていることを確認します。

      keyAlgorithm:
        rsa:
          modulusSize: 4096
    
  4. CA が証明書鍵と同じ鍵ファミリーを使用していることを確認します。

アプリケーションの証明書がクライアント、サーバー、またはピアによって拒否される

  1. ピア アプリケーションが同じ信頼バンドルを使用して証明書を検証することを確認します。
  2. 使用中の証明書の有効期限が切れていないことを確認します(証明書チェーンとリーフ証明書: "/var/run/secrets/workload-spiffe-credentials/certificates.pem")。

###

設定プロセス中に Pod が保留状態のままである場合は、デプロイ仕様の Pod の CPU とメモリリソースを増やします。

--enable-mesh-certificates フラグを指定してクラスタを作成できない

gcloud CLI の最新バージョンを実行していることを確認します。

gcloud components update

--enable-mesh-certificates フラグは gcloud beta でのみ機能します。

Pod が起動しない

証明書のプロビジョニングが失敗した場合、GKE メッシュ証明書を使用する Pod が起動しない可能性があります。これは、次のような状況で発生します。

  • WorkloadCertificateConfig または TrustConfig が正しく構成されていないか、存在しない。
  • CSR が承認されていない。

証明書のプロビジョニングが失敗するかどうかを確認するには、Pod イベントを確認します。

  1. Pod のステータスを確認します。

    kubectl get pod -n POD_NAMESPACE POD_NAME
    

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

    • POD_NAMESPACE: Pod の名前空間。
    • POD_NAME: Pod の名前。
  2. Pod の最近のイベントを確認します。

    kubectl describe pod -n POD_NAMESPACE POD_NAME
    
  3. 証明書のプロビジョニングに失敗した場合、Type=WarningReason=FailedMountFrom=kubelet が含まれるイベントと、先頭が MountVolume.SetUp failed for volume "gke-workload-certificates"Message フィールドが表示されます。Message フィールドにはトラブルシューティング情報が含まれています。

    Events:
      Type     Reason       Age                From       Message
      ----     ------       ----               ----       -------
      Warning  FailedMount  13s (x7 over 46s)  kubelet    MountVolume.SetUp failed for volume "gke-workload-certificates" : rpc error: code = Internal desc = unable to mount volume: store.CreateVolume, err: unable to create volume "csi-4d540ed59ef937fbb41a9bf5380a5a534edb3eedf037fe64be36bab0abf45c9c": caPEM is nil (check active WorkloadCertificateConfig)
    
  4. Pod が起動しない原因がオブジェクトの構成が適切でないか、CSR が拒否されたことである場合は、以下のトラブルシューティングの手順をご覧ください。

WorkloadCertificateConfig または TrustConfig の構成に誤りがある

WorkloadCertificateConfig オブジェクトと TrustConfig オブジェクトが正しく作成されていることを確認してください。kubectl を使用して、これらのオブジェクトの構成ミスを診断できます。

  1. 現在のステータスを取得します。

    WorkloadCertificateConfig:

    kubectl get WorkloadCertificateConfig default -o yaml
    

    TrustConfig:

    kubectl get TrustConfig default -o yaml
    
  2. ステータスの出力を検査します。有効なオブジェクトには、type: Readystatus: "True" の条件が設定されます。

    status:
      conditions:
      - lastTransitionTime: "2021-03-04T22:24:11Z"
        message: WorkloadCertificateConfig is ready
        observedGeneration: 1
        reason: ConfigReady
        status: "True"
        type: Ready
    

    無効なオブジェクトの場合は、status: "False" が代わりに表示されます。reason フィールドと message フィールドには、追加のトラブルシューティングの詳細が含まれます。

CSR が承認されていない

CSR 承認プロセス中に問題が発生した場合は、CSR の type: Approved 条件と type: Issued 条件でエラーの詳細を確認できます。

  1. kubectl を使用して、関連する CSR を一覧表示します。

    kubectl get csr \
      --field-selector='spec.signerName=spiffe.gke.io/spiffe-leaf-signer'
    
  2. ApprovedIssued ではない CSR、または Approved でない CSR を選択します。

  3. kubectl を使用して、選択した CSR の詳細を取得します。

    kubectl get csr CSR_NAME -o yaml
    

    CSR_NAME を、選択した CSR の名前に置き換えます。

有効な CSR には、type: Approvedstatus: "True" の条件と、status.certificate フィールドに有効な証明書があります。

status:
  certificate: <base64-encoded data>
  conditions:
  - lastTransitionTime: "2021-03-04T21:58:46Z"
    lastUpdateTime: "2021-03-04T21:58:46Z"
    message: Approved CSR because it is a valid SPIFFE SVID for the correct identity.
    reason: AutoApproved
    status: "True"
    type: Approved

無効な CSR のトラブルシューティング情報が message フィールドと reason フィールドに表示されます。

Pod に証明書がない

  1. Pod の Pod 仕様を取得します。

    kubectl get pod -n POD_NAMESPACE POD_NAME -o yaml
    

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

    • POD_NAMESPACE: Pod の名前空間。
    • POD_NAME: Pod の名前。
  2. Pod 仕様に、mTLS 認証を受け取るように Pod を構成するで説明されている security.cloud.google.com/use-workload-certificates アノテーションが含まれていることを確認します。

  3. GKE メッシュ証明書のアドミッション コントローラが workloadcertificates.security.cloud.google.com タイプの CSI ドライバ ボリュームを Pod 仕様に正常に挿入したことを確認します。

    volumes:
    ...
    -csi:
      driver: workloadcertificates.security.cloud.google.com
      name: gke-workload-certificates
    ...
    
  4. 各コンテナにボリューム マウントが存在することを確認します。

    containers:
    - name: ...
      ...
      volumeMounts:
      - mountPath: /var/run/secrets/workload-spiffe-credentials
        name: gke-workload-certificates
        readOnly: true
      ...
    
  5. 次の証明書バンドルと秘密鍵が Pod 内の次の場所にあることを確認します。

    • 証明書チェーン バンドル: /var/run/secrets/workload-spiffe-credentials/certificates.pem
    • 秘密鍵: /var/run/secrets/workload-spiffe-credentials/private_key.pem
    • CA トラスト アンカー バンドル: /var/run/secrets/workload-spiffe-credentials/ca_certificates.pem
  6. ファイルを利用できない場合は、次の手順を実行します。

    1. クラスタの CA Service(プレビュー)インスタンスを取得します。

      kubectl get workloadcertificateconfigs default -o jsonpath '{.spec.certificateAuthorityConfig.certificateAuthorityServiceConfig.endpointURI}'
      
    2. CA Service(プレビュー)インスタンスのステータスを取得します。

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

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

      • ISSUING_CA_TYPE: 発行 CA のタイプ(subordinates または roots のいずれか)。
      • ISSUING_CA_NAME: 発行 CA の名前。
      • ISSUING_CA_LOCATION: 発行 CA のリージョン。
    3. ルート CA の IAM ポリシーを取得します。

      gcloud privateca roots get-iam-policy ROOT_CA_NAME
      

      ROOT_CA_NAME は、ルート CA の名前に置き換えます。

    4. IAM ポリシーで、privateca.auditor ポリシー バインディングが存在することを確認します。

      ...
      - members:
        - serviceAccount:service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.auditor
      ...
      

      この例では、PROJECT_NUMBER はクラスタのプロジェクト番号です。

    5. 下位 CA の IAM ポリシーを取得します。

      gcloud privateca subordinates get-iam-policy SUBORDINATE_CA_NAME
      

      SUBORDINATE_CA_NAME は、下位 CA 名に置き換えます。

    6. IAM ポリシーで、privateca.certificateManager ポリシー バインディングが存在することを確認します。

      ...
      - members:
        - serviceAccount: service-PROJECT_NUMBER@container-engine-robot.iam.gserviceaccount.com
        role: roles/privateca.certificateManager
      ...
      

      この例では、PROJECT_NUMBER はクラスタのプロジェクト番号です。

アプリケーションで発行済みの mTLS 認証情報を使用できない

  1. 証明書の有効期限が切れていないことを確認します。

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  2. 使用しているキータイプがアプリケーションでサポートされていることを確認します。

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Public Key Algorithm" -A 3
    
  3. 発行 CA が証明書鍵と同じ鍵ファミリーを使用していることを確認します。

    1. CA Service(プレビュー)インスタンスのステータスを取得します。

      gcloud privateca ISSUING_CA_TYPE describe ISSUING_CA_NAME \
        --location ISSUING_CA_LOCATION
      

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

      • ISSUING_CA_TYPE: 発行 CA のタイプ(subordinates または roots のいずれか)。
      • ISSUING_CA_NAME: 発行 CA の名前。
      • ISSUING_CA_LOCATION: 発行 CA のリージョン。
    2. 出力の keySpec.algorithmWorkloadCertificateConfig YAML マニフェストで定義したのと同じ鍵アルゴリズムであることを確認します。出力は次のようになります。

      config:
        ...
        subjectConfig:
          commonName: td-sub-ca
          subject:
            organization: TestOrgLLC
          subjectAltName: {}
      createTime: '2021-05-04T05:37:58.329293525Z'
      issuingOptions:
        includeCaCertUrl: true
      keySpec:
        algorithm: RSA_PKCS1_2048_SHA256
       ...
      

証明書が拒否される

  1. ピア アプリケーションが同じ信頼バンドルを使用して証明書を検証することを確認します。
  2. 証明書の有効期限が切れていないことを確認します。

    cat /var/run/secrets/workload-spiffe-credentials/certificates.pem | openssl x509 -text -noout | grep "Not After"
    
  3. gRPC Go Credentials Reloading API を使用していない場合、クライアント コードがファイルシステムから認証情報を定期的に更新することを確認します。

  4. ワークロードが CA と同じ信頼ドメインに存在することを確認します。GKE メッシュ証明書は、単一の信頼ドメインにあるワークロード間の通信をサポートします。

制限事項

Traffic Director サービスのセキュリティは GKE でのみサポートされています。Compute Engine ではサービスのセキュリティをデプロイできません。

Traffic Director は、1 つのエンドポイントに同等に一致する 2 つ以上のエンドポイント ポリシー リソースがあるシナリオをサポートしていません。たとえば、同じラベルとポート向けの 2 つのポリシーや、1 つのエンドポイントのラベルに同等に一致する異なるラベル向けの 2 つ以上のポリシーです。エンドポイント ポリシーを 1 つのエンドポイントのラベルと一致させる方法については、EndpointPolicy.EndpointMatcher.MetadataLabelMatcher の API をご覧ください。このような状況では、Traffic Director はいかなる競合するポリシーからもセキュリティ構成を生成しません。