この記事は CyberAgent Developers Advent Calendar 2022 の6日目の記事です。
AI事業本部の黒崎(@kuro_m88)です。CyberAgent Developers Advent Calendar 8回目の参戦です!

今年はCloudflare Zero Trustを利用してオフィスでもリモートワークでも安全に必要な人だけが開発環境にアクセスできる仕組みを作ったので、それについてご紹介します。

概要

開発環境におけるアクセス制御の課題

私が所属するサイバーエージェント AI事業本部の小売DX部門では様々な小売企業のアプリやCDPと呼ばれるデータ基盤の開発をしています。
事業内容についてはこちらをご参照ください。

この組織では、立ち上げから2年以上が経過し、組織として抱えるプロジェクトやメンバ、職種がかなり多くなってきました。
大きな組織の中で複数の顧客の環境を取り扱うには適切なアクセス制御が必要です。
従来はテナントごとにVPNを用意したり、通信元のIPアドレスを固定するためのVPNを作ったりといった運用をしていました。
最初のうちはこれで十分だったのですが、VPNサーバの人的運用コストだったり、複数のプロジェクトに関わるメンバは都度VPNを切り替えないといけないといった面倒な手間が発生しており、改善する必要がありました。

ZTNA(Zero Trust Network Access)とは?

突然ですが、ZTNA(Zero Trust Network Access)という概念をご存知でしょうか。

綺麗に説明できる自信がないのでWikipediaを参考にさせていただくと、
ZTNAとは、 強力な本人認証、アクセス許可前のデバイスのコンプライアンス検証などにより、明示的に許可されたリソースのみへの最小権限のアクセスを保証することによって実装されるアクセス方法です。
Wikipedia: Zero trust security model

強力な本人認証とは、我々でいうと会社のシングルサインオンのことを指します。
弊社は内製のID Providerがあり、一般的な多要素認証はもちろん、FIDO U2FやWebAuthnにも対応しています。

認証/認可基盤PERMANの紹介

あとはこの認証に紐づいた通信の識別と、認証されたユーザが許可されている場合のみ通信ができるようになっていれば、
どこに居ても安全なアクセスができ、アクセス権のコントロールも柔軟にできるようになります。これがZTNAです。

VPNと何が違うか分かりづらいですが、VPNは一度接続してしまえば接続先のネットワークへのアクセスはほぼ自由だったり、ユーザごとに適用するポリシを変えることが難しいのに対して、ZTNAは接続先(アプリケーション)単位でポリシ制御ができるができる点が異なります。
技術的にはZTNAはVPNの技術を応用していることが多いように思いますが、必ずしもVPNの形態をとらなければならないわけではないため、概念(考えかた)が異なるものと捉えておくのがよいかもしれません。

Cloudflare Zero Trustの検討

いきなり組織全体でZTNAを実現することは難しいため、まずは私が担当しているいくつかのプロジェクトで試してみることにしました。
いくつかZTNAが実現できそうな製品の候補を挙げ比較検討したのち、今回はCloudflare Zero Trustを導入しています。

https://www.cloudflare.com/ja-jp/products/zero-trust/

Cloudflare Zero TrustはZTNAだけでなく、ゼロトラストアーキテクチャを実現するための様々な機能が実装されています。
機能が豊富であるため今回は全容のご紹介はできませんが、気になる方は製品サイトをご覧ください

今回はCloudflare Zero Trustの中の特にCloudflare Accessという機能を利用しています。無料プランは50人まで利用でき、それ以降も1人あたり月額$3〜と業務で利用することを考えると安価だなと感じました。
データ転送量課金がないのはCDN事業者だからなのでしょうか。常時接続するケースでは非常に嬉しいと思います。

Cloudflare Zero Trustで開発環境へのVPNと送信元アクセス制限を実装する

一般的なVPNとの大きな違いは高レベルなアクセスポリシが書けることです。例えば画像では、SAMLのattributeで team-nameというフィールドにteam-Aという値が含まれていてかつ、アクセス元が日本国内のIPアドレスと思われる場合に通信を許可する、というポリシの設定例です。

ポリシ設定の例

こういったポリシをSaaSだったり、自社の社内アプリだったり、開発環境に対して適用することで、柔軟なアクセス制御ができます。
利用者のメールアドレスでグルーピングして挙動を変えることもできますし、SAMLのattributeに応じて挙動が変わるようにすれば、Cloudflare Zero Trust側で設定をせずとも、SAMLのプロバイダ側で属性が変化すれば適用されるポリシも勝手に変化するようにできるため、運用が非常に楽になります。
うまく設定を組み合わせれば、部署異動にともなって権限の自動付与、剥奪が行われるようにすることも可能です。

Cloudflare Tunnel

Cloudflare TunnelというVPN+プロキシのようなソフトウェアがあり、これを使うことでインターネットから直接アクセス不可能なアプリケーションをCloudflare Zero Trustに接続することができるようになります。
cloudflare / cloudflared
以前はArgo Tunnelという名前だったようです。

cloudflared
https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/

今回はcloudflaredをEC2インスタンスの上で稼働させています。EC2インスタンスは中から外(インターネット方向)への通信はできますが、外から中への通信は遮断されています。cloudflaredが自動でCloudflare Zero TrustとVPNを貼ってくれるため、ファイアウォールに穴を開けることなくCloudflare Zero Trustを経由して許可された通信のみが到達できるようになっています。
冗長化も非常に簡単でEC2インスタンスを複数建てて同様の設定をするだけです。

cloudflaredの動作例
cloudflaredの動作例

クライアント(PC, スマホ)側はCloudflareのWARPというアプリを使います。スマホも標準で対応しているのはありがたいですね。PC版のクライアントソフトは以下のような見た目で、一度設定してしまえば有効化するときはスライダをスライドするだけで接続が完了します。

「送信元IPアドレス制限」の用途に対応する

残念なことですが、2022年も「IPアドレス制限」のための固定IPアドレスの需要はなくなりませんでした。
オフィスのインターネットアクセスの送信元IPアドレスを設定することを想定しているSaaSがあったり、開発環境のアクセス制御として送信元IPアドレスを利用することはよくあると思います。この要求は特にリモートワークと非常に相性が悪く、また部署で共有のVPNサーバを利用して送信元IPアドレスの固定を行うと、必要のない人までアクセス許可がされてしまいます。

この問題に対してもCloudflare AccessとCloudflare Tunnelを利用して解決することができました。以下の図に沿って説明していきます。

概略図
概略図

ここでは送信元IPアドレス制限がかかっているシステムのホスト名をprivate-system.example.com、またそのIPアドレスを203.0.113.1とします。

  1. まず、Cloudflare Gateway Policyという機能で、 private-system.example.com のDNSのクエリ(名前解決)結果を上書きします。
    ここでは適当に 100.64.0.1 としました。既存で利用しているプライベートIPアドレス等と被らなければなんでもよいです。
  2. 次に、Cloudflare AccessのApplicationという機能で、タイプがPrivate NetowrkのApplicationを定義します。ここで先ほどのIPアドレス 100.64.0.1 を指定します。このアプリケーションは100.64.0.1のIPアドレスで動作しているという設定になります。
  3. Applicationのポリシ設定で、許可された人(特定のグループに所属しているなど)だけがアクセスできるようなポリシを設定します
  4. 先ほどのCloudflare TunnelのPrivate Network設定で、100.64.0.1/32を定義します。これで、100.64.0.1/32宛の通信がCloudflare Tunnel経由になります。
  5. Cloudflare Tunnelを動作させているEC2インスタンスのループバックインターフェイスに100.64.0.1/32を追加します(ip addr add 100.64.0.1/32 dev lo)
  6. NginxでTCP Proxyを動作させます。

NginxのTCP Proxyに関しては、HTTPSのリバースプロキシとして動作させてもよいのですが、HTTPSをプロキシで終端するとなると、TLSの証明書を取り扱わないといけなくなってしまいます。今回は通信内容を覗き見する必要はないので、TCPのレイヤでプロキシしています。
このサーバはDNSクエリの応答の上書きは行われていないため、このサーバから名前解決すると、本来のIPアドレス203.0.113.1が得られます。
今回はたまたまNginxを利用しましたが、名前解決しつつTCPのプロキシができる方法であれば、ソフトウェアはなんでもよさそうです。

これでCloudflare Accessを利用しているクライアント(PC等)からは、private-system.example.comへのアクセスをするときの送信元IPアドレスがCloudflare TunnelのEC2インスタンスのIPアドレスに固定されます。

必要な接続先に応じて同様にIPアドレスを払い出して設定を行えば、1台のCloudflare Tunnelで多数の接続先をサポートできます。

導入してみて

既にこの構成で30名程度が利用しており、快適に利用ができています。
セキュリティ面の機能が充実しているのに加え、インターネットアクセスをCloudflare経由にしても特に速度面で不満がなく、旧来のVPNサーバであれば通信量や利用者の拡大によるVPNの帯域逼迫などの懸念がなくなり快適になったのはユーザ体験としてもよかったです。
一方で利用できるプロジェクトを増やしていくためには、現状Cloudflare Tunnelのサーバの設定を手動で行なっているため、ここの運用負担を減らす必要があると感じています。簡単な作業なので、設定変更を自動化するツールを実装すると運用の手間はほぼなくなりそうだなと感じています。

実は固定IPが使いたい場合はEnterpriseプランを契約すると自前でサーバを用意せずとも専有のIPアドレスが払い出されるようですが、もちろんライセンス費用は上がるのと、固定IP運用に頼ってしまうと結局ZTNAの機能が使われず旧来のVPNによるアクセス制御と同じようになってしまうのではないかという懸念があるため、今回紹介したような手法をとりました。

今回ほぼ紹介しませんでしたが、不審なドメインのブロッキングや、マルウェア検知、シャドーITの検出機能などもついているため、普段使いはもちろん、ワーケーションや出張先で信用できるインターネット接続が確保できない場合の対策にもなり得るかもしれません。

ということで、今年はCloudflare Zero Trustを利用して開発環境への安全なアクセス方法を構築した事例をご紹介しました。また来年お会いしましょう!