外部サービスへのアクセス

Istio が有効になっている Pod からの発信トラフィックはすべて、デフォルトでそのサイドカープロキシにリダイレクトされるため、クラスタ外の URL のアクセス可能性はプロキシの設定に依存します。デフォルトでは、Istio は、不明なサービスへのリクエストを通過させるように Envoy プロキシを設定します。これは Istio を使い始めるには便利な方法ですが、通常はより厳密な制御を設定することが望ましいです。

このタスクでは、外部サービスにアクセスする 3 つの異なる方法を示します。

  1. Envoy プロキシが、メッシュ内で設定されていないサービスへのリクエストを通過させるようにします。
  2. サービスエントリを設定して、外部サービスへの制御されたアクセスを提供します。
  3. 特定の IP 範囲に対して、Envoy プロキシを完全にバイパスします。

始める前に

  • インストールガイドの手順に従って Istio をセットアップします。demo 構成プロファイルを使用するか、またはEnvoy のアクセスログを有効にします。

  • curl サンプルアプリを、リクエストを送信するためのテストソースとしてデプロイします。自動サイドカーインジェクションが有効になっている場合は、次のコマンドを実行してサンプルアプリをデプロイします。

    Zip
    $ kubectl apply -f @samples/curl/curl.yaml@
    

    それ以外の場合は、次のコマンドを使用して curl アプリケーションをデプロイする前に、サイドカーを手動で注入します。

    Zip
    $ 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 の評価をすぐに開始できます。その後、外部サービスへのアクセスを設定するかどうかを決定できます。

  1. このアプローチが実際に機能することを確認するには、Istio のインストールが meshConfig.outboundTrafficPolicy.mode オプションを ALLOW_ANY に設定して構成されていることを確認する必要があります。Istio をインストールするときに明示的に REGISTRY_ONLY モードに設定していない限り、デフォルトで有効になっている可能性があります。

    不明な場合は、次のコマンドを実行してメッシュ構成を表示できます。

    $ kubectl get configmap istio -n istio-system -o yaml
    

    meshConfig.outboundTrafficPolicy.modeREGISTRY_ONLY の値で明示的に設定されているのを確認できない限り、オプションは ALLOW_ANY に設定されていると確信できます。これは、他に可能な唯一の値であり、デフォルトです。

  2. 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 モードに変更する必要があります。

  1. 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
    
  2. 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サービスへのアクセス

  1. 外部 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
    
  2. 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 に注目してください。

  3. 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サービスへのアクセス

  1. 外部 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
    
  2. SOURCE_POD から外部 HTTPS サービスにリクエストを送信します。

    $ kubectl exec "$SOURCE_POD" -c curl -- curl -sSI https://www.google.com | grep  "HTTP/"
    HTTP/2 200
    
  3. 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 サービスへの呼び出しにタイムアウトルールを設定します。

  1. テストソースとして使用されている 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)を返す必要があります。

  2. 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
  1. 数秒待ってから、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

外部サービスへの直接アクセス

特定の 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

  1. 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
    
  2. --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 つの方法を見てきました。

  1. 任意の外部サービスへのアクセスを許可するように Envoy を構成します。

  2. サービスエントリを使用して、メッシュ内のアクセス可能な外部サービスを登録します。これは推奨されるアプローチです。

  3. 再マップされた IP テーブルから外部 IP を除外するように Istio サイドカーを構成します。

最初のアプローチでは、メッシュ内で不明なサービスへの呼び出しを含め、トラフィックを Istio サイドカープロキシ経由で送信します。このアプローチを使用する場合、外部サービスへのアクセスを監視したり、Istio のトラフィック制御機能を活用したりすることはできません。特定のサービスについて 2 番目のアプローチに簡単に切り替えるには、それらの外部サービスに対するサービスエントリを作成するだけです。このプロセスにより、最初は任意の外部サービスにアクセスでき、後で必要に応じてアクセスを制御するか、トラフィック監視を有効にするか、トラフィック制御機能を使用するかを決定できます。

2 番目のアプローチでは、クラスター内外のサービスへの呼び出しに対して、Istio サービスメッシュのすべての同じ機能を使用できます。このタスクでは、外部サービスへのアクセスを監視し、外部サービスへの呼び出しにタイムアウトルールを設定する方法を学びました。

3 番目のアプローチでは、Istio サイドカープロキシをバイパスし、サービスが任意の外部サーバーに直接アクセスできるようにします。ただし、この方法でプロキシを構成するには、クラスタープロバイダー固有の知識と構成が必要です。最初のアプローチと同様に、外部サービスへのアクセスの監視も失われ、外部サービスへのトラフィックに Istio の機能を適用することもできません。

セキュリティに関する注意

より安全な方法でエグレストラフィック制御を実装するには、エグレスゲートウェイを介してエグレストラフィックを送信し、追加のセキュリティに関する考慮事項セクションで説明されているセキュリティ上の懸念事項を確認する必要があります。

クリーンアップ

curl サービスをシャットダウンします。

Zip
$ kubectl delete -f @samples/curl/curl.yaml@
この情報は役に立ちましたか?
改善のための提案はありますか?

フィードバックありがとうございます。