Cloudflare Tunnelで認証して、転送先のサーバにSSOする方法

January 15, 2024
tag icon
cloudflare
tag icon
authentication
tag icon
sso
tag icon
JWT

Cloudflare Tunnelを使うと、アウトバウント接続のみでプライベートのサーバを公開することができて、とても便利です。

そのままの状態でもWAFでのチェックもしてもらえるのですが(無料で!)、さらにCloudflare側で認証を追加することもできます(無料で!!)。そうすると認証を通ってないアクセスがトンネル内に入ってこないので、非常に安心です。

しかしながら、Grafanaのように標準で認証が有効になっているサーバを使うと、連続で2回認証をする必要があり、さすがに不便です。そこでCloudflareで認証したらそのままSSOでログインできる方法を見つけたので紹介します。

システム構成概要とシーケンスイメージ

cloudflareでssoする流れ

システム要件

本項では以下のシステム要件が必要です。

  • cloudflaredと公開用サーバがInternetアクセスできること
  • 公開用サーバがJWT認証に対応していること1

ポイントとキーワード

Cloudflareで認証をすると、トークンとしてJWTを付与した形で、サーバにリクエストを転送することができます。受け取ったサーバがJWTを使って認証することができればSSOログインが実現できます。

JWTを使って認証するときには改ざんやなりすましされていないかを検証するのがセキュアです2。そこでサーバはJWT検証用の公開鍵を提供するJWKS(JSON Web Key Set)エンドポイントにアクセスして、公開鍵を入手し、JWTの検証をします3

JWKS接続時は、cloudflaredを経由しないので、普通のInternetアクセス(アウトバウンド)が必要です4

設定手順

今回は下記の設定が必要になります。

  • Cloudflare Tunnel:
    • Tunnelの追加
    • Access Groupの追加
    • Applicationの追加
  • Grafana:
    • grafana.iniの設定
    • ログイン用ユーザーの追加

今回は既存のTunnelに新しいURLを追加します。Tunnelの新規作成とは異なりますが、Access GroupやApplicationの設定は同様です。

Cloudflare Tunnelの追加

Cloudflareの管理画面でZero Trust > Access > Tunnels と選択すると編集画面が出るので既存のトンネル名をクリックします。

2024-01-14-man01-cloudflare

トンネルの情報画面が出るので、Configure をクリックして編集画面に入ります。

2024-01-14-man02-cloudflare

Add a public hostname でサーバ用URLの追加画面に入ります。

2024-01-14-man03-cloudflare

今回は既存のドメインに Subdomain を追加します。このURLで転送するGrafanaのURLとポートも併せて指定します。

2024-01-14-man04-cloudflare

URLと転送先の設定はこれで完了です。

Access groupsの設定

認証を使うのが初めての場合、ログインを許可するユーザーの登録を行います。

Zero Trust > Access > Access Groups で画面に入り Add a group をクリックします。

2024-01-14-man05-cloudflare

Group name は任意です。今回はメールアドレス宛にOne-time PINを発行する方法にするので、グループの定義情報として Selector にEmailを選択し、 Value に認証したいメールアドレスを入力します。

なお、認証に使えるユーザー数はプランによって上限があり、フリープランでは50名です(すごい!)。

2024-01-14-man06-cloudflare

画面に従って保存すればOKです。

Applicationの追加

最後に認証する対象のURL、ログインを許可するAccess Groupなどを1つのアプリケーションとして設定します。

Zero Trust > Access > Application で画面に入り Self-hosted を選択します

2024-01-14-man08-cloudflare

Application name は任意ですが、この後Cloudflareで認証する画面に表示されるので、どこにログインしようとしている画面か直感的にわかる名前にするとよいと思います。

SubdomainDomain は今回はTunnelで設定したものと同様にします。

2024-01-14-man09-cloudflare

また同じ画面でどの認証方法を使うかも設定できます。今回はOne-time PINが自動的に選ばれています。

2024-01-14-man10-cloudflare

Policy name は任意です。Assign a groupにログインさせたいユーザーを登録したグループが選択されていることを確認します。

2024-01-14-man11-cloudflare

画面に沿って Add application を押して完了です。

この時点で、URLにアクセスすると、Cloudflare Accessの認証画面が表示されるようになります。

Grafana.iniの設定

Cloudflare Accessの認証結果を使ってJWT認証をするためにgrafana.iniは下記のように設定が必要です。

########## Users ##########
[users]
allow_sign_up = false
auto_assign_org = true

########## Auth JWT ##########
[auth.jwt]
enabled = true
header_name = Cf-Access-Jwt-Assertion
email_claim = email
username_claim = email
jwk_set_url = https://<your-team-name>.cloudflareaccess.com/cdn-cgi/access/certs

# for extra verification, set to "Application Audience (AUD) Tag"
# which can be found in the app you create in Cloudflare Access
expect_claims = {"aud":"<Application Audience (AUD) Tag>"}

auto_sign_up = true

jwk_set_urlで指定する<your-team-name>はZero Trust > Settings > Custom Pages で確認することができます。

また<Application Audience (AUD) Tag>は先ほど設定したApplicationページの設定画面に再度入ると、OverviewタブのApplication domainの下に表示されています。

今回はDockerでGrafanaを上げているので、環境変数 GF_PATHS_CONFIG を変更し、作成したgrafana.iniを読み込ませます。

Grafanaユーザー作成

JWT認証すると自動的にユーザーが作成されるはずですが、今回は管理者権限を付与したかったので、あらかじめGrafanaでユーザーを作成し、権限を付与しておきました。

この時Name、Email、UsernameはすべてJWTで渡されるメールアドレスと同じにしておきます。

動作確認

Application で設定したURLにアクセスすると下記画面が出てきます。

2024-01-14-man12-cloudflare

Emailに認証したいメールアドレスを入れるとPINコードが送られてくるので、下記画面にPINコードを入力します。

2024-01-14-man13-cloudflare

Grafanaに自動ログインすることができます。

2024-01-14-man14-cloudflare

お疲れさまでした。

参考文献


  1. 今回はJWT認証を使いましたが、Cloudflare Tunnelを認証プロキシとして認証する方法もあるようです。
  2. JSON Web Signature(JWS)として規定されています。
  3. この仕組みはOAuthでも使われています(ということを筆者は調べていて知りました)。
  4. Grafanaの場合は、公開鍵をダウンロードして、grafana.iniで指定することで閉域でのトークン検証も可能です。ただし公開鍵のローテーションごとに手動ダウンロードが必要になります。

Profile picture

i氏 システムのデザインが好きな自称システムアーキテクト。データサイエンティスト見習い。Jamstackのアーキテクチャーに感動して、Gatsbyでブログを始めました。