Envoy でサービス セキュリティを設定する

このガイドでは、Cloud Service Mesh と Envoy プロキシでデプロイされたサービスの認証と認可を構成の手順について説明します。Cloud Service Mesh サービスのセキュリティの詳細については、Cloud Service Mesh サービスのセキュリティをご覧ください。

要件

Envoy で Cloud Service Mesh のサービス セキュリティを構成する前に、次の前提条件を満たしていることを確認してください。

設定を準備する

以降のセクションでは、Cloud Service Mesh セキュリティ サービスを設定する前に完了しておく必要のあるタスクについて説明します。タスクは次のとおりです。

  • Google Cloud CLI の更新
  • 変数の設定
  • Cloud Service Mesh が Certificate Authority Service と連携するために必要な API の有効化

gcloud コマンドライン ツールを更新する

Google Cloud CLI を更新するには、ローカルマシンで次のコマンドを実行します。

gcloud components update

環境変数の設定

このドキュメントの例では、一貫した値を含むコードをコピーして貼り付けできるように、次の変数を設定します。次の値を使用します。

  • PROJECT_ID: プロジェクトの ID に置き換えます。
  • CLUSTER_NAME: 使用するクラスタ名(secure-td-cluster など)に置き換えます。
  • ZONE: クラスタが配置されているゾーンに置き換えます。
  • GKE_CLUSTER_URL: https://container.googleapis.com/v1/projects/PROJECT_ID/locations/ZONE/clusters/CLUSTER_NAME に置き換えます。
  • WORKLOAD_POOL: PROJECT_ID.svc.id.goog に置き換えます。
  • K8S_NAMESPACE: default に置き換えます。
  • DEMO_CLIENT_KSA: 実際のクライアントの Kubernetes サービス アカウントの名前に置き換えます。
  • DEMO_SERVER_KSA: 実際のサーバーの Kubernetes サービス アカウントの名前に置き換えます。
  • PROJNUM: プロジェクトのプロジェクト番号に置き換えます。プロジェクト番号は、Google Cloud Console または次のコマンドで確認できます。

    gcloud projects describe PROJECT_ID --format="value(projectNumber)"
    
  • SA_GKE: service-PROJNUM@container-engine-robot.iam.gserviceaccount.com に置き換えます。

  • CLUSTER_VERSION: 利用可能な最新のバージョンに置き換えます。詳細については、Rapid チャンネルのリリースノートをご覧ください。必要な最小バージョンは 1.21.4-gke.1801 です。これは、この例で使用する GKE クラスタ バージョンです。

ここで値を設定します。

# Substitute your project ID
PROJECT_ID=PROJECT_ID

# GKE cluster name and zone for this example.
CLUSTER_NAME=CLUSTER_NAME
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=K8S_NAMESPACE
DEMO_CLIENT_KSA=DEMO_CLIENT_KSA
DEMO_SERVER_KSA=DEMO_SERVER_KSA

# Compute other values
# Project number for your project
PROJNUM=PROJNUM

CLUSTER_VERSION=CLUSTER_VERSION
SA_GKE=service-PROJNUM@container-engine-robot.iam.gserviceaccount.com

API を有効にする

gcloud services enable コマンドを使用して、Certificate Authority Service で Cloud Service Mesh のセキュリティを設定するために必要なすべての 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

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

Cloud Service Mesh サービスのセキュリティは、GKE と CA Service のインテグレーションに依存します。GKE クラスタは、設定要件に加えて、次の要件を満たしている必要があります。

  • 使用できる最小のクラスタ バージョンは 1.21.4-gke.1801 です。新しいバージョンの機能が必要な場合は、Rapid リリース チャンネルからそのバージョンを取得できます。
  • 証明書を発行する認証局の作成で説明されているように、GKE クラスタを有効にして、メッシュ証明書で構成する必要があります。
  1. GKE 用 Workload Identity 連携を使用する新しいクラスタを作成します。既存のクラスタを更新する場合は、次のステップに進みます。--tags に指定する値は、Cloud Load Balancing コンポーネントを使用した Cloud Service Mesh の構成セクションで説明している 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 Federation for GKE と 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
    

マルチクラスタ環境でのデプロイ

マルチクラスタ環境にデプロイする場合は、このセクションで説明する一般的な手順を行います。以下の手順は、一方のクラスタでクライアント Pod が実行され、もう一方のクラスタでサーバー Pod が実行されていることを前提としています。

  1. 前のセクションの手順に沿って、クラスタを作成または更新します。

  2. 次のコマンドを使用して、各クラスタの Pod IP アドレス範囲を取得します。

    gcloud compute firewall-rules list \
      --filter="name~gke-{CLUSTER_NAME}-[0-9a-z]*-all" \
      --format="value(sourceRanges)"
    

    たとえば、cluster-acluster-b という名前のクラスタの場合、次のような結果が返されます。

    cluster-a, pod CIDR: 10.4.0.0/14, node network tag: gke-cluster-a-9cd18751-node
    cluster-b, pod CIDR: 10.8.0.0/14, node network tag: gke-cluster-b-acd14479-node
    
  3. クラスタが互いに通信できるようにする VPC ファイアウォール ルールを作成します。たとえば、次のコマンドは、cluster-a Pod IP アドレスが cluster-b ノードと通信できるようにするファイアウォール ルールを作成します。

    gcloud compute firewall-rules create per-cluster-a-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-b-acd14479-node"
    

    次のコマンドは、cluster-b Pod IP アドレスが cluster-a ノードと通信することを許可するファイアウォール ルールを作成します。

    gcloud compute firewall-rules create per-cluster-b-pods \
      --allow="tcp,udp,icmp,esp,ah,sctp" \
      --target-tags="gke-cluster-a-9cd18751-node"
    

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

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 Dammam
me-west1 テルアビブ
northamerica-northeast1 モントリオール
northamerica-northeast2 トロント
southamerica-east1 サンパウロ
southamerica-west1 サンチアゴ
us-central1 アイオワ
us-east1 サウスカロライナ
us-east4 北バージニア
us-east5 コロンバス
us-south1 Dallas
us-west1 Oregon
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
    

ID およびアクセス管理を構成する

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

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

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

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

次の手順では、デフォルトのサービス アカウントで Cloud Service Mesh のセキュリティ API にアクセスし、Kubernetes サービス アカウントを作成します。

  1. デフォルトのサービス アカウントが Cloud Service Mesh Security API にアクセスできるように IAM を構成します。

    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
    
  2. Kubernetes サービス アカウントを設定します。次のセクションで説明するクライアントとサーバーのデプロイでは、Kubernetes サーバーとクライアントのサービス アカウント名を使用します。

    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_SERVER_KSA
    kubectl create serviceaccount --namespace K8S_NAMESPACE DEMO_CLIENT_KSA
    
  3. Kubernetes サービス アカウントがデフォルトの Compute Engine サービス アカウントに成り代われるようにするには、両者の間に IAM ポリシー バインディングを作成します。このバインディングにより、Kubernetes サービス アカウントがデフォルトの Compute Engine サービス アカウントとして機能します。

    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_SERVER_KSA]" ${GSA_EMAIL}
    
    gcloud iam service-accounts add-iam-policy-binding  \
      --role roles/iam.workloadIdentityUser  \
      --member "serviceAccount:PROJECT_ID.svc.id.goog[K8S_NAMESPACE/DEMO_CLIENT_KSA]" ${GSA_EMAIL}
    
  4. Kubernetes サービス アカウントにアノテーションを付け、デフォルトの Compute Engine サービス アカウントに関連付けます。

    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_SERVER_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    
    kubectl annotate --namespace K8S_NAMESPACE \
      serviceaccount DEMO_CLIENT_KSA \
      iam.gke.io/gcp-service-account=${GSA_EMAIL}
    

Cloud Service Mesh を設定する

次の手順に沿って、サイドカー インジェクタをインストールし、テストサービスを設定して、他のデプロイタスクを完了します。

クラスタに Envoy サイドカー インジェクタをインストールする

自動 Envoy インジェクションによる GKE Pod での Traffic Director の設定の以下の両セクションの手順に沿って、クラスタで Envoy サイドカー インジェクションをデプロイして有効にします。

テストサービスを設定する前に、両方の手順が完了していることを確認してください。

テストサービスを設定する

Envoy サイドカー インジェクタをインストールしたら、次の手順で Deployment のテストサービスを設定します。

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/service_sample.yaml | sed -e s/DEMO_SERVER_KSA_PLACEHOLDER/DEMO_SERVER_KSA/g > service_sample.yaml

kubectl apply -f service_sample.yaml

ファイル service_sample.yaml には、デモサーバー アプリケーションの PodSpec が含まれています。Cloud Service Mesh セキュリティに固有のアノテーションも含まれます。

Cloud Service Mesh プロキシ メタデータ

PodSpec は proxyMetadata アノテーションを指定します。

spec:
...
      annotations:
        cloud.google.com/proxyMetadata: '{"app": "payments"}'
...

Pod が初期化されると、サイドカー プロキシはこのアノテーションを取得し、Cloud Service Mesh に送信します。Cloud Service Mesh はこの情報を使用して、フィルタされた構成を返します。

  • このガイドの後半では、エンドポイント ポリシーでエンドポイント マッチャーが指定されます。
  • エンドポイント マッチャーは、名前が app、値が payments のラベルを持つクライアントだけがフィルタされた構成を受信するよう指定します。

CA Service によって署名されたメッシュ証明書と鍵を使用する

PodSpec は enableManagedCerts アノテーションを指定します。

spec:
...
      annotations:
        ...
        cloud.google.com/enableManagedCerts: "true"
...

Pod が初期化されると、CA Service の署名付き証明書と鍵が自動的にローカル サイドカー プロキシ ファイル システムにマウントされます。

受信トラフィック インターセプト ポートの構成

PodSpec は includeInboundPorts アノテーションを指定します。

spec:
...
      annotations:
        ...
        cloud.google.com/includeInboundPorts: "8000"
...

これは、サーバー アプリケーションが接続をリッスンするポートです。Pod が初期化されると、サイドカー プロキシはこのアノテーションを取得し、Cloud Service Mesh に送信します。Cloud Service Mesh はこの情報を使用してフィルタされた構成を返します。これにより、このポートへのすべての着信トラフィックが傍受され、セキュリティ ポリシーを適用できます。

ヘルスチェック ポートはアプリケーション ポートとは異なるものにする必要があります。そうしないと、ヘルスチェック ポートへの受信接続に同じセキュリティ ポリシーが適用され、接続が拒否されてサーバーが誤って異常としてマークされる可能性があります。

NEG を使用して GKE サービスを構成する

GKE サービスは、Cloud Service Mesh バックエンド サービスのバックエンドとして構成できるように、ネットワーク エンドポイント グループ(NEG)で公開されている必要があります。この設定ガイドで提供されている service_sample.yaml パッケージは、次のアノテーションで NEG 名 service-test-neg を使用します。

...
metadata:
  annotations:
    cloud.google.com/neg: '{"exposed_ports": {"80":{"name": "service-test-neg"}}}'
spec:
  ports:
  - port: 80
    name: service-test
    protocol: TCP
    targetPort: 8000

service_sample.yaml ファイルを変更する必要はありません。

NEG の名前を保存する

NEG の名前を NEG_NAME 変数に保存します。

NEG_NAME="service-test-neg"

クライアント アプリケーションを GKE にデプロイする

次のコマンドを実行して、Envoy プロキシをサイドカーとして使用するデモ クライアントを起動します。これは、セキュリティ機能のデモに必要です。

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/client_sample.yaml | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > client_sample.yaml

kubectl apply -f client_sample.yaml

クライアント PodSpec には、enableManagedCerts アノテーションのみが含まれます。これは、CA Service インスタンスによって署名された GKE マネージド メッシュ証明書と鍵に必要なボリュームをマウントするために必要です。

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

このセクションでは、Cloud Service Mesh のヘルスチェック、ファイアウォール ルール、バックエンド サービス リソースを作成します。

  1. ヘルスチェックを作成します。

    gcloud compute health-checks create http td-gke-health-check \
      --use-serving-port
    
  2. ヘルス チェッカーの IP アドレス範囲を許可するファイアウォール ルールを作成します。

    gcloud compute firewall-rules create fw-allow-health-checks \
       --action ALLOW \
       --direction INGRESS \
       --source-ranges 35.191.0.0/16,130.211.0.0/22 \
      --rules tcp
    
  3. バックエンド サービスを作成し、バックエンド サービスにヘルスチェックを関連付けます。

    gcloud compute backend-services create td-gke-service \
      --global \
      --health-checks td-gke-health-check \
      --load-balancing-scheme INTERNAL_SELF_MANAGED
    
  4. 前に作成した NEG をバックエンドとしてバックエンド サービスに追加します。

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

Mesh リソースと HTTPRoute リソースを構成する

このセクションでは、Mesh リソースと HTTPRoute リソースを作成します。

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

    name: sidecar-mesh
    interceptionPort: 15001
    

    mesh.yaml ファイルで指定しない場合、インターセプト ポートはデフォルトで 15001 になります。

  2. mesh.yaml 仕様を使用して Mesh リソースを作成します。

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

    PROJECT_ID または PROJECT_NUMBER を使用できます。

    name: helloworld-http-route
    hostnames:
    - service-test
    meshes:
    - projects/PROJNUM/locations/global/meshes/sidecar-mesh
    rules:
    - action:
       destinations:
       - serviceName: "projects/PROJNUM/locations/global/backendServices/td-gke-service"
    
  4. http_route.yaml ファイルの仕様を使用して、HTTPRoute リソースを作成します。

    gcloud network-services http-routes import helloworld-http-route \
      --source=http_route.yaml \
      --location=global
    

Cloud Service Mesh の構成が完了し、認証ポリシーと認可ポリシーを構成できるようになりました。

サービス間のセキュリティを設定する

サービス間のセキュリティを設定するには、次のセクションの手順を使用します。

メッシュで mTLS を有効にする

メッシュに mTLS を設定するには、バックエンド サービスへの送信トラフィックを保護し、エンドポイントへの着信トラフィックを保護する必要があります。

ポリシー参照の形式

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

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

次に例を示します。

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

バックエンド サービスへの送信トラフィックを保護する

送信トラフィックを保護するには、まず次のことを行うクライアント TLS ポリシーを作成します。

  • clientCertificate のプラグインとして google_cloud_private_spiffe を使用します。このプラグインは、Envoy が GKE マネージド メッシュ証明書をクライアント ID として使用するようにプログラミングします。
  • serverValidationCa のプラグインとして google_cloud_private_spiffe を使用します。このプラグインは、Envoy が GKE マネージド メッシュ証明書をサーバー検証に使用するようにプログラミングします。

次に、バックエンド サービスにクライアント TLS ポリシーを接続します。これにより、以下が実行されます。

  • クライアント TLS ポリシーの認証ポリシーを、バックエンド サービスのエンドポイトへの送信接続に適用します。
  • SAN(サブジェクト代替名)は、接続先サーバーの正確な ID を表明するようにクライアントに指示します。
  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. クライアント TLS ポリシーをインポートします。

    gcloud network-security client-tls-policies import client-mtls-policy \
        --source=client-mtls-policy.yaml --location=global
    
  3. クライアント TLS ポリシーをバックエンド サービスに接続します。これにより、クライアントからこのバックエンド サービスへのすべての送信リクエストに mTLS 認証が適用されます。

    gcloud compute backend-services export td-gke-service \
        --global --destination=demo-backend-service.yaml
    

    次の行を demo-backend-service.yaml に追加します。

    securitySettings:
      clientTlsPolicy: projects/PROJECT_ID/locations/global/clientTlsPolicies/client-mtls-policy
      subjectAltNames:
        - "spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA"
    
  4. 次の値をインポートします。

    gcloud compute backend-services import td-gke-service \
        --global --source=demo-backend-service.yaml
    
  5. 必要に応じて、次のコマンドを実行して、リクエストが失敗するかどうかを確認します。クライアントがエンドポイントからの証明書を要求しているものの、エンドポイントがセキュリティ ポリシーでプログラミングされていないため、これは想定内の失敗となります。

    # Get the name of the Podrunning Busybox.
    BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')
    
    # Command to execute that tests connectivity to the service service-test.
    TEST_CMD="wget -q -O - service-test; echo"
    
    # Execute the test command on the pod.
    kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"
    

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

    wget: server returned error: HTTP/1.1 503 Service Unavailable
    

エンドポイントへの受信トラフィックを保護する

受信トラフィックを保護するには、まず、次のことを行うサーバー TLS ポリシーを作成します。

  • serverCertificate のプラグインとして google_cloud_private_spiffe を使用します。このプラグインは、Envoy が GKE マネージド メッシュ証明書をサーバー ID として使用するようにプログラミングします。
  • clientValidationCa のプラグインとして google_cloud_private_spiffe を使用します。これは、Envoy が GKE マネージド メッシュ証明書をクライアント検証に使用するようにプログラミングします。
  1. サーバーの TLS ポリシー値を server-mtls-policy.yaml というファイルに保存します。

    name: "server-mtls-policy"
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    mtlsPolicy:
      clientValidationCa:
      - certificateProviderInstance:
          pluginInstance: google_cloud_private_spiffe
    
  2. サーバーの TLS ポリシーを作成します。

    gcloud network-security server-tls-policies import server-mtls-policy \
        --source=server-mtls-policy.yaml --location=global
    
  3. エンドポイント マッチャーを含む ep_mtls.yaml というファイルを作成し、サーバーの TLS ポリシーを接続します。

    endpointMatcher:
      metadataLabelMatcher:
        metadataLabelMatchCriteria: MATCH_ALL
        metadataLabels:
        - labelName: app
          labelValue: payments
    name: "ep"
    serverTlsPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-mtls-policy
    type: SIDECAR_PROXY
    
  4. エンドポイント マッチャーをインポートします。

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

設定を検証する

次の curl コマンドを実行します。リクエストが正常に完了すると、出力に x-forwarded-client-cert が表示されます。ヘッダーは、接続が mTLS 接続の場合にのみ出力されます。

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

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

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: 10.48.0.6
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

x-forwarded-client-cert ヘッダーはサーバー側の Envoy によって挿入され、独自の ID(サーバー)とソース クライアントの ID が含まれます。クライアント ID とサーバー ID の両方が表示されているため、これは mTLS 接続のシグナルです。

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

この手順では、ホスト名が service-test、ポートが 8000、HTTP メソッドが GETDEMO_CLIENT_KSA アカウントによってリクエストが送信されることを許可する認可ポリシーを作成します。認可ポリシーを作成する前に、認可を使用してアクセスを制限するの注意事項をお読みください。

  1. authz-policy.yaml という名前のファイルを作成して認可ポリシーを作成します。

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        ports:
        - 8000
        methods:
        - GET
    
  2. ポリシーをインポートします。

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

    authorizationPolicy: projects/PROJECT_ID/locations/global/authorizationPolicies/authz-policy
    

    エンドポイント ポリシーでは、Envoy サイドカー プロキシが app:payments というラベルを持つ Pod への受信リクエストに対して、mTLS と認可ポリシーの両方を適用する必要があることを指定しています。

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

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

設定を検証する

次のコマンドを実行して設定を検証します。

# Get the name of the Podrunning Busybox.
BUSYBOX_POD=$(kubectl get po -l run=client -o=jsonpath='{.items[0].metadata.name}')

# Command to execute that tests connectivity to the service service-test.
# This is a valid request and will be allowed.
TEST_CMD="wget -q -O - service-test; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

予想される出力は次のようになります。

GET /get HTTP/1.1
Host: service-test
content-length: 0
x-envoy-internal: true
accept: */*
x-forwarded-for: redacted
x-envoy-expected-rq-timeout-ms: 15000
user-agent: curl/7.35.0
x-forwarded-proto: http
x-request-id: redacted
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA

次のコマンドを実行して、認可ポリシーが無効なリクエストを正しく却下するどうかをテストします。

# Failure case
# Command to execute that tests connectivity to the service service-test.
# This is an invalid request and server will reject because the server
# authorization policy only allows GET requests.
TEST_CMD="wget -q -O - service-test --post-data='' ; echo"

# Execute the test command on the pod.
kubectl exec -it $BUSYBOX_POD -c busybox -- /bin/sh -c "$TEST_CMD"

予想される出力は次のようになります。

<RBAC: access denied HTTP/1.1 403 Forbidden>

GKE のサイドカーで認可ポリシーを設定する

このセクションでは、GKE の Cloud Service Mesh サイドカーにさまざまな種類の認可ポリシーを設定する方法について説明します。

認可ポリシーを作成する前に、GCPAuthzPolicy CustomResourceDefinition(CRD)をインストールする必要があります。

curl https://github.com/GoogleCloudPlatform/gke-networking-recipes/blob/main/gateway-api/config/mesh/crd/experimental/gcpauthzpolicy.yaml \
| kubectl apply -f -

リクエストを拒否する認可ポリシー

cron ジョブなど、発信のみを行うワークロードがある場合は、ワークロードへの受信 HTTP リクエストを拒否するように認可ポリシーを構成できます。次の例では、ワークロード example-app への受信 HTTP リクエストを拒否します。

次のステップを実行して、拒否認可ポリシーを作成して適用します。

  1. deny-all-authz-policy.yaml という名前のファイルを作成してカスタム ポリシーを作成します。

    cat >deny-all-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - to:
        operations:
        - paths:
          - type: Prefix
            value: "/"
    action: DENY
    EOF
    
  2. ポリシーを適用します。

    kubectl apply -f deny-all-authz-policy.yaml
    

リクエストを許可する認可ポリシー

特定の条件に一致するリクエストのみを許可し、残りを拒否する許可ポリシーを構成することもできます。次の例では、ID が spiffee://cluster.local/ns1/pod1 の Pod からの mTLS リクエストのみを許可するように、example-app Deployment で認可ポリシーを構成します。

次のステップを実行して、許可認可ポリシーを作成して適用します。

  1. allow-authz-policy.yaml という名前のファイルを作成してカスタム ポリシーを作成します。

    cat >allow-authz-policy.yaml <<EOF
    apiVersion: networking.gke.io/v1
    kind: GCPAuthzPolicy
    metadata:
      name: my-workload-authz
      namespace: ns1
    spec:
    targetRefs:
    - kind: Deployment
      name: example-app
    httpRules:
    - from:
        sources:
        - principals:
          - type: Exact
            value: "spiffee://cluster.local/ns1/pod1"
    action: ALLOW
    EOF
    
  2. ポリシーを適用します。

    kubectl apply -f allow-authz-policy.yaml
    

Ingress ゲートウェイ セキュリティを設定する

このセクションは、サイドカー自動インジェクタを使用した GKE クラスタの設定、認証局の作成、エンドポイント ポリシーの作成など、サービス間のセキュリティ セクションを完了していることを前提としています。

このセクションでは、TLS 接続を終端し、クラスタの内部クライアントからのリクエストを承認する Ingress ゲートウェイとして Envoy プロキシをデプロイします。

Ingress ゲートウェイでの TLS の終端(クリックして拡大)
Ingress ゲートウェイでの TLS の終端(クリックして拡大)

TLS を終端するように Ingress ゲートウェイを設定する手順は次のとおりです。

  1. クラスタの内部 IP アドレスを使用して到達可能な Kubernetes Service をデプロイします。
    1. このデプロイは、Kubernetes Service として公開され、Cloud Service Mesh に接続するスタンドアロンの Envoy プロキシで構成されています。
  2. TLS を終端するサーバー TLS ポリシーを作成します。
  3. 受信リクエストを認可する認可ポリシーを作成します。

Ingress ゲートウェイ サービスを GKE にデプロイする

次のコマンドを実行して、GKE に Ingress ゲートウェイ サービスをデプロイします。

wget -q -O -  https://storage.googleapis.com/traffic-director/security/ga/gateway_sample_xdsv3.yaml | sed -e s/PROJECT_NUMBER_PLACEHOLDER/PROJNUM/g | sed -e s/NETWORK_PLACEHOLDER/default/g | sed -e s/DEMO_CLIENT_KSA_PLACEHOLDER/DEMO_CLIENT_KSA/g > gateway_sample.yaml

kubectl apply -f gateway_sample.yaml

ファイル gateway_sample.yaml は Ingress ゲートウェイの仕様です。以下のセクションでは、この仕様への追加について説明します。

Cloud Service Mesh サイドカー インジェクションの無効化

gateway_sample.yaml 仕様では、Envoy プロキシを唯一のコンテナとしてデプロイします。前のステップでは、Envoy をサイドカーとしてアプリケーション コンテナに挿入しました。複数の Envoy でリクエストを処理しないように、次のステートメントを使用して、この Kubernetes Service のサイドカー インジェクションを無効にできます。

sidecar.istio.io/inject: "false"

正しいボリュームをマウントする

gateway_sample.yaml 仕様ではボリューム gke-workload-certificates をマウントします。このボリュームはサイドカーのデプロイでも使用されますが、アノテーション cloud.google.com/enableManagedCerts: "true" が検出されると、サイドカー インジェクタによって自動的に追加されます。gke-workload-certificates ボリュームには、設定した CA Service インスタンスによって署名される GKE マネージド SPIFFE 証明書と鍵が含まれます。

クラスタの内部 IP アドレスを設定する

ClusterInternal タイプのサービスを使用して Ingress ゲートウェイを構成します。これにより、mesh-gateway の内部解決可能な DNS ホスト名が作成されます。クライアントが mesh-gateway:443 にリクエストを送信すると、Kubernetes はすぐにリクエストを Ingress ゲートウェイ Envoy デプロイのポート 8080 にルーティングします。

Ingress ゲートウェイで TLS を有効にする

Ingress ゲートウェイで TLS を有効にする手順は次のとおりです。

  1. server-tls-policy.yaml という名前のファイル内の値を使用して、TLS 接続を終了するサーバー TLS ポリシー リソースを作成します。

    description: tls server policy
    name: server-tls-policy
    serverCertificate:
      certificateProviderInstance:
        pluginInstance: google_cloud_private_spiffe
    
  2. サーバーの TLS ポリシーをインポートします。

    gcloud network-security server-tls-policies import server-tls-policy \
        --source=server-tls-policy.yaml --location=global
    
  3. 新しいターゲット Gateway を作成し、td-gke-gateway.yaml ファイルに保存します。これにより、サーバー TLS ポリシーが接続され、受信 TLS トラフィックを終了するように Envoy プロキシ Ingress ゲートウェイが構成されます。

    name: td-gke-gateway
    scope: gateway-proxy
    ports:
    - 8080
    type: OPEN_MESH
    serverTLSPolicy: projects/PROJECT_ID/locations/global/serverTlsPolicies/server-tls-policy
    
  4. ゲートウェイをインポートします。

    gcloud network-services gateways import td-gke-gateway \
      --source=td-gke-gateway.yaml \
      --location=global
    
  5. ゲートウェイを参照してすべてのリクエストを td-gke-service に転送する、td-gke-route という新しい HTTPRoute を作成して保存します。

    name: td-gke-route
    hostnames:
    - mesh-gateway
    gateways:
    - projects/PROJECT_NUMBER/locations/global/gateways/td-gke-gateway
    rules:
    - action:
        destinations:
        - serviceName: "projects/PROJECT_NUMBER/locations/global/backendServices/td-gke-service"
    
  6. HTTPRoute をインポートします。

    gcloud network-services httproutes import td-gke-route \
      --source=td-gke-route.yaml \
      --location=global
    
    
  7. 必要に応じて、以下のすべての条件が満たされる場合に、バックエンドの承認ポリシーを更新し、リクエストを許可します。

    • DEMO_CLIENT_KSA によって送信されたリクエスト。(Ingress ゲートウェイのデプロイでは、DEMO_CLIENT_KSA サービス アカウントが使用されます。)
    • ホストが mesh-gateway または service-test のリクエスト
    • ポート: 8000

    バックエンドの認可ポリシーを構成していない限り、これらのコマンドを実行する必要はありません。エンドポイントに認可ポリシーがない場合、または認可ポリシーにホストまたはソースのプリンシパルの一致が含まれない場合、このステップなしでリクエストが許可されます。これらの値を authz-policy.yaml に追加します。

    action: ALLOW
    name: authz-policy
    rules:
    - sources:
      - principals:
        - spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
      destinations:
      - hosts:
        - service-test
        - mesh-gateway
        ports:
        - 8000
        methods:
        - GET
    
  8. ポリシーをインポートします。

    gcloud network-security authorization-policies import authz-policy \
      --source=authz-policy.yaml \
      --location=global
    

Ingress ゲートウェイの Deployment を検証する

debug という新しいコンテナを使用して Ingress ゲートウェイにリクエストを送信し、Deployment を検証します。

次の仕様では、アノテーション "sidecar.istio.io/inject":"false" によって Cloud Service Mesh サイドカー インジェクタがサイドカー プロキシを自動的に挿入しないようにしています。リクエスト ルーティングで debug コンテナをサポートするサイドカーはありません。コンテナは、ルーティングのために Ingress ゲートウェイに接続する必要があります。

この仕様には、サーバー証明書の検証を無視する --no-check-certificate フラグが含まれています。debug コンテナには、TLS を終了するために Ingress ゲートウェイが使用する、CA Service によって署名された有効な証明書に必要な認証局検証証明書がありません。

本番環境では、CA Service の検証証明書をダウンロードし、それをクライアントにマウントまたはインストールすることをおすすめします。検証証明書をインストールしたら、wget コマンドの --no-check-certificate オプションを削除します。

次のコマンドを実行します。

kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway; echo"

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

GET / HTTP/1.1
Host: 10.68.7.132
x-forwarded-client-cert: By=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_SERVER_KSA;Hash=Redacted;Subject="Redacted;URI=spiffe://PROJECT_ID.svc.id.goog/ns/K8S_NAMESPACE/sa/DEMO_CLIENT_KSA
x-envoy-expected-rq-timeout-ms: 15000
x-envoy-internal: true
x-request-id: 5ae429e7-0e18-4bd9-bb79-4e4149cf8fef
x-forwarded-for: 10.64.0.53
x-forwarded-proto: https
content-length: 0
user-agent: Wget

次のネガティブ テスト コマンドを実行します。

# Negative test
# Expect this to fail because gateway expects TLS.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - http://mesh-gateway:443/headers; echo"

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

wget: error getting response: Connection reset by peer

次のネガティブ テスト コマンドを実行します。

# Negative test.
# AuthorizationPolicy applied on the endpoints expect a GET request. Otherwise
# the request is denied authorization.
kubectl run -i --tty --rm debug --image=busybox --restart=Never  --overrides='{ "metadata": {"annotations": { "sidecar.istio.io/inject":"false" } } }'  -- /bin/sh -c "wget --no-check-certificate -qS -O - https://mesh-gateway --post-data=''; echo"

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

HTTP/1.1 403 Forbidden
wget: server returned error: HTTP/1.1 403 Forbidden

Deployment を削除する

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

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

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

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

gcloud compute backend-services delete td-gke-service --global --quiet
cloud compute network-endpoint-groups delete service-test-neg --zone ZONE --quiet
gcloud compute firewall-rules delete fw-allow-health-checks --quiet
gcloud compute health-checks delete td-gke-health-check --quiet
gcloud network-services endpoint-policies delete ep \
    --location=global --quiet
gcloud network-security authorization-policies delete authz-gateway-policy \
   --location=global --quiet
gcloud network-security authorization-policies delete 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

制限事項

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

トラブルシューティング

このセクションでは、セキュリティ サービスの設定中に発生した問題を修正する方法について説明します。

接続エラー

upstream connect エラーまたは disconnect/reset before headers エラーで接続が失敗した場合は、Envoy のログを調べます。次のいずれかのログメッセージが表示される場合があります。

gRPC config stream closed: 5, Requested entity was not found

gRPC config stream closed: 2, no credential token is found

Envoy のログにこれらのエラーが記録されている場合は、サービス アカウント トークンが正しくマウントされていないか、別の audience が使用されている、またはその両方の可能性があります。

詳細については、Envoy のログのエラー メッセージが構成の問題を示しているをご覧ください。

Pod が作成されない

この問題のトラブルシューティングを行うには、GKE Pod の自動デプロイのトラブルシューティングをご覧ください。

Envoy が Cloud Service Mesh で認証されない

Envoy(envoy-proxy)が Cloud Service Mesh に接続して xDS 構成を取得する場合、(ブートストラップが変更されている場合を除き)GKE 用 Workload Identity 連携と Compute Engine VM のデフォルト サービス アカウントを使用します。認証に失敗した場合、Envoy は準備完了状態になりません。

--workload-identity-certificate-authority flag を指定してクラスタを作成できない

このエラーが表示された場合は、Google Cloud CLI の最新バージョンを実行していることを確認してください。

gcloud components update

Pod が保留状態のままになる

設定プロセス中に 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 フィールドに表示されます。

アプリケーションで発行済みの 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 メッシュ証明書は、単一の信頼ドメインにあるワークロード間の通信をサポートします。