📧

TerraformでCloudflare Email RoutingのWorkerをセットアップする

に公開

Cloudflareのメール転送で、Workerを使おうと思いたったけど、コンソールをポチポチするのがとにかく嫌い(だいたいやらかす)なので、terraformでEmail RoutingとWorkerのセットアップに手を染めました。Cloudflareのterraform providerはネット上でも情報が少なく、公式のドキュメントもあっさりしすぎた説明なので何気に苦労したので、メモをかねてtipsを残したいと思い立ち、筆を取りました。

ESM Worker利用時は main_module を指定する

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 引数でエントリーポイントとなるファイル名を指定します。

main.tf
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_rulecloudflare_email_routing_catch_all)を作成し、特定のアドレスに来たメールをWorkerに転送する設定します。

このとき、action ブロックでWorkerを指定しますが、value に与える値についてドキュメントでは明快な説明がなく、試行錯誤した結果、script_nameを指定すればうまく行きました。

main.tf
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スプレッドシートをフロントエンドにした、グループアドレス(同報)対応のメール転送設定ツールです。興味ありましたら、スターつけていただくと元気が出ます。

GitHubで編集を提案

Discussion