サービスメッシュなしのサービス間認証

Cloud Run上のサイドカープロキシパターン:イングレス認証、中央の内部APIハブ経由のエグレス、パスベースルーティングの内部ロードバランサー——メッシュの重さなしにメッシュの利益を。

十数サービス規模のプラットフォームでサービスメッシュを見積もるたび、計算は同じ答えを返してきました:問題は本物、メッシュは問題に対して機械が大きすぎる。このプラットフォーム——内部ロードバランサーの背後でCloud Runに載ったGoマイクロサービス群——で実際に必要だったのは3つです:サービスは誰からのトラフィックでも受け入れるべきではない。アウトバウンド呼び出しは1つの管理された経路を通るべき。そしてそのロジックはアプリケーションコードに住むべきではない。3つとも、サイドカープロキシパターンと意図的に退屈なルーティング層1つで手に入りました。

部品

  • サービス間呼び出しの玄関としての、パスベースルーティングの内部ロードバランサー。安定した内部ホスト名が1つあり、/orders/* は注文サービスへ、/payments/* は決済ゲートウェイへ、という具合にルーティングされます。外部に面するものの前にはCloud Armor。
  • 各Cloud Runサービス内のサイドカーコンテナが、信頼の両方向を扱います:
    • イングレス:リクエストがアプリケーションコンテナに届く前に呼び出し元を認証する——IDトークンを検証し、呼び出し元がこのサービスの許可リストにあるかを確認し、それ以外はすべて拒否。
    • エグレス:アウトバウンド呼び出しはサイドカーを通って中央の内部APIハブへ向かいます。ハブは、すべての内部サービス(と、依存していた少数の外部API)への到達方法を知る唯一の場所です。
  • すべてをTerraformで——LB、ルート、Cloud Armorポリシー、サービス設定。diffできないルーティング層は、信頼できないルーティング層です。

一方、アプリケーションコンテナは localhost にプレーンなHTTPを話します。サービスのビジネスコードには、トークンの発行も、ピアの検証も、認証失敗時のリトライもありません——サイドカーにリクエストを投げれば、あとはプラットフォームがやります。

なぜ直接呼び出しではなくハブか

すべてのサービスが他のすべてのサービスに直接ダイヤルできるのがデフォルトで、それは「何が何を呼んでいるのか」にインシデント中に答える必要が生じるまでは機能します。エグレスを中央ハブに通したことで得たもの:

  • 依存関係の一覧が1つ。 ハブの設定がそのままサービス依存グラフです——プルリクエストでレビューでき、深夜2時にgrepできます。
  • 横断的ポリシーのチョークポイントが1つ。 タイムアウト、リトライ予算、アウトバウンド許可リストが1か所に住み、ばらばらに漂流する12個の http.Client 設定にはなりません。
  • 外部APIに到達する場所が1つ。 サードパーティのエンドポイント、認証情報、レート制限はハブの問題です。サービスはURLではなく、能力を要求します。

コストは、ハブが何であるかについての正直さです:ルーティングの単一点(スケールし複製されるが、概念としては単一)と、1ホップ分のレイテンシ。ビジネスロジックがミリ秒単位のインタラクティブなトラフィックでは、そのホップはノイズでした。実際に私たちを呼び出した故障モードにおいては、ハブこそ証拠の在り処でした。

メッシュが足したはずのもの——そして足さなかったもの

メッシュがその複雑さに見合うのは、あらゆる場所でmTLSが要るとき、トラフィック分割やクラスタ横断ポリシーが要るとき、多数のチームが所有する数百のサービスを運用しているときです。私たちには十数のサービス、1チーム分の所有権、そしてTLS終端とIDトークンをすでに扱ってくれるマネージドプラットフォームがありました。サイドカーパターンは、メッシュの価値提案のうち実際に使う部分——認証されたイングレス、管理されたエグレス、均一なポリシー——を、プラットフォームがすでに持つプリミティブで与えてくれました。

持ち帰った判断ルール:最初の6か月で有効にするメッシュ機能を数えること。 リストが「サービス間の認証と、何が何と話すかの把握」なら、それはすでに理解しているサイドカーとロードバランサーで作れます——そして curl でデバッグできます。

運用からの教訓

  • 許可リストのチェックはアプリではなくサイドカーに置く。 認可ロジックが一度でもアプリケーションコードに漏れると、サービスごとにドリフトが始まり、12個の実装を監査する羽目に戻ります。
  • パスベースルーティングは歳を取らない。 サービスの追加はTerraformのルート1本と許可リストのエントリ1つ——DNSの儀式も、クライアントの再デプロイもなし。
  • サイドカーはデプロイ時の契約である。 ライブラリのアップグレードと同じように、バージョンを付け、意図的に、サービスごとに、移行期間中は旧バージョンも受け入れながらロールアウトすること。
  • 信頼モデルを書き下す。 私たちのものは半ページに収まりました:外部トラフィックはエッジで終端する。内部の呼び出し元はイングレスでIDトークンにより認証される。エグレスはハブを通る。 この半ページは、どんな図よりもオンボーディングに効きました。

どれも新奇ではありません——メッシュの発想を10分の1のスケールでやっただけです。腕の見せどころは有名なツールを選ぶことではなく、有名なツールが「自分にはない問題」を解いていると気づき、必要な3つの機能を頭に収まる部品で組むことにあります。