IAP と Anthos Service Mesh の統合

このガイドでは、Identity-Aware Proxy(IAP)を Anthos Service Mesh と統合する方法について説明します。IAP を Anthos Service Mesh と統合すると、Google の BeyondCorp の原則に基づいて、サービスに安全にアクセスできるようになります。IAP は、ユーザー ID とリクエストのコンテキストを確認し、ユーザーにアプリケーションまたはリソースへのアクセスを許可するかどうかを決定します。IAP を Anthos Service Mesh と統合すると、次のメリットがあります。

  • Anthos Service Mesh で実行されるワークロードに対するコンテキストアウェア アクセスの制御。発信元リクエストの属性(ユーザー ID、IP アドレス、デバイスの種類など)に基づいて、きめ細かいアクセス ポリシーを設定できます。リクエスト URL のホスト名とパスに基づいて、アクセス ポリシーと制限を組み合わせることができます。

  • Anthos Service Mesh 認証におけるコンテキストアウェア クレームのサポート。

  • Google Cloud ロードバランサを介したアプリケーションに対する、スケーラブルで安全かつ可用性の高いアクセス。高パフォーマンスの負荷分散では、組み込みの保護機能で分散型サービス拒否(DDoS)攻撃を防ぎ、グローバルなエニーキャスト IP アドレスを使用できます。

前提事項

このガイドでは、次の準備ができていることを前提としています。

Anthos Service Mesh によるクラスタの設定

IAP の統合には、プロジェクト、クラスタ、Anthos Service Mesh のインストール時に使用する構成ファイルに関する特定の設定が必要です。

新規インストール

このセクションの手順は、GKE での高度なインストールガイドの手順を補完するものです。これらの手順では、インストール ガイドで作成した環境変数を使用します。

  1. プロジェクトを設定するときに、必要な他の API に加えて iap.googleapis.com も有効にします。

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. クラスタを更新するときに、クラスタに必要な他の更新に加えて、HttpLoadBalancing アドオンも有効にします。HttpLoadBalancing アドオンを使用すると、クラスタの HTTP(L7)負荷分散コントローラが有効になります。

    gcloud container clusters update ${CLUSTER_NAME} \
      --project=PROJECT_ID \
      --update-addons=HttpLoadBalancing=ENABLED
    

    デフォルトのゾーンまたはリージョンを設定しなかった場合、前のコマンドでリージョン(--region=${CLUSTER_LOCATION})またはゾーン(--zone=${CLUSTER_LOCATION})を指定する必要があります。

  3. クラスタを更新したら、インストール ガイドに沿って、認証情報と権限を設定し、インストール ファイルをダウンロードします。リソース構成ファイルの準備のところで作業を止めて、次の操作を行います。

    1. Anthos Service Mesh パッケージのリソース構成ファイル用に新しいディレクトリを作成します。クラスタ名をディレクトリ名として使用することをおすすめします。

    2. Anthos Service Mesh パッケージをダウンロードするディレクトリに変更します。

    3. asm-iap パッケージをダウンロードします。このパッケージは、istio-ingressgateway サービスの type フィールドを NodePort に設定します。この構成では、istio-ingressgateway はサービス メッシュで特定のポートを開きます。また、ドメイン名に送信されたトラフィックがこのポートに転送されるようにロードバランサを設定できます。

      kpt pkg get https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages.git/asm-iap@release-1.6-asm asm
      
    4. クラスタが作成されたプロジェクトのプロジェクト ID を設定します。

      kpt cfg set asm gcloud.core.project PROJECT_ID
      
    5. フリート ホスト プロジェクトのプロジェクト番号を設定します。

      kpt cfg set asm gcloud.project.environProjectNumber ${FLEET_PROJECT_NUMBER}
      
    6. クラスタ名を設定します。

      kpt cfg set asm gcloud.container.cluster ${CLUSTER_NAME}
      
    7. デフォルトのゾーンまたはリージョンを設定します。

      kpt cfg set asm gcloud.compute.location ${CLUSTER_LOCATION}
      
    8. リビジョン ラベルを使用するように Webhook の検証を設定します。

      kpt cfg set asm anthos.servicemesh.rev asm-1614-2
      
    9. 構成プロファイルを設定します。IAP 統合では、asm-gcp プロファイルを設定します。

      kpt cfg set asm anthos.servicemesh.profile asm-gcp
      
    10. ロードバランサの HTTP とステータス ポートを設定します。デフォルトのステータス ポートは 31223、デフォルトの HTTP ポートは 31224 です。これらのポートがすでに使用されている場合は、以下のポートを設定します。

      kpt cfg set asm gcloud.container.cluster.ingress.httpPort HTTP_PORT
      
      kpt cfg set asm gcloud.container.cluster.ingress.statusPort STATUS_PORT
      
    11. kpt セッターの値を出力します。

      kpt cfg list-setters asm
      

      コマンドの出力で、次のセッターの値が正しいことを確認します。

      • anthos.servicemesh.rev
      • gcloud.compute.location
      • gcloud.container.cluster
      • gcloud.container.cluster.ingress.httpPort
      • gcloud.container.cluster.ingress.statusPort
      • gcloud.core.project
      • gcloud.project.environProjectNumber
  4. Anthos Service Mesh のインストール セクションのインストール ガイドに進みます。Anthos Service Mesh のインストール後、このガイドに戻り、次のセクションに進んで IAP との統合を設定します。

アップグレード

このセクションの手順は、GKE での Anthos Service Mesh のアップグレードの手順を補完するものです。これらの手順では、アップグレード ガイドで作成した環境変数を使用します。このセクションでは、次のアップグレードのユースケースについて説明します。

  • IAP 統合はすでにセットアップ済みで、Anthos Service Mesh をアップグレードする。この例では、プロジェクトで iap.googleapis.com が、クラスタで HttpLoadBalancing アドオンがすでに有効になっているため、ステップ 3 までスキップできます。

  • Anthos Service Mesh をアップグレードし、初めて IAP との統合を設定する。この場合、以下の手順をすべて完了し、Anthos Service Mesh をアップグレードします。アップグレードが完了したらこのガイドに戻り、統合を完了します。

  1. iap.googleapis.com を有効にします。

    gcloud services enable \
      --project=$PROJECT_ID \
      iap.googleapis.com
    
  2. HttpLoadBalancing アドオンを有効にします。HttpLoadBalancing アドオンを使用すると、クラスタの HTTP(L7)負荷分散コントローラが有効になります。

    gcloud container clusters update ${CLUSTER_NAME} \
      --project=PROJECT_ID \
      --update-addons=HttpLoadBalancing=ENABLED
    

    デフォルトのゾーンまたはリージョンを設定しなかった場合、前のコマンドでリージョン(--region=${CLUSTER_LOCATION})またはゾーン(--zone=${CLUSTER_LOCATION})を指定する必要があります。

  3. アップグレード ガイドに沿って、認証情報と権限を設定し、インストール ファイルをダウンロードしてください。リソース構成ファイルの準備のところで作業を止めて、次の操作を行います。

    1. Anthos Service Mesh パッケージのリソース構成ファイル用に新しいディレクトリを作成します。クラスタ名をディレクトリ名として使用することをおすすめします。

    2. Anthos Service Mesh パッケージをダウンロードするディレクトリに変更します。

    3. asm-iap パッケージをダウンロードします。このパッケージは、istio-ingressgateway サービスの type フィールドを NodePort に設定します。この構成では、istio-ingressgateway はサービス メッシュで特定のポートを開きます。また、ドメイン名に送信されたトラフィックがこのポートに転送されるようにロードバランサを設定できます。

      kpt pkg get https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages.git/asm-iap@release-1.6-asm asm
      
    4. クラスタが作成されたプロジェクトのプロジェクト ID を設定します。

      kpt cfg set asm gcloud.core.project PROJECT_ID
      
    5. フリート ホスト プロジェクトのプロジェクト番号を設定します。

      kpt cfg set asm gcloud.project.environProjectNumber ${FLEET_PROJECT_NUMBER}
      
    6. クラスタ名を設定します。

      kpt cfg set asm gcloud.container.cluster ${CLUSTER_NAME}
      
    7. デフォルトのゾーンまたはリージョンを設定します。

      kpt cfg set asm gcloud.compute.location ${CLUSTER_LOCATION}
      
    8. リビジョン ラベルを使用するように Webhook の検証を設定します。

      kpt cfg set asm anthos.servicemesh.rev asm-1614-2
      
    9. 構成プロファイルを設定します。IAP 統合では、asm-gcp プロファイルを設定します。

      kpt cfg set asm anthos.servicemesh.profile asm-gcp
      
    10. ロードバランサの HTTP とステータス ポートを設定します。デフォルトのステータス ポートは 31223、デフォルトの HTTP ポートは 31224 です。

      既存の HTTP Cloud ロードバランサを更新する場合は、次のコマンドを実行して既存の HTTP ポートとステータス ポートを保持してください。

      kpt cfg set asm gcloud.container.cluster.ingress.httpPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
      
      kpt cfg set asm gcloud.container.cluster.ingress.statusPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')
      

      必要に応じて、上記の kpt セッターを使用して、ポートの他の値を設定できます。

    11. kpt セッターの値を出力します。

      kpt cfg list-setters asm
      

      コマンドの出力で、次のセッターの値が正しいことを確認します。

      • anthos.servicemesh.rev
      • gcloud.compute.location
      • gcloud.container.cluster
      • gcloud.container.cluster.ingress.httpPort
      • gcloud.container.cluster.ingress.statusPort
      • gcloud.core.project
      • gcloud.project.environProjectNumber
  4. Anthos Service Mesh のアップグレード セクションのアップグレード ガイドをご覧ください。

静的 IP アドレスの予約と DNS の構成

Identity-Aware Proxy を Anthos Service Mesh と統合するには、Google Cloud HTTP(S) ロードバランサを設定する必要があります。この設定では、静的 IP アドレスを参照するドメイン名が必要です。静的外部 IP アドレスを予約すると、明示的に解放するまで、このアドレスを無期限でプロジェクトに割り当てることができます。

  1. 静的外部 IP アドレスを予約します。

    gcloud compute addresses create example-static-ip --global
    
  2. 静的 IP アドレスを取得します。

    gcloud compute addresses describe example-static-ip --global
    
  3. ドメイン名登録事業者で、静的 IP アドレスを含む完全修飾ドメイン名(FQDN)を構成します。通常、DNS 設定に A レコードを追加します。FQDN の A レコードを追加する構成手順と用語は、使用するドメイン名登録事業者によって異なります。

    DNS 設定が反映されるまでに、24~48 時間かかります。このガイドに従って引き続き設定を行うことはできますが、DNS 設定が反映されるまで設定のテストはできません。

サンプル アプリケーションのデプロイ

IAP を有効にする前に、GKE クラスタでアプリケーションを実行して、すべてのリクエストに ID があることを確認する必要があります。このガイドでは、Bookinfo サンプルを使用して、HTTP(S) ロードバランサを設定して IAP を有効にします。

Bookinfo をデプロイします。ロードバランサをデプロイするまで、Bookinfo アプリケーションは GKE クラスタの外部(ブラウザなど)からアクセスできません。

外部リクエスト

Bookinfo のゲートウェイ リソース(samples/bookinfo/networking/bookinfo-gateway.yaml で定義)は、事前構成の istio-ingressgateway を使用します。Anthos Service Mesh をデプロイするときに、istio-ingressgatewayNodePort を指定しました。これにより、サービス メッシュで特定のポートが開きます。クラスタ内のノードには外部 IP アドレスが設定されていますが、クラスタの外部からのリクエストは Google Cloud ファイアウォール ルールによってブロックされます。IAP を使用すると、ロードバランサを使用してアプリケーションを公共のインターネットに公開できます。IAP をバイパスするファイアウォール ルールを使用してノードアドレスを公開しないでください。

Bookinfo にリクエストをルーティングするには、Google Cloud プロジェクトに HTTP(S) ロードバランサを設定します。ロードバランサはプロジェクト内にあります。これはファイアウォールの内側にあるため、クラスタ内のノードにアクセスできます。静的 IP アドレスとドメイン名を使用してロードバランサを構成すると、ドメイン名にリクエストを送信できるようになります。ロードバランサは、これらのリクエストをクラスタ内のノードに転送します。

IAP の有効化

IAP を有効にする手順は以下のとおりです。

  1. list コマンドを使用して、既存のブランドがあるかどうかを確認します。1 つのプロジェクトで使用できるブランドは 1 つだけです。

    gcloud iap oauth-brands list
    

    ブランドがある場合の gcloud のレスポンスは次のとおりです。

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    
  2. ブランドが存在しない場合は、create コマンドを使用します。

    gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL
    

    上記のフィールドは、この API を呼び出すときに必要になります。

    • supportEmail: OAuth 同意画面に表示されるサポートメール。このメールアドレスは、ユーザーのアドレスでも、Google グループのエイリアスでもかまいません。サービス アカウントにもメールアドレスがありますが、これは実際のメールアドレスではないため、ブランドの作成には使用できません。ただし、サービス アカウントは Google グループのオーナーに設定できます。新しい Google グループを作成するか、既存のグループを構成し、目的のサービス アカウントをそのグループのオーナーに設定します。

    • applicationTitle: OAuth 同意画面に表示されるアプリケーション名。

    レスポンスには、次のフィールドが含まれます。

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    

IAP OAuth クライアントの作成

  1. create コマンドを使用してクライアントを作成します。前のステップのブランド name を使用します。

    gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME
    

    レスポンスには、次のフィールドが含まれます。

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]/identityAwareProxyClients/[CLIENT_ID]
    secret: [CLIENT_SECRET]
    displayName: [NAME]
    
  2. クライアント ID(上記の手順では CLIENT_ID)と CLIENT_SECRET を使用して IAP を有効にします。OAuth クライアントのマテリアルを使用して Kubernetes Secret を作成します。

    kubectl create secret generic -n istio-system my-secret --from-literal=client_id=CLIENT_ID \
    --from-literal=client_secret=CLIENT_SECRET
    

ロードバランサのデプロイ

Ingress リソースを使用すると、自動構成の SSL 証明書で HTTP(S) ロードバランサを作成できます。Google マネージド SSL 証明書はドメインに対してプロビジョニング、更新、管理が行われます。

  1. ManagedCertificate リソースを作成します。このリソースは、SSL 証明書のドメインを指定します。spec.domains リストに複数のドメインを入れることはできません。ワイルドカード ドメインはサポートされていません。次の YAML で、DOMAIN_NAME を外部静的 IP アドレス用に構成したドメイン名に置き換えます。

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.gke.io/v1beta1
    kind: ManagedCertificate
    metadata:
      name: example-certificate
      namespace: istio-system
    spec:
      domains:
        - DOMAIN_NAME
    EOF
  2. BackendConfig リソースを作成します。このリソースは、Ingress Gateway でヘルスチェックを実行する方法と Identity-Aware Proxy の構成方法を GCLB に指示します。まず、Ingress Gateway からヘルスチェックに関するいくつかの値を収集します。

    • ヘルスチェックの Ingress ポート: istio-ingress のヘルスチェック ポート。

      export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')

    • ヘルスチェック Ingress パス: istio-ingress のヘルスチェック パス。

      export HC_INGRESS_PATH=$(kubectl -n istio-system get deployments istio-ingressgateway -o jsonpath='{.spec.template.spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')

    cat <<EOF | kubectl apply -n istio-system -f -
    apiVersion: cloud.google.com/v1beta1
    kind: BackendConfig
    metadata:
      name: http-hc-config
    spec:
      healthCheck:
        checkIntervalSec: 2
        timeoutSec: 1
        healthyThreshold: 1
        unhealthyThreshold: 10
        port: ${HC_INGRESS_PORT}
        type: HTTP
        requestPath: ${HC_INGRESS_PATH}
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: my-secret
    EOF
  3. Ingress サービスに BackendConfig のアノテーションを付けます。

        kubectl annotate -n istio-system service/istio-ingressgateway --overwrite \
          cloud.google.com/backend-config='{"default": "http-hc-config"}' \
          cloud.google.com/neg='{"ingress":false}'
    
  4. ロードバランサを作成するには、Ingress リソースを定義します。

    • 前の手順で作成した証明書の名前 example-certificatenetworking.gke.io/managed-certificates アノテーションに設定します。

    • 予約した静的 IP アドレスの名前 example-static-ipkubernetes.io/ingress.global-static-ip-name アノテーションに設定します。

    • serviceNameistio-ingressgateway に設定します。これは、Bookinfo サンプルのゲートウェイ リソースで使用されます。

    cat <<EOF | kubectl create -f -
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: istio-system
      annotations:
        kubernetes.io/ingress.global-static-ip-name: example-static-ip
        networking.gke.io/managed-certificates: example-certificate
    spec:
      backend:
        serviceName: istio-ingressgateway
        servicePort: 80
    EOF
  5. Google Cloud コンソールで、[Kubernetes Engine] > [Services と Ingress] ページに移動します。

    [Services と Ingress] ページに移動

    [ステータス] 列に「Creating Ingress」と表示されます。GKE に Ingress が完全にプロビジョニングされてから次に進みます。数分ごとにページを更新し、Ingress の最新ステータスを確認します。Ingress がプロビジョニングされると、「OK」ステータスが表示されるか、「All backend services are in UNHEALTHY state.」というエラーが表示されます。デフォルトのヘルスチェックでは、GKE がプロビジョニングするリソースの 1 つが対象になります。エラー メッセージが表示された場合、Ingress がプロビジョニングされ、デフォルトのヘルスチェックが実行されています。「OK」ステータスまたはエラーが表示されている場合は、次のセクションでロードバランサのヘルスチェックを構成します。

IAP アクセスリストを構成する

IAP のアクセス ポリシーにユーザーを追加するには:

gcloud beta iap web add-iam-policy-binding \
    --member=user:EMAIL_ADDRESS \
    --role=roles/iap.httpsResourceAccessor

EMAIL_ADDRESS は、ユーザーの完全なメールアドレスです(例: alice@example.com)。

  1. ロードバランサをテストします。ブラウザで次の URL にアクセスします。

    http://DOMAIN_NAME/productpage

    ここで、DOMAIN_NAME は、外部静的 IP アドレスで構成したドメイン名です。

    Bookinfo アプリケーションの productpage が表示されます。ページを複数回更新すると、さまざまなバージョンのビューがラウンドロビン スタイル(赤い星、黒い星、星なし)で表示されます。

    Bookinfo への https アクセスもテストする必要があります。

サービス メッシュで RCToken サポートを有効にする

デフォルトでは、IAP は OAuth クライアントをスコープとする JSON Web Token(JWT)を生成します。Anthos Service Mesh では、RequestContextToken(RCToken)を生成するように IAP を構成できます。これは、JWT ですが、オーディエンスは構成可能です。RCToken を使用すると、JWT のオーディエンスに任意の文字列を構成できます。これを Anthos Service Mesh ポリシーで使用し、きめ細かい認証を実施できます。

RCToken を構成するには:

  1. プロジェクト番号の環境変数を作成します。これは、プロジェクトの作成時に自動的に生成され、割り当てられた番号です(プロジェクト ID とは異なります)。

    export PROJECT_NUMBER=YOUR_PROJECT_NUMBER
  2. RCToken オーディエンスの環境変数を作成します。任意の文字列を指定できます。

    export RCTOKEN_AUD="your-rctoken-aud"
    
  3. 既存の IAP 設定を取得します。

    gcloud beta iap settings get --format json \
    --project=${PROJECT_NUMBER} --resource-type=compute > iapSettings.json
    
  4. RCToken オーディエンスで IapSettings を更新します。

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > updatedIapSettings.json
    
    gcloud beta iap settings set updatedIapSettings.json --format json \
    --project=${PROJECT_NUMBER} --resource-type=compute
    
  5. Istio Ingress ゲートウェイで RCToken 認証を有効にします。

    cat <<EOF | kubectl apply -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "RequestAuthentication"
    metadata:
      name: "ingressgateway-jwt-policy"
      namespace: "istio-system"
    spec:
      selector:
        matchLabels:
          app: istio-ingressgateway
      jwtRules:
      - issuer: "https://cloud.google.com/iap"
        jwksUri: "https://www.gstatic.com/iap/verify/public_key-jwk"
        audiences:
        - $RCTOKEN_AUD
        fromHeaders:
        - name: ingress-authorization
          prefix: "Istio "
        outputPayloadToHeader: "verified-jwt"
        forwardOriginalToken: true
    EOF
    
  6. Bookinfo productpage へのリクエストが成功していることを確認します。

    http://DOMAIN_NAME/productpage

ポリシーをテストするには:

  1. IapSettings リクエスト オブジェクトを作成します。ただし、rctokenAud には別の文字列を設定します。

    echo $(cat <<EOF
    {
       "name": "projects/${PROJECT_NUMBER}/iap_web/compute",
       "applicationSettings": {
         "csmSettings": {
           "rctokenAud": "some-other-arbitrary-string"
         }
       }
     }
    EOF
    ) > request.txt
  2. IapSettings API を呼び出して、RCtoken オーディエンスを設定します。

    curl --request PATCH --header "Authorization: Bearer $(gcloud beta auth application-default print-access-token)" ${IAP_SETTINGS_API}
  3. Bookinfo productpage にリクエストを送信すると失敗します。

    http://DOMAIN_NAME/productpage

クリーンアップ

このチュートリアルを完了したら、アカウントで不要な請求が発生しないように、以下のリソースを削除します。

  1. マネージド証明書を削除します。

    kubectl delete managedcertificates example-certificate
  2. Ingress を削除します。これにより、負荷分散リソースの割り当てが解除されます。

    kubectl -n istio-system delete ingress example-ingress

  3. 静的 IP アドレスを削除します。

    gcloud compute addresses delete example-static-ip --global

    これを行う場合は、ドメイン登録事業者から IP アドレスを削除してください。

  4. クラスタを削除します。これにより、クラスタを構成するリソース(コンピューティング インスタンス、ディスク、ネットワーク リソースなど)が削除されます。

    gcloud container clusters delete ${CLUSTER_NAME}