TerraformでCloudflare Email RoutingのWorkerをセットアップする
Cloudflareのメール転送で、Workerを使おうと思いたったけど、コンソールをポチポチするのがとにかく嫌い(だいたいやらかす)なので、terraformでEmail RoutingとWorkerのセットアップに手を染めました。Cloudflareのterraform providerはネット上でも情報が少なく、公式のドキュメントもあっさりしすぎた説明なので何気に苦労したので、メモをかねてtipsを残したいと思い立ち、筆を取りました。
main_module
を指定する
ESM Worker利用時は WorkerのjsをESM(ES6)形式で記載した場合、何も考えずに書くと以下のようなエラーが発生し、AIアシスタントに聞いても「古いJavaScriptで書き直したら?」という始末。
│ Error: failed to make http request
│
│ with cloudflare_workers_script.email_forwarder,
│ on main.tf line 8, in resource "cloudflare_workers_script" "email_forwarder":
│ 8: resource "cloudflare_workers_script" "email_forwarder" {
│
│ PUT
│ "https://api.cloudflare.com/client/v4/accounts/5c81d268fa635d33ea2621cedd56c69f/workers/scripts/email-forwarder-worker":
│ 400 Bad Request {
│ "result": null,
│ "success": false,
│ "errors": [
│ {
│ "code": 10021,
│ "message": "Uncaught SyntaxError: Unexpected token 'export'\n at worker.js:10\n"
│ }
│ ],
│ "messages": []
│ }
│
╵
仕方なく、自力で解決策を探していたら、https://github.com/cloudflare/terraform-provider-cloudflare/issues/1870にそのまんまのissueがありました。結論は、main_module
にエントリーポイントとなるファイル名を指定すれば良いとのこと。
最近のWorker開発ではES Modules (ESM) 形式が主流ですが、ESMのWorkerをアップロードする場合、content
引数ではなく main_module
引数でエントリーポイントとなるファイル名を指定します。
resource "cloudflare_workers_script" "email_forwarder" {
account_id = var.cloudflare_account_id
script_name = "email-forwarder-worker"
content = file("${path.module}/../worker/src/worker.js")
main_module = "worker.js" # エントリーポイントとなるファイル名を指定
# bindingsやobservabilityなどは省略
# ...
}
APIトークンに必要な権限
APIトークンに必要な権限をつけておかないと、権限エラーでapplyがこけてしまうため、以下を設定しておきました。自分の場合は、Workers KV Storageを利用したので、Workers KV Storageに対する編集権限も追加しています。
- アカウント - Email Routingアドレス: 編集
- アカウント - Workersスクリプト: 編集
- アカウント - アカウント設定: 読み取り
- ゾーン - Email Routingルール: 編集
- ゾーン - ゾーン設定: 編集
- ゾーン - ゾーン: 読み取り
Email Routing RuleとWorkerの紐付け
Email Routingのルール(cloudflare_email_routing_rule
や cloudflare_email_routing_catch_all
)を作成し、特定のアドレスに来たメールをWorkerに転送する設定します。
このとき、action
ブロックでWorkerを指定しますが、value
に与える値についてドキュメントでは明快な説明がなく、試行錯誤した結果、script_name
を指定すればうまく行きました。
resource "cloudflare_email_routing_catch_all" "example_email_routing_catch_all" {
zone_id = var.cloudflare_zone_id
name = "Send all emails to worker"
enabled = true
# 一致条件 (すべてのメールを対象)
matchers = [{
type = "all"
}]
# アクション (Workerに転送)
actions = [{
type = "worker"
# ここにはscript_nameを指定する
value = [cloudflare_workers_script.email_forwarder.script_name]
}]
}
まとめ
TerraformでCloudflare Email RoutingとWorkerを設定する際の3つのTIPSを紹介しました。
- ESM Workerでは
main_module
を使う - APIトークンには「Email Routingルール: 編集」「Workersスクリプト: 編集」など、上記で挙げた必要な権限を設定する
- ルーティングルールのアクションではWorkerの
script_name
を指定する
これらのTIPSを踏まえた完全な実装例として、Google Spreadsheetsと連携したグループメール転送システムを開発しました。実際のコードは、https://github.com/fujiba/tegaki-relay に公開しています。
tegaki-relay
はGoogleスプレッドシートをフロントエンドにした、グループアドレス(同報)対応のメール転送設定ツールです。興味ありましたら、スターつけていただくと元気が出ます。
Discussion