OpenShift Weblog

サービスメッシュのエッジでの設計上の考慮事項

2020年8月10日、寄稿者:Raffaele Spazzoli、Trevor Box、Joshua Mathianas

はじめに

Red Hat OpenShift Service Mesh を実装した経験から、私たちは、メッシュはエンタープライズ・ネットワーク内にある特別なゾーンのように動作することを発見しました。その内部では、構成は明確であり、厳密に守られています。メッシュの外部にあるものは制御の対象外であり、メッシュ外にはあらゆるものが存在し得ると考えるべきです。

適切なトレーニングと教育により、標準の Istio API を使用してサービスメッシュ内のトラフィックポリシーを構成する方法をすばやく習得し、それを CI/CD パイプラインや GitOps ワークフローで活かすことができます。

意外な発見だったのですが、私たちは、ほとんどの時間がメッシュのエッジの設計に費やされていることに気づきました。メッシュのエッジでは、外界との共存を構成する必要があります。

この記事では、メッシュとのインバウンドおよびアウトバウンド・トラフィックに関する一連の設計パターンを紹介します。

インバウンドおよびアウトバウンド・トラフィックに関する一般的な考慮事項

次に説明する内容をより深く理解するには、Istio でトラフィックのルーティングがどのように決定されるかを思い出してください (これから説明するモデルは、HTTP トラフィックでうまく機能します)。次の図をご覧ください。

進行方向は左から右です。

  1. 1. 接続がメッシュのメンバーに到達すると (すべてのメンバーで同じように機能する Ingress ゲートウェイを想像してみましょう)、すべてのルーティングの決定はホスト名 (ヘッダーの host フィールド) に基づいて行われます。
  2. 2. Ingress ゲートウェイは、Gateway オブジェクトに基づいて、特定のポート上の接続と特定のホスト名をリッスンするように構成されます。ゲートウェイ構成は、ラベルセレクターに基づいて、それが適用されるゲートウェイポッドを選択します。Gateway オブジェクトは、ゲートウェイポッドが存在するのと同じ名前空間で定義する必要があります。
  3. 3. デフォルトでは、Ingress ゲートウェイはメッシュ内のサービスを認識しません。Ingress ゲートウェイにメッシュ内のサービスを認識させるには、VirtualService を定義して Gateway オブジェクトに適用する必要があります。VirtualService が Gateway オブジェクトと同じ名前空間にない場合 (ほとんどの場合はそうだと思います)、Gateway オブジェクトは NamespacedName 形式 (<namespace>/<gateway>) で参照する必要があります。そのはこちらで確認できます。
  4. 4. VirtualService を DestinationRule と組み合わせて、きめ細かなトラフィック管理を行うことができます。
  5. 5. そして、VirtualService は、Kubernetes サービスのアクティブなメンバー (自動検出) や ServiceEntry にルーティングします。ServiceEntries (はこちら) には、自動検出できないエンドポイントを手動で定義する機能があり、メッシュ外の宛先を表す場合があります (location: MESH_EXTERNAL)。

Ingress トラフィックの設計

インバウンド・トラフィックの場合、トラフィックをサービスに到達させる前に 1 つ以上の Ingress ゲートウェイを通過させるのが、一般に適切な方法です。

サービスメッシュの Ingress ゲートウェイをデプロイする方法を設計する場合、主に次の 2 点について考慮する必要があります。

  1. 1. 必要な Ingress ゲートウェイの数
  2. 2. Ingress ゲートウェイと OpenShift ルーターの関係

ほとんどの場合、メッシュごとに 1 つの Ingress ゲートウェイ (OpenShift ServiceMesh は、単一の OpenShift インスタンスにデプロイされた複数のサービスメッシュをサポートします) で十分です。

しかし、追加のゲートウェイが必要になるシナリオもあります。根本的に異なる 2 つの構成をサポートする必要がある、または、2 種類のトラフィックを物理的に分離しておく必要がある (この構成の例はこちら) といったシナリオもあります。Ingress ゲートウェイが複数ある場合のもう 1 つの例は、名前空間内の個々のテナントが Ingress ゲートウェイを所有する必要がある場合です。

次の図は、Ingress ゲートウェイの 3 つのデプロイメントパターンを示しています。

3 つ目の構成セットアップは、現在 OpenShift ServiceMesh オペレーターでサポートされていないため、テナントが手動でセットアップする必要があります。

その他の重要な決定事項は、OpenShift ルーターを介して Ingress ゲートウェイを公開するか、LoadBalancer サービスを介して外部トラフィックに直接公開するかです。

この図では、2 つのシナリオを示しています。1 つは OpenShift ルーターと Ingress ゲートウェイがチェーンされている場合、もう 1 つは Ingress ゲートウェイが直接公開されている場合です。

概念的には、ルーターはトラフィックが OpenShift SDN に入るエントリポイントであり、サービスメッシュの Ingress ゲートウェイはトラフィックがメッシュに入るポイントです。ルーターと Ingress ゲートウェイの両方をチェーンするとホップがあまりにも多くなり、サービスコールのレイテンシーが増加する場合があります。

1 番目のシナリオは、トラフィックが HTTP(s) または SNI+TLS の場合に適しています。これは、ルーターがサポートするタイプのトラフィックで、レイテンシーが増加しても問題にならない場合です。サービスメッシュのコントロールプレーンは、定義されている Gateway オブジェクトと一貫したルートを自動的に作成 (ior_enabled: true) するように構成できます。

2 番目のシナリオは、ルーターがネイティブにサポートしないタイプのトラフィックである場合、または良好なレイテンシーパフォーマンスを得ることが重要である場合に適切です。これらのシナリオでは、メッシュ管理者は、適切な DNS レコードとともに LoadBalancer サービスを構成する必要があります。DNS レコードの作成は、externalDNS Operator を使用して自動化できます (例はこちら)。

Ingress トラフィックの制御

上記の考慮事項は、Ingress トラフィックの形状を設計するのに役立ちますが、作成した Ingress のパスウェイを、唯一許可されるトラフィックの形式として強制することもできます。NetworkPolicy は、そのような処理に適したツールです (100% 正確ではないが適切なメンタルモデルでは、NetworkPolicies はレイヤー 4 でトラフィックルールを実施する方法で、Istio 構成はレイヤー 7でトラフィックルールを実施する方法だと見なされます)。メッシュまたはデフォルトルーターからのトラフィックのみを許可する一連のネットワークポリシーは、サービスメッシュのコントロールプレーンによってすでにデプロイされています。ここで必要なのは、トラフィックがテナントの名前空間のメッシュからのみ送信されるようにすることです。ルーター (RFE) からのトラフィックを許可しないようにサービスメッシュのコントロールプレーンを構成する方法はないようです。

RBAC 経由でルートを作成する権限を削除することで、トラフィックがサービスメッシュからのみ送信されるようにすることもできます。また、作成されたネットワークポリシーをテナントが変更できないようにする (こちらも RBAC 経由で) 必要もあるでしょう。

これらの強制ルールを構成する場合、OpenShift Service Mesh では、サービスメッシュの名前空間のテナントは引き続き、注入される Istio サイドカーにオプトインする必要があることにも注意してください。サイドカーが注入されていない場合、ポッドは本質的にメッシュ外にあるため、強制されるポリシーの対象となりません。Kubernetes レベルのポリシーは、すべてのポッドが強制的にメッシュの一部になるように (たとえば、Open Policy Agent を介して) 構成することもできます。

Egress トラフィックの設計

Egress トラフィックの場合も、必要な Egress ゲートウェイの数を決定しなければなりません。必要な数がゼロの場合もあります。しかしほとんどの場合は、Egress ゲートウェイが 1 つあると便利です。

メッシュ内のポッドからのアウトバウンド・トラフィックは常に Envoy ゲートウェイを通過するため、Egress ゲートウェイを通過しない場合でも、そのトラフィックはある程度制御されます。しかし、Egress ゲートウェイによって次のことが可能になります。

  • TLS の発信と信頼ドメインの移行。これにより、2 つの PKI ドメインを共存させることができますEgress ゲートウェイを使用して、サービスメッシュの内部 PKI からの TLS 接続を終了し、外部 PKI の証明書を使用して新しい接続を開始できます。
  • 既知の Egress IP の使用。メッシュ内のサービスからのアウトバウンド接続を既知の IP から発信してファイアウォールルールを適用できるようにする必要がある場合は、すべてのアウトバウンド接続を Egress ゲートウェイに迂回させ、Egress ゲートウェイが定義される名前空間で Egress IP を定義します。
  • Egress IP のユースケースと同様に、すべてのアウトバウンド・トラフィックを特定のノードセットから発信することが要件とされている場合があります。その要件を満たすには、Egress ゲートウェイを通過するトラフィックを抑制し、Egress ゲートウェイポッドがそれらのノードにデプロイされていることを確認します。

Egress トラフィックの制御

EgressNetworkPolicies を作成して、Egress ゲートウェイがデプロイされている名前空間以外のクラスタからトラフィックが分離されないようにすることができます。また、Egress ルールを持つネットワークポリシーを使用して、メッシュポッドから分離するトラフィックがメッシュ内に留まるようにすることもできます (ここでも、ユーザーがネットワークポリシーを管理できないようにする必要があります)。

さらに、Istio は、メッシュに認識されていないアドレスのルーティングを禁止するように構成できます。通常、アプリケーションがメッシュに認識されていないアドレスに接続しようとすると、Istio は DNS を使用してアドレスを解決し、リクエストを実行します。global.outboundTrafficPolicy モードのオプションを REGISTRY_ONLY に設定すると、既知のアドレス (つまり、VirtualService が定義されているアドレス) への接続のみを許可するように Istio を構成できます。

エッジトラフィックの OAuth 認証の構成

Istio は、エンドユーザーの認可ポリシーの一部として OAuth トークンの信頼性を確認できます。しかし、OAuth トークンを含まない要求の OIDC 認証ワークフローは処理できません。

Istio では、最初の認証 (トークンが作成される場所) がメッシュ外で実行されることを前提としていますが、これら 2 つのユースケース (認証フローとトークン検証) が密接に関連していることは明らかです。

実際、多くのアプリケーションで期待される動作は、トークンが利用できない場合にユーザーが認証フローにリダイレクトされることです。

このユースケースを処理する方法の 1 つは、Ingress ゲートウェイの前に認証ワークフローを処理できる OAuth プロキシ を追加することです。このコンテナは、次の図に示すようにサイドカーとしてデプロイすることもできます。

このシナリオの実例は、こちらで確認できます

認証されていないトラフィックや別の認証方法を使用するトラフィックを処理する必要がある場合は、このサービスメッシュのデプロイにゲートウェイを追加できます。

認証ワークフローを介してトークンが作成されたらそれを検証するように、Ingress ゲートウェイを構成できます。さらに、メッシュ内のすべてのサービスを構成してトークンを再検証し、セキュリティを向上させることができます。これが機能するためには、すべての段階でサービスがトークンを転送する必要があります。

エッジトラフィックの TLS および mTLS の構成

Ingress および Egress ゲートウェイは、異なる PKI の信頼ドメイン間での TLS 接続の処理方法を構成するのに役立ちます。Istio はデフォルトで内部の信頼ドメインを使用して独自の PKI を管理しているので、メッシュ外に他の信頼ドメインがあると考えて問題ありません。

次の図は、このシナリオを示しています。

上の図では、サービスメッシュ内でサービスを使用しているアプリケーションは信頼ドメイン A にあります。この場合、mTLS はコンシューマーと Ingress ゲートウェイの間に構成されています (この実行方法についてのインストラクションはこちらで確認できます)。次に、このアプリケーションは、信頼ドメイン B に属している外部サービスにアウトバウンドコールを発信します。mTLS は、Egress ゲートウェイに正しい証明書をデプロイすることで構成されます (これについてのインストラクションはこちらで確認できます)。

ゲートウェイレベルで証明書を管理することにより、次のことが可能になります。

  1. 1. より容易な構成:追加の証明書をサイドカーにデプロイする簡単な方法はありませんが、ゲートウェイに証明書のマテリアルを追加するのは比較的容易です。
  2. 2. 一元化された構成:証明書の構成は、メッシュ内のすべてのサービスで再利用できます。

当然、クライアント証明書の代わりに CA バンドルをデプロイすることにより、通常の TLS デプロイメントをセットアップすることもできます。どちらにせよ、この決定はサービスメッシュのテナントに影響を与えません。

証明書を自動的にプロビジョニングするメカニズムがあれば、この種のセットアップは非常に単純化されます。Cert-manager Operator は、この分野では理想的なオプションです。

ゲートウェイ用に TLS/mTLS をセットアップする方法に関する詳しいインストラクションは、こちらこちらで確認できます。

エッジトラフィックのレート制限の構成

シナリオによっては、メッシュからのアウトバウンド・トラフィックにレート制限を適用する必要が生じる場合もあるでしょう。このようなタイプのトラフィック制御は、アップストリームサービスが価格帯や、一定期間内に特定の量の要求または同時接続しか処理できないレガシーシステムに基づいて制限が課される場合に役立ちます。

さらに、さまざまなソースから発信されるトラフィックにさまざまな SLA が適用され、これらのトラフィックタイプを異なる方法でレート制限する必要が生じる場合があります。

宛先ルールとトラフィックポリシーをサーキットブレーカーと組み合わせて使用することで、メッシュ外に伝播するときに、さまざまな SLA のインバウンド要求に優先順位を付ける方法を管理できます。

上の図では、異なる SLA クラスが割り当てられた 2 つの異なるインバウンド要求 (ヘッダーの割り当てなど) を使用して、さまざまな宛先ルールと対応するトラフィックポリシーを適用する方法を示しています (例はこちら)。これらの方法を使用して、正常なアップストリームシステムを維持し、メッシュ内のサービスが機能を継続する、あるいは制限に達したときにサーキットブレーカー・パターンを適用することができます。

まとめ

この記事で説明したユースケースに加えて、より大規模なサービスメッシュのエコシステムでは、「メッシュのエッジで」重要な作業が行われているようです。

1 つの Kubernetes クラスタを超えたところや外部エンドポイントにメッシュを拡張できるのであれば、ある程度のゲートウェイ・フェデレーションを使用する可能性があるでしょう。たとえば、Istio はこの方法でフェデレーションメッシュをサポートし、Hashicorp Consul メッシュの最近のリリースも、WAN メッシュゲートウェイの導入によりこのレベルのサポートを獲得しました。

また、異なるベンダーのメッシュをフェデレートする機能には、おそらくゲートウェイの概念が利用されるでしょう。solo.ioMesh-hub は、この分野で実験中のプロジェクトです。

そして、WASM プロキシパッケージを使用して新しい機能を Envoy プロキシにプラグインする機能の導入により、ゲートウェイのメッシュのエッジにデプロイされる機能がますます増えるでしょう。

たとえば、IDS/IPSWAFDDoS 緩和システムSIEM へのアクセスイベントのフィード、ユーザー認証システム (OIDC 認証の例を見てきましたが、他のメカニズムも将来サポートされる可能性があります) などの DMZ にデプロイされた機能のほとんどは、Envoy フィルターとして追加するだけでよくなるかもしれません。これにより、DMZ の必要性が低下し、DMZ が完全になくなる可能性さえあります。

もう 1 つの例は、API ゲートウェイの機能性に関するものです。サービスメッシュと API ゲートウェイの機能性には重複する部分がありますが、API ゲートウェイに固有の機能セット (たとえば、開発者ポータルと API の価格設定/収益化) があります。今後の流れとして、これらの API ゲートウェイ機能は WASM の拡張機能として利用できるようになり、適切な機能セットを有効にすることにより、メッシュ Ingress ゲートウェイを使用して API ゲートウェイを作成できるようになるだろうと私たちは考えています。

Red Hat OpenShift

お問い合わせ

Red Hat OpenShiftのご質問やご相談は
メールにてお気軽にお問合わせください。