このチュートリアルでは、Cloud Service Mesh の Egress ゲートウェイやその他の Google Cloud コントロールを使用して、Google Kubernetes Engine クラスタにデプロイされたワークロードからの送信トラフィック(下り、外向き)を保護する方法について説明します。このチュートリアルは、GKE クラスタで Cloud Service Mesh Egress ゲートウェイを使用するためのベスト プラクティスを補完するものです。
このチュートリアルの対象読者は、1 つ以上のソフトウェア配信チームが使用する Google Kubernetes Engine クラスタを管理するネットワーク エンジニア、プラットフォーム エンジニア、セキュリティ エンジニアです。ここで説明する制御は、規制(GDPR や PCI など)の遵守を実証しなければならない組織に特に有効です。
目標
- Cloud Service Mesh を実行するためのインフラストラクチャを設定します。
- カスタム VPC ネットワークとプライベート サブネット
- インターネット アクセス用の Cloud NAT
- Egress ゲートウェイ Pod 用の追加のノードプールを持つ限定公開 GKE クラスタ
- 制限付き下り(外向き)VPC ファイアウォール ルール。ゲートウェイ ノードのみが外部ホストに到達できます。
- Container Registry と Google API に接続するための限定公開の Google アクセス
- Cloud Service Mesh をインストールします。
- 専用のノードプールで実行される Egress ゲートウェイ プロキシをインストールします。
- Egress ゲートウェイを使用して、外部トラフィックのマルチテナント ルーティング ルールを構成します。
- Namespace
team-x
のアプリケーションはexample.com
に接続できます - Namespace
team-y
のアプリケーションはhttpbin.org
に接続できます
- Namespace
Sidecar
リソースを使用して、各名前空間のサイドカー プロキシ下り(外向き)構成の範囲を制限します。- 認証ポリシーを構成して、下り(外向き)ルールを適用します。
- プレーン HTTP リクエストを TLS にアップグレードするように Egress ゲートウェイを構成します(TLS発信)。
- TLS トラフィックを通過させるように Egress ゲートウェイを構成します。
- Kubernetes ネットワーク ポリシーを追加の下り(外向き)制御として設定します。
- 限定公開の Google アクセスと Identity and Access Management(IAM)権限を使用して、Google API への直接アクセスを構成します。
費用
このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。
- Compute Engine
- Google Kubernetes Engine (GKE)
- Container Registry
- Cloud Service Mesh
- Cloud Load Balancing
- Cloud NAT
- Networking
- Cloud Storage
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このチュートリアルの終了後に作成したリソースを削除すれば、それ以上の請求は発生しません。詳しくは、クリーンアップをご覧ください。
始める前に
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
-
Make sure that billing is enabled for your Google Cloud project.
-
In the Google Cloud console, activate Cloud Shell.
このチュートリアルで使用する作業ディレクトリを作成します。
mkdir -p ~/WORKING_DIRECTORY cd ~/WORKING_DIRECTORY
シェル スクリプトを作成して、チュートリアル用に環境を初期化します。変数は、プロジェクトや設定に応じて置き換えて編集します。シェル セッションが期限切れになった場合は、
source
コマンドを使用してこのスクリプトを実行して環境を再初期化します。cat << 'EOF' > ./init-egress-tutorial.sh #! /usr/bin/env bash PROJECT_ID=YOUR_PROJECT_ID REGION=REGION ZONE=ZONE gcloud config set project ${PROJECT_ID} gcloud config set compute/region ${REGION} gcloud config set compute/zone ${ZONE} EOF
compute.googleapis.com
の有効化:gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
スクリプトを実行可能にして、
source
コマンドで実行し、環境を初期化します。compute.googleapis.com
を有効にするよう求められたら、[Y
] を選択します。chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
インフラストラクチャの設定
VPC ネットワークとサブネットを作成する
新しい VPC ネットワークを作成します。
gcloud compute networks create vpc-network \ --subnet-mode custom
Pod とサービスに事前に割り振られたセカンダリ IP アドレス範囲を使用して、クラスタを実行するためのサブネットを作成します。限定公開の Google アクセスを有効にすると、内部 IP アドレスしか割り当てられていないアプリケーションが Google API やサービスにアクセスできるようになります。
gcloud compute networks subnets create subnet-gke \ --network vpc-network \ --range 10.0.0.0/24 \ --secondary-range pods=10.1.0.0/16,services=10.2.0.0/20 \ --enable-private-ip-google-access
Cloud NAT を構成する
Cloud NAT を使用すると、外部 IP アドレスのないワークロードがインターネット上の宛先に接続し、それらの宛先からの受信レスポンスを受け取れるようになります。
Cloud Router を作成します。
gcloud compute routers create nat-router \ --network vpc-network
ルーターに NAT 構成を追加します。
gcloud compute routers nats create nat-config \ --router nat-router \ --nat-all-subnet-ip-ranges \ --auto-allocate-nat-external-ips
GKE ノードプールごとにサービス アカウントを作成する
2 つの GKE ノードプールで使用する 2 つのサービス アカウントを作成します。VPC ファイアウォール ルールを特定のノードに適用できるように、ノードプールには別々のサービス アカウントが割り当てられます。
デフォルトのノードプール内のノードで使用するサービス アカウントを作成します。
gcloud iam service-accounts create sa-application-nodes \ --description="SA for application nodes" \ --display-name="sa-application-nodes"
ゲートウェイ ノードプール内のノードで使用するサービス アカウントを作成します。
gcloud iam service-accounts create sa-gateway-nodes \ --description="SA for gateway nodes" \ --display-name="sa-gateway-nodes"
サービス アカウントに権限を付与する
最小限の IAM ロールをアプリケーションとゲートウェイのサービス アカウントに追加します。これらのロールは、Container Registry から非公開コンテナ イメージをロギング、モニタリング、pull するために必要です。
project_roles=(
roles/logging.logWriter
roles/monitoring.metricWriter
roles/monitoring.viewer
roles/storage.objectViewer
)
for role in "${project_roles[@]}"
do
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
gcloud projects add-iam-policy-binding ${PROJECT_ID} \
--member="serviceAccount:sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \
--role="$role"
done
ファイアウォール ルールを作成する
次のステップでは、デフォルトですべての下り(外向き)トラフィックを拒否するように、VPC ネットワークにファイアウォール ルールを適用します。クラスタが機能し、ゲートウェイ ノードが VPC の外部の宛先に到達できるようにするには、専用の接続が必要です。特定のファイアウォール ルールの最小限のセットは、デフォルトのすべて拒否ルールをオーバーライドして、必要な接続を許可します。
VPC ネットワークからの下り(外向き)トラフィックをすべて拒否するデフォルトの(優先度が低い)ファイアウォール ルールを作成します。
gcloud compute firewall-rules create global-deny-egress-all \ --action DENY \ --direction EGRESS \ --rules all \ --destination-ranges 0.0.0.0/0 \ --network vpc-network \ --priority 65535 \ --description "Default rule to deny all egress from the network."
ゲートウェイ サービス アカウントを持つノードのみがインターネットに到達できるようにルールを作成します。
gcloud compute firewall-rules create gateway-allow-egress-web \ --action ALLOW \ --direction EGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --network vpc-network \ --priority 1000 \ --description "Allow the nodes running the egress gateways to connect to the web"
ノードが Kubernetes コントロール プレーンに到達できるようにします。
gcloud compute firewall-rules create allow-egress-to-api-server \ --action ALLOW \ --direction EGRESS \ --rules tcp:443,tcp:10250 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
省略可: マネージド Cloud Service Mesh を使用する場合、このファイアウォール ルールは必要ありません。
Cloud Service Mesh は、ワークロードにサイドカー プロキシを挿入する際に Webhook を使用します。GKE API サーバーが、ノードで実行されているサービス メッシュ コントロール プレーンによって公開された Webhook を呼び出すようにします。
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow the API server to call the webhooks exposed by istiod discovery"
クラスタ上で実行されているノードと Pod 間の下り(外向き)接続を許可します。GKE は、対応する上り(内向き)ルールを自動的に作成します。iptables ルーティング チェーンは常に Service の IP アドレスを Pod の IP アドレスに変換するため、Service の接続にルールは必要ありません。
gcloud compute firewall-rules create allow-egress-nodes-and-pods \ --action ALLOW \ --direction EGRESS \ --rules all \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 10.0.0.0/24,10.1.0.0/16 \ --network vpc-network \ --priority 1000 \ --description "Allow egress to other Nodes and Pods"
Google API や Container Registry などのサービスを提供するために、限定公開の Google アクセスで使用される予約済みの IP アドレスセットへのアクセスを許可します。
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --destination-ranges 199.36.153.8/30 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the VIPs used by Google Cloud APIs (Private Google Access)"
クラスタで実行されている Pod へのアクセスを Google Cloud ヘルス チェッカー サービスに許可します。詳細については、ヘルスチェックをご覧ください。
gcloud compute firewall-rules create allow-ingress-gcp-health-checker \ --action ALLOW \ --direction INGRESS \ --rules tcp:80,tcp:443 \ --target-service-accounts sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com,sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com \ --source-ranges 35.191.0.0/16,130.211.0.0/22,209.85.152.0/22,209.85.204.0/22 \ --network vpc-network \ --priority 1000 \ --description "Allow workloads to respond to Google Cloud health checks"
Google Cloud APIs へのプライベート アクセスの構成
限定公開の Google アクセスを使用すると、内部 IP アドレスしか持たない VM や Pod から Google API やサービスにアクセスできるようになります。Google API とサービスは外部 IP から提供されますが、限定公開の Google アクセスを使用する場合、ノードからのトラフィックが Google ネットワークの外に出ることはありません。
Cloud DNS API を有効にします。
gcloud services enable dns.googleapis.com
限定公開の Google アクセスとホスト名 private.googleapis.com
を使用してノードとワークロードが Google API およびサービスに接続できるように、限定公開の DNS ゾーン、CNAME
レコード、A
レコードを作成します。
gcloud dns managed-zones create private-google-apis \
--description "Private DNS zone for Google APIs" \
--dns-name googleapis.com \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-google-apis
gcloud dns record-sets transaction add private.googleapis.com. \
--name "*.googleapis.com" \
--ttl 300 \
--type CNAME \
--zone private-google-apis
gcloud dns record-sets transaction add "199.36.153.8" \
"199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name private.googleapis.com \
--ttl 300 \
--type A \
--zone private-google-apis
gcloud dns record-sets transaction execute --zone private-google-apis
Container Registry へのプライベート アクセスの構成
限定公開の Google アクセスとホスト名 gcr.io
を使用してノードが Container Registry に接続できるように、限定公開の DNS ゾーン、CNAME
レコード、A
レコードを作成します。
gcloud dns managed-zones create private-gcr-io \
--description "private zone for Container Registry" \
--dns-name gcr.io \
--visibility private \
--networks vpc-network
gcloud dns record-sets transaction start --zone private-gcr-io
gcloud dns record-sets transaction add gcr.io. \
--name "*.gcr.io" \
--ttl 300 \
--type CNAME \
--zone private-gcr-io
gcloud dns record-sets transaction add "199.36.153.8" "199.36.153.9" "199.36.153.10" "199.36.153.11" \
--name gcr.io \
--ttl 300 \
--type A \
--zone private-gcr-io
gcloud dns record-sets transaction execute --zone private-gcr-io
限定公開 GKE クラスタの作成
Cloud Shell の外部 IP アドレスを見つけて、クラスタの API サーバーへのアクセスが許可されているネットワークのリストに追加できるようにします。
SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com)
Cloud Shell VM の外部 IP アドレスは、一定期間使用されていない場合に変更できます。その場合は、クラスタの承認済みネットワークのリストを更新する必要があります。次のコマンドを初期化スクリプトに追加します。
cat << 'EOF' >> ./init-egress-tutorial.sh SHELL_IP=$(dig TXT -4 +short @ns1.google.com o-o.myaddr.l.google.com) gcloud container clusters update cluster1 \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 EOF
Google Kubernetes Engine API を有効にします。
gcloud services enable container.googleapis.com
限定公開 GKE クラスタを作成します。
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-dataplane-v2 \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --network "vpc-network" \ --subnetwork "subnet-gke" \ --cluster-secondary-range-name "pods" \ --services-secondary-range-name "services" \ --workload-pool "${PROJECT_ID}.svc.id.goog" \ --zone ${ZONE}
クラスタの作成には数分かかります。クラスタには、内部 IP アドレスを持つプライベート ノードが含まれます。Pod とサービスには、VPC サブネットの作成時に定義した名前付きセカンダリ範囲から IP が割り振られます。
クラスタ内コントロール プレーンを使用する Cloud Service Mesh では、クラスタノードで 4 つ以上の vCPU を備えたマシンタイプを使用する必要があります。
ノードが Cloud Service Mesh でサポートされている Kubernetes バージョンを実行できるように、クラスタを「通常の」リリース チャネルに登録することをおすすめします。
クラスタ内コントロール プレーンを使用して Cloud Service Mesh を実行する場合の前提条件については、クラスタ内の前提条件をご覧ください。
マネージド Cloud Service Mesh を実行するための要件と制限事項の詳細については、マネージド Cloud Service Mesh でサポートされている機能をご覧ください。
クラスタで Workload Identity Federation for GKEが有効になっています。Cloud Service Mesh には Workload Identity Federation for GKE が必要です。また、Cloud Service Mesh は GKE ワークロードから Google API にアクセスする場合のおすすめの方法です。
gateway というノードプールを作成します。Egress ゲートウェイは、このノードプールにデプロイされます。ゲートウェイ ノード プール内のすべてのノードに
dedicated=gateway:NoSchedule
taint が追加されます。gcloud container node-pools create "gateway" \ --cluster "cluster1" \ --machine-type "e2-standard-4" \ --node-taints dedicated=gateway:NoSchedule \ --service-account "sa-gateway-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --num-nodes "1"
Kubernetes の taint と容認は、Egress ゲートウェイ Pod のみがゲートウェイ ノードプール内のノードで実行されるようにするのに役立ちます。
kubectl でクラスタに接続できるように認証情報をダウンロードします。
gcloud container clusters get-credentials cluster1
ゲートウェイ ノードに適切な taint があることを確認します。
kubectl get nodes -l cloud.google.com/gke-nodepool=gateway -o yaml \ -o=custom-columns='name:metadata.name,taints:spec.taints[?(@.key=="dedicated")]'
出力は次のようになります。
name taints gke-cluster1-gateway-9d65b410-cffs map[effect:NoSchedule key:dedicated value:gateway]
Cloud Service Mesh のインストールと設定
Cloud Service Mesh のいずれかのインストール ガイドに従ってください。
Cloud Service Mesh をインストールしたら、Ingress または Egress ゲートウェイをインストールせずに、このチュートリアルに戻ります。
Egress ゲートウェイをインストールする
Egress ゲートウェイの Kubernetes Namespace を作成します。
kubectl create namespace istio-egress
インジェクションの名前空間を有効にします。手順は、コントロール プレーンの実装によって異なります。
マネージド(TD)
デフォルトのインジェクション ラベルを名前空間に適用します。
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
マネージド(Istiod)
推奨: 次のコマンドを実行して、デフォルトのインジェクション ラベルを名前空間に適用します。
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
マネージド Istiod コントロール プレーンを使用している既存のユーザーの場合: デフォルトのインジェクションを使用することをおすすめしますが、リビジョンベースのインジェクションもサポートされています。次の手順を行います。
利用可能なリリース チャンネルを探すには、次のコマンドを実行します。
kubectl -n istio-system get controlplanerevision
出力は次のようになります。
NAME AGE asm-managed-rapid 6d7h
出力で、
NAME
列の値は、Cloud Service Mesh バージョンで使用可能なリリース チャンネルに対応するリビジョン ラベルです。リビジョン ラベルを名前空間に適用します。
kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
クラスタ内
推奨: 次のコマンドを実行して、デフォルトのインジェクション ラベルを名前空間に適用します。
kubectl label namespace istio-egress \ istio.io/rev- istio-injection=enabled --overwrite
デフォルトのインジェクションを使用することをおすすめしますが、リビジョンベースのインジェクションがサポートされています。 次の手順を使用します。
次のコマンドを使用して、
istiod
のリビジョン ラベルを探します。kubectl get deploy -n istio-system -l app=istiod -o \ jsonpath={.items[*].metadata.labels.'istio\.io\/rev'}'{"\n"}'
リビジョン ラベルを名前空間に適用します。次のコマンドで、
REVISION_LABEL
は前の手順でメモしたistiod
リビジョン ラベルの値です。kubectl label namespace istio-egress \ istio-injection- istio.io/rev=REVISION_LABEL --overwrite
Egress ゲートウェイのオペレータ マニフェストを作成します。
cat << EOF > egressgateway-operator.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: egressgateway-operator annotations: config.kubernetes.io/local-config: "true" spec: profile: empty revision: REVISION components: egressGateways: - name: istio-egressgateway namespace: istio-egress enabled: true values: gateways: istio-egressgateway: injectionTemplate: gateway tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
istioctl
ツールをダウンロードします。Cloud Service Mesh バージョン 1.15 以前を使用している場合でも、バージョン 1.16.2-asm.2 以降を使用する必要があります。正しい istioctl バージョンのダウンロードをご覧ください。ダウンロードしたアーカイブを展開したら、
istioctl
ツールのパスを格納する環境変数を設定し、初期化スクリプトに追加します。ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
オペレータ マニフェストと
istioctl
を使用して、Egress ゲートウェイのインストール マニフェストを作成します。${ISTIOCTL} manifest generate \ --filename egressgateway-operator.yaml \ --output egressgateway \ --cluster-specific
Egress ゲートウェイをインストールします。
kubectl apply --recursive --filename egressgateway/
Egress ゲートウェイが
gateway
ノードプールのノードで実行されていることを確認します。kubectl get pods -n istio-egress -o wide
Egress ゲートウェイ Pod には、
gateway
ノードプール内のノードに対するaffinity
と、taint が付与されたゲートウェイ ノードで実行できる toleration があります。Egress ゲートウェイ Pod のノード アフィニティと toleration を確認します。kubectl -n istio-egress get pod -l istio=egressgateway \ -o=custom-columns='name:metadata.name,node-affinity:spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms,tolerations:spec.tolerations[?(@.key=="dedicated")]'
出力は次のようになります。
name node-affinity tolerations istio-egressgateway-754d9684d5-jjkdz [map[matchExpressions:[map[key:cloud.google.com/gke-nodepool operator:In values:[gateway]]]]] map[key:dedicated operator:Equal value:gateway]
Envoy アクセス ロギングを有効にする
Envoy アクセスログを有効にする手順は、Cloud Service Mesh のタイプ(マネージドまたはクラスタ内)によって異なります。
管理対象
マネージド Cloud Service Mesh でアクセスログを有効にするの手順に沿って操作します。
クラスタ内
クラスタ内 Cloud Service Mesh でアクセスログを有効にするの手順に沿って操作します。
メッシュとテスト アプリケーションの準備
STRICT 相互 TLS が有効になっていることを確認します。
istio-system
名前空間のメッシュにデフォルトのPeerAuthentication
ポリシーを適用します。cat <<EOF | kubectl apply -f - apiVersion: "security.istio.io/v1beta1" kind: "PeerAuthentication" metadata: name: "default" namespace: "istio-system" spec: mtls: mode: STRICT EOF
この構成をオーバーライドするには、特定の名前空間に
PeerAuthentication
リソースを作成します。テスト ワークロードのデプロイに使用する名前空間を作成します。このチュートリアルの後半のステップでは、名前空間ごとに異なる下り(外向き)転送ルールを構成する方法について説明します。
kubectl create namespace team-x kubectl create namespace team-y
名前空間にラベルを付けて、Kubernetes ネットワーク ポリシーで選択できるようにします。
kubectl label namespace team-x team=x kubectl label namespace team-y team=y
Cloud Service Mesh がプロキシ サイドカーを自動的に挿入するように、ワークロードの Namespace にコントロール プレーンのリビジョン ラベルを設定します。
kubectl label ns team-x istio.io/rev- istio-injection=enabled --overwrite kubectl label ns team-y istio.io/rev- istio-injection=enabled --overwrite
テストデプロイに使用する YAML ファイルを作成します。
cat << 'EOF' > ./test.yaml apiVersion: v1 kind: ServiceAccount metadata: name: test --- apiVersion: v1 kind: Service metadata: name: test labels: app: test spec: ports: - port: 80 name: http selector: app: test --- apiVersion: apps/v1 kind: Deployment metadata: name: test spec: replicas: 1 selector: matchLabels: app: test template: metadata: labels: app: test spec: serviceAccountName: test containers: - name: test image: gcr.io/google.com/cloudsdktool/cloud-sdk:slim command: ["/bin/sleep", "infinity"] imagePullPolicy: IfNotPresent EOF
テスト アプリケーションを
team-x
名前空間にデプロイします。kubectl -n team-x create -f ./test.yaml
テスト アプリケーションがデフォルト プール内のノードにデプロイされ、プロキシ サイドカー コンテナが挿入されていることを確認します。Pod のステータスが
Running
になるまで、次のコマンドを繰り返します。kubectl -n team-x get po -l app=test -o wide
出力は次のようになります。
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES test-d5bdf6f4f-9nxfv 2/2 Running 0 19h 10.1.1.25 gke-cluster1-default-pool-f6c7a51f-wbzj
2 つのコンテナは両方
Running
です。1 つのコンテナはテスト アプリケーション、もう 1 つはプロキシ サイドカーです。Pod は、デフォルトのノードプール内のノードで実行されます。
テストコンテナから外部サイトに HTTP リクエストを作成できないことを確認します。
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test -- curl -v http://example.com
global-deny-egress-all
ファイアウォール ルールによってアップストリーム接続が拒否されるため、サイドカー プロキシからのエラー メッセージが生成されます。
サイドカー リソースを使用してサイドカー プロキシ構成の範囲を制限する
サイドカー リソースを使用して、サイドカー プロキシ用に構成された下り(外向き)リスナーのスコープを制限できます。構成の肥大化とメモリ使用量を減らすために、すべての名前空間にデフォルトの Sidecar
リソースを適用することをおすすめします。
Cloud Service Mesh がサイドカーで実行するプロキシは Envoy です。Envoy の用語では、cluster
は負荷分散の宛先として使用される、論理的に類似したアップストリーム エンドポイントのグループです。
istioctl proxy-config
コマンドを実行して、テスト Pod の Envoy サイドカー プロキシで構成されている送信クラスタを調べます。${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
このリストには、Egress ゲートウェイを含む Envoy クラスタが約 11 個あります。
プロキシ構成を、Egress 名前空間と
team-x
名前空間のサービス エントリによって明示的に定義された下り(外向き)ルートに制限します。Sidecar
リソースをteam-x
Namespace に適用します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-x spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-x/*' EOF
送信トラフィック ポリシーモードを
REGISTRY_ONLY
に設定すると、プロキシ構成が制限されます。サービス エントリを定義することで、メッシュのサービス レジストリに明示的に追加された外部ホストのみが含まれるようになります。egress.hosts
を設定すると、サイドカー プロキシはexportTo
属性を使用して使用可能な Egress Namespace からのルートのみを選択します。「team-x/*
」の部分には、team-x
Namespace でローカルに構成されたルートが含まれます。Envoy サイドカー プロキシで構成された送信クラスタを確認し、
Sidecar
リソースを適用する前に構成されたクラスタのリストと比較します。${ISTIOCTL} pc c $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}).team-x --direction outbound
Egress ゲートウェイのクラスタと、テスト Pod 自体のクラスタが表示されます。
Egress ゲートウェイ経由でトラフィックをルーティングするように Cloud Service Mesh を構成する
ポート 80 上の HTTP トラフィックに対して
Gateway
を構成します。Gateway
は、Egress Namespace にデプロイした Egress ゲートウェイ プロキシを選択します。Gateway
構成が Egress Namespace に適用され、すべてのホストのトラフィックを処理します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL EOF
認証および暗号化用の相互 TLS を使用する Egress ゲートウェイの
DestinationRule
を作成します。すべての外部ホストに対して単一の共有宛先ルールを使用します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: tls: mode: ISTIO_MUTUAL EOF
Egress Namespace に
ServiceEntry
を作成し、team-x
Namespace のメッシュのサービス レジストリに example.com を明示的に登録します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: example.com spec: hosts: - example.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'team-x' - 'istio-egress' EOF
Egress ゲートウェイ経由で example.com にトラフィックを転送する
VirtualService
を作成します。一致条件は 2 つあります。1 つ目の条件はトラフィックを Egress ゲートウェイに転送し、2 番目の条件はトラフィックを Egress ゲートウェイから宛先ホストに転送します。exportTo
プロパティは、仮想サービスを使用できる名前空間を制御します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
istioctl analyze
を実行して、構成エラーを確認します。${ISTIOCTL} analyze -n istio-egress --revision REVISION
出力は次のようになります。
✔ No validation issues found when analyzing namespace: istio-egress.
Egress ゲートウェイ経由で外部サイトに複数のリクエストを送信します。
for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- \ curl -s -o /dev/null -w "%{http_code}\n" http://example.com done
4 つのレスポンスすべてに
200
ステータス コードが表示されます。プロキシ アクセスログを調べて、リクエストが Egress ゲートウェイ経由で送信されていることを確認します。まず、テスト アプリケーションでデプロイされたプロキシ サイドカーのアクセスログを確認します。
kubectl -n team-x logs -f $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) istio-proxy
送信するリクエストごとに、次のようなログエントリが表示されます。
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/1.1" 200 - "-" "-" 0 0 5 4 "-" "curl/7.67.0" "d57ea5ad-90e9-46d9-8b55-8e6e404a8f9b" "example.com" "10.1.4.12:8080" outbound|80||istio-egressgateway.istio-egress.svc.cluster.local 10.1.0.17:42140 93.184.216.34:80 10.1.0.17:60326 - -
また、Egress ゲートウェイのアクセスログも確認します。
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
送信するリクエストごとに、次のような Egress ゲートウェイのアクセスログ エントリが表示されます。
[2020-09-14T17:37:08.045Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 4 3 "10.1.0.17" "curl/7.67.0" "095711e6-64ef-4de0-983e-59158e3c55e7" "example.com" "93.184.216.34:80" outbound|80||example.com 10.1.4.12:37636 10.1.4.12:8080 10.1.0.17:44404 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
2 番目の名前空間用に別のルーティングを構成する
2 番目の外部ホストのルーティングを構成して、チームごとに異なる外部接続を構成する方法を確認します。
team-y
名前空間のSidecar
リソースを作成します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Sidecar metadata: name: default namespace: team-y spec: outboundTrafficPolicy: mode: REGISTRY_ONLY egress: - hosts: - 'istio-egress/*' - 'team-y/*' EOF
テスト アプリケーションを
team-y
名前空間にデプロイします。kubectl -n team-y create -f ./test.yaml
2 番目の外部ホストを登録して、
team-x
名前空間とteam-y
名前空間にエクスポートします。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: httpbin-org-ext namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: httpbin.org spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
Egress ゲートウェイ経由で httpbin.org にトラフィックを転送する仮想サービスを作成します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
istioctl analyze
を実行して、構成エラーを確認します。${ISTIOCTL} analyze -n istio-egress --revision REVISION
次の出力を確認できます。
✔ No validation issues found when analyzing namespace: istio-egress.
team-y
テストアプリから httpbin.org にリクエストを送信します。kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test -o \ jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
200 OK
レスポンスが表示されます。また、
team-x
テストアプリからも httpbin.org にリクエストを送信します。kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://httpbin.org
200 OK
レスポンスが表示されます。team-y
名前空間から example.com へのリクエストを試みます。kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
example.com
ホスト用に送信ルートが構成されていないため、このリクエストは失敗します。
認証ポリシーを使用してトラフィックを詳細に制御する
このチュートリアルでは、Egress ゲートウェイの認証ポリシーが istio-egress
名前空間に作成されます。ネットワーク管理者のみが istio-egress
名前空間にアクセスできるように Kubernetes RBAC を構成できます。
AuthorizationPolicy
を作成して、team-x
名前空間のアプリケーションが example.com に接続できるが、ポート 80 を使用してリクエストを送信するときに他の外部ホストに接続できないようにします。Egress ゲートウェイ Pod の対応するtargetPort
は 8080 です。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-x-to-example-com namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-x' to: - operation: hosts: - 'example.com' when: - key: destination.port values: ["8080"] EOF
team-x
名前空間のテスト アプリケーションから example.com にリクエストできることを確認します。kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
200 OK
レスポンスが表示されます。team-x
名前空間のテスト アプリケーションから httpbin.org へのリクエストを試みます。kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
このリクエストは失敗し、
RBAC: access denied
メッセージと 403 Forbidden ステータス コードが返されます。認証ポリシーが有効になるまでに少しの遅延があるため、数秒かかることがあります。認証ポリシーは、どのトラフィックを許可または拒否するかを詳細に制御します。次の認証ポリシーを適用して、
team-y
名前空間内のテストアプリが、ポート 80 を使用してリクエストを送信するときに、1 つの特定の URL パスを使用して httpbin.org にリクエストを送信できるようにします。Egress ゲートウェイ Pod の対応するtargetPort
は 8080 です。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-team-y-to-httpbin-teapot namespace: istio-egress spec: action: ALLOW rules: - from: - source: namespaces: - 'team-y' to: - operation: hosts: - httpbin.org paths: ['/status/418'] when: - key: destination.port values: ["8080"] EOF
team-y
名前空間のテストアプリから httpbin.org への接続を試みます。kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -w " %{http_code}\n" \ http://httpbin.org
このリクエストは失敗し、RBAC: access denied メッセージと 403 Forbidden ステータス コードが返されます。
次に、同じアプリから httpbin.org/status/418 にリクエストを送信します。
kubectl -n team-y exec -it $(kubectl -n team-y get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl http://httpbin.org/status/418
パスが認証ポリシーのパターンと一致するため、このリクエストは成功します。出力は次のようになります。
-=[ teapot ]=- _...._ .' _ _ `. | ."` ^ `". _, \_;`"---"`|// | ;/ \_ _/ `"""`
Egress ゲートウェイでの TLS 開始
TLS または相互 TLS へのプレーン HTTP リクエストの upgrade
(開始)を行うように、Egress ゲートウェイを構成できます。Istio 相互 TLS および TLS 発信において、アプリケーションでプレーン HTTP リクエストを行えるようにすることの利点はいくつかあります。詳しくは、ベスト プラクティス ガイドをご覧ください。
DestinationRule. The DestinationRule
を作成すると、example.com への TLS 接続をゲートウェイで開始するように指定できます。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: example-com-originate-tls namespace: istio-egress spec: host: example.com subsets: - name: example-com-originate-TLS trafficPolicy: portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
example.com の仮想サービスを更新し、ゲートウェイのポート 80 に対するリクエストが宛先ホストへの送信時にポート 443 の TLS に
upgraded
されるようにします。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 EOF
team-x
名前空間のテストアプリから example.com へのリクエストをいくつか行います。for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com done
前と同様に、リクエストが成功すると
200 OK
レスポンスが返されます。Egress ゲートウェイのログを調べて、ゲートウェイが送信元の TLS 接続経由でリクエストを宛先ホストに転送したことを確認します。
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath=" {.items[0].metadata.name}") istio-proxy
出力は次のようになります。
[2020-09-24T17:58:02.548Z] "HEAD / HTTP/2" 200 - "-" "-" 0 0 6 5 "10.1.1.15" "curl/7.67.0" "83a77acb-d994-424d-83da-dd8eac902dc8" "example.com" "93.184.216.34:443" outbound|443|example-com-originate-TLS|example.com 10.1.4.31:49866 10.1.4.31:8080 10.1.1.15:37334 outbound_.80_.target-egress-gateway-mTLS_.istio-egressgateway.istio-egress.svc.cluster.local -
プロキシ サイドカーは、ポート 80 とポート 443 で開始された TLS を使用してゲートウェイにリクエストを送信し、宛先ホストにリクエストを送信しました。
HTTPS / TLS 接続のパススルー
既存のアプリケーションで、外部サービスと通信するときにすでに TLS 接続を使用している場合があります。TLS 接続を復号せずに通過させるように Egress ゲートウェイを構成できます。
Egress ゲートウェイがポート 443 への接続に TLS パススルーを使用するように構成を変更します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egressgateway servers: - port: number: 80 name: https protocol: HTTPS hosts: - '*' tls: mode: ISTIO_MUTUAL - port: number: 443 name: tls protocol: TLS hosts: - '*' tls: mode: PASSTHROUGH EOF
Egress ゲートウェイを指す
DestinationRule
を更新し、ゲートウェイのポート 443 に対して 2 つ目のサブセットを追加します。この新しいサブセットは相互 TLS を使用しません。Istio 相互 TLS は、TLS 接続のパススルーではサポートされていません。ポート 80 上の接続では、引き続き mTLS が使用されます。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: target-egress-gateway namespace: istio-egress spec: host: istio-egressgateway.istio-egress.svc.cluster.local subsets: - name: target-egress-gateway-mTLS trafficPolicy: portLevelSettings: - port: number: 80 tls: mode: ISTIO_MUTUAL - name: target-egress-gateway-TLS-passthrough EOF
ポート 443 での TLS トラフィックがゲートウェイを通過するように example.com の仮想サービスを更新します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: example-com-through-egress-gateway namespace: istio-egress spec: hosts: - example.com gateways: - mesh - istio-egress/egress-gateway http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: example.com port: number: 443 subset: example-com-originate-TLS weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - example.com route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - example.com route: - destination: host: example.com port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' EOF
ポート 443 での TLS トラフィックがゲートウェイを通過するように httpbin.org の仮想サービスを更新します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-org-through-egress-gateway namespace: istio-egress spec: hosts: - httpbin.org gateways: - istio-egress/egress-gateway - mesh http: - match: - gateways: - mesh port: 80 route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-mTLS port: number: 80 weight: 100 - match: - gateways: - istio-egress/egress-gateway port: 80 route: - destination: host: httpbin.org port: number: 80 weight: 100 tls: - match: - gateways: - mesh port: 443 sniHosts: - httpbin.org route: - destination: host: istio-egressgateway.istio-egress.svc.cluster.local subset: target-egress-gateway-TLS-passthrough port: number: 443 - match: - gateways: - istio-egress/egress-gateway port: 443 sniHosts: - httpbin.org route: - destination: host: httpbin.org port: number: 443 weight: 100 exportTo: - 'istio-egress' - 'team-x' - 'team-y' EOF
Egress ゲートウェイ サービスのポート 443 に送信されるトラフィックを許可する認証ポリシーを追加します。ゲートウェイ Pod の対応する
targetPort
は 8443 です。cat <<EOF | kubectl apply -f - apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: egress-all-443 namespace: istio-egress spec: action: ALLOW rules: - when: - key: destination.port values: ["8443"] EOF
istioctl analyze
を実行して、構成エラーを確認します。${ISTIOCTL} analyze -n istio-egress --revision REVISION
次の出力を確認できます。
✔ No validation issues found when analyzing namespace: istio-egress.
team-x
名前空間のテスト アプリケーションから example.com へのプレーン HTTP リクエストを作成します。kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
リクエストが成功すると、
200 OK
レスポンスが返されます。次に、
team-x
名前空間のテスト アプリケーションから TLS(HTTPS)リクエストをいくつか作成します。for i in {1..4} do kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -s -o /dev/null \ -w "%{http_code}\n" \ https://example.com done
200 件のレスポンスが表示されます。
Egress ゲートウェイのログを再度確認します。
kubectl -n istio-egress logs -f $(kubectl -n istio-egress get pod -l istio=egressgateway \ -o jsonpath="{.items[0].metadata.name}") istio-proxy
次のようなログエントリが表示されます。
[2020-09-24T18:04:38.608Z] "- - -" 0 - "-" "-" 1363 5539 10 - "-" "-" "-" "-" "93.184.216.34:443" outbound|443||example.com 10.1.4.31:51098 10.1.4.31:8443 10.1.1.15:57030 example.com -
HTTPS リクエストは TCP トラフィックとして処理され、ゲートウェイ経由で宛先ホストに渡されるため、HTTP 情報はログに含まれません。
Kubernetes NetworkPolicy を追加の制御として使用する
アプリケーションがサイドカー プロキシをバイパスできるシナリオは数多くあります。Kubernetes NetworkPolicy
を使用して、ワークロードに許可する接続をさらに指定できます。単一のネットワーク ポリシーを適用した後、特に許可されていないすべての接続は拒否されます。
このチュートリアルでは、ネットワーク ポリシーの下り接続と下り(外向き)セレクタのみが考慮されています。自身のクラスタで、ネットワーク ポリシーで上り(内向き)を制御する場合は、下り(外向き)ポリシーに合わせて上り(内向き)ポリシーを作成する必要があります。たとえば、team-x
名前空間内のワークロードから team-y
名前空間への下り(外向き)を許可する場合は、team-x
名前空間から team-y
名前空間への上り(内向き)も許可する必要があります。
team-x
名前空間にデプロイされたワークロードとプロキシがistiod
と Egress ゲートウェイに接続できるようにします。cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-control-plane namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": istio-egress podSelector: matchLabels: istio: egressgateway EOF
ワークロードとプロキシが DNS をクエリできるようにします。
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-dns namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": kube-system ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
ワークロードとプロキシが、Cloud Service Mesh 認証局を含む Google API とサービスを提供する IP に接続できるようにします。
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-google-apis namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - ipBlock: cidr: 199.36.153.4/30 - ipBlock: cidr: 199.36.153.8/30 EOF
ワークロードとプロキシが GKE メタデータ サーバーに接続できるようにします。
cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-metadata-server namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: # For GKE data plane v2 - ipBlock: cidr: 169.254.169.254/32 - to: # For GKE data plane v1 - ipBlock: cidr: 127.0.0.1/32 # Prior to 1.21.0-gke.1000 - ipBlock: cidr: 169.254.169.252/32 # 1.21.0-gke.1000 and later ports: - protocol: TCP port: 987 - protocol: TCP port: 988 EOF
省略可:
team-x
名前空間のワークロードとプロキシが相互に接続できるようにします。cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-same-namespace namespace: team-x spec: podSelector: {} ingress: - from: - podSelector: {} egress: - to: - podSelector: {} EOF
省略可:
team-x
名前空間のワークロードとプロキシが、別のチームによりデプロイされたワークロードに接続できるようにします。cat <<EOF | kubectl apply -f - apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-to-team-y namespace: team-x spec: podSelector: {} policyTypes: - Egress egress: - to: - namespaceSelector: matchLabels: "kubernetes.io/metadata.name": team-y EOF
サイドカー プロキシ間の接続は維持されます。新しいネットワーク ポリシーを適用しても、既存の接続は閉じられません。team-x 名前空間のワークロードを再起動して、既存の接続が閉じられていることを確認します。
kubectl -n team-x rollout restart deployment
team-x
名前空間のテスト アプリケーションから example.com に HTTP リクエストを実行できることを確認します。kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- curl -I http://example.com
リクエストが成功すると、
200 OK
レスポンスが返されます。
限定公開の Google アクセスと IAM 権限を使用して Google API に直接アクセスする
Google の API とサービスは、外部 IP アドレスを使用して公開されます。VPC ネイティブのエイリアス IP アドレスを持つ Pod が限定公開の Google アクセスを使用して Google API に接続する場合、トラフィックが Google のネットワークの外に出ることはありません。
このチュートリアルのインフラストラクチャを設定する際、GKE Pod で使用されるサブネットの限定公開の Google アクセスを有効にしています。限定公開の Google アクセスで使用される IP アドレスへのアクセスを許可するために、ルート、VPC ファイアウォール ルール、プライベート DNS ゾーンを作成しています。この構成のため、Pod は Egress ゲートウェイ経由でトラフィックを送信しなくても、Google API に直接アクセスできます。Workload Identity Federation for GKE と IAM を使用すると、特定の Kubernetes サービス アカウント(ここでは名前空間)で使用できる API を制御できます。Egress ゲートウェイが Google API への接続を処理していないため、Istio の承認は有効になりません。
Pod が Google API を呼び出せるようにするには、IAM を使用して権限を付与する必要があります。このチュートリアルで使用するクラスタは Workload Identity Federation for GKE を使用するように構成されているため、Kubernetes サービス アカウントを Google サービス アカウントとして機能させることができます。
アプリケーションで使用する Google サービス アカウントを作成します。
gcloud iam service-accounts create sa-test-app-team-x
Kubernetes サービス アカウントを Google サービス アカウントとして使用できるようにします。
gcloud iam service-accounts add-iam-policy-binding \ --role roles/iam.workloadIdentityUser \ --member "serviceAccount:${PROJECT_ID}.svc.id.goog[team-x/test]" \ sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com
team-x
名前空間のテストアプリの Kubernetes サービス アカウントに、Google サービス アカウントのメールアドレスでアノテーションを付けます。cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: annotations: iam.gke.io/gcp-service-account: sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com name: test namespace: team-x EOF
テスト アプリケーション Pod は、Google API を呼び出すための一時的な認証情報を取得するために、Google メタデータ サーバー(DaemonSet として稼働)にアクセスできる必要があります。GKE メタデータ サーバーのサービス エントリを作成します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: metadata-google-internal namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: metadata.google.internal spec: hosts: - metadata.google.internal ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
また、private.googleapis.com と storage.googleapis.com のサービス エントリも作成します。
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: private-googleapis-com namespace: istio-egress labels: # Show this service and its telemetry in the Cloud Service Mesh page of the Google Cloud console service.istio.io/canonical-name: googleapis.com spec: hosts: - private.googleapis.com - storage.googleapis.com ports: - number: 80 name: http protocol: HTTP - number: 443 name: tls protocol: TLS resolution: DNS location: MESH_EXTERNAL exportTo: - 'istio-egress' - 'team-x' EOF
Kubernetes サービス アカウントが Google サービス アカウントとして機能するように構成されていることを確認します。
kubectl -n team-x exec -it $(kubectl -n team-x get pod -l app=test \ -o jsonpath={.items..metadata.name}) -c test -- gcloud auth list
Google サービス アカウントがアクティブな唯一の ID として表示されます。
Cloud Storage バケットにテストファイルを作成します。
echo "Hello, World!" > /tmp/hello gcloud storage buckets create gs://${PROJECT_ID}-bucket gcloud storage cp /tmp/hello gs://${PROJECT_ID}-bucket/
サービス アカウントにバケット内のファイルを一覧表示する権限を付与します。
gcloud storage buckets add-iam-policy-binding gs://${PROJECT_ID}-bucket/ \ --member=serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com \ --role=roles/storage.objectViewer
テスト アプリケーションがテストバケットにアクセスできることを確認します。
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gcloud storage cat gs://${PROJECT_ID}-bucket/hello
次の出力を確認できます。
Hello, World!
クリーンアップ
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。
このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、以下のセクションの手順を完了します。
プロジェクトの削除
課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。
- In the Google Cloud console, go to the Manage resources page.
- In the project list, select the project that you want to delete, and then click Delete.
- In the dialog, type the project ID, and then click Shut down to delete the project.
次のステップ
- コンパニオンのベスト プラクティス ガイドを読む。
- GKE 強化ガイドを読む。
- CA Service を使用して Cloud Service Mesh Ingress ゲートウェイの TLS 証明書管理を自動化する方法を学習する。
- GKE Enterprise 構成管理で、すべてのインフラストラクチャの構成とポリシーを管理する方法を学習する。
- リファレンス アーキテクチャ、図、ベスト プラクティスについては、Cloud アーキテクチャ センターをご確認ください。