Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

ドメイン単位で送信トラフィックを許可:FQDN Egress Control

By Joshua FoxFeb 7, 20237 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

FQDN Egress Control

セキュアなアプリケーションを構築する際は、Virtual Private Cloud(VPC)外への接続を通常は遮断します。ただ、サードパーティAPIへアクセスする必要があるなど、一部の通信だけは許可したい場面もあります。

FQDN Egress Control

Lovecraft風「ドメインへのゲートウェイ」。Credit: StableDiffusion

定石は、Google Cloud PlatformのFirewallやAWSのNetwork ACLで、必要なIPアドレスにのみ送信を許可する設定にすることです。しかしIPアドレスは時間とともに変わり得る一方、Fully Qualified Domain Name(FQDN)、たとえば api.example.com は安定した公開エンドポイントとして機能します。実際、ほとんどのアプリケーションはIPアドレスではなくFQDNを指定してアクセスするよう構成されています。

allow egres

本記事では、特定のFQDNに対してのみ送信を許可するさまざまな方法を、それぞれのメリット・デメリットとあわせて解説します。

条件は、低コスト・運用しやすい・堅牢・シンプルであること。

加えて、Kubernetesに対応した選択肢も取り上げます。たとえばアプリケーションをKubernetes上で動かしている場合、特定のKubernetes namespaceからのみ送信を許可したい、といったニーズに応えるものです。

さらに、ドメイン単位での細やかな制御についても触れます。1つのIPアドレスが複数のドメインをホストすることもあるためです。本記事で紹介するソリューションの多くはこの点を考慮しておらず、あるIPアドレスを持つドメインへのアクセスを許可すると、そのアドレスの裏側にある全ドメインへの送信が許可されてしまいます。同一IPアドレス上のドメインは通常、同じ事業者が管理しているため、これがセキュリティ上の問題になることはあまりありません。とはいえname-based virtual hostingではこのシナリオも起こり得るため、これに対応するソリューションもいくつか紹介します。

本記事で取り上げる選択肢は次のとおりです:

  • Squid:セルフマネージド型プロキシの代表例
  • AWS Network Gateway:ディープパケットインスペクションにより、virtual hosting環境でもドメイン単位の制御が可能
  • Google Firewallの新機能:サーバーレスサービスの手軽さでFQDN制御を実現
  • 新登場のGoogle Secure Web Gateway:ドメイン、さらにはURL単位まで踏み込んだきめ細かな制御を追加
  • Kubernetes対応ソリューション:CiliumとIstio

(OSI層についての補足:ドメイン名とDNSはOSIネットワークモデルの「アプリケーション層」、すなわちLayer 7に位置するため、FQDN Egress Controlは「Layer 7 Egress Control」と呼ばれることもあります。一方、IPアドレスが定義されるLayer 3は、一般的なfirewallやNetwork ACLで制御される領域です。)

自前で実装する場合

まずは、自前で実装するとどうなるかを考えてみましょう。推奨するわけではありませんが、各ソリューションが内部で何をしているのかを理解する助けになります。

アプリケーションはサードパーティAPIのFQDNを使って構成されていますが、ネットワークトラフィックはすべてIPアドレスでやり取りされるため、ブロックの実装はIPアドレスレベルで行う必要があります。ドメイン名が関係するのは接続を試みる前、クライアントがドメイン名からIPアドレスを引くタイミングだけです。

また、1つのFQDNが複数のIPアドレスに対応することもあります。これは特に問題にはなりません。通常のDNS lookupでこれらが返ってくるため、IPアドレスのリストへのアクセスを許可すれば済む話です。

まず、関連するIPアドレス以外のすべてのトラフィックをブロックするFirewallまたはNetwork ACLを用意します。

続いて、APIのFQDN(api.example.com)の現在のIPアドレスをDNSで定期的に確認するアプリケーションを作成・デプロイします。(低コストで動かす手段としては、定期トリガーで実行するGCP Cloud FunctionsやAWS Lambdaが好適です。)IPアドレスが変わった稀なケースで、このアプリケーションがFirewallまたはNetwork ACLを更新する仕組みです。

セルフマネージドのリバースWebプロキシ

FQDN Egress Controlの「定番」ソリューションの1つがリバースWebプロキシで、オープンソースではSquidが最もよく知られています。クラウドのルーティングサービスを使い、すべての送信トラフィックをSquidプロキシ稼働中のVMに通します。プロキシはACLホワイトリストに登録されたドメイン名とIPアドレスを照合し、一致する場合のみ通信を転送します。

SquidはAWS Marketplaceで利用可能です。こちらのアーキテクチャ解説も参考になります。GCP Marketplaceでも利用でき、こちらのネットワーク設定例が参考になります。SquidやDiscrimiNAT、AviatrixといったプロキシでのFQDN egress controlについては、こちらの解説記事もご覧ください。

Squidに代表されるVM上で稼働するプロキシは、VMのOSアップグレードやクラッシュ対応など運用負荷が伴います。すべてのネットワークトラフィックが1つのVMに集中するため(別途ロードバランス構成を組まない限り)、負荷が高くなりやすく、堅牢性を損なう恐れがあります。さらに、ピーク時に備えて大型VMを24時間365日稼働させる必要が生じ、コスト面の負担も無視できません。

AWS Network Firewall

AWS Network Firewallはディープパケットインスペクションを行うため、より強力なフィルタリングが可能です。その意味で、AWS Network ACLにより近い位置づけのGoogle Firewallと単純に比較できるものではありません。

AWS Network Firewallはstateful domain list rule groupsを用いてFQDN Egress Controlに対応します。HTTPSトラフィックのTCP接続ネゴシエーション時に送信されるServer Name Indicator(SNI)を利用することで、virtual hostingシナリオでもドメインを区別できます。

Network FirewallはRoute 53 DNS Firewallと連携でき、DNSの解決自体をブロックすることも可能です。これによって、たとえばVPC内アプリケーションからの api.example.com に対するDNSクエリがIPアドレスに解決されないようにできます。ただし、DNS Firewall自体はそのIPアドレスへのアクセスを止めるわけではなく、それを担うのはNetwork Firewallです。

Network Firewallは有力な選択肢ですが、コストがかさむこともあります。複雑なマルチネットワークを抱えるエンタープライズ環境を想定したサービスだからです。(AWSの多彩なFirewall系サービスのユースケース比較については、DoiT Blogの記事をご覧ください。)

Google FirewallとWeb Gateway

VMを自前で運用するより、クラウドプロバイダーがフルマネージドで提供するソリューションを使うほうが手軽です。そしてGoogleは今まさに、これを実現する選択肢を続々と打ち出しています。詳しい使い方は続編の記事で解説する予定ですが、ここではポイントだけ紹介します。

Google Firewallには新たにFQDN Objects機能が登場し、現在は限定プレビュー中です。Cloud DNSを30秒ごとに参照し、外部サービスの現在のIPアドレスを取得する仕組みになっています。

同じく限定プレビュー中のSecure Web Gatewayもドメインレベルの制御が可能です。実現方法としては、GCP Certificate Manager内のSSL証明書へのアクセス権を与え、HTTPSトラフィックの復号・暗号化を任せる形になります。この深いアクセスがあるからこそ、virtual hostingシナリオでもドメイン単位の送信制御が可能になります。HTTPリクエスト全体を読み取れるため、URL単位での制御まで行える点も特長です。

Cilium

ここまでのソリューションはVPCレベルで動作します。しかしアプリケーションをKubernetes上で動かしている場合、Kubernetesの概念に沿った形で送信制御を行いたい場面も出てきます。そこで使えるのがCiliumNetworkPolicyです。これはCustom Resource Definition(CRD)で、ドメイン名からIPアドレスへの解決ロジックを実行し、eBPFベースのCiliumネットワーク層でトラフィックを許可・遮断します。(DoiT blogの2本の記事もご参照ください。)このCRDはKubernetesに対応しており、namespaceでpodを区別できます。たとえば外部APIへのアクセスを許可するpodと許可しないpodを使い分けることが可能です。もう1つのCRDであるCiliumClusterwideNetworkPolicyも同等の機能を提供しますが、設定はnamespaceをまたいでクラスタ全体に適用されます。

このソリューションは、追加でCiliumネットワーク層を必要とするため、クラスタにある程度の複雑さをもたらします。Ciliumのドキュメントには「近いうちに、すべての機能が標準のリソースフォーマットに統合され、このCRDは不要になる」と記載されています。標準仕様はまだ公開されていませんが、現在Kubernetes Networking Special Interest Groupで策定が進められています。

Istio

最も多機能なソリューションは、Istioサービスメッシュが提供します。Istioはトラフィックを完全に制御し、ServiceEntryで定義したもの以外は送信をすべてブロックできます。resolution: DNS を指定すれば、クライアント(pod)が接続先としているIPアドレスに頼らず、ドメイン名をDNSで定期的に解決するようIstioに指示できます。Istioサービスは、選んだnamespaceにのみ公開することも可能です。Istioは最も強力な制御を提供しますが、サービスメッシュ層の機能をフルに備える分、Ciliumよりも複雑さは増します。

結局どれを選ぶべきか?

選択肢は多岐にわたります。実績豊富なSquid(あるいは他のリバースWebプロキシ)、新しいマネージドサービスのGoogle Firewall FQDN ObjectsとAWS Network Firewall、HTTPプロキシ型のSecure Web Gateway、そしてKubernetes対応のCiliumとIstio。

安定したマネージドソリューションが欲しいなら、おすすめは新しいGoogle Firewall(成熟してから)とAWS Network Firewall(料金が予算に収まる場合)です。Kubernetes namespace単位の制御が必要なら、最もシンプルなのはCilium CRDです。Kubernetesネイティブの標準が登場した暁には、そちらへ移行するとよいでしょう。