😽

Cloudflare TunnelをKubernetesで使ってみる

2024/08/10に公開

Cloudflare Tunnelとは

Cloudflare Tunnelは、パブリックにルーティング可能なIPアドレスなしでCloudflareにリソースを接続する安全な方法を提供します。
Tunnelでは、外部IPにトラフィックを送信するのではなく、お客様のインフラ(cloudflared)内の軽量デーモンがCloudflareのグローバルネットワークへのアウトバウンド専用接続を作成します。
Cloudflare TunnelはHTTPウェブサーバー、SSHサーバー、リモートデスクトップ、その他のプロトコルを安全にCloudflareに接続できます。
こうすることで、Cloudflareをバイパスする攻撃に対して脆弱になることなく、オリジンはCloudflareを通してトラフィックを提供することができます。

Cloudflaredは、お客様のリソースとCloudflareのグローバルネットワーク間のアウトバウンド接続(トンネル)を確立します。
トンネルはDNSレコードにトラフィックをルーティングする永続オブジェクトです。
同じトンネル内で、必要な数の「cloudflared」プロセス(コネクタ)を実行できます。
これらのプロセスはCloudflareへの接続を確立し、最も近いCloudflareデータセンターにトラフィックを送信します。

要するに、グローバルなIPアドレスを持っていなくても、Cloudflare Tunnelを作成し、そのトンネル経由でグローバルに自身のサービスを公開することができるということです。

環境

Kubernetesの環境はPoxmox上に2台のUbuntu22.04を構築し、クラスター構成を組んでいます。
構築に関してはProxmoxを使ってお家Kubernetesクラスター構築を参照してください。

事前準備

Cloudflare tunnelの設定を実際に行う前に、次のことを準備しておきます。

  • Cloudflareのアカウントを持っており、サイトを登録していること
  • 自分のドメインを保持していること
  • ドメインのネームサーバがCloudflareのネームサーバを指していること

※Cloudflareでドメインを購入すると、デフォルトでCloudflareのネームサーバを指すので楽です。

Zero Trustサービスへの申し込み

まずはZero Trustサービスへの申し込みをします。
ダッシュボード左メニューバーの「Zero Trust」をクリックします。

チーム名を入力します。
ユニークな名前である必要があり、後から変更は出来ないようですので、ご注意ください。

Zero Trustのプランを選択します。
多分フリーでいいはず。。。

プランの確認をします。
問題なければ「Proceed to payment」をクリックします。

これでZero Trustサービスへの申し込みが完了しました。

Cloudflare Tunnelのチュートリアルの実施

https://developers.cloudflare.com/cloudflare-one/tutorials/many-cfd-one-tunnel/

Kubernetes環境にcloudflaredをインストールする

wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb

Kubernetes環境からCloudflareにログインする

cloudflared loginコマンドを実行すると、認証用のURLが生成されるのでブラウザでアクセスします。

root@master:~/cloudflare# cloudflared 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*******y9P3rga5Or1yQA%3D

Leave cloudflared running to download the cert automatically.

ブラウザにURLを入れてアクセスすると、アカウントが所持しているドメイン名が表示されるのでCloudflare Tunnelで使用するドメインを選択します。
その後、「承認」ボタンをクリックします。

成功と出ていればOKです。

Cloudflare tunnelの作成

トンネルを作成します。
トンネル名はチュートリアルどおり、「example-tunnel」としました。

root@master:~/cloudflare# cloudflared tunnel create example-tunnel
Tunnel credentials written to /root/.cloudflared/c74ee24*********d80c24.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 example-tunnel with id c74ee24*********d80c24
root@master:~/cloudflare#

トンネル認証情報をKubernetesにアップロードする

生成されたトンネル認証情報ファイルを Kubernetes クラスターのシークレットとしてアップロードします。また、トンネル認証情報ファイルが作成されたファイルパスも指定する必要があります。
cloudflared tunnel create example-tunnelの実行ログの以下の部分
Tunnel credentials written to /root/.cloudflared/c74ee24*********d80c24.json.

root@master:~/cloudflare# kubectl create secret generic tunnel-credentials --from-file=credentials.json=/root/.cloudflared/c74ee24*********d80c24.json
secret/tunnel-credentials created
root@master:~/cloudflare#

トンネルをDNSレコードに関連付ける

チュートリアルで使用する外部アクセス用ドメインをCNAMEレコードとして登録します。

設定項目 設定値 備考
タイプ CNAME -
名前 dev サブドメインをCNAMEで登録するのでdev.kyamisama.comとしました
ターゲット c74ee24*********d80c24..cfargotunnel.com 認証データのjsonファイル名に.cfargotunnel.comをつけた名前を設定


ルーティングの設定を実施。

cloudflared tunnel route dns example-tunnel dev.kyamisama.com

必要なマニフェストの取得

Cloudflaedのマニフェストと、公開ページのマニフェストを取得します。

wget https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/custom-resources.yaml
wget https://raw.githubusercontent.com/cloudflare/argo-tunnel-examples/master/named-tunnel-k8s/app.yaml

Cloudflaedのマニフェストのhostnameを修正

---
# This ConfigMap is just a way to define the cloudflared config.yaml file in k8s.
# It's useful to define it in k8s, rather than as a stand-alone .yaml file, because
# this lets you use various k8s templating solutions (e.g. Helm charts) to
# parameterize your config, instead of just using string literals.
apiVersion: v1
kind: ConfigMap
metadata:
  name: cloudflared
data:
  config.yaml: |
    # Name of the tunnel you want to run
    tunnel: example-tunnel
    credentials-file: /etc/cloudflared/creds/credentials.json
    〜略〜
    ingress:
    # The first rule proxies traffic to the httpbin sample Service defined in app.yaml
    - hostname: dev.kyamisama.com ★ここを修正
      service: http://web-service:80
    # This rule sends traffic to the built-in hello-world HTTP server. This can help debug connectivity
    # issues. If hello.example.com resolves and tunnel.example.com does not, then the problem is
    # in the connection from cloudflared to your local service, not from the internet to cloudflared.
    - hostname: dev.kyamisama.com ★ここを修正
      service: hello_world
    # This rule matches any traffic which didn't match a previous rule, and responds with HTTP 404.
    - service: http_status:404

Podを展開する

kubectl apply -f cloudflared.yaml
kubectl apply -f app.yaml

ブラウザにアクセスしてみる

無事チュートリアル通り外部公開できていることを確認できました。

これでやっと自分のサービスを公開できる準備が整いました!!

Discussion