はじめに
こんにちは、enechainでSREを務めている taro です。
私たちSREチームは、全社の基盤設計、運用、信頼性とセキュリティの強化に注力しています。
最近、eCompassというプロダクトで外部データ取得のためのForward Proxyサーバの構築を行いました。この記事ではその過程と技術選定についてご紹介します。
背景と課題
enechain では、eCompass という世界中のエネルギー需給情報やマーケット価格を分析しやすい形で視覚化し、タイムリーに届けるマーケットダッシュボードを提供しています。
そのために様々な外部のデータを収集する必要があり、以前の環境ではCloud SchedulerとCloud Functionsで行なっていました。
しかし、この構成には以下のような課題がありました。
- 実行時間とメモリの上限が設定されている
- インフラが全社標準ではなく、管理コストが高い
- 環境が古く、整備されていないため、設定に手間がかかる
- パイプラインの実行制御が難しい
当社のアプリケーションやジョブ実行基盤は、GCP/GKEに移行中です(移行の背景などはこちらをご覧ください)。Batch/Workflow Jobに関しても、ガバナンスを効かせるという観点から基本的に全チームArgo Workflowを利用し、同じ方法で実装しています。
既存の仕組みにのればArgo Workflow自体の管理も整備されており、構成やCI/CD、デプロイ方法、移行や運用管理コストも高くはありません。
ただし、Workflowを実行する上で、以下の2つの要件を満たす必要があります。
- アクセス元IPを固定できること(IP制限があるデータ取得先向け)
- アクセス元IPを容易に変更できること(利便性の向上とセキュリティ強化)
に関しては、GKEのネットワークのCloud NATにStatic IPを割り当てることで実現できます。その際、アクセス制限をしているデータの提供元にStatic IPをお伝えし、Whitelistとして登録してもらいアクセスすることができるようになります。
に関しては、稀に運が悪いとGCPで取得したIPに対して最初からアクセス制限をされている場合があります。データ連携先も今後増える見込みもあり、アクセス元IPを変更する可能性は高くなっていきます。
そうした場合、アクセス元のNATのIPアドレスを変更して再度データを取得するしかありません。そうすると、Whitelist形式でIP許可申請も全部再度申請をやり直さなければならなくなってしまい、大きな手間が伴います。また複数のStatic IPをNATに紐づけることもできますが、PodごとにどのStatic IP経由で外部にアクセスするといったようなこともできません。
そこで、影響を最小限に抑えつつ、アクセス元IPを用途ごとに変更するための新しいアプローチが必要となりました。
今回はProxy Serverを立てる方法で実現することになったのですが、Proxy Serverはサイバー攻撃に合いやすいので、セキュリティ強化の意味でもアクセス元IPを容易に変更できることを要件として入れました。
課題の解決方法
この問題を克服するために、私たちは別の場所にプロキシサーバーを設置し、特定のジョブだけをプロキシ経由でアクセスさせる方法を検討しました。具体的には次の3つのアプローチを考えました。
- Cloud RunでForward Proxyをデプロイし、特定のJobをProxy Server経由でアクセスする
- マルチネットワークGKEクラスタを作成し、特定のJobのみ別のNetworkからアクセスさせる
- Compute EngineにProxy Serverを構築し、特定のJobのみProxy Server経由でアクセスさせる
1. Cloud RunでProxyを構築する方法
1つ目のCloud RunにForward Proxyを構築する方法は、コンテナベースかつ簡単に構築できることもあり、第一候補の方法でした。Whitelist申請が必要な外部データを取りに行く際は、GKEのNATのStatic IPを利用し、それ以外の外部データを取りに行く際は、Cloud RunのProxy経由でアクセスする方法です。仮にアクセス元IPアドレスが運悪くアクセスできない場合でも、すぐに切り替えることができ、他の収集Jobに影響はありません。
しかしながら、Cloud Runは HTTP CONNECT に対応していないため、利用できませんでした。
Forward Proxyは、HTTP CONNECTメソッドが通信に利用されます。HTTPS通信をプロキシ経由で行う場合、通信内容はSSLによって暗号化されるため、プロキシサーバーは送信先のサーバー情報を知ることができません。CONNECTメソッドを使用することで、Forward Proxyは通信内容を知る必要なく、クライアントとサーバー間の通信を仲介することが可能となります。
2. GKE Multi Pod Networkを利用する方法
2つ目の方法は、GKEでMulti Pod Networkを有効化して、特定用途ごとにPod Networkを分離する方法です。こちらはProxy Serverを立てる必要もなく、特定の外部データを取得するPodのみ異なるNetworkにデプロイすれば、アクセス元IPアドレスを用途に応じて変更することができます。
比較的新しい機能で、GKE v1.27から利用可能ですが、まだPreview状態であることと、クリティカルな問題として既存クラスタにMulti Pod Networkを有効化すると、GKEクラスタが再作成となってしまいます。
既にGKEクラスタは本番利用もしており、業務影響が大きいので、今回この方法を取ることは見送りました。
というわけでなんとも原始的ではありますが、最終的にCompute EngineにForward Proxyを構築するという方法を取りました。
3. Compute EngineでForward Proxyを構築
アーキテクチャとしては以下のような形になりました。
Compute EngineのProxy構築方法についてはWeb上に多くの情報が公開されているため、以下に構築にあたり重要なポイントだけをまとめました。
Topic | Description |
---|---|
Load Balancing | - 外部NWから直接Compute Engineへのアクセスは危険なので、TCP Load Balancerを利用 - TCP LBなので、Firewallで外部からのIP制限を行い、GKEのNATのStatic IPのみからアクセス可能とする - GCLBにStatic IPとドメインを紐付け |
Compute Engine | - Global IPは未割り当てで、VPC経由でアクセス - Service AccountをDefaultのものから制限を絞ったSAに変更 - 起動時にGARに登録したSquidのDocker Imageを指定して起動 - COSを利用 |
Network | - Default NWは削除 - NetworkとSubnetを作成 - Static IP + Cloud NAT + Cloud Router - Compute EngineへのIngressは、GCLBのIP Rangeのみ許可し、squidへのportのみ許可 |
Squid(Proxy Server) | - Terraform構築時に同時に作成。terraform agent内でskaffold+cloudbuildを利用してbuild&GARへpush - inboundはGCLBからのIP Rangeとlocalからのアクセスに絞る - 特定IP以外は拒否設定 |
基本的なセキュリティや設定を適用すると、結果としてかなり複雑なアーキテクチャが形成されることにもなります。
ここで触れた内容以外にも、インフラストラクチャのコード化、ログやモニタリングの仕組み、SquidやCompute Engineの更新やセキュリティパッチの適用など、考慮すべき点は多岐にわたります。これら全てに深く思いを巡らせると、その複雑さに頭が痛くなることもあります。
しかし、最終的には当初実現したかったJobの用途に応じてアクセス元IPアドレスを切り替えるアーキテクチャを無事実現できました。
最後に
今回はやや古典的な方法でCompute Engineを用いてプロキシサーバーを構築しましたが、近い将来、とある事情でGKEを再構築する機会があります。それを機にMulti Pod Networkを導入し、よりシンプルなジョブ基盤を作成する計画です。
そのため、次のステップとして、Multi Pod Networkを用いたGKEの挙動について事前に深く調査し、検証を行います。得られた知見をもとに、適切なタイミングでその内容を記事にして共有する予定です。
enechainのSREデスクはplatform engineering, site reliability, securityの3つのミッションを持っており、横軸エンジニアリングを推進できる非常に魅力的な環境です。 enechainではSREはもちろん、一緒に事業・組織を盛り上げてくれるエンジニア/デザイナー/マネジャーを募集しています。
興味を持っていただけたら、是非ご連絡ください。お待ちしております!