このチュートリアルでは、Anthos Service Mesh の Egress ゲートウェイやその他の Google Cloud コントロールを使用して、Google Kubernetes Engine クラスタにデプロイされたワークロードからの送信トラフィック(下り、外向き)を保護する方法について説明します。このチュートリアルは、ベスト プラクティス ガイドの補足として位置付けられています。
このチュートリアルの対象読者は、1 つ以上のソフトウェア配信チームが使用する Google Kubernetes Engine クラスタを管理するネットワーク エンジニア、プラットフォーム エンジニア、セキュリティ エンジニアです。ここで説明する制御は、規制(GDPR や PCI など)の遵守を実証しなければならない組織に特に有効です。
目標
- Anthos Service Mesh を実行するためのインフラストラクチャを設定します。
- カスタム VPC ネットワークとプライベート サブネット
- インターネット アクセス用の Cloud NAT
- Egress ゲートウェイ Pod 用の追加のノードプールを持つ限定公開 GKE クラスタ
- 制限付き下り(外向き)VPC ファイアウォール ルール。ゲートウェイ ノードのみが外部ホストに到達できます。
- Container Registry と Google API に接続するための限定公開の Google アクセス
- 専用ノードプールで実行される Egress ゲートウェイを備えた Anthos Service Mesh をインストールします。
- Egress ゲートウェイを使用して、外部トラフィックのマルチテナント ルーティング ルールを構成します。
- 名前空間「team-x」のアプリケーションは example.com に接続できます。
- 名前空間「team-y」のアプリケーションは httpbin.org に接続できます。
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
- Anthos Service Mesh
- Cloud Load Balancing
- Cloud NAT
- ネットワーキング
- 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
スクリプトを実行可能にして、
source
コマンドで実行し、環境を初期化します。chmod +x ./init-egress-tutorial.sh source ./init-egress-tutorial.sh
必要な Identity and Access Management(IAM)のロールを設定します。プロジェクト オーナーの場合は、インストールを完了するために必要なすべての権限が付与されます。プロジェクト オーナーでない場合は、管理者に次の IAM ロールを付与するよう依頼します。次のコマンドで、 PROJECT_EMAIL_ADDRESS を Google Cloud へのログインに使用するアカウントに変更します。
gcloud projects add-iam-policy-binding ${PROJECT_ID} \ --member user:PROJECT_EMAIL_ADDRESS \ --role=roles/editor \ --role=roles/compute.admin \ --role=roles/container.admin \ --role=roles/resourcemanager.projectIamAdmin \ --role=roles/iam.serviceAccountAdmin \ --role=roles/iam.serviceAccountKeyAdmin \ --role=roles/gkehub.admin \ --role=roles/serviceusage.serviceUsageAdmin
チュートリアルに必要な API を有効にします。
gcloud services enable \ dns.googleapis.com \ container.googleapis.com \ compute.googleapis.com \ monitoring.googleapis.com \ logging.googleapis.com \ cloudtrace.googleapis.com \ meshca.googleapis.com \ meshconfig.googleapis.com \ iamcredentials.googleapis.com \ gkeconnect.googleapis.com \ gkehub.googleapis.com \ cloudresourcemanager.googleapis.com \ stackdriver.googleapis.com
API の有効化に数分かかることがあります。API が有効になると、次のような出力が表示されます。
Operation "operations/acf.601db672-88e6-4f98-8ceb-aa3b5725533c" finished successfully.
インフラストラクチャの設定
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 \ --destination-ranges 10.5.0.0/28 \ --network vpc-network \ --priority 1000 \ --description "Allow nodes to reach the Kubernetes API server."
Anthos Service Mesh は、ワークロードにサイドカー プロキシを挿入する際に Webhook を使用します。GKE API サーバーが、ノードで実行されているサービス メッシュ コントロール プレーンによって公開された Webhook を呼び出すようにします。
gcloud compute firewall-rules create allow-ingress-api-server-to-webhook \ --action ALLOW \ --direction INGRESS \ --rules tcp:15017 \ --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 は、対応する上り(内向き)ルールを自動的に作成します。
gcloud compute firewall-rules create allow-egress-pods-and-services \ --action ALLOW \ --direction EGRESS \ --rules all \ --destination-ranges 10.1.0.0/16,10.2.0.0/20 \ --network vpc-network \ --priority 1000 \ --description "Allow pods and services on nodes to reach each other"
Calico というサービスは、GKE に
NetworkPolicy
API 機能を提供します。サブネット内での Calico の接続を許可します。gcloud compute firewall-rules create allow-egress-calico \ --action ALLOW \ --direction EGRESS \ --rules tcp:5473 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow Calico Typha within the subnet"
GKE がノード指標を読み取るには、kubelet 読み取り専用ポートが必要です。サブネット内でのこのポートへのアクセスを許可します。
gcloud compute firewall-rules create allow-egress-kubelet-readonly \ --action ALLOW \ --direction EGRESS \ --rules tcp:10255 \ --destination-ranges 10.0.0.0/24 \ --network vpc-network \ --priority 1000 \ --description "Allow access to the kubelet read-only port within the subnet"
Google API や Container Registry などのサービスを提供するために、限定公開の Google アクセスで使用される予約済みの IP アドレスセットへのアクセスを許可します。
gcloud compute firewall-rules create allow-egress-gcp-apis \ --action ALLOW \ --direction EGRESS \ --rules tcp \ --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 \ --source-ranges 130.211.0.0/22,35.191.0.0/16,35.191.0.0/16,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 ネットワークの外に出ることはありません。
限定公開の 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
限定公開 GKE クラスタを作成します。
gcloud container clusters create cluster1 \ --enable-ip-alias \ --enable-private-nodes \ --release-channel "regular" \ --no-enable-basic-auth \ --no-issue-client-certificate \ --enable-master-authorized-networks \ --master-authorized-networks ${SHELL_IP//\"}/32 \ --master-ipv4-cidr 10.5.0.0/28 \ --enable-network-policy \ --service-account "sa-application-nodes@${PROJECT_ID}.iam.gserviceaccount.com" \ --machine-type "e2-standard-4" \ --num-nodes "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 が割り振られます。
Anthos Service Mesh では、少なくとも 4 つの vCPU を備えたマシンタイプをクラスタノードで使用する必要があります。ノードが Anthos Service Mesh でサポートされている Kubernetes バージョンを実行できるように、クラスタを「通常の」リリース チャネルに登録することをおすすめします。詳細については、Anthos Service Mesh のインストール ガイドをご覧ください。
Workload Identity はクラスタで有効になります。Anthos Service Mesh には Workload Identity が必要です。また、Anthos 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]
Anthos Service Mesh のインストールと設定
このチュートリアルでは、Anthos Service Mesh のオプション機能を使用します。スクリプトを使用した Anthos Service Mesh のインストールについては、ドキュメントのインストール ガイドをご覧ください。
デプロイするサービス メッシュ コントロール プレーンと Egress ゲートウェイの名前空間を作成します。
kubectl create ns istio-system kubectl create ns istio-egress
istio-egress、istio-system、kube-system の名前空間にラベルを付けます。
kubectl label ns istio-egress istio=egress istio-injection=disabled kubectl label ns istio-system istio=system kubectl label ns kube-system kube-system=true
これらのラベルは、Kubernetes NetworkPolicy を適用するために後で使用されます。
istio-injection=disabled
ラベルは、istioctl
分析の実行時に誤った警告が表示されることを防止します。Istio OperatorAPI を使用して、マニフェスト ファイルを作成し、Anthos Service Mesh のインストールをカスタマイズします。
cat << 'EOF' > ./asm-custom-install.yaml apiVersion: install.istio.io/v1alpha1 kind: IstioOperator metadata: name: "egress-gateway" spec: meshConfig: accessLogFile: "/dev/stdout" components: egressGateways: - name: "istio-egressgateway" enabled: true namespace: "istio-egress" label: istio: "egress" k8s: tolerations: - key: "dedicated" operator: "Equal" value: "gateway" nodeSelector: cloud.google.com/gke-nodepool: "gateway" EOF
このファイルはインストール スクリプトの引数として提供され、次の構成を指定します。
- 容認と nodeSelector を使用して
istio-egress
名前空間で実行される Egress ゲートウェイの Deployment。gateway
ノード上でのみ実行されます。 - すべてのサイドカー プロキシの stdout へのアクセスロギング。
- 容認と nodeSelector を使用して
インストール スクリプトをダウンロードします。
curl -O https://storage.googleapis.com/csm-artifacts/asm/install_asm
スクリプトを実行可能にします。
chmod +x install_asm
次のコマンドを実行して、Anthos Service Mesh をインストールします。
./install_asm \ --mode install \ --project_id ${PROJECT_ID} \ --cluster_name cluster1 \ --cluster_location ${ZONE} \ --custom_overlay ./asm-custom-install.yaml \ --output_dir ./ \ --enable_all
スクリプトが完了したら、環境変数を設定して
istioctl
ツールへのパスを保持し、初期化スクリプトに追加します。ISTIOCTL=$(find "$(pwd -P)" -name istioctl) echo "ISTIOCTL=\"${ISTIOCTL}\"" >> ./init-egress-tutorial.sh
Anthos Service Mesh のインストールを確認する
Anthos Service Mesh のコントロール プレーン コンポーネントが
istio-system
名前空間で実行されていることを確認します。kubectl get pod -n istio-system
istio-ingressgateway
Pod とistiod-asm
Pod が実行中であることが確認できます。Egress ゲートウェイ Pod が
istio-egress
名前空間とgateway
ノードプールのノードで実行されていることを確認します。kubectl get pods -n istio-egress -o wide
Egress ゲートウェイ Pod には、
gateway
ノードプール内のノードを選択するためのnodeSelector
と、taint されたゲートウェイ ノードで実行するための容認機能が備わっています。Egress ゲートウェイ Pod の nodeSelector と容認機能を調べます。kubectl -n istio-egress get pod -l app=istio-egressgateway \ -o=custom-columns='name:metadata.name,nodeSelector:spec.nodeSelector,\ tolerations:spec.tolerations[?(@.key=="dedicated")]'
出力は次のようになります。
name nodeSelector tolerations istio-egressgateway-74687946f5-dg9mp map[cloud.google.com/gke-nodepool:gateway] map[key:dedicated operator:Equal value:gateway]
メッシュとテスト アプリケーションの準備
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
Anthos Service Mesh でプロキシ サイドカーを自動的に挿入するには、ワークロードの名前空間にリビジョン ラベルを設定する必要があります。リビジョン ラベルは、クラスタにデプロイされている Anthos Service Mesh コントロール プレーンのリビジョンと一致する必要があります。
istiod
Pod のリビジョン ラベルを検索して、環境変数に保存します。REVISION_LABEL=$(kubectl get pod -n istio-system -l app=istiod \ -o jsonpath='{.items[0].metadata.labels.istio\.io/rev}')
team-x
およびteam-y
名前空間にリビジョン ラベルを設定します。kubectl label ns team-x istio.io/rev=${REVISION_LABEL} kubectl label ns team-y istio.io/rev=${REVISION_LABEL}
テストデプロイに使用する 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
リソースを適用することをおすすめします。
Anthos 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
このリストには Envoy クラスタが約 20 個あり、Egress ゲートウェイ用のものもいくつかあります。
プロキシ構成を、
istio-egress
名前空間とteam-x
名前空間のサービス エントリによって明示的に定義された下り(外向き)ルートに制限します。Sidecar
リソースをteam-x
名前空間に適用します。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
に設定すると、プロキシ構成が制限されます。サービス エントリを定義することで、メッシュのサービス レジストリに明示的に追加された外部ホストのみが含まれるようになります。「
istio-egress/*
」部分は、サイドカー プロキシがexportTo
属性を使用して使用可能になるistio-egress
名前空間からルートを選択することを指定します。「team-x/*
」部分には、team-x
名前空間でローカルに構成されたルートが含まれます。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 ゲートウェイ経由でトラフィックをルーティングするように Anthos Service Mesh を構成する
ポート 80 上の HTTP トラフィックに対して
Gateway
を構成します。Gateway
により、インストーラがistio-egress
名前空間にデプロイしたistio-egressgateway
プロキシが選択されます。Gateway
構成がistio-egress
名前空間に適用され、すべてのホストのトラフィックを処理します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: egress-gateway namespace: istio-egress spec: selector: istio: egress 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: loadBalancer: simple: ROUND_ROBIN tls: mode: ISTIO_MUTUAL EOF
istio-egress
名前空間にServiceEntry
を作成し、team-x
名前空間のメッシュのサービス レジストリに example.com を明示的に登録します。cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: example-com-ext namespace: istio-egress 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
出力は次のようになります。
✔ 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=egress \ -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 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
次の出力を確認できます。
✔ 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: 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: 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 開始
プレーン HTTP リクエストを TLS にアップグレード(TLS 開始)するように、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: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE sni: example.com EOF
example.com の仮想サービスを更新して、ゲートウェイのポート 80 へのリクエストが、宛先ホストに送信されるときにポート 443 の TLS にアップグレードされるようにします。
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=egress \ -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: egress 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: loadBalancer: simple: ROUND_ROBIN 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: rules: - when: - key: destination.port values: ["8443"] EOF
istioctl analyze
を実行して、構成エラーを確認します。${ISTIOCTL} analyze -n istio-egress
次の出力を確認できます。
✔ 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=egress \ -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: istio: system podSelector: matchLabels: istio: istiod - namespaceSelector: matchLabels: istio: egress podSelector: matchLabels: istio: egress 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: kube-system: "true" ports: - port: 53 protocol: UDP - port: 53 protocol: TCP EOF
ワークロードとプロキシが、Mesh CA を含む 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 ports: - 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: 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 と IAM を使用すると、特定の Kubernetes サービス アカウント(ここでは名前空間)で使用できる API を制御できます。Egress ゲートウェイが Google API への接続を処理していないため、Istio の承認は有効になりません。
Pod が Google API を呼び出せるようにするには、IAM を使用して権限を付与する必要があります。このチュートリアルで使用するクラスタは Workload Identity を使用するように構成されているため、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 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 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 gsutil mb gs://${PROJECT_ID}-bucket gsutil cp /tmp/hello gs://${PROJECT_ID}-bucket/
サービス アカウントにバケット内のファイルを一覧表示する権限を付与します。
gsutil iam ch \ serviceAccount:sa-test-app-team-x@${PROJECT_ID}.iam.gserviceaccount.com:objectViewer \ gs://${PROJECT_ID}-bucket/
テスト アプリケーションがテストバケットにアクセスできることを確認します。
kubectl -n team-x exec -it \ $(kubectl -n team-x get pod -l app=test -o jsonpath={.items..metadata.name}) \ -c test \ -- gsutil 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 強化ガイドを読む。
- GKE Enterprise 構成管理で、すべてのインフラストラクチャの構成とポリシーを管理する方法を学習する。
- リファレンス アーキテクチャ、図、ベスト プラクティスについては、Cloud アーキテクチャ センターをご確認ください。