外部サービスへのアクセス
Istio が有効になっている Pod からの発信トラフィックはすべて、デフォルトでそのサイドカープロキシにリダイレクトされるため、クラスタ外の URL のアクセス可能性はプロキシの設定に依存します。デフォルトでは、Istio は、不明なサービスへのリクエストを通過させるように Envoy プロキシを設定します。これは Istio を使い始めるには便利な方法ですが、通常はより厳密な制御を設定することが望ましいです。
このタスクでは、外部サービスにアクセスする 3 つの異なる方法を示します。
- Envoy プロキシが、メッシュ内で設定されていないサービスへのリクエストを通過させるようにします。
- サービスエントリを設定して、外部サービスへの制御されたアクセスを提供します。
- 特定の IP 範囲に対して、Envoy プロキシを完全にバイパスします。
始める前に
インストールガイドの手順に従って Istio をセットアップします。
demo
構成プロファイルを使用するか、またはEnvoy のアクセスログを有効にします。curl サンプルアプリを、リクエストを送信するためのテストソースとしてデプロイします。自動サイドカーインジェクションが有効になっている場合は、次のコマンドを実行してサンプルアプリをデプロイします。
$ kubectl apply -f @samples/curl/curl.yaml@
それ以外の場合は、次のコマンドを使用して
curl
アプリケーションをデプロイする前に、サイドカーを手動で注入します。$ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
SOURCE_POD
環境変数を、ソース Pod の名前に設定します。$ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath='{.items..metadata.name}')
外部サービスへのEnvoyパススルー
Istio には、インストールオプションである meshConfig.outboundTrafficPolicy.mode
があり、これは外部サービス、つまり Istio の内部サービスレジストリで定義されていないサービスのサイドカー処理を設定します。このオプションが ALLOW_ANY
に設定されている場合、Istio プロキシは不明なサービスへの呼び出しを通過させます。オプションが REGISTRY_ONLY
に設定されている場合、Istio プロキシは、メッシュ内で定義された HTTP サービスまたはサービスエントリがないホストをブロックします。ALLOW_ANY
がデフォルト値であり、外部サービスへのアクセスを制御せずに、Istio の評価をすぐに開始できます。その後、外部サービスへのアクセスを設定するかどうかを決定できます。
このアプローチが実際に機能することを確認するには、Istio のインストールが
meshConfig.outboundTrafficPolicy.mode
オプションをALLOW_ANY
に設定して構成されていることを確認する必要があります。Istio をインストールするときに明示的にREGISTRY_ONLY
モードに設定していない限り、デフォルトで有効になっている可能性があります。不明な場合は、次のコマンドを実行してメッシュ構成を表示できます。
$ kubectl get configmap istio -n istio-system -o yaml
meshConfig.outboundTrafficPolicy.mode
がREGISTRY_ONLY
の値で明示的に設定されているのを確認できない限り、オプションはALLOW_ANY
に設定されていると確信できます。これは、他に可能な唯一の値であり、デフォルトです。SOURCE_POD
から外部 HTTPS サービスにいくつかのリクエストを行い、正常な200
応答を確認します。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://edition.cnn.com | grep "HTTP/" HTTP/2 200 HTTP/2 200
おめでとうございます!メッシュからの送信トラフィックを正常に送信しました。
外部サービスにアクセスするこの簡単なアプローチには、外部サービスへのトラフィックに対する Istio の監視と制御が失われるという欠点があります。次のセクションでは、メッシュの外部サービスへのアクセスを監視および制御する方法について説明します。
外部サービスへのアクセス制御
Istio の ServiceEntry
構成を使用すると、Istio クラスタ内から公開されている任意のサービスにアクセスできます。このセクションでは、Istio のトラフィック監視および制御機能を失うことなく、外部 HTTP サービスである httpbin.org および外部 HTTPS サービスである www.google.com へのアクセスを設定する方法を示します。
デフォルトでブロックするポリシーへの変更
外部サービスへのアクセスを有効にする制御された方法を示すために、meshConfig.outboundTrafficPolicy.mode
オプションを ALLOW_ANY
モードから REGISTRY_ONLY
モードに変更する必要があります。
meshConfig.outboundTrafficPolicy.mode
オプションをREGISTRY_ONLY
に変更します。IstioOperator
CR を使用して Istio をインストールした場合は、次のフィールドを構成に追加します。spec: meshConfig: outboundTrafficPolicy: mode: REGISTRY_ONLY
それ以外の場合は、同等の設定を元の
istioctl install
コマンドに追加します。例:$ istioctl install <flags-you-used-to-install-Istio> \ --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY
SOURCE_POD
から外部 HTTPS サービスにいくつかのリクエストを行い、それらがブロックされていることを確認します。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://www.google.com | grep "HTTP/"; kubectl exec "$SOURCE_POD" -c curl -- curl -sI https://edition.cnn.com | grep "HTTP/" command terminated with exit code 35 command terminated with exit code 35
外部HTTPサービスへのアクセス
外部 HTTP サービスへのアクセスを許可する
ServiceEntry
を作成します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: httpbin-ext spec: hosts: - httpbin.org ports: - number: 80 name: http protocol: HTTP resolution: DNS location: MESH_EXTERNAL EOF
SOURCE_POD
から外部 HTTP サービスにリクエストを送信します。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS http://httpbin.org/headers { "headers": { "Accept": "*/*", "Host": "httpbin.org", ... "X-Envoy-Decorator-Operation": "httpbin.org:80/*", ... } }
Istio サイドカープロキシによって追加されたヘッダー
X-Envoy-Decorator-Operation
に注目してください。SOURCE_POD
のサイドカープロキシのログを確認します。$ kubectl logs "$SOURCE_POD" -c istio-proxy | tail [2019-01-24T12:17:11.640Z] "GET /headers HTTP/1.1" 200 - 0 599 214 214 "-" "curl/7.60.0" "17fde8f7-fa62-9b39-8999-302324e6def2" "httpbin.org" "35.173.6.94:80" outbound|80||httpbin.org - 35.173.6.94:80 172.30.109.82:55314 -
httpbin.org/headers
への HTTP リクエストに関連するエントリに注目してください。
外部HTTPSサービスへのアクセス
外部 HTTPS サービスへのアクセスを許可する
ServiceEntry
を作成します。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: ServiceEntry metadata: name: google spec: hosts: - www.google.com ports: - number: 443 name: https protocol: HTTPS resolution: DNS location: MESH_EXTERNAL EOF
SOURCE_POD
から外部 HTTPS サービスにリクエストを送信します。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep "HTTP/" HTTP/2 200
SOURCE_POD
のサイドカープロキシのログを確認します。$ kubectl logs "$SOURCE_POD" -c istio-proxy | tail [2019-01-24T12:48:54.977Z] "- - -" 0 - 601 17766 1289 - "-" "-" "-" "-" "172.217.161.36:443" outbound|443||www.google.com 172.30.109.82:59480 172.217.161.36:443 172.30.109.82:59478 www.google.com
www.google.com
への HTTPS リクエストに関連するエントリに注目してください。
外部サービスへのトラフィックの管理
クラスタ間リクエストと同様に、ServiceEntry
構成を使用してアクセスする外部サービスに対してルーティングルールを設定することもできます。この例では、httpbin.org
サービスへの呼び出しにタイムアウトルールを設定します。
テストソースとして使用されている Pod 内から、httpbin.org 外部サービスの
/delay
エンドポイントに curl リクエストを送信します。$ kubectl exec "$SOURCE_POD" -c curl -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5 200 real 0m5.024s user 0m0.003s sys 0m0.003s
リクエストは、約 5 秒で 200(OK)を返す必要があります。
kubectl
を使用して、httpbin.org
外部サービスへの呼び出しに 3 秒のタイムアウトを設定します。
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
http:
- timeout: 3s
route:
- destination:
host: httpbin.org
weight: 100
EOF
$ kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin-ext
spec:
parentRefs:
- kind: ServiceEntry
group: networking.istio.io
name: httpbin-ext
hostnames:
- httpbin.org
rules:
- timeouts:
request: 3s
backendRefs:
- kind: Hostname
group: networking.istio.io
name: httpbin.org
port: 80
EOF
数秒待ってから、curl リクエストをもう一度実行します。
$ kubectl exec "$SOURCE_POD" -c curl -- time curl -o /dev/null -sS -w "%{http_code}\n" http://httpbin.org/delay/5 504 real 0m3.149s user 0m0.004s sys 0m0.004s
今回は、3 秒後に 504 (Gateway Timeout) が表示されます。httpbin.org が 5 秒待っていたにもかかわらず、Istio はリクエストを 3 秒で打ち切りました。
外部サービスへのアクセス制御のクリーンアップ
$ kubectl delete serviceentry httpbin-ext google
$ kubectl delete virtualservice httpbin-ext --ignore-not-found=true
$ kubectl delete serviceentry httpbin-ext
$ kubectl delete httproute httpbin-ext --ignore-not-found=true
外部サービスへの直接アクセス
特定の IP 範囲に対して Istio を完全にバイパスする場合は、Envoy サイドカーが外部リクエストをインターセプトしないように構成できます。バイパスを設定するには、global.proxy.includeIPRanges
または global.proxy.excludeIPRanges
構成オプションのいずれかを変更し、kubectl apply
コマンドを使用して istio-sidecar-injector
構成マップを更新します。これは、traffic.sidecar.istio.io/includeOutboundIPRanges
などの対応するアノテーションを設定して、Pod で構成することもできます。istio-sidecar-injector
構成を更新すると、今後のすべてのアプリケーション Pod のデプロイに影響します。
すべての外部 IP がサイドカープロキシにリダイレクトされないようにする簡単な方法は、global.proxy.includeIPRanges
構成オプションを、内部クラスタサービスで使用される IP 範囲に設定することです。これらの IP 範囲の値は、クラスタが実行されているプラットフォームによって異なります。
プラットフォームの内部IP範囲の決定
クラスタプロバイダーに応じて values.global.proxy.includeIPRanges
の値を設定します。
IBM Cloud Private
cluster/config.yaml
の IBM Cloud Private 構成ファイルからservice_cluster_ip_range
を取得します。$ grep service_cluster_ip_range cluster/config.yaml
以下は出力例です。
service_cluster_ip_range: 10.0.0.1/24
--set values.global.proxy.includeIPRanges="10.0.0.1/24"
を使用します。
IBM Cloud Kubernetes Service
クラスタで使用されている CIDR を確認するには、ibmcloud ks cluster get -c <CLUSTER-NAME>
を使用して、Service Subnet
を探します。
$ ibmcloud ks cluster get -c my-cluster | grep "Service Subnet"
Service Subnet: 172.21.0.0/16
次に、--set values.global.proxy.includeIPRanges="172.21.0.0/16"
を使用します。
Google Kubernetes Engine(GKE)
範囲は固定されていないため、使用する範囲を決定するには、gcloud container clusters describe
コマンドを実行する必要があります。例:
$ gcloud container clusters describe XXXXXXX --zone=XXXXXX | grep -e clusterIpv4Cidr -e servicesIpv4Cidr
clusterIpv4Cidr: 10.4.0.0/14
servicesIpv4Cidr: 10.7.240.0/20
--set values.global.proxy.includeIPRanges="10.4.0.0/14\,10.7.240.0/20"
を使用します。
Azure Kubernetes Service(AKS)
Kubenet
クラスターで使用されているサービス CIDR および Pod CIDR を確認するには、az aks show
を使用し、serviceCidr
を探してください。
$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep Cidr
"podCidr": "10.244.0.0/16",
"podCidrs": [
"serviceCidr": "10.0.0.0/16",
"serviceCidrs": [
次に、--set values.global.proxy.includeIPRanges="10.244.0.0/16\,10.0.0.0/16"
を使用します。
Azure CNI
Azure CNI を非オーバーレイネットワーキングモードで使用している場合は、以下の手順に従ってください。Azure CNI をオーバーレイネットワーキングで使用している場合は、Kubenet の手順に従ってください。詳細については、Azure CNI オーバーレイのドキュメントを参照してください。
クラスターで使用されているサービス CIDR を確認するには、az aks show
を使用し、serviceCidr
を探してください。
$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep serviceCidr
"serviceCidr": "10.0.0.0/16",
"serviceCidrs": [
クラスターで使用されている Pod CIDR を確認するには、az
CLI を使用して vnet
を調べてください。
$ az aks show --resource-group "${RESOURCE_GROUP}" --name "${CLUSTER}" | grep nodeResourceGroup
"nodeResourceGroup": "MC_user-rg_user-cluster_region",
"nodeResourceGroupProfile": null,
$ az network vnet list -g MC_user-rg_user-cluster_region | grep name
"name": "aks-vnet-74242220",
"name": "aks-subnet",
$ az network vnet show -g MC_user-rg_user-cluster_region -n aks-vnet-74242220 | grep addressPrefix
"addressPrefixes": [
"addressPrefix": "10.224.0.0/16",
次に、--set values.global.proxy.includeIPRanges="10.244.0.0/16\,10.0.0.0/16"
を使用します。
Minikube、Docker For Desktop、ベアメタル
デフォルト値は 10.96.0.0/12
ですが、固定ではありません。実際の値を確認するには、次のコマンドを使用してください。
$ kubectl describe pod kube-apiserver -n kube-system | grep 'service-cluster-ip-range'
--service-cluster-ip-range=10.96.0.0/12
--set values.global.proxy.includeIPRanges="10.96.0.0/12"
を使用します。
プロキシバイパスの設定
プラットフォーム固有の IP 範囲を使用して、istio-sidecar-injector
設定マップを更新します。たとえば、範囲が 10.0.0.1/24 の場合は、次のコマンドを使用します。
$ istioctl install <flags-you-used-to-install-Istio> --set values.global.proxy.includeIPRanges="10.0.0.1/24"
Istio のインストールに使用したのと同じコマンドを使用し、--set values.global.proxy.includeIPRanges="10.0.0.1/24"
を追加します。
外部サービスへのアクセス
バイパス設定は新しいデプロイにのみ影響するため、「始める前に」セクションで説明されているように、curl
アプリケーションを終了してから再デプロイする必要があります。
istio-sidecar-injector
configmap を更新し、curl
アプリケーションを再デプロイした後、Istio サイドカーは、クラスター内の内部リクエストのみをインターセプトして管理します。外部リクエストはサイドカーをバイパスし、意図された宛先に直接送信されます。例:
$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS http://httpbin.org/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
...
}
}
HTTP または HTTPS を介した外部サービスへのアクセスとは異なり、Istio サイドカーに関連するヘッダーは表示されず、外部サービスに送信されたリクエストはサイドカーのログには表示されません。Istio サイドカーをバイパスするということは、外部サービスへのアクセスを監視できなくなることを意味します。
外部サービスへの直接アクセスのクリーンアップ
IP 範囲に対するサイドカープロキシのバイパスを停止するように構成を更新します。
$ istioctl install <flags-you-used-to-install-Istio>
何が起こったかの理解
このタスクでは、Istio メッシュから外部サービスを呼び出すための 3 つの方法を見てきました。
任意の外部サービスへのアクセスを許可するように Envoy を構成します。
サービスエントリを使用して、メッシュ内のアクセス可能な外部サービスを登録します。これは推奨されるアプローチです。
再マップされた IP テーブルから外部 IP を除外するように Istio サイドカーを構成します。
最初のアプローチでは、メッシュ内で不明なサービスへの呼び出しを含め、トラフィックを Istio サイドカープロキシ経由で送信します。このアプローチを使用する場合、外部サービスへのアクセスを監視したり、Istio のトラフィック制御機能を活用したりすることはできません。特定のサービスについて 2 番目のアプローチに簡単に切り替えるには、それらの外部サービスに対するサービスエントリを作成するだけです。このプロセスにより、最初は任意の外部サービスにアクセスでき、後で必要に応じてアクセスを制御するか、トラフィック監視を有効にするか、トラフィック制御機能を使用するかを決定できます。
2 番目のアプローチでは、クラスター内外のサービスへの呼び出しに対して、Istio サービスメッシュのすべての同じ機能を使用できます。このタスクでは、外部サービスへのアクセスを監視し、外部サービスへの呼び出しにタイムアウトルールを設定する方法を学びました。
3 番目のアプローチでは、Istio サイドカープロキシをバイパスし、サービスが任意の外部サーバーに直接アクセスできるようにします。ただし、この方法でプロキシを構成するには、クラスタープロバイダー固有の知識と構成が必要です。最初のアプローチと同様に、外部サービスへのアクセスの監視も失われ、外部サービスへのトラフィックに Istio の機能を適用することもできません。
セキュリティに関する注意
より安全な方法でエグレストラフィック制御を実装するには、エグレスゲートウェイを介してエグレストラフィックを送信し、追加のセキュリティに関する考慮事項セクションで説明されているセキュリティ上の懸念事項を確認する必要があります。
クリーンアップ
curl サービスをシャットダウンします。
$ kubectl delete -f @samples/curl/curl.yaml@