Skip to main content

When to use

Before running terraform apply on the iac-access/foundation/ layer — whether for a first-time environment bootstrap, a routine change, or after a terraform taint cloudflare_turnstile_widget.access.

The foundation layer manages Cloudflare Turnstile resources in addition to GCP resources. The Cloudflare API token must carry the right scopes or the apply fails silently with a bare 403.

Preconditions

  • Access to the iac-access repository and the target environment's tfvars.
  • CLOUDFLARE_API_TOKEN with both of the following scopes:
    • Account > Turnstile > Edit
    • Account > Account Settings > Read
  • TF_VAR_iac_project set (or injected by Terraflow via TF_VAR_*).
  • GCP credentials with the permissions normally required by the foundation layer (Cloud SQL admin, Secret Manager admin, IAM admin, etc.).

Verifying CF API token scopes

  1. Go to Cloudflare Dashboard → My ProfileAPI Tokens.
  2. Find the token used for Terraform CI (or your local token).
  3. Click Edit and confirm both scopes are present under the correct account.

If the token is managed via GCP Secret Manager (CI flow), the token value is in terraform-cf-api-token secret. Update the secret version after editing the token in the CF Dashboard.

Procedure

Via Terraflow (standard — CI)

# Push your changes and open a PR against iac-access/main
# CI runs terraform plan automatically for the foundation layer.

# Review the plan comment posted by eigenoid-terraflow-bot.
# If the plan is correct, comment on the PR:
/terraflow apply foundation/
bash

Terraflow sets CLOUDFLARE_API_TOKEN from the CF_API_TOKEN secret configured in the GitHub environment. Ensure the secret value is up to date if the token was recently rotated.

Local apply (break-glass)

export CLOUDFLARE_API_TOKEN="<token with Turnstile+Edit and Account Settings+Read>"
export TF_VAR_iac_project="eigenoid-dev" # or qa/prd

cd iac-access/foundation
terraform init
terraform plan -var-file=tfvars/dev.tfvars
terraform apply -var-file=tfvars/dev.tfvars
bash

After apply — copy sitekey to Workers Builds

The Turnstile sitekey is not automatically propagated to the Cloudflare Worker build environment. After each apply:

# Get the sitekey
terraform -chdir=foundation output turnstile_sitekey
bash

Then:

  1. Go to CF Dashboard → Workers & Pagesapp-access-public-{env}.
  2. Navigate to SettingsBuildsBuild variables.
  3. Set or update PUBLIC_TURNSTILE_SITE_KEY to the value from terraform output.
  4. Trigger a new build (push a commit or click Trigger deploy).

This manual step is required because the Cloudflare provider v5.19.0 does not expose Workers Builds variables as a Terraform resource. Tracked in ADR-0018.

Verification

# Confirm the Turnstile secret key version exists in Secret Manager
gcloud secrets versions list access-turnstile-secret-key \
--project=eigenoid-{env} \
--format="table(name, state, createTime)"
# Expect: at least one version with state ENABLED

# Confirm the public portal picks up the new sitekey
# (after Workers Builds step above):
curl -s https://access-{env}.eigenoid.com | grep turnstile
# Expect: the sitekey value appearing in the page source
bash

Troubleshooting

403 on cloudflare_turnstile_widget.access creation

Symptom: terraform apply fails with a 403 error, no resource name in the message.

Cause: CLOUDFLARE_API_TOKEN is missing Account > Turnstile > Edit or Account > Account Settings > Read.

Fix: Update the CF API token to include both scopes. For CI, update the CF_API_TOKEN secret in the GitHub environment (iac-access → Settings → Environments → dev/qa/prd).


Secret version already exists — apply is a no-op on the secret

Symptom: terraform plan shows google_secret_manager_secret_version.turnstile_secret_key will be replaced (not just updated).

Cause: A previous manual secret version exists. Terraform will create a new version (Secret Manager keeps all versions).

Fix: After apply, disable or destroy the old manual version if needed to keep the secret clean:

gcloud secrets versions list access-turnstile-secret-key --project=eigenoid-{env}
# Identify old manual versions and disable them:
gcloud secrets versions disable VERSION_ID \
--secret=access-turnstile-secret-key \
--project=eigenoid-{env}
bash

service/ wave fails — "no version found for secret access-turnstile-secret-key"

Cause: foundation/ was not applied before service/, or the apply failed partway through.

Fix: Ensure foundation/ completed successfully (check CI logs or terraform output turnstile_sitekey), then re-apply service/.

Rollback

The cloudflare_turnstile_widget resource cannot be partially rolled back — a recreated widget issues a new sitekey/secret pair. If a widget is accidentally destroyed:

  1. Run terraform apply foundation/ again — this recreates the widget and repopulates the secret automatically.
  2. Copy the new turnstile_sitekey to the Workers Builds env var (see After apply).
  3. Existing challenge tokens issued against the old widget are invalidated — users will need to complete a new Turnstile challenge.

Escalation

Escalate to @shoootyou if the apply fails with an error not covered above.

References