Amazon Web Services ブログ

Amazon VPC Lattice と Amazon EKS で実現するアプリケーションネットワーキング

イントロダクション

クラウドネイティブなアプリケーションの構築や、マイクロサービスアーキテクチャを採用してアプリケーションのモダナイズをおこなう AWS のお客様は、Amazon Elastic Kubernetes Service (Amazon EKS) を採用することで、イノベーションと市場投入までの時間を加速し、総所有コストを削減できます。多くのお客様は、テナントを分離し組織の要件を満たすために、複数の Amazon EKS クラスターを運用しています。多くの場合、これらのクラスターで実行されているサービスは互いに通信する必要があります。現在、ロードバランサーやサービスメッシュなど、クラスターに追加のネットワークインフラストラクチャコンポーネントをプロビジョニングするなど、様々なアプローチによってこのタスクを達成しています。これらのアプローチはすべて、クラスター間の IP リーチャビリティを必要とし、アーキテクチャを実現する上での複雑さが増します。それにより、プラットフォームチームと開発チームに追加の運用負荷を与えています。

Amazon VPC Lattice は、AWS のネットワークインフラストラクチャに直接組み込まれた、フルマネージドなアプリケーションネットワーキングサービスです。複数のアカウントと VPC にまたがる全てのサービスの接続、セキュリティ、監視に使用します。Amazon EKS では、Kubernetes Gateway API の実装である AWS Gateway API コントローラーを使用することで、Amazon VPC Lattice を活用できます。VPC Lattice を使用することで、EKS を利用しているお客様はシンプルかつ一貫性のある方法で、標準的な Kubernetes のセマンティクスでのクラスター間接続を設定することができます。

この記事では、VPC Lattice を使用して、ある EKS クラスターのサービスが、別のクラスターや VPC のサービスと通信するユースケースを紹介します。またサービスディスカバリの仕組みを、サービスのカスタムドメイン名のサポートと共に説明します。また VPC Lattice によって、プライベート NAT ゲートウェイやトランジットゲートウェイのようなネットワーク構成を必要とせずに、CIDR が重複する EKS クラスター内のサービスが相互に通信する方法を紹介します。セキュリティの観点では、SSL/TLS と VPC Lattice の認証ポリシーを使用して EKS サービスへのアクセスを保護し、他の EKS 上のクライアントサービスからその保護されたサービスへのリクエストを認証するセキュアな接続の詳細について説明します。

ソリューションアーキテクチャ

VPC Lattice によるクラスター間接続を実証するために使用したソリューションアーキテクチャを、以下の図に示します。このアーキテクチャの重要な点は、以下のとおりです。

  • 同じ AWS リージョンに 2 つの VPC がセットアップされていて、どちらも同じ RFC 1918 のアドレス範囲である 192.168.48.0/20 を使用しています。
  • 各々の VPC に EKS クラスターがプロビジョニングされています。この実装では、どちらのクラスターも Kubernetes 1.24 を使用しています。クラスターは「Amazon EKS クラスターの作成」で述べられているアプローチのいずれかを使用して作成することができます。VPC Lattice は、EKS クラスターの Kubernetes バージョンに関する特定の要件を課さないことに注意してください。EKS が現在サポートしている 4 つのバージョン (1.22 から 1.25) のうち、いずれかを選択できます。クラスターが VPC Lattice と共に動作するには、AWS VPC CNI プラグイン v1.8.0 以降を使用する必要があります。
  • VPC-A の EKS クラスターには HTTP Web サービスが配置され、REST API エンドポイントのセットが公開されています。もう 1 つの REST API サービスは、VPC-B の EKS クラスターに配置され、同じ VPC 内の Aurora PostgreSQL データベースと通信します。
  • AWS Gateway API コントローラーは、Gateway や HTTPRoute などの Kubernetes Gateway API リソースを管理するために、両方のクラスターで使用されています。これらのカスタムリソースは、クラスターにデプロイされた Kubernetes サービス間の通信を可能にする、サービスネットワークサービス、ターゲットグループなどの AWS VPC Lattice リソースを統合しています。AWS Gateway API コントローラーが Gateway API で定義されたカスタムリソースを拡張し、Kubernets API を使用して VPC Lattice リソースを作成できるようにする方法の詳細については、こちらの記事を参照してください。

ウォークスルー

クラスター間通信の実装

まずドキュメントの手順に従って、Gateway API コントローラーを両方の EKS クラスターにデプロイします。次に、GatewayClass と Gateway リソースを定義する Kubernetes マニフェストを、両方のクラスターに適用します。Gateway API コントローラーは、サービスネットワークが存在しない場合は Gateway と同じ eks-lattice-network という名前でサービスネットワークを作成し、VPC にアタッチします。VPC Lattice では、より高度なデプロイを実現するため、クラスターに複数の Gateway をデプロイすることができます。しかし、VPC は単一の Lattice のサービスネットワークにのみ関連付けることができます。したがって、どの時点でも単一の Gateway リソースがクラスター VPC に関連付けられています。これは、以下の図のように Amazon VPC コンソールで Lattice サービスネットワークの「VPC の関連付け」タブから確認することができます。

次に、VPC-B の EKS クラスターに、データストアサービスをデプロイします。このサービスは Aurora PostgreSQL データベースを持ち、/popular /summary というパスプレフィックスを持つ REST API エンドポイントを公開しています。カナリアでのトラフィックシフトを説明するために、こちらの Deployment マニフェストを使用して、データストアサービスの 2 つのバージョンをクラスターにデプロイします。他の VPC のクライアントが Amazon VPC Lattice を通じてこのサービスに到達できるようにするには、Lattice のサービスネットワークにこのサービスを登録する必要があります。これは、eks-lattice-network Gateway を参照する HTTPRoute リソースと、データストアサービスのバージョンを指定した Pod を選択する Kubernetes ClusterIP Service リソースをクラスターにデプロイすることによっておこなわれます。

カスタムドメイン名の実装

今回のセットアップでは、パスプレフィックス /popular への受信トラフィックが全てデータストアサービスの v1 に送信され、パスプレフィックス /summary へのトラフィックは HTTPRoute で定義された重み付けに基づいて v1 と v2 というサービスに分割されるシナリオを示します。Gateway API コントローラーは、HTTPRoute リソースに対応する Lattice サービスを作成します。これは、以下の図のように VPC コンソールで確認することができます。この Lattice サービスは、HTTPRoute リソースで指定したカスタムドメイン名 datastore.lattice.io を使ってクライアントに公開されるように設定されています。カスタムドメイン名は、HTTPRoute リソースを作成する時にだけ関連付けることができます。既存の HTTPRoute を変更してカスタムドメインを設定することはできません。

カスタムドメイン名は、VPC-B に関連付けられた Route 53 プライベートホストゾーンの DNS CNAME レコードによって、Lattice が生成したドメイン名とマッピングされます。このマッピング方法の詳細については、VPC Lattice のユーザーガイド内のドキュメントを参照してください。

Lattice はデータストアサービスへのトラフィックルーティングを管理するために HTTP リスナーターゲットグループを作成します。作成されたリソースは、以下の図で示すように、VPC コンソールの Lattice サービスの「ルーティング」タブで確認することができます。

この時点で、データストアサービスを VPC-B 内の EKS クラスターにデプロイし、eks-lattice-network Lattice サービスネットワークに関連付けられた他の全ての VPC のクライアントにカスタムドメイン名を使用して公開する全ての手順が完了しました。次に、データストアサービスが VPC Lattice フリートからのトラフィックを受信できるように仮想ファイヤウォールのルールを設定する必要があります。これは、VPC Lattice のリンクローカルアドレスの範囲である 169.254.171.0/24 からの全てのポート宛のトラフィックを許可するインバウンドルールを持つセキュリティグループを作成することによっておこなわれます。このセキュリティグループは、VPC-B の EKS クラスターのワーカーノードにアタッチされます。推奨されるベストプラクティスは、このルールをクラスター作成時に EKS によって作成されるクラスターセキュリティグループに追加することです。このタスクを実行する CLI コマンドは、こちらのドキュメントのステップ 3 に記載されています。以下は、これまで説明した Lattice と Kubernetes のリソースをデプロイするための一連の CLI コマンドです。

kubectl apply -f gateway-lattice.yaml          # GatewayClass and Gateway
kubectl apply -f route-datastore-canary.yaml   # HTTPRoute and ClusterIP Services
kubectl apply -f datastore.yaml                # Deployment
Bash

では、このマニフェストを使用して、VPC-A の EKS クラスターにフロントエンドサービスをデプロイします。このサービスは、カスタムドメイン名を使って VPC-B のデータストアサービスと通信するよう構成されています。これを有効にするには、次の図に示すように、VPC-A をカスタムドメイン名 datastore.lattice.io の DNS CNAME レコードを含む Route 53 プライベートホストゾーンと関連付ける必要があります。EKS ワーカーノードにアタッチされたクラスターセキュリティグループは、デフォルトで全ての送信トラフィックを許可します。したがって、VPC-A のクライアント側では追加のネットワーク設定は必要ありません。フロントエンドとデータストアのサービスは、CIDR 192.168.48.0/20 が重複する別々のクラスターにデプロイされていることに注目してください。NAT Gateway や Transit Gateway のようなネットワークインフラのコンポーネントを必要とせず、Lattice を介して互いに通信します。

以下に、VPC-A の EKS クラスターに Lattice と Kubernetes リソースをデプロイする一連の CLI コマンドを記載します。これには、kubectl port-forward を使用して、送信トラフィックをローカルポートからフロントエンドサービスの 1 つの Pod の 3000 サーバーポートに転送するコマンドも含まれており、これによりロードバランサーを必要とせずにこのユースケースをエンドツーエンドでテストすることができます。以下の図は、フロントエンドサービスの API エンドポイントを呼び出して受信したレスポンスを示しています。この API エンドポイントは Lattice 経由でデータストアサービスを呼び出します。この結果は /summary エンドポイントからの応答が、データストアサービスの 2 つのバージョン間で変化していることを示しています。

kubectl apply -f gateway-lattice.yaml                          # GatewayClass and Gateway
kubectl apply -f frontend.yaml                                 # Deployment and ClusterIP Service
kubectl -n apps port-forward frontend-6545dc979c-hqgvj 80:3000 # Port Forwarding
Bash

転送時の暗号化の実装

転送中のデータ保護を保証するために、お客様は SSL/TLS を使用して Lattice サービスと通信することができます。HTTPS リスナーを作成し、TLS バージョン 1.2 を使用して、VPC Lattice との HTTPS 接続を終端させることができます。また、カスタムドメイン名に関連付けられた独自の TLS 証明書を持ち込むこともできます。VPC Lattice は HTTP/1.1 および HTTP/2 で TLS をサポートします。

Gateway API を使って Lattice サービスに SSL/TLS を実装するには、こちらのマニフェストで示しているように、Gateway リソースに 1 つまたは複数の HTTPS リスナーを設定する必要があります。この例では tls-with-default-domain という HTTPS リスナーが、VPC Lattice によって生成された完全修飾ドメイン名 (FQDN) と関連付けられています。VPC Lattice はこの FQDN に対して TLS 証明書を提供し管理するため、リスナーは追加の設定を必要としません。tls-with-custom-domain という HTTP リスナーは、この記事で使用したカスタムドメイン名 datastore.lattice.io と関連付けられています。このリスナーは、ユーザーが作成し、AWS Certificate Manager (ACM) から提供されたプライベート TLS 証明書で通信を保護するように構成されています。SSL/TLS 証明書を作成するには、ACM のユーザーガイドを参照してください。お客様は、ご自身の TLS 証明書を持ち込み、ACM にインポートすることができます。

設定された HTTPS リスナーは HTTPRoute リソースから参照され、対応する Lattice サービスを SSL/TLS で保護します。VPC Lattice が生成した FQDN でデータストアサービスを公開し、VPC Lattice によって生成された TLS 証明書を使ってそれを保護する例がこちらのマニフェストで示されており、tls-with-default-domain という名前のリスナーを参照しています。カスタムドメイン名 datastore.lattice.io でデータストアサービスを公開し、ユーザーによって作成された TLS 証明書 によって保護される HTTPRoute は、こちらのマニフェストで示されており、tls-with-custom-domain という名前のリスナーを参照しています。以下の図は、カスタムドメイン名で構成され、ACM でユーザーによって作成された TLS 証明書を用いてセキュリティが保護されたサービスのコンソールビューを示しています。

アクセスコントロールの実装

Amazon VPC Lattice の設計は、デフォルトでセキュアです。Lattice 経由での EKS Service へのアクセスを有効にしたい場合は、クラスター VPC を Lattice サービスネットワークと関連付ける必要があります。そして、HTTPRoute で定義されたマッピングを使って、1 つ以上の EKS Service にトラフィックをルーティングできる Lattice サービスを作成する必要があります。Lattice サービスへのアクセスは、ネットワーク ACL やセキュリティグループのような、ネットワークレベルのプリミティブなリソースを使用して、さらに制限をかけることができます。これらのレイヤーに加えて、AWS Identity and Access Management (AWS IAM) のリソースベースポリシーを Lattice サービスのネットワークまたはサービスに適用して、サービスの呼び出し元をよりきめ細やかに制御することができます。Kubernetes RBAC は、Lattice を介して共有される EKS Service へのアクセス制御を実装するうえで、いかなる役割も果たさないことに注意してください。すべて、IAM の領域で完結しています。これらの実装の詳細について、これから説明します。

最初のステップは、Lattice のサービスネットワークに対して IAM 認証を有効化し、以下に示す CLI コマンドを使って IAM リソースベースポリシーを適用することです。また、VPC コンソールから作業することも可能です。コマンドで使用するポリシーファイル lattice-service-network-policy.json は、サービスネットワークへのアクセスをアクセスを全て許可する非常に寛容なポリシーを定義しています。このアクセスコントロールモデルは、サービスネットワークで Lattice のサービスを呼び出すクライアントに、IAM 認証のクレデンシャルを提示することを要求します。

aws vpc-lattice update-service-network --service-network-identifier $SERVICE_NETWORK_ID --auth-type AWS_IAM
aws vpc-lattice put-auth-policy --resource-identifier $SERVICE_NETWORK_ID --policy file://lattice-service-network-policy.json
Bash

次に、以下に示す CLI コマンドを使用して、Lattice サービスの IAM 認証を有効にし、IAM リソースベースポリシーを適用します。コマンドで使用するポリシーファイル lattice-service-policy.json は、クライアントが以下の条件を全て満たす場合のみ Lattice サービスを呼び出す許可を付与するという、きめ細やかなポリシーを定義しています。

  1. クライアントは、aws-sigv4-client という特定の IAM ロールのクレデンシャルを提示する必要があります。
  2. クライアントは、特定のサービスのみを呼び出すことができます。(ポリシー内のリソース ID は、VPC-B 内のデータストア EKS サービスにマッピングされた Lattice サービスのものです)
  3. クライアントは特定の VPC を起点とする必要があります。(ポリシー内の送信元 VPC ID は、VPC-A に関連します)
aws vpc-lattice update-service --service-identifier $SERVICE_ID --auth-type AWS_IAM
aws vpc-lattice put-auth-policy --resource-identifier $SERVICE_ID --policy file://lattice-service-policy.json
Bash

これで、サービス側のセットアップは完了です。クライアント側では、呼び出し元が 2 つの要件を満たす必要があります。まず初めに、呼び出し元は IAM ユーザーまたはロールの有効なクレデンシャルを提示する必要があります。VPC Lattice では、クライアント認証に AWS Signature Version 4 (SigV4) を使用しています。したがって、呼び出し元は IAM クレデンシャルを使って SigV4 でリクエストに署名する必要があります。次に、呼び出し元が使用する IAM ユーザーまたはロールは、Lattice サービスを呼び出すための権限を持っている必要があります。認可の要件は、IAM ユーザーまたはロールに適切な IAM アイデンティティベースポリシーをアタッチすることで満たすことができます。

認証の要件を満たすためには、SigV4 を使ってクライアントからの全てのリクエストに署名する仕組みが必要です。リクエストの署名は、AWS SDK を使用してアプリケーションコードに直接実装することができます。AWS Signature Version 4 の署名計算の例については、ドキュメントを参照してください。Kubernetes では、サイドカーパターンを用いてこのような横断的な課題を実装することが一般的です。VPC Lattice は一貫してこのプロセスの改善に取り組んでいるため、お客様のフィードバックを歓迎しています。

この記事では、クライアントのリクエストに認証情報を提供する署名の計算のため AWS SigV4 Proxy を使用しています。VPC-A の EKS クラスターにデプロイされたフロントエンドサービスなどのクライアントからこのプロキシを利用するには、サイドカーパターンを使用します。IAM roles for service accounts (IRSA) を使用するようにプロキシを構成することで、プロキシが IAM ロールのクレデンシャルを使用してリクエストに署名するようにできます。lattice-client-policy.json ファイルで定義されたアイデンティティベースのポリシーを IAM ロールにアタッチすることで、VPC-B のデータストア EKS Service にマッピングされた Lattice サービスを呼び出す権限を IAM ロールに付与することができます。最後に、Lattice サービスに適用したリソースベースポリシーで使用されたものと同じ IAM ロール aws-sigv4-client を使用する必要があります。ヘルパースクリプト createIRSA.sh は、IRSA の構成に必要な全ての IAM アーティファクトを作成します。EKS クラスターの OIDC プロバイダーが生成した JSON ウェブトークン (JWT) には、この認証スキームではどこにも使われない ServiceAccount の Identity が含まれることに注意してください。SigV4 Proxy に IAM ロールのクレデンシャルを公開する便利な仕組みとして IRSA を使用しているだけです。

Lattice サービスを呼び出す必要があるクライアント Pod に 対する SigV4 プロキシコンテナの注入を自動化するために、上図のように AWS SIGv4 Proxy アドミッションコントローラーを利用しています。このアドミッションコントローラーは、以下に示す Helm コマンドを使用して EKS クラスターにデプロイされます。さらに、EKS クラスターにフロントエンドサービスなどの Lattice クライアントをデプロイする前に、サイドカーを注入するターゲットとしての Pod を識別し、Lattice サービスの FQDN を指定し、HTTP/HTTPS を使用して通信するかどうかを決めるため、このマニフェストのように Annotations を追加する必要があります。

helm install aws-sigv4-proxy-admission-controller eks/aws-sigv4-proxy-admission-controller \
--namespace kube-system \
--set image.repository=public.ecr.aws/aws-observability/aws-sigv4-proxy-admission-controller \
--set image.tag=1.2 \
--set image.pullPolicy=Always \
--set env.awsSigV4ProxyImage=public.ecr.aws/aws-observability/aws-sigv4-proxy:1.7
Bash

まとめると、Lattice サービスにアクセスコントロールを実装する手順は、以下のとおりです。

サービス側:

  • サービスネットワークのレベルで IAM 認証を有効化し、粗い IAM リソースベースポリシーを適用します。このステップはオプションですが、強く推奨します。
  • サービスのレベルで IAM 認証を有効化し、きめ細やかな IAM リソースベースポリシーを適用します。

クライアント側:

  • IAM roles for service accounts をセットアップし、IAM アイデンティティベースポリシーを使用して、Lattice サービスを呼び出す側の IAM ロールに適切な権限を付与します。これは、Lattice サービスに適用されるリソースベースのポリシーで使用されるのと同じ IAM ロールであることを確認してください。
  • AWS SIGv4 Proxy アドミッションコントローラーを EKS クラスターにデプロイします。
  • IRSA をセットアップする時に作成された ServiceAccount で実行するよう構成された Lattice クライアントをクラスターにデプロイします。クライアントの Deployment マニフェストには、サイドカーとして AWS SigV4 プロキシを注入するために必要な Annotations が含まれていることを確認します。

SSL/TLS による VPC Lattice サービスの保護と、IAM によるサービスへのアクセスコントロールは、全く別のセキュリティ機構であることに注意してください。お客様は、一方を使用せずにもう一方を使用するか、サービスに対して両方を有効にする選択肢があります。お客様は AWS の責任共有モデルを理解し、サービスに必要なアクセスコントロールとデータ保護のレベルを評価し、それに応じてこれらのセキュリティ機構を活用することが重要です。

結論

この記事では、VPC Lattice を使用した複数の EKS クラスターにまたがるサービス間の通信について紹介しました。VPC Lattice によって、CIDR が重複する EKS クラスター内のサービスが互いに通信できることを確認しました。また、カスタムドメイン名を使用して VPC Lattice サービスを公開し、お客様の TLS 証明書を使用してそれらを保護する方法を示しました。また、VPC Lattice の認証ポリシーを用いて、IAM を使用して EKS Service へのアクセスを保護し、他の EKS クライアントサービスがそのような保護されたサービスに対するリクエストを認証できるようにする方法の詳細を説明しました。

この記事では、主に高レベルのソリューションアーキテクチャとワークフローに焦点を当てました。Kubernetes Gateway API と HTTPRoute リソースの詳細については、サンプルの Git リポジトリで共有されているマニフェストで学習することをお勧めします。AWS Gateway API コントローラードキュメントは、Apache License 2.0 が適用されたオープンソースプロジェクトです。試しに使ってみて、興味のある機能について教えてください。新機能、追加のドキュメント、バグ修正のための貢献を歓迎します。

翻訳はソリューションアーキテクトの後藤が担当しました。原文はこちらです。