2024-11-17

Cloudflare Accessを使ってDiscordサーバーに入っている人のみにWebサイトを公開する

自宅鯖でstable-diffusion-webuiを建てました。自分だけ使うのはもったいないけど世界中に公開するのは怖い・・・と思ったので身内Discordサーバーに入っている人だけがアクセスできるようにしました。今回はその手順を紹介します。

ざっくりやること#

(以下を見て「わかった!」って方はもう記事を見なくてもいいかもです)

Cloudflare Workers + DiscordのOauthを使ってOpenID Connectに使える認証サーバを構築し、それをCloudflare Zero Trustの認証プロバイダに登録する。Cloudflare Accessで認証したユーザのClaimを確認し、Discordサーバーに入っているか判定する。

本編#

前提#

1. Discord Developer Portalでアプリを作る#

まずはDiscord Developer Portalにアクセスして認証に使う用のApplicationsを作ります。「OAuth2」のページの「Client information」にある「Client ID」と「Client Secret」をメモしておきます。

2. Cloudflare Workersで認証サーバを構築#

自分で作ってもいいですが既に以下の実装を公開している方がいるのでそれを使います。

Erisa/discord-oidc-worker: Sign into Discord on Cloudflare Access, powered by Cloudflare Workers!

まずはgit cloneなどを使いリポジトリをダウンロードします。

git clone https://github.com/Erisa/discord-oidc-worker

discord-oidc-workerをセットアップしていきす。
セットアップ方法はGithubのREADMEに書いてありますがここでも解説します。

まずはnpmを使って依存関係をダウンロードします。

cd discord-oidc-worker
npm install

Cloudflare Workers KVを用意します。セットアップ方法は二種類あります。wranglerを使った方法とCloudflareのWebコンソールからぽちぽちやる方法です。wranglerの方が簡単なのでこちらを紹介します。

以下のコマンドでcloudflare workers KVを作成します。このKVはJSON Web Key(JWK)の保管に使います。

wranglerのバージョンが3.60.0以上であればkv:namespaceではなくkv namespaceに読み替えてください。

npx wrangler kv:namespace create "discord_oidc_keys"

成功すると以下のような出力が出ると思います。

🌀 Creating namespace with title "worker-discord_oidc_keys"
✨ Success!
Add the following to your configuration file in your kv_namespaces array:
{ binding = "discord_oidc_keys", id = "..." }

これの{ binding = "discord_oidc_keys", ...}bindingKVに変更してwrangler.tomlにコピペします。
wrangler.tomlは以下のようになります。

name = "discord-oidc"
main = "worker.js"
compatibility_date = "2022-12-24"
 
kv_namespaces = [
  { binding = "KV", id = "..." },
]

次はconfig.sample.jsonをもとにconfig.jsonを作成します。

cp config.sample.json config.json

config.jsonを編集します。1でメモしたclient idとclient secretを使います。以下の通り書き換えてください。

{
  "clientId": "YOUR_DISCORD_CLIENT_ID",
  "clientSecret": "YOUR_DISCORD_CLIENT_SECRET",
  "redirectURL": "https://YOUR_CLOUDFLARE_USER_NAME.cloudflareaccess.com/cdn-cgi/access/callback",
  "serversToCheckRolesFor": ["YOUR_DISCORD_SERVER_ID"]
}
  • YOUR_DISCORD_CLIENT_IDを実際のdiscordのclient idに書き換える
  • YOUR_DISCORD_CLIENT_SECRETを実際のdiscordのclient secretに書き換える
  • YOUR_CLOUDFLARE_USER_NAMEを実際のcloudflareのユーザネームに書き換える
  • YOUR_DISCORD_SERVER_IDをwebサイトにアクセスできるユーザーの入っているDiscordサーバーに書き換える(複数登録できます)

最後にデプロイします

npx wrangler publish

wranglerのバージョンが新しければ以下を実行します

npx wrangler deploy

3. Cloudflare Zero Trustを設定する#

先ほどたてたCloudflare WorkersをCloudflare Zero Trustの認証プロバイダに登録します。

「Settings」の「Authentication」に行き、「Login Methods」の項目の「Add New」をクリックして「Add OpenID Connect」ページに移動します。

Login Methodsの項目。右上に"Add New"がある

Add OpenID Connectページのフォーム

フォームの項目を以下の通りに埋めます。

  • Name: 自由。好きな名前を設定してください
  • App ID: DiscordのClient ID
  • Client secret: DiscordのClient secret
  • Auth URL: https://discord-oidc.YOUR_CLOUDFLARE_USER_NAME.workers.dev/authorize/guilds
  • Token URL: https://discord-oidc.YOUR_CLOUDFLARE_USER_NAME.workers.dev/token
  • Certificate URL: https://discord-oidc.YOUR_CLOUDFLARE_USER_NAME.workers.dev/jwks.json
  • Proof Key for Code Exchange (PKCE): オンにする
  • Email claim: 入力不要

OIDC Claimsは以下のように設定します

  • id
  • username
  • discriminator
  • guilds

OIDC Claimsの設定例

以上を記入したら「Test」を押して実際に試してみるとよいでしょう。よさそうであれば「Save」を押して保存してください。

4. Cloudflare Accessを設定する#

3で作った認証をCloudflare Accessで使う設定をします。
Cloudflare Accessのページに行き、「Add an application」ボタンでアプリを作ります。

Cloudflare Accessの設定ページ。中央に「Add an apllication」ボタンがある

「Self Hosted」を選択します。

Add an applicationページ。一番右がSelf Hosted

Application Configurationでアクセスを制限したいアプリのドメインを設定します。

  • Session Durationはセッションが有効な期間を設定します

Identity ProvidersはOpenID Connectのみに設定します。

Identity Providersの設定。OpenID Connectのみ設定されている

「Next」を押してPoliciesの設定へ進みます。

Configure Rulesを設定します。

Includeに以下を追加します

  • OIDC Claimsを選択
  • 「Claim name」に「guilds」を入力する
  • 「Claim value」にDiscordのサーバーIDを入力

Configure Rules

「Save Policy」を押して保存すれば設定完了。対象のドメインに移動して以下のような画面になっていれば成功しています。ログインして動作確認してみてください。

対象のドメインにアクセスしたときのスクリーンショット。中央にログインを促すフォームが出ている

まとめ#

予想以上に簡単にできてよかったです。discord-oidc-workerはサーバだけでなくユーザ自身での認証もできるのでそちらも使うことがあるかもしれません。