Skip to content

fix(lolice-member-portal): declare CF_API_TOKEN/RESEND_API_KEY to prevent binding deletion - #11330

Merged
boxp merged 6 commits into
mainfrom
feature/BOXP-120-lolice-member-portal
Jul 20, 2026
Merged

boxp merged 6 commits into
mainfrom
feature/BOXP-120-lolice-member-portal

Conversation

@boxp

@boxp boxp commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Summary

  • PR feat(BOXP-120): lolice cluster メンバーポータルのセルフサービス化 #11314 がマージ済みだったが、codex-review で指摘された Worker secret binding 削除問題を修正する後続 PR
  • cloudflare_workers_script を更新すると、Terraform が宣言していない binding を削除するため CF_API_TOKEN / RESEND_API_KEY が消去される問題を修正
  • AWS SSM Parameter Store (/lolice-member-portal/CF_API_TOKEN, /lolice-member-portal/RESEND_API_KEY) から値を読み取り、cloudflare_workers_secret リソースとして宣言することで常に保持される

Changes

  • worker.tf: data.aws_ssm_parameter + cloudflare_workers_secret を追加
  • backend.tf: AWS provider (hashicorp/aws ~> 5.0) を追加
  • provider.tf: provider "aws" { region = "ap-northeast-1" } を追加
  • .terraform.lock.hcl: AWS provider v5.100.0 のハッシュを追加

Prerequisites

boxp が作成済みの SSM パラメータ(SecureString):

  • /lolice-member-portal/CF_API_TOKEN
  • /lolice-member-portal/RESEND_API_KEY

Test plan

  • terraform plan が通ること (CI で確認)
  • apply 後、Cloudflare Dashboard で Worker の secret binding に CF_API_TOKENRESEND_API_KEY が存在すること
  • Worker を再 apply しても secret binding が削除されないこと

🤖 Generated with Claude Code

…oudflare_workers_secret

Terraform's cloudflare_workers_script only sends declared bindings on update,
which deletes any manually-set CF_API_TOKEN / RESEND_API_KEY secret bindings.
Fix by adding cloudflare_workers_secret resources that read values from AWS SSM
Parameter Store (/lolice-member-portal/CF_API_TOKEN, /lolice-member-portal/RESEND_API_KEY).
Also add AWS provider to backend.tf, provider.tf, and .terraform.lock.hcl.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@boxp-tfaction

This comment has been minimized.

…de workers_script

cloudflare_workers_secret resources are only applied when the secret value
changes. When cloudflare_workers_script is updated, Cloudflare re-uploads
the worker with only the bindings declared inside the script resource,
causing separately-managed secrets to be silently deleted.

Moving CF_API_TOKEN and RESEND_API_KEY into secret_text_binding blocks
inside cloudflare_workers_script ensures they are always included in every
script upload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@boxp-tfaction

This comment has been minimized.

boxp and others added 2 commits July 20, 2026 08:39
…r secrets without TF state exposure

Replace aws_ssm_parameter data sources + secret_text_binding (which stored
decrypted values in Terraform state) with a null_resource local-exec
provisioner that reads SSM params via AWS CLI and sets them directly on the
Worker via the Cloudflare API at apply time. Values are never written to state.

- Remove data "aws_ssm_parameter" and secret_text_binding from worker.tf
- Add null_resource.worker_secrets with local-exec provisioner triggered on
  script content hash so secrets are re-applied after every script update
- Replace hashicorp/aws provider with hashicorp/null in backend.tf and provider.tf
- Update .terraform.lock.hcl: remove aws provider, add null provider 3.2.4
- Update README to document SSM as source of truth and warn against manual
  Wrangler/Dashboard updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@boxp-tfaction

This comment has been minimized.

@boxp-tfaction

boxp-tfaction Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Plan Result (terraform/cloudflare/b0xp.io/lolice-member-portal)

CI link

Plan: 1 to add, 0 to change, 0 to destroy.
  • Create
    • null_resource.worker_secrets
Change Result (Click me)
  # null_resource.worker_secrets will be created
  + resource "null_resource" "worker_secrets" {
      + id       = (known after apply)
      + triggers = {
          + "always_run" = (known after apply)
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Warning: Deprecated Resource

  with cloudflare_worker_route.lolice_member_portal,
  on worker.tf line 92, in resource "cloudflare_worker_route" "lolice_member_portal":
  92: resource "cloudflare_worker_route" "lolice_member_portal" {

`cloudflare_worker_route` is now deprecated and will be removed in the next
major version. Use `cloudflare_workers_route` instead.

⚠️ Warnings

Warning: Deprecated Resource

  with cloudflare_worker_route.lolice_member_portal,
  on worker.tf line 92, in resource "cloudflare_worker_route" "lolice_member_portal":
  92: resource "cloudflare_worker_route" "lolice_member_portal" {

`cloudflare_worker_route` is now deprecated and will be removed in the next
major version. Use `cloudflare_workers_route` instead.

⚠️ Errors

  • failed to add a label terraform/cloudflare/b0xp.io/lolice-member-portal/add-or-update: label name is too long (max: 50)

@boxp
boxp merged commit 3291846 into main Jul 20, 2026
13 checks passed
@boxp
boxp deleted the feature/BOXP-120-lolice-member-portal branch July 20, 2026 08:53
@boxp-tfaction

boxp-tfaction Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

❌ Apply Failed (terraform/cloudflare/b0xp.io/lolice-member-portal)

CI link

Error: local-exec provisioner error

  with null_resource.worker_secrets,
  on worker.tf line 66, in resource "null_resource" "worker_secrets":
  66:   provisioner "local-exec" {

Error running command 'set -euo pipefail
ACCOUNT_ID="1984a4314b3e75f3bedce97c7a8e0c81"
for SECRET in CF_API_TOKEN RESEND_API_KEY; do
  VALUE=$(aws ssm get-parameter \
    --name "/lolice-member-portal/$$SECRET" \
    --with-decryption \
    --query Parameter.Value \
    --output text \
    --region ap-northeast-1)
  BODY=$(jq -n --arg name "$$SECRET" --arg text "$$VALUE" '{"name":$name,"text":$text,"type":"secret_text"}')
  curl -sf -X PUT \
    "https://api.cloudflare.com/client/v4/accounts/$$ACCOUNT_ID/workers/scripts/lolice-member-portal/secrets" \
    -H "Authorization: Bearer $$CLOUDFLARE_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$$BODY"
  echo "Set secret $$SECRET"
done
': exit status 254. Output: 
aws: [ERROR]: An error occurred (ParameterNotFound) when calling the
GetParameter operation:
Details (Click me)
Jul 20 08:54:20.612 WRN The policy file is ignored unless it is allowed by "aqua policy allow" command.

$ aqua policy allow "/home/runner/work/arch/arch/aqua/aqua-policy.yaml"

If you want to keep ignoring the policy file without the warning, please run "aqua policy deny" command.

$ aqua policy deny "/home/runner/work/arch/arch/aqua/aqua-policy.yaml"

  program=aqua version=2.62.0 env=linux/amd64 exe_name=terraform package_name=hashicorp/terraform package_version=v1.15.8 registry=standard policy_file=/home/runner/work/arch/arch/aqua/aqua-policy.yaml doc=https://aquaproj.github.io/docs/reference/codes/003
null_resource.worker_secrets: Creating...
null_resource.worker_secrets: Provisioning with 'local-exec'...
null_resource.worker_secrets (local-exec): Executing: ["/bin/bash" "-c" "set -euo pipefail\nACCOUNT_ID=\"1984a4314b3e75f3bedce97c7a8e0c81\"\nfor SECRET in CF_API_TOKEN RESEND_API_KEY; do\n  VALUE=$(aws ssm get-parameter \\\n    --name \"/lolice-member-portal/$$SECRET\" \\\n    --with-decryption \\\n    --query Parameter.Value \\\n    --output text \\\n    --region ap-northeast-1)\n  BODY=$(jq -n --arg name \"$$SECRET\" --arg text \"$$VALUE\" '{\"name\":$name,\"text\":$text,\"type\":\"secret_text\"}')\n  curl -sf -X PUT \\\n    \"https://api.cloudflare.com/client/v4/accounts/$$ACCOUNT_ID/workers/scripts/lolice-member-portal/secrets\" \\\n    -H \"Authorization: Bearer $$CLOUDFLARE_API_TOKEN\" \\\n    -H \"Content-Type: application/json\" \\\n    -d \"$$BODY\"\n  echo \"Set secret $$SECRET\"\ndone\n"]

null_resource.worker_secrets (local-exec): aws: [ERROR]: An error occurred (ParameterNotFound) when calling the GetParameter operation:

Error: local-exec provisioner error

  with null_resource.worker_secrets,
  on worker.tf line 66, in resource "null_resource" "worker_secrets":
  66:   provisioner "local-exec" {

Error running command 'set -euo pipefail
ACCOUNT_ID="1984a4314b3e75f3bedce97c7a8e0c81"
for SECRET in CF_API_TOKEN RESEND_API_KEY; do
  VALUE=$(aws ssm get-parameter \
    --name "/lolice-member-portal/$$SECRET" \
    --with-decryption \
    --query Parameter.Value \
    --output text \
    --region ap-northeast-1)
  BODY=$(jq -n --arg name "$$SECRET" --arg text "$$VALUE" '{"name":$name,"text":$text,"type":"secret_text"}')
  curl -sf -X PUT \
    "https://api.cloudflare.com/client/v4/accounts/$$ACCOUNT_ID/workers/scripts/lolice-member-portal/secrets" \
    -H "Authorization: Bearer $$CLOUDFLARE_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d "$$BODY"
  echo "Set secret $$SECRET"
done
': exit status 254. Output: 
aws: [ERROR]: An error occurred (ParameterNotFound) when calling the
GetParameter operation:

@boxp-tfaction

boxp-tfaction Bot commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

terraform/cloudflare/b0xp.io/lolice-member-portal: Follow up PR was created

Build link

@boxp

Apply failed. Please handle the problem. ⚠️ Don't rerun GitHub Actions Workflow

  1. Check the error message
  2. Check chore(terraform/cloudflare/b0xp.io/lolice-member-portal): follow up #11330 #11331
  3. Add commits to chore(terraform/cloudflare/b0xp.io/lolice-member-portal): follow up #11330 #11331 to fix the problem if needed
  4. Review and merge chore(terraform/cloudflare/b0xp.io/lolice-member-portal): follow up #11330 #11331

boxp added a commit that referenced this pull request Jul 20, 2026
…lare__b0xp.io__lolice-member-portal-20260720T085432

chore(terraform/cloudflare/b0xp.io/lolice-member-portal): follow up #11330
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant