外部サービスのトラフィック遮断とパススルーの監視
Istioを使用して、遮断された外部トラフィックとパススルーされた外部トラフィックを監視する方法について説明します。
外部サービスへのアクセスを理解し、制御し、保護することは、Istioのようなサービスメッシュから得られる重要な利点の1つです。セキュリティと運用上の観点から、ブロックされている外部サービスのトラフィックを監視することが重要です。これは、アプリケーションがアクセスしてはならないサービスと通信しようとしている場合、誤った設定やセキュリティ上の脆弱性を明らかにする可能性があるためです。同様に、現在、すべての外部サービスアクセスを許可するポリシーがある場合、トラフィックを監視することで、アクセスを許可する明示的なIstio設定を段階的に追加し、クラスタのセキュリティを向上させることが有益です。いずれの場合も、テレメトリを介してこのトラフィックの可視性を確保することは非常に役立ちます。アラートやダッシュボードを作成し、セキュリティ体制についてより適切に判断できるようになるためです。これはIstioの運用ユーザーから非常に要望の高かった機能であり、1.3リリースでこのサポートが追加されたことを嬉しく思っています。
これを実装するために、Istioのデフォルトメトリクスは、ブロックされた外部サービスのトラフィックとパススルーされた外部サービスのトラフィックをキャプチャするために、明示的なラベルで拡張されます。このブログでは、これらの拡張されたメトリクスを使用してすべての外部サービストラフィックを監視する方法について説明します。
Istioコントロールプレーンは、BlackHoleClusterとPassthroughという、それぞれすべてのトラフィックをブロックまたは許可する事前定義されたクラスタを使用して、サイドカープロキシを設定します。これらのクラスタを理解するために、Istioサービスメッシュにおける外部サービスと内部サービスの意味から始めましょう。
外部サービスと内部サービス
内部サービスは、プラットフォームの一部であり、メッシュ内にあると見なされるサービスとして定義されます。内部サービスの場合、Istioコントロールプレーンはデフォルトでサイドカーに必要なすべての構成を提供します。たとえば、Kubernetesクラスタでは、IstioはすべてのKubernetesサービスのサイドカーを設定して、すべてのサービスが互いに通信できるというKubernetesのデフォルトの動作を維持します。
外部サービスは、プラットフォームの一部ではないサービス、つまりメッシュ外のサービスです。外部サービスの場合、Istioは2つのオプションを提供します。1つはすべての外部サービスアクセスをブロックする(global.outboundTrafficPolicy.mode
をREGISTRY_ONLY
に設定することで有効化)、もう1つはすべての外部サービスへのアクセスを許可する(global.outboundTrafficPolicy.mode
をALLOW_ANY
に設定することで有効化)です。この設定のデフォルトオプション(Istio 1.3時点)は、すべての外部サービスアクセスを許可することです。このオプションはメッシュ構成を介して設定できます。
ここで、BlackHoleとPassthroughのクラスタが使用されます。
BlackHoleとPassthroughのクラスタとは?
BlackHoleCluster - BlackHoleClusterは、
global.outboundTrafficPolicy.mode
がREGISTRY_ONLY
に設定されている場合に、Envoy構成に作成される仮想クラスタです。このモードでは、各サービスにサービスエントリが明示的に追加されない限り、外部サービスへのすべてのトラフィックはブロックされます。これを実装するために、元の宛先を使用する0.0.0.0:15001
のデフォルトの仮想アウトバウンドリスナーは、BlackHoleClusterを静的クラスタとするTCPプロキシとして設定されます。BlackHoleClusterの構成は以下のようになります。{ "name": "BlackHoleCluster", "type": "STATIC", "connectTimeout": "10s" }
ご覧のとおり、このクラスタはエンドポイントを持たない静的なクラスタであるため、すべてのトラフィックはドロップされます。さらに、Istioは、リクエストが同じポートの外部サービスに対して行われた場合、仮想リスナーの代わりにヒットするプラットフォームサービスのすべてのポート/プロトコル組み合わせに対して一意のリスナーを作成します。その場合、Envoyのすべての仮想ルートのルート構成は、次のようにBlackHoleClusterを追加するように拡張されます。
{ "name": "block_all", "domains": [ "*" ], "routes": [ { "match": { "prefix": "/" }, "directResponse": { "status": 502 } } ] }
ルートは
502
応答コードを持つ直接応答として設定されています。つまり、他のルートが一致しない場合、Envoyプロキシは502
HTTPステータスコードを直接返します。PassthroughCluster - PassthroughClusterは、
global.outboundTrafficPolicy.mode
がALLOW_ANY
に設定されている場合に、Envoy構成に作成される仮想クラスタです。このモードでは、任意の外部サービスへのすべてのトラフィックが許可されます。これを実装するために、SO_ORIGINAL_DST
を使用する0.0.0.0:15001
のデフォルトの仮想アウトバウンドリスナーは、PassthroughClusterを静的クラスタとするTCPプロキシとして設定されます。PassthroughClusterの構成は以下のようになります。{ "name": "PassthroughCluster", "type": "ORIGINAL_DST", "connectTimeout": "10s", "lbPolicy": "ORIGINAL_DST_LB", "circuitBreakers": { "thresholds": [ { "maxConnections": 102400, "maxRetries": 1024 } ] } }
このクラスタは元の宛先ロードバランシングポリシーを使用しており、Envoyはトラフィックを元の宛先、つまりパススルーに送信するように構成されます。
BlackHoleClusterと同様に、ポート/プロトコルベースの各リスナーについて、仮想ルート構成はPassthroughClusterをデフォルトルートとして追加するように拡張されます。
{ "name": "allow_any", "domains": [ "*" ], "routes": [ { "match": { "prefix": "/" }, "route": { "cluster": "PassthroughCluster" } } ] }
Istio 1.3より前は、メトリクスが報告されていなかったか、報告されていてもこれらのクラスタにトラフィックがヒットしたときに明示的なラベルが設定されていなかったため、メッシュを流れるトラフィックの可視性が不足していました。
次のセクションでは、仮想アウトバウンドリスナーまたは明示的なポート/プロトコルリスナーのいずれかがヒットしたかどうかによってメトリクスとラベルの発行が条件付けられるため、この機能強化を活用する方法について説明します。
拡張されたメトリクスの使用
いずれの場合(BlackHoleまたはPassthrough)でもすべての外部サービストラフィックをキャプチャするには、istio_requests_total
とistio_tcp_connections_closed_total
メトリクスを監視する必要があります。呼び出されるEnvoyリスナーの種類、つまりTCPプロキシリスナーまたはHTTPプロキシリスナーに応じて、これらのメトリクスのいずれかがインクリメントされます。
さらに、TCPプロキシリスナーの場合、BlackHoleまたはPassthroughクラスタを介してブロックまたは許可されている外部サービスのIPアドレスを確認するには、destination_ip
ラベルをistio_tcp_connections_closed_total
メトリクスに追加する必要があります。このシナリオでは、外部サービスのホスト名はキャプチャされません。このラベルはデフォルトでは追加されず、属性生成とPrometheusハンドラのIstio構成を拡張することで簡単に追加できます。多くのサービスでIPアドレスが不安定な場合、時系列の基数爆発には注意する必要があります。
PassthroughClusterメトリクス
このセクションでは、Envoyで呼び出されるリスナーの種類に基づいて発行されるメトリクスとラベルについて説明します。
HTTPプロキシリスナー:これは、外部サービスのポートがクラスタで定義されているサービスポートの1つと同じである場合に発生します。このシナリオでは、PassthroughClusterがヒットすると、
istio_requests_total
は次のように増加します。{ "metric": { "__name__": "istio_requests_total", "connection_security_policy": "unknown", "destination_app": "unknown", "destination_principal": "unknown", "destination_service": "httpbin.org", "destination_service_name": "PassthroughCluster", "destination_service_namespace": "unknown", "destination_version": "unknown", "destination_workload": "unknown", "destination_workload_namespace": "unknown", "instance": "100.96.2.183:42422", "job": "istio-mesh", "permissive_response_code": "none", "permissive_response_policyid": "none", "reporter": "source", "request_protocol": "http", "response_code": "200", "response_flags": "-", "source_app": "sleep", "source_principal": "unknown", "source_version": "unknown", "source_workload": "sleep", "source_workload_namespace": "default" }, "value": [ 1567033080.282, "1" ] }
destination_service_name
ラベルは、このクラスタがヒットしたことを示すためにPassthroughClusterに設定され、destination_service
は外部サービスのホストに設定されます。TCPプロキシ仮想リスナー - 外部サービスポートがクラスタ内のHTTPベースのサービスポートにマップされない場合、このリスナーが呼び出され、
istio_tcp_connections_closed_total
がインクリメントされるメトリクスになります。{ "status": "success", "data": { "resultType": "vector", "result": [ { "metric": { "__name__": "istio_tcp_connections_closed_total", "connection_security_policy": "unknown", "destination_app": "unknown", "destination_ip": "52.22.188.80", "destination_principal": "unknown", "destination_service": "unknown", "destination_service_name": "PassthroughCluster", "destination_service_namespace": "unknown", "destination_version": "unknown", "destination_workload": "unknown", "destination_workload_namespace": "unknown", "instance": "100.96.2.183:42422", "job": "istio-mesh", "reporter": "source", "response_flags": "-", "source_app": "sleep", "source_principal": "unknown", "source_version": "unknown", "source_workload": "sleep", "source_workload_namespace": "default" }, "value": [ 1567033761.879, "1" ] } ] } }
この場合、
destination_service_name
はPassthroughClusterに設定され、destination_ip
は外部サービスのIPアドレスに設定されます。destination_ip
ラベルを使用して逆引きDNSルックアップを行い、外部サービスのホスト名を取得できます。このクラスタはパススルーであるため、istio_tcp_connections_opened_total
、istio_tcp_received_bytes_total
、istio_tcp_sent_bytes_total
などの他のTCP関連メトリクスも更新されます。
BlackHoleClusterメトリクス
PassthroughClusterと同様に、このセクションでは、Envoyで呼び出されるリスナーの種類に基づいて発行されるメトリクスとラベルについて説明します。
HTTPプロキシリスナー:これは、外部サービスのポートがクラスタで定義されているサービスポートの1つと同じである場合に発生します。このシナリオでは、BlackHoleClusterがヒットすると、
istio_requests_total
は次のように増加します。{ "metric": { "__name__": "istio_requests_total", "connection_security_policy": "unknown", "destination_app": "unknown", "destination_principal": "unknown", "destination_service": "httpbin.org", "destination_service_name": "BlackHoleCluster", "destination_service_namespace": "unknown", "destination_version": "unknown", "destination_workload": "unknown", "destination_workload_namespace": "unknown", "instance": "100.96.2.183:42422", "job": "istio-mesh", "permissive_response_code": "none", "permissive_response_policyid": "none", "reporter": "source", "request_protocol": "http", "response_code": "502", "response_flags": "-", "source_app": "sleep", "source_principal": "unknown", "source_version": "unknown", "source_workload": "sleep", "source_workload_namespace": "default" }, "value": [ 1567034251.717, "1" ] }
destination_service_name
ラベルはBlackHoleClusterに設定され、destination_service
は外部サービスのホスト名に設定されていることに注意してください。この場合、応答コードは常に502
になります。TCPプロキシ仮想リスナー - 外部サービスポートがクラスタ内のHTTPベースのサービスポートにマップされない場合、このリスナーが呼び出され、
istio_tcp_connections_closed_total
がインクリメントされるメトリクスになります。{ "metric": { "__name__": "istio_tcp_connections_closed_total", "connection_security_policy": "unknown", "destination_app": "unknown", "destination_ip": "52.22.188.80", "destination_principal": "unknown", "destination_service": "unknown", "destination_service_name": "BlackHoleCluster", "destination_service_namespace": "unknown", "destination_version": "unknown", "destination_workload": "unknown", "destination_workload_namespace": "unknown", "instance": "100.96.2.183:42422", "job": "istio-mesh", "reporter": "source", "response_flags": "-", "source_app": "sleep", "source_principal": "unknown", "source_version": "unknown", "source_workload": "sleep", "source_workload_namespace": "default" }, "value": [ 1567034481.03, "1" ] }
destination_ip
ラベルは外部サービスのIPアドレスを表し、destination_service_name
はメッシュによってこのトラフィックがブロックされたことを示すためにBlackHoleClusterに設定されていることに注意してください。BlackHoleクラスタの場合、接続が確立されることがないため、istio_tcp_connections_opened_total
などの他のTCP関連メトリクスは増加しないことに注意することが興味深いです。
これらのメトリクスを監視することで、運用者はクラスタ内のアプリケーションによって消費されるすべての外部サービスを簡単に理解できます。