Skip to content

feat(website): add the email sign-in settings and ONE's SES roles - #48

Merged
jm-rivera merged 3 commits into
devfrom
feat/website-email-sign-in
Oct 23, 2026
Merged

jm-rivera merged 3 commits into
devfrom
feat/website-email-sign-in

Conversation

@jm-rivera

@jm-rivera jm-rivera commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds the settings that the website's sign-in by emailed code reads (DevelopmentFinanceObservatory/website#28) to the website stack in dev and prod, and points each environment at its SES sender role in ONE's AWS account (961128127831, us-east-1). AUTH_EMAIL_FROM is fixed at DFO Studio <studio@developmentfinance.org>, the one address the roles may send as. The new ses object sets SES_ROLE_ARN, SES_REGION and SES_TOKEN_AUDIENCE together, and a validation refuses one whose ARN, region or audience is malformed or blank. Each role trusts only its environment's runtime service account, and only with that environment's audience: dfo-dev-website-staging-run with development-finance-observatory-staging, and dfo-prod-website-run with development-finance-observatory-production. Both env.auto.tfvars files set their role. TURNSTILE_SITE_KEY comes from turnstile_site_key, which defaults to null and leaves the env var out. Both tfvars files set it to the site key of their widget in the ONE Campaign Cloudflare account, "DFO website staging" for the run.app host and "DFO website production" for developmentfinance.org.

TURNSTILE_SECRET_KEY mounts latest from a new secret, <website name>-turnstile-secret-key, in infra/stacks/website/email_sign_in.tf. Its placeholder first version is a single space, which the app trims to blank and reads as unset, so email sign-in stays off whatever else is set until the real key is added as a new version. The service's readiness_dependencies names that placeholder version, so the first apply cannot start a revision before the secret has a version to read.

Email sign-in stays off after this merges, until each widget's secret key is added as a version of <website name>-turnstile-secret-key and the service rolls onto a new revision. Each environment's README "Email sign-in" section has the command that adds the Turnstile secret key, the role and audience each service uses, and when a revision needs a manual roll. The deployed website ignores all six settings, so this can merge before website#28. The DKIM and DMARC records for the sending domain are in #57.

Testing: terraform fmt -check passes, and terraform validate passes in both environments. A terraform plan -lock=false against dev state shows 3 to add (the secret, its placeholder version and the runtime account's accessor grant) and 1 in-place change to the service, which gains AUTH_EMAIL_FROM, SES_ROLE_ARN, SES_REGION, SES_TOKEN_AUDIENCE, TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY and the readiness annotation. Plans with a malformed ARN, an empty region, a blank audience or a missing attribute are refused. No token has been exchanged at AWS STS against either role yet.

The website's sign-in by emailed code reads five settings. The stack
now sets AUTH_EMAIL_FROM, mounts TURNSTILE_SECRET_KEY from a new
secret whose placeholder version is a single space, and passes
SES_ROLE_ARN, SES_REGION and TURNSTILE_SITE_KEY from variables that
stay null until the values exist. Email sign-in stays off until all
five are set.

The revision waits for the placeholder version through
readiness_dependencies, so the first apply cannot start a revision
that mounts a secret with no version.
@jm-rivera
jm-rivera marked this pull request as ready for review October 20, 2026 13:41
@jm-rivera
jm-rivera removed the request for review from tillywoodfield October 20, 2026 16:13
ONE's AWS account (961128127831, us-east-1) has one SES sender role per
environment, and each trusts only that environment's runtime service
account with its own token audience. The website stack's ses object sets
SES_ROLE_ARN, SES_REGION and SES_TOKEN_AUDIENCE together, and both
env.auto.tfvars files now set it to their role.
@jm-rivera jm-rivera changed the title feat(website): add the email sign-in settings feat(website): add the email sign-in settings and ONE's SES roles Oct 23, 2026
The widgets "DFO website staging" and "DFO website production" exist in
the ONE Campaign Cloudflare account. Email sign-in turns on once each
secret key is added as a version of its turnstile-secret-key secret.
@jm-rivera
jm-rivera merged commit f04a835 into dev Oct 23, 2026
5 checks passed
@github-actions

Copy link
Copy Markdown

Terraform Apply — website

Apply complete! Resources: 3 added, 1 changed, 0 destroyed.

Init Validate Apply
pass pass pass
Show apply output
ephemeral.random_password.website_better_auth_secret: Opening...
ephemeral.random_password.website_caller_hmac_key: Opening...
ephemeral.random_password.website_caller_hmac_key: Opening complete after 0s
ephemeral.random_password.website_better_auth_secret: Opening complete after 0s
google_secret_manager_secret.website_turnstile_secret_key: Creating...
google_secret_manager_secret.website_turnstile_secret_key: Creation complete after 0s [id=projects/dev-fin-observatory/secrets/dfo-dev-website-staging-turnstile-secret-key]
google_secret_manager_secret_version.website_turnstile_secret_key_placeholder: Creating...
module.website_service.google_secret_manager_secret_iam_member.runtime_secret_access["dfo-dev-website-staging-turnstile-secret-key"]: Creating...
google_secret_manager_secret_version.website_turnstile_secret_key_placeholder: Creation complete after 1s [id=projects/41292283861/secrets/dfo-dev-website-staging-turnstile-secret-key/versions/1]
module.website_service.google_secret_manager_secret_iam_member.runtime_secret_access["dfo-dev-website-staging-turnstile-secret-key"]: Creation complete after 4s [id=projects/dev-fin-observatory/secrets/dfo-dev-website-staging-turnstile-secret-key/roles/secretmanager.secretAccessor/serviceAccount:dfo-dev-website-staging-run@dev-fin-observatory.iam.gserviceaccount.com]
module.website_service.google_cloud_run_v2_service.this: Modifying... [id=projects/dev-fin-observatory/locations/northamerica-northeast1/services/dfo-dev-website-staging]
module.website_service.google_cloud_run_v2_service.this: Still modifying... [id=projects/dev-fin-observatory/locations/...east1/services/dfo-dev-website-staging, 00m10s elapsed]
module.website_service.google_cloud_run_v2_service.this: Modifications complete after 12s [id=projects/dev-fin-observatory/locations/northamerica-northeast1/services/dfo-dev-website-staging]
ephemeral.random_password.website_better_auth_secret: Closing...
ephemeral.random_password.website_caller_hmac_key: Closing...
ephemeral.random_password.website_caller_hmac_key: Closing complete after 0s
ephemeral.random_password.website_better_auth_secret: Closing complete after 0s

Apply complete! Resources: 3 added, 1 changed, 0 destroyed.

Outputs:

database_endpoint_ip = "10.100.1.2"
database_host = "bbd723248b19.3niso0mm9bket.northamerica-northeast1.sql.goog"
database_name = "website-staging"
database_runtime_user = "dfo-dev-website-staging-run@dev-fin-observatory.iam"
migrate_job_name = "dfo-dev-website-staging-migrate"
migrator_database_user = "dfo-dev-website-stg-migrator@dev-fin-observatory.iam"
migrator_service_account = "dfo-dev-website-stg-migrator@dev-fin-observatory.iam.gserviceaccount.com"
runtime_service_account = "dfo-dev-website-staging-run@dev-fin-observatory.iam.gserviceaccount.com"
service_name = "dfo-dev-website-staging"
service_url = "https://dfo-dev-website-staging-zms5lj4zhq-nn.a.run.app"
website_url = "https://dfo-dev-website-staging-zms5lj4zhq-nn.a.run.app"

Stack website · f04a835 · @jm-rivera · run

This branch was successfully deployed

1 active deployment
dev-plan — 45749d6e Deployed Oct 23, 2026 by jm-rivera via plan (website) #76
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant