本チュートリアルでは、Istio 1.5とService Mesh Hubによるメッシュフェデレーションを活用し、プライベート環境でマルチクラスタ・サービスメッシュを構築する方法を紹介します。マルチリージョンに展開したプライベートなGoogle Kubernetes Engine (GKE) クラスタ上で稼働するIstioのworkloadsを、Internal Load Balancer (ILB) で接続することで実現します。

はじめに
Istio 1.5は3月5日にリリースされ、このメジャーアップデートにはいくつかの重要な変更が含まれています。一方で、Hashicorp Vaultを外部CAとして利用する機能のサポートは現在も開発中です。そこで、共通のルートCAを安全に管理する別の手段を探したところ、solo.ioのオープンソースプロジェクトであるService Mesh Hubに行き着きました。Service Mesh Hubは、複数のサービスメッシュ間でルートアイデンティティを統合できるソリューションです。これにより、すべての中間証明書が同一のルートCAで署名され、クラスタ間およびサービス間で正しくエンドツーエンドのmTLSを確立できます。
仕組み
本チュートリアルでは、
次のアーキテクチャを構築していきます。

Google Kubernetes Engine (GKE) クラスタをインターネットから隔離する理由はいくつかありますが、最大の理由はセキュリティです。プライベートクラスタではノードがRFC 1918のプライベートアドレスのみを保持し、マスターのプライベートエンドポイントとプライベートネットワーク経由で通信します。これにより、外部インターネットからのアクセスを認可の有無にかかわらず遮断できます。
TCP/UDP Internal Load Balancerには、あまり知られていないベータ機能としてGlobal Accessがあります。これを有効にすると、VPCネットワーク内のどのリージョンのクライアントからでも、内部TCP/UDPロードバランサにアクセスできるようになります。Global Accessが無効の場合、VPCネットワーク内のクライアントから発生するトラフィックは、ロードバランサと同一リージョン内に留まる必要があります。プライベートKubernetesクラスタでは、次のアノテーションを使うことで、Service単位でGlobal Accessを有効化できます。
networking.gke.io/internal-load-balancer-allow-global-access:"true".
本実装例では、ingressGatewayのKubernetes Serviceに直接アノテーションを付与し、Global Accessを備えたGCP ILBをプロビジョニングします。Global Accessを適用すれば、異なるリージョンで稼働するプライベートクラスタ間にネットワーク接続が確立されます。
これで完了です。ここで、サービスA (sleep.foo.cluster-1)から別メッシュ上のサービスB (httpbin.bar.cluster-2)へ通信するケースを考えてみましょう。あるメッシュのサービスが別メッシュのサービスを利用する場合、両メッシュ間でアイデンティティと信頼をフェデレートする必要があります。そのためには、メッシュ間でトラストバンドルを交換しなければなりません。
Service Mesh Hubでは、複数のメッシュをVirtualMeshと呼ばれるオブジェクトにまとめてグループ化できます。このリソースを作成することで、Service MeshはVirtual Mesh内のクラスタ間で共通のルートアイデンティティを確立し、サービスをフェデレートします。
共通ルートのプロセスを理解する

VirtualMeshリソースを作成すると、次のように動作します。
- Service Mesh Hubが、共通ルートによるアイデンティティ統合のプロセスを開始します。
- Service Mesh Hubが各クラスタのCertificate Signing Request (CSR) エージェントを使って新しい鍵/証明書ペアを作成し、中間CAを構成します。各クラスタの中間CAは、そのクラスタ上のメッシュで利用されます。
- 続いて、VirtualMeshCertificateSigningRequest CRで表現される証明書署名要求を作成します。
- Service Mesh Hubが、VirtualMeshで指定されたルートCAで証明書に署名します。
- 処理が完了したら、
istiodコントロールプレーンを再起動する必要があります。これは、IstioコントロールプレーンがCitadel用のCAを取得した後、十分な頻度でローテーションを行わないためです。この点は今後のIstioのバージョンで改善される予定です。
信頼関係が確立されると、Service Mesh Hubはサービスのフェデレーションを開始し、サービスエントリを自動生成して、クラスタをまたいだアクセスを可能にします。

本チュートリアルではenforceAccessControlフラグを無効にしていますが、この点については次回以降の記事で詳しく取り上げる予定です。そこでは、Istioが提供する強固なアイデンティティ、強力なポリシー、認証・認可・監査 (AAA) の各機能によって、サービスとデータをどのように保護できるかを紹介します。
チュートリアルのコード
参考資料
- 実装コード — https://github.com/palimarium/multicluster-istio-smh-private-gke
- GCP — Private GKE Clusters — https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters
- GCP — TCP/UDP Internal Load Balancer — https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balancing
- Istio — サンプルサービスの構成 — https://istio.io/docs/setup/install/multicluster/gateways/#configure-the-example-services
- Service Mesh Hub — コンセプト — https://docs.solo.io/service-mesh-hub/latest/concepts/
本チュートリアルでは、メッシュ間通信を備えたサービスメッシュをいかに手軽に実装できるかをご紹介しました。サービス間通信はGoogle CloudのGlobal Networkの外に出ることなく、安全なmTLSによって内部で完結します。