外部HTTPSプロキシの使用

エグレスゲートウェイの構成に関する例はこちら。これは、エグレスゲートウェイと呼ばれるIstioエッジコンポーネントを介して、メッシュから外部サービスへのトラフィックを転送する方法を示しています。ただし、外部サービスにアクセスするために、外部のレガシー(非Istio)HTTPSプロキシが必要となる場合があります。たとえば、企業が既にそのようなプロキシを導入しており、組織内のすべてのアプリケーションがそのプロキシを介してトラフィックを転送する必要がある場合などです。

この例では、外部HTTPSプロキシへのアクセスを有効にする方法を示します。アプリケーションはHTTP CONNECTメソッドを使用してHTTPSプロキシとの接続を確立するため、外部HTTPSプロキシへのトラフィックの構成は、外部HTTPおよびHTTPSサービスへのトラフィックの構成とは異なります。

始める前に

  • インストールガイドの手順に従ってIstioを設定します。

  • リクエスト送信のテストソースとして使用するサンプルアプリ curl をデプロイします。自動サイドカーインジェクション を有効にしている場合は、以下のコマンドを実行してサンプルアプリをデプロイしてください。

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

    それ以外の場合は、以下のコマンドを使用してサイドカーを手動で注入してからcurlアプリケーションをデプロイしてください。

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
    
  • ソースポッドの名前をSOURCE_POD環境変数に設定します。

    $ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
    

HTTPSプロキシのデプロイ

レガシープロキシをシミュレートするため、そしてこの例のためだけに、クラスタ内にHTTPSプロキシをデプロイします。また、クラスタの外で実行されているより現実的なプロキシをシミュレートするために、プロキシのポッドにはKubernetesサービスのドメイン名ではなく、IPアドレスでアクセスします。この例ではSquidを使用していますが、HTTP CONNECTをサポートするHTTPSプロキシであれば何でも使用できます。

  1. サイドカーインジェクションのためのラベル付けを行わずに、HTTPSプロキシ用の名前空間を作成します。ラベルがないと、新しい名前空間ではサイドカーインジェクションが無効になり、Istioはその名前空間内のトラフィックを制御しません。プロキシがクラスタの外にあることをシミュレートするには、この動作が必要です。

    $ kubectl create namespace external
    
  2. Squidプロキシの設定ファイルを作成します。

    $ cat <<EOF > ./proxy.conf
    http_port 3128
    
    acl SSL_ports port 443
    acl CONNECT method CONNECT
    
    http_access deny CONNECT !SSL_ports
    http_access allow localhost manager
    http_access deny manager
    http_access allow all
    
    coredump_dir /var/spool/squid
    EOF
    
  3. プロキシの設定を保持するためのKubernetes ConfigMapを作成します。

    $ kubectl create configmap proxy-configmap -n external --from-file=squid.conf=./proxy.conf
    
  4. Squidを含むコンテナをデプロイします。

    $ kubectl apply -f - <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: squid
      namespace: external
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: squid
      template:
        metadata:
          labels:
            app: squid
        spec:
          volumes:
          - name: proxy-config
            configMap:
              name: proxy-configmap
          containers:
          - name: squid
            image: sameersbn/squid:3.5.27
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - name: proxy-config
              mountPath: /etc/squid
              readOnly: true
    EOF
    
  5. Istioトラフィック制御なしでプロキシへのトラフィックをテストするために、external名前空間にcurlサンプルをデプロイします。

    Zip
    $ kubectl apply -n external -f @samples/curl/curl.yaml@
    
  6. プロキシポッドのIPアドレスを取得し、それを格納するためにPROXY_IP環境変数を定義します。

    $ export PROXY_IP="$(kubectl get pod -n external -l app=squid -o jsonpath={.items..podIP})"
    
  7. プロキシのポートを格納するためにPROXY_PORT環境変数を定義します。この場合、Squidはポート3128を使用します。

    $ export PROXY_PORT=3128
    
  8. external名前空間内のcurlポッドから、プロキシ経由で外部サービスへのリクエストを送信します。

    $ kubectl exec "$(kubectl get pod -n external -l app=curl -o jsonpath={.items..metadata.name})" -n external -- sh -c "HTTPS_PROXY=$PROXY_IP:$PROXY_PORT curl https://en.wikipedia.org/wiki/Main_Page" | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  9. プロキシのアクセスログでリクエストを確認します。

    $ kubectl exec "$(kubectl get pod -n external -l app=squid -o jsonpath={.items..metadata.name})" -n external -- tail /var/log/squid/access.log
    1544160065.248    228 172.30.109.89 TCP_TUNNEL/200 87633 CONNECT en.wikipedia.org:443 - HIER_DIRECT/91.198.174.192 -
    

これまでの作業は、Istioを使用せずに完了しました。

  • HTTPSプロキシをデプロイしました。
  • curlを使用して、プロキシ経由で外部サービスwikipedia.orgにアクセスしました。

次に、Istio対応ポッドからのトラフィックがHTTPSプロキシを使用するように設定する必要があります。

外部HTTPSプロキシへのトラフィックの構成

  1. HTTPSプロキシ用のTCP(HTTPではない!)サービスエントリを定義します。アプリケーションはHTTPSプロキシとの接続確立にHTTP CONNECTメソッドを使用しますが、プロキシはHTTPではなくTCPトラフィック用に設定する必要があります。接続が確立されると、プロキシは単にTCPトンネルとして機能します。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: ServiceEntry
    metadata:
      name: proxy
    spec:
      hosts:
      - my-company-proxy.com # ignored
      addresses:
      - $PROXY_IP/32
      ports:
      - number: $PROXY_PORT
        name: tcp
        protocol: TCP
      location: MESH_EXTERNAL
      resolution: NONE
    EOF
    
  2. default名前空間内のcurlポッドからリクエストを送信します。curlポッドにはサイドカーがあるため、Istioがトラフィックを制御します。

    $ kubectl exec "$SOURCE_POD" -c curl -- sh -c "HTTPS_PROXY=$PROXY_IP:$PROXY_PORT curl https://en.wikipedia.org/wiki/Main_Page" | grep -o "<title>.*</title>"
    <title>Wikipedia, the free encyclopedia</title>
    
  3. Istioサイドカープロキシのログでリクエストを確認します。

    $ kubectl logs "$SOURCE_POD" -c istio-proxy
    [2018-12-07T10:38:02.841Z] "- - -" 0 - 702 87599 92 - "-" "-" "-" "-" "172.30.109.95:3128" outbound|3128||my-company-proxy.com 172.30.230.52:44478 172.30.109.95:3128 172.30.230.52:44476 -
    
  4. プロキシのアクセスログでリクエストを確認します。

    $ kubectl exec "$(kubectl get pod -n external -l app=squid -o jsonpath={.items..metadata.name})" -n external -- tail /var/log/squid/access.log
    1544160065.248    228 172.30.109.89 TCP_TUNNEL/200 87633 CONNECT en.wikipedia.org:443 - HIER_DIRECT/91.198.174.192 -
    

発生した状況の理解

この例では、次の手順を実行しました。

  1. 外部プロキシをシミュレートするためにHTTPSプロキシをデプロイしました。
  2. Istio制御トラフィックを外部プロキシに有効にするためにTCPサービスエントリを作成しました。

wikipedia.orgなど、外部プロキシ経由でアクセスする外部サービスに対してサービスエントリを作成してはならないことに注意してください。これは、Istioの観点からはリクエストが外部プロキシのみに送信されるためです。Istioは、外部プロキシがリクエストをさらに転送するという事実を認識していません。

クリーンアップ

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

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@
    
  2. external名前空間内のcurlサービスをシャットダウンします。

    Zip
    $ kubectl delete -f @samples/curl/curl.yaml@ -n external
    
  3. Squidプロキシをシャットダウンし、ConfigMapと設定ファイルを削除します。

    $ kubectl delete -n external deployment squid
    $ kubectl delete -n external configmap proxy-configmap
    $ rm ./proxy.conf
    
  4. external名前空間を削除します。

    $ kubectl delete namespace external
    
  5. サービスエントリを削除します。

    $ kubectl delete serviceentry proxy
    
この情報は役に立ちましたか?
改善のための提案はありますか?

ご意見ありがとうございます!