Cloudflare Zero Trust で Private Network を作成 ~ CLI編

Cloudflare Zero Trust で ZTNA を実装するための Cloudflare Access を CLI で設定する方法について紹介します。
2023.08.28

当ブログは、こちらのブログで紹介した設定のCLI版になります。利用ケースなども併せてご確認ください。

構成

構成イメージとしては以下のようになります。

やってみる

まず cloudflared と呼ばれるコネクターをインストールするインスタンスをたてます。
コネクターとなるインスタンスは Amazon Linux 2023 arm64 で立ててみました。
接続先のサービスAは Amazon Linux 2023 x86-64 で立てています。

手順の流れ

  1. コネクターをダウンロードしてインストール
  2. コネクターの認証
  3. コネクターとクラウドフレア間のトンネル作成
  4. コネクターの設定ファイルの作成
  5. ルーティングの設定
  6. トンネルの起動
  7. トンネルのステータス確認
  8. (どのサービスにアクセスさせるか)Ingressルールの設定

コネクターをダウンロードしてインストール

今回 Amazon Linux をインストールしたので、コネクターとなるインスタンスに「yum」のパッケージからインストールします。

まずレポジトリを参照できるように設定します。

$ curl -fsSl https://pkg.cloudflare.com/cloudflared-ascii.repo | sudo tee /etc/yum.repos.d/cloudflared-ascii.repo

パッケージを最新状態にして、「cloudflared」をインストールします。

$ sudo yum update
$ sudo yum install cloudflared

その他のLinuxディストリビューションのパッケージからのインストールはこちらを参照するとよいです。

WindowsやMacOSへのインストールもサポートされているので、その場合はこちらのWindows、MacOSの手順になります。
また、ソースコードからインストールしたい場合は同様に「Build from source」の手順でインストールできます。
ソースコードからインストールした場合は、コマンドラインcloudflared updateを使ってアップデートできるようになります。
パッケージからインストールしている場合のアップデートはyum updateなどのパッケージによって管理されます。

コネクターの認証

次にコネクターの認証を行います。

cloudflared tunnel loginでコマンド実行します。

$ cloudflared tunnel login
Please open the following URL and log in with your Cloudflare account:

https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F%2Flogin.cloudflareaccess.org%2F***************

Leave cloudflared running to download the cert automatically.

コマンドの出力結果に認証のためのリンクが表示されるので、そのリンクをブラウザでアクセスします。
クラウドフレアに登録されているサイト(ドメインまたはサブドメイン)を選択する必要があるので、選択し、認証します。

コネクターのCloudflareにデフォルトディレクトリーにcert.pemがダウンロードされていることを確認します。

$ ls -la $HOME/.cloudflared/
total 4
drwx------. 2 ec2-user ec2-user   22 Aug 27 00:51 .
drwx------. 4 ec2-user ec2-user   94 Aug 27 00:50 ..
-rw-------. 1 ec2-user ec2-user 1942 Aug 27 00:51 cert.pem

デフォルトディレクトリーは環境毎に変わり、Linuxだと「~/.cloudflared, /etc/cloudflared, /usr/local/etc/cloudflared」のいずれかに存在するので、上記の場所に無い場合は確認してみます。

参考:

サイトの認証手順の「サイト登録」についての補足

Cloudflare では、内部リソースにリモートからアクセスする手段として、Public Hostname または Private Network の2つの方法があります。
それぞれの違いについては下記のブログを読んでいただくと分かるかと思いますが、Public Hostname では、2つのことを事前に準備しておく必要があります。

  • Cloudflareで権威DNSを管理するための設定
  • Accessに接続させるドメインまたはサブドメインをサイトとして登録

Public Hostname によるリモートアクセス:

Private Network によるリモートアクセス:

CLIでコネクターを設定した場合は、Private Network の接続方式であっても、この「コネクターの認証」手順でサイトへの紐づけが必要となります。(Private Network で接続した場合は実際は証明書「cert.pem」は必要とせず、関係のないサイトを選択しても問題ありません。※Public Hostname の接続の場合は、実際にアクセスするドメインを選択する必要があります。
これまでサイトを Cloudflare に登録していない、または登録する必要がない場合で、Private Network の接続方式をとりたい場合は、GUIで設定することでサイトを Cloudflare に登録することなく、実装することが可能です。その場合はこちらを参照してください。

コネクターとクラウドフレア間のトンネル作成

cloudflared tunnel create <トンネル名>でコマンド実行します。

$ cloudflared tunnel create sakai-tunnel
Tunnel credentials written to /home/ec2-user/.cloudflared/<UUID>.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.

Created tunnel sakai-tunnel with id <UUID>

クラウドフレア上でUUIDが生成され、コネクターとの紐づけが行われます。
コンソールの Access > Tunnels でトンネルが作成されていることとUUIDが生成されたことが確認できます。
この時点では、トンネルの作成のみで「INACTIVE」のステータスとなります。

コネクターの設定ファイルの作成

「.cloudflared」のパスの配下に「config.yml」という名前で設定ファイルを作り設定します。
当ブログでは Amazon Linux で「ec2-user」ユーザー環境で作業しています。「$HOME/.cloudflared/」の配下に置きます。

Private Network で接続する場合は以下の設定となります。

tunnel: <Tunnel-UUID>
credentials-file: /home/ec2-user/.cloudflared/<Tunnel-UUID>.json
warp-routing:
  enabled: true

ルーティングの設定

Private Network でアクセスする先のネットワークセグメントへの通信時に、作成したトンネルにルーティングされるように構成します。
cloudflared tunnel route ip add <IP/CIDR> <UUID or NAME>でコマンドを実行します。

$ cloudflared tunnel route ip add 172.31.36.0/24 sakai-tunnel
Successfully added route for 172.31.36.0/24 over tunnel <Tunnel-UUID>
$ cloudflared tunnel route ip add 172.31.47.0/24 sakai-tunnel
Successfully added route for 172.31.47.0/24 over tunnel <Tunnel-UUID>

コンソールの Access > Tunnels でトンネルを見ると、ルーティングが設定されていることが確認できます。

トンネルの起動

cloudflared tunnel --config <パス> run <トンネル名 or UUID>でトンネルを起動します。

$ cloudflared tunnel --config $HOME/.cloudflared/config.yml run sakai-tunnel
2023-08-28T02:25:26Z INF Starting tunnel tunnelID=**
2023-08-28T02:25:26Z INF Version 2023.7.3
2023-08-28T02:25:26Z INF GOOS: linux, GOVersion: go1.19.6, GoArch: amd64
2023-08-28T02:25:26Z INF Settings: map[config:/home/ec2-user/.cloudflared/config.yml cred-file:/home/ec2-user/.cloudflared/**.json credentials-file:/home/ec2-user/.cloudflared/**.json]
2023-08-28T02:25:26Z INF Generated Connector ID: **
2023-08-28T02:25:26Z WRN No ingress rules were defined in provided config (if any) nor from the cli, cloudflared will return 503 for all incoming HTTP requests
2023-08-28T02:25:26Z INF cloudflared will not automatically update if installed by a package manager.
2023-08-28T02:25:26Z INF Initial protocol quic
2023-08-28T02:25:26Z INF ICMP proxy will use 172.31.36.20 as source for IPv4
2023-08-28T02:25:26Z INF ICMP proxy will use fe80::4bc:60ff:fe1d:7585 in zone enX0 as source for IPv6
2023-08-28T02:25:26Z INF Warp-routing is enabled
2023-08-28T02:25:26Z INF Starting metrics server on 127.0.0.1:44929/metrics
2023/08/28 02:25:26 failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2023-08-28T02:25:27Z WRN Your version 2023.7.3 is outdated. We recommend upgrading it to 2023.8.0
2023-08-28T02:25:27Z INF Registered tunnel connection connIndex=0 connection=d3756588-76e8-4de3-a58e-87411efc8451 event=0 ip=198.41.192.107 location=NRT protocol=quic
2023-08-28T02:25:28Z INF Registered tunnel connection connIndex=1 connection=27d913d7-4a6d-4361-9b87-d82be3c26a2b event=0 ip=198.41.200.23 location=KIX protocol=quic
2023-08-28T02:25:29Z INF Registered tunnel connection connIndex=2 connection=21361c36-4eb2-400e-bc84-09ce84825ea6 event=0 ip=198.41.200.73 location=KIX protocol=quic
2023-08-28T02:25:30Z INF Registered tunnel connection connIndex=3 connection=d7d4b0f9-3dbe-405d-837f-8933ded99277 event=0 ip=198.41.192.57 location=NRT protocol=quic

コンソールから確認しても正常に動作していそうです。

ただ、サービスとして起動しておきたいので、サービスで起動できるようにします。
先程起動したトンネルを「Ctrl + C」など「SIGINT」を送信して中断させます。

ディレクトリごと、rootディレクト配下に移動します。

$ sudo mv $HOME/.cloudflared /root/

rootディレクトリ配下に移した「config.yml」ファイルの「credential-file」を編集します。

credentials-file: /root/.cloudflared/<Tunnel-UUID>.json

cloudflaredサービスをインストールします。

$ sudo cloudflared service install
2023-08-28T02:37:00Z INF Using Systemd
2023-08-28T02:37:01Z INF Linux service for cloudflared installed successfully

サービスを起動して、サービスのステータス確認をします。

$ sudo systemctl start cloudflared
$ systemctl status cloudflared
● cloudflared.service - cloudflared
     Loaded: loaded (/etc/systemd/system/cloudflared.service; enabled; preset: disabled)
     Active: active (running) since Mon 2023-08-28 02:37:01 UTC; 1min 9s ago
   Main PID: 71007 (cloudflared)
      Tasks: 7 (limit: 1114)
     Memory: 19.2M
        CPU: 222ms
     CGroup: /system.slice/cloudflared.service
             └─71007 /usr/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run

トンネルのステータス確認

cloudflared tunnel info <トンネル名 or UUID>のコマンドでステータスを確認できます。

サービスをroot権限で起動していますので、rootユーザーでコマンドを実行します。

$ sudo cloudflared tunnel info sakai-tunnel
NAME:     sakai-tunnel
ID:       **
CREATED:  2023-08-27 00:59:53.034246 +0000 UTC

CONNECTOR ID                         CREATED              ARCHITECTURE VERSION  ORIGIN IP    EDGE
**                                   2023-08-28T02:37:01Z linux_amd64  2023.7.3 **           2xKIX, 1xNRT, 1xnrt07

出力結果 2xKIX, 1xNRT, 1xnrt07 より合計4つのコネクションが(2つのコネクションが)クラウドフレアのKIX(大阪リージョン)、(2つのコネクションが)クラウドフレアのNRT(東京リージョン)に接続されていることが分かります。
公式ドキュメントでも一つのコネクターにつき4つのコネクションを張ることが記載されています。

ここまでで、コネクターからクラウドフレアにトンネルを張る設定が完了しました。

(どのサービスにアクセスさせるか)Ingressルールの設定

コネクターを経由してどのサービスにアクセスできるようにするかのルールを「config.yml」の中に記述します。
各コンフィグの詳細については下記で参照することができます。

Private Network でアクセスする時は、「hostname」にクライアント端末からアクセスする時のIPアドレスを、「service」にコネクターから到達する時のプロトコル+IP+ポートを指定します。
今回はコネクター自身へのSSH接続と、コネクターの背後にあるインスタンスへのSSH接続を行います。
「ingress」という設定以下を追記していきます。

tunnel: <UUID>
credentials-file: /root/.cloudflared/<UUID>.json
warp-routing:
  enabled: true

ingress:
  - hostname: 172.31.36.20
    service: ssh://127.0.0.1:22
  - hostname: 172.31.47.97
    service: ssh://172.31.47.97:22
  - service: http_status: 404

クライアント端末へ WARP のインストールと Split Tunnel 設定

アクセス元のクライアント端末へは WARP のインストールが必要です。また、アクセスする宛先となるリモートのプライベート空間を Split Tunnel の設定が必要になります。
この2つの設定は、下記ブログの「エージェントWarpのインストール」と「Split Tunnelの設定」と同じ要領での設定となるので、こちらを参照して設定してください。

接続テスト

準備ができたので、接続テストを行います。

Warpをインストールした端末の SSHクライアント を使って、リモートのプライベート空間にアクセスします。

コネクターにアクセスしてみます。

アクセスすることができました。

続いてサービスAにアクセスしてみます。

アクセスすることができました。

まとめ

CLIベースでの Cloudflare Access を使ったZTNAの構築をやってみました。
ここまでやってみた所感だと、当ブログと同じように Private Network の接続方法を実装したい場合は、サイトの登録が必要ないので、GUIベースで設定するのが良いと感じました。
ただ、GUIベースで設定を行った場合でも、実際の運用シーンでは「cloudflared」コマンドや設定ファイルの構成をローカルで実行したり参照する場合も出てくるかと思いますので、コマンドに慣れたり構成を把握しておくのに良いかと思いました。
ぜひ本記事がどなたかの一助になれば幸いです。