IAP を Cloud Service Mesh と統合する
このガイドでは、Identity-Aware Proxy(IAP)を Cloud Service Mesh と統合する方法について説明します。IAP を Cloud Service Meshh と統合すると、Google の BeyondCorp の原則に基づいて、サービスに安全にアクセスできるようになります。IAP は、ユーザー ID とリクエストのコンテキストを確認し、ユーザーにアプリケーションまたはリソースへのアクセスを許可するかどうかを決定します。IAP を Cloud Service Mesh と統合すると、次のメリットがあります。
Cloud Service Mesh で実行されるワークロードに対するコンテキストアウェア アクセスの制御。発信元リクエストの属性(ユーザー ID、IP アドレス、デバイスの種類など)に基づいて、きめ細かいアクセス ポリシーを設定できます。リクエスト URL のホスト名とパスに基づいて、アクセス ポリシーと制限を組み合わせることができます。
Cloud Service Mesh 認証におけるコンテキストアウェア クレームのサポート。
Google Cloud ロードバランサを介したアプリケーションに対する、スケーラブルで安全かつ可用性の高いアクセス。高パフォーマンスの負荷分散では、組み込みの保護機能で分散型サービス拒否(DDoS)攻撃を防ぎ、グローバルなエニーキャスト IP アドレスを使用できます。
前提条件
依存ツールのインストールとクラスタの検証の手順に沿って、次の操作を行います。さらに、このガイドでは、次の準備ができていることを前提としています。
Cloud Service Mesh によるクラスタの設定
このセクションでは、新しくインストールされた Cloud Service Mesh とアップグレードの IAP 統合を設定する方法について説明します。
新規インストール
iap.googleapis.com
を有効にします。次のコマンドで、PROJECT_ID
を Cloud Service Mesh をインストールするプロジェクトに置き換えます。gcloud services enable \ --project=PROJECT_ID \ iap.googleapis.com
更新するクラスタに
--addons=HttpLoadBalancing
オプションを設定する必要があります。HttpLoadBalancing
アドオンを使用すると、クラスタの HTTP(L7)負荷分散コントローラが有効になります。次のコマンドを実行し、Cloud Service Mesh に必要なオプションを使用してクラスタを更新します。デフォルトのゾーンまたはリージョンを設定済みでない限り、コマンドでリージョン(--region=REGION)またはゾーン(--zone=ZONE)を指定する必要があります。gcloud container clusters update CLUSTER_NAME \ --project=PROJECT_ID \ --update-addons=HttpLoadBalancing=ENABLED
デフォルトでは、
iap-operator.yaml
ファイルのポート 31223 がステータス ポート、ポート 31224 が HTTP ポートとして設定されています。31223 ポートがすでにクラスタで使用されている場合は、次のコマンドを実行して別のステータス ポートを設定します。kpt cfg set asm gcloud.container.cluster.ingress.statusPort STATUS_PORT
31224 がすでにクラスタで使用されている場合は、次のコマンドを実行して別の HTTP ポートを設定します。
kpt cfg set asm gcloud.container.cluster.ingress.httpPort HTTP_PORT
デフォルトの機能と Mesh CA をインストールするの手順に沿って、Google 提供のスクリプトを使用して Cloud Service Mesh をインストールします。スクリプトの実行時に、次のオプションを指定します。
--option iap-operator
次に例を示します。
./asmcli install \ --project_id "PROJECT_ID" \ --cluster_name "CLUSTER_NAME" \ --cluster_location "CLUSTER_LOCATION" \ --fleet_id FLEET_PROJECT_ID \ --output_dir DIR_PATH \ --enable_all \ --option iap-operator
Cloud Service Mesh のインストール時に、
iap-operator.yaml
ファイルがistio-ingressgateway
サービスのtype
フィールドをNodePort
に設定します。これにより、サービス メッシュ上の特定のポートを開くようにゲートウェイが構成されます。また、ドメイン名に送信されたトラフィックがこのポートに転送されるようにロードバランサを設定できます。マネージド Cloud Service Mesh をインストールする場合は、次の手順も完了してください。
istio-system
名前空間にリビジョン ラベルを追加します。IAP 向け Istio Ingress ゲートウェイ サービス仕様をダウンロードし、名前を
iap_operator.yaml
にします。Ingress を NodePort Service としてインストールします。詳細については、IstioOperator から移行するをご覧ください。
asmcli experimental mcp-migrate-check -f iap_operator.yaml istioctl install -f /asm-generated-configs/gateways-istiooperator/"GATEWAY_NAME".yaml
Cloud Service Mesh のインストール後、このガイドに戻り、次のセクションに進んで IAP との統合を設定します。
アップグレード
このセクションでは、次のアップグレードのユースケースについて説明します。
IAP 統合はすでにセットアップ済みで、Cloud Service Mesh をアップグレードする。この例では、プロジェクトで
iap.googleapis.com
が、クラスタでHttpLoadBalancing
アドオンがすでに有効になっています。手順 3 に進んでasm
パッケージをダウンロードし、Cloud Service Mesh をアップグレードします。Cloud Service Mesh をアップグレードし、初めて IAP との統合を設定する。この場合、以下の手順をすべて完了し、Cloud Service Mesh をアップグレードします。アップグレードが完了したらこのガイドに戻り、統合を完了します。
iap.googleapis.com
を有効にします。次のコマンドで、PROJECT_ID
を Cloud Service Mesh をインストールするプロジェクトに置き換えます。gcloud services enable \ --project=PROJECT_ID \ iap.googleapis.com
更新するクラスタに
--addons=HttpLoadBalancing
オプションを設定する必要があります。HttpLoadBalancing
アドオンを使用すると、クラスタの HTTP(L7)負荷分散コントローラが有効になります。次のコマンドを実行し、Cloud Service Mesh に必要なオプションを使用してクラスタを更新します。デフォルトのゾーンまたはリージョンを設定済みでない限り、コマンドでリージョン(--region=REGION)またはゾーン(--zone=ZONE)を指定する必要があります。gcloud container clusters update CLUSTER_NAME \ --project=PROJECT_ID --update-addons=HttpLoadBalancing=ENABLED
機能している既存の 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}')
Cloud Service Mesh のアップグレードの手順に沿って Google 提供のスクリプトを使用し、Cloud Service Mesh をアップグレードします。
Cloud Service Mesh のアップグレード時に、
iap-operator.yaml
ファイルがistio-ingressgateway
サービスのtype
フィールドをNodePort
に設定します。これにより、サービス メッシュ上の特定のポートを開くようにゲートウェイが構成されます。また、ドメイン名に送信されたトラフィックがこのポートに転送されるようにロードバランサを設定できます。デフォルトでは、
iap-operator.yaml
ファイルのポート 31223 がステータス ポート、ポート 31224 が HTTP ポートとして設定されています。スクリプトの実行時に、次のオプションを指定します。
--option iap-operator
次に例を示します。
./asmcli install \ --project_id "PROJECT_ID" \ --cluster_name "CLUSTER_NAME" \ --cluster_location "CLUSTER_LOCATION" \ --fleet_id FLEET_PROJECT_ID \ --output_dir DIR_PATH \ --enable_all \ --option iap-operator
ワークロードの自動サイドカー プロキシ インジェクションをトリガーして、アップグレードを完了します。詳しくは、ワークロードのデプロイと再デプロイをご覧ください。
アップグレードの完了後、このガイドに戻り、次のセクションに進んで IAP との統合を設定します。
静的 IP アドレスの予約と DNS の構成
Identity-Aware Proxy を Cloud Service Mesh と統合するには、Google Cloud HTTP(S) ロードバランサを設定する必要があります。この設定では、静的 IP アドレスを参照するドメイン名が必要です。静的外部 IP アドレスを予約すると、明示的に解放するまで、このアドレスを無期限でプロジェクトに割り当てることができます。
静的外部 IP アドレスを予約します。
gcloud compute addresses create example-static-ip --global
静的 IP アドレスを取得します。
gcloud compute addresses describe example-static-ip --global
ドメイン名登録事業者で、静的 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
を使用します。Cloud Service Mesh をデプロイするときに、istio-ingressgateway
に NodePort
を指定しました。これにより、サービス メッシュで特定のポートが開きます。クラスタ内のノードには外部 IP アドレスが設定されていますが、クラスタの外部からのリクエストは Google Cloud ファイアウォール ルールによってブロックされます。IAP を使用すると、ロードバランサを使用してアプリケーションを公共のインターネットに公開できます。IAP をバイパスするファイアウォール ルールを使用してノードアドレスを公開しないでください。
Bookinfo にリクエストを転送するには、Google Cloud プロジェクトに HTTP(S) ロードバランサを設定します。ロードバランサはプロジェクト内にあります。これはファイアウォールの内側にあるため、クラスタ内のノードにアクセスできます。静的 IP アドレスとドメイン名を使用してロードバランサを構成すると、ドメイン名にリクエストを送信できるようになります。ロードバランサは、これらのリクエストをクラスタ内のノードに転送します。
IAP の有効化
IAP を有効にする手順は以下のとおりです。
同意画面の構成
list コマンドを使用して、既存のブランドがあるかどうかを確認します。1 つのプロジェクトで使用できるブランドは 1 つだけです。
gcloud iap oauth-brands list
ブランドがある場合の gcloud のレスポンスは次のとおりです。
name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID] applicationTitle: [APPLICATION_TITLE] supportEmail: [SUPPORT_EMAIL] orgInternalOnly: true
ブランドが存在しない場合は、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 クライアントの作成
create コマンドを使用してクライアントを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]
クライアント 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) ロードバランサを作成できます。マネージド SSL 証明書はドメインに対してプロビジョニング、更新、管理が行われます。
ManagedCertificate リソースを作成します。このリソースは、SSL 証明書のドメインを指定します。
spec.domains
リストに複数のドメインを入れることはできません。ワイルドカード ドメインはサポートされていません。次の YAML で、DOMAIN_NAME
を外部静的 IP アドレス用に構成したドメイン名に置き換えます。cat <<EOF | kubectl apply -f - apiVersion: networking.gke.io/v1 kind: ManagedCertificate metadata: name: example-certificate namespace: istio-system spec: domains: - DOMAIN_NAME EOF
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 get pods -n istio-system -l app=istio-ingressgateway -o jsonpath='{.items[0].spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')
cat <<EOF | kubectl apply -n istio-system -f - apiVersion: cloud.google.com/v1 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
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}'
ロードバランサを作成するには、Ingress リソースを定義します。
前の手順で作成した証明書の名前
example-certificate
をnetworking.gke.io/managed-certificates
アノテーションに設定します。予約した静的 IP アドレスの名前
example-static-ip
をkubernetes.io/ingress.global-static-ip-name
アノテーションに設定します。serviceName
をistio-ingressgateway
に設定します。これは、Bookinfo サンプルのゲートウェイ リソースで使用されます。
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 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: defaultBackend: service: name: istio-ingressgateway port: number: 80 EOF
Google Cloud コンソールで、[Kubernetes Engine] > [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
)。
ロードバランサをテストします。ブラウザで次の URL にアクセスします。
http://DOMAIN_NAME/productpage
ここで、
DOMAIN_NAME
は、外部静的 IP アドレスで構成したドメイン名です。Bookinfo アプリケーションの
productpage
が表示されます。ページを複数回更新すると、さまざまなバージョンのビューがラウンドロビン スタイル(赤い星、黒い星、星なし)で表示されます。Bookinfo への
https
アクセスもテストする必要があります。
サービス メッシュで RCToken サポートを有効にする
デフォルトでは、IAP は OAuth クライアントをスコープとする JSON Web Token(JWT)を生成します。Cloud Service Mesh では、RequestContextToken(RCToken)を生成するように IAP を構成できます。これは、JWT ですが、オーディエンスは構成可能です。RCToken を使用すると、JWT のオーディエンスに任意の文字列を構成できます。これを Cloud Service Mesh ポリシーで使用し、詳細な認証を実施できます。
RCToken を構成するには:
RCToken オーディエンスの環境変数を作成します。任意の文字列を指定できます。
export RCTOKEN_AUD="your-rctoken-aud"
省略可: 次のステップでは
BACKEND_SERVICE_ID
が必要です。BACKEND_SERVICE_ID
を確認する必要がある場合は、次のコマンドを実行します。kubectl -n istio-system get Ingress example-ingress -o json | jq \ '.metadata.annotations."ingress.kubernetes.io/backends"'
予想される出力は
"{\"BACKEND_SERVICE_ID\":\"HEALTHY\"}"
のようになります。例:"ingress.kubernetes.io/backends": "{\"k8s-be-31224--51f3b55cd1457fb6\":\"HEALTHY\"}"
。この例のBACKEND_SERVICE_ID
はk8s-be-31224--51f3b55cd1457fb6
です。既存の IAP 設定を取得します。
gcloud iap settings get --format json \ --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID > iapSettings.json
RCToken オーディエンスで
IapSettings
を更新します。cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \ '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \ > updatedIapSettings.json
gcloud iap settings set updatedIapSettings.json --format json \ --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID
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
省略可: 有効な JWT のないリクエストが拒否されていることを確認します。
cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: iap-gateway-require-jwt namespace: istio-system spec: selector: matchLabels: app: istio-iap-ingressgateway action: DENY rules: - from: - source: notRequestPrincipals: ["*"] EOF
Bookinfo
productpage
へのリクエストが成功していることを確認します。http://DOMAIN_NAME/productpage
ポリシーをテストするには:
IapSettings
リクエスト オブジェクトを作成します。ただし、rctokenAud
には別の文字列を設定します。cat iapSettings.json | jq --arg RCTOKEN_AUD_STR wrong-rctoken-aud \ '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \ > wrongIapSettings.json
IapSettings
API を呼び出して、RCtoken オーディエンスを設定します。gcloud beta iap settings set wrongIapSettings.json --project=PROJECT_ID --resource-type=compute --service=BACKEND_SERVICE
Bookinfo
productpage
にリクエストを送信すると失敗します。http://DOMAIN_NAME/productpage
クリーンアップ
このチュートリアルを完了したら、アカウントで不要な請求が発生しないように、以下のリソースを削除します。
マネージド証明書を削除します。
kubectl delete managedcertificates example-certificate
Ingress を削除します。これにより、負荷分散リソースの割り当てが解除されます。
kubectl -n istio-system delete ingress example-ingress
静的 IP アドレスを削除します。
gcloud compute addresses delete example-static-ip --global
これを行う場合は、ドメイン登録事業者から IP アドレスを削除してください。
クラスタを削除します。これにより、クラスタを構成するリソース(コンピューティング インスタンス、ディスク、ネットワーク リソースなど)が削除されます。
gcloud container clusters delete CLUSTER_NAME