Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/terraform-apply-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ env:
TF_VERSION: '1.9.8'
TF_IN_AUTOMATION: 'true'
TF_ENV: 'production'
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.TF_STATE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TF_STATE_R2_SECRET_ACCESS_KEY }}
AWS_REGION: 'auto'
Expand Down Expand Up @@ -108,7 +109,8 @@ jobs:
- name: Verify operator secrets are set
run: |
missing=""
[ -z "${CLOUDFLARE_API_TOKEN}" ] && missing="${missing} CLOUDFLARE_API_TOKEN"
[ -z "${CLOUDFLARE_EMAIL}" ] && missing="${missing} CLOUDFLARE_EMAIL"
[ -z "${CLOUDFLARE_API_KEY}" ] && missing="${missing} CLOUDFLARE_API_KEY"
[ -z "${AWS_ACCESS_KEY_ID}" ] && missing="${missing} TF_STATE_R2_ACCESS_KEY_ID"
[ -z "${AWS_SECRET_ACCESS_KEY}" ] && missing="${missing} TF_STATE_R2_SECRET_ACCESS_KEY"
[ -z "${CF_ACCOUNT_ID}" ] && missing="${missing} CF_ACCOUNT_ID"
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/terraform-apply-staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ env:
TF_VERSION: '1.9.8'
TF_IN_AUTOMATION: 'true'
TF_ENV: 'staging'
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# Global Key via EMAIL+KEY env vars (CLOUDFLARE_API_TOKEN forces Bearer
# which Global Keys fail on Rulesets/R2/account-scoped endpoints — 9106).
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.TF_STATE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TF_STATE_R2_SECRET_ACCESS_KEY }}
AWS_REGION: 'auto'
Expand Down Expand Up @@ -72,7 +75,8 @@ jobs:
- name: Verify operator secrets are set
run: |
missing=""
[ -z "${CLOUDFLARE_API_TOKEN}" ] && missing="${missing} CLOUDFLARE_API_TOKEN"
[ -z "${CLOUDFLARE_EMAIL}" ] && missing="${missing} CLOUDFLARE_EMAIL"
[ -z "${CLOUDFLARE_API_KEY}" ] && missing="${missing} CLOUDFLARE_API_KEY"
[ -z "${AWS_ACCESS_KEY_ID}" ] && missing="${missing} TF_STATE_R2_ACCESS_KEY_ID"
[ -z "${AWS_SECRET_ACCESS_KEY}" ] && missing="${missing} TF_STATE_R2_SECRET_ACCESS_KEY"
[ -z "${CF_ACCOUNT_ID}" ] && missing="${missing} CF_ACCOUNT_ID"
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ jobs:
working-directory: terraform/cloudflare
# CF creds + state-backend creds passed in via env, not inlined in run:.
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# Global Key via EMAIL+KEY env vars (provider uses X-Auth-* headers).
# NOT CLOUDFLARE_API_TOKEN — that's Bearer-only and Global Keys fail
# Bearer auth on Rulesets / R2 / account-scoped endpoints (9106).
CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
CLOUDFLARE_API_KEY: ${{ secrets.CLOUDFLARE_API_KEY }}
AWS_ACCESS_KEY_ID: ${{ secrets.TF_STATE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.TF_STATE_R2_SECRET_ACCESS_KEY }}
AWS_REGION: 'auto'
Expand All @@ -95,7 +99,8 @@ jobs:
# pointing at the README and the exact missing variable names.
run: |
missing=""
[ -z "${CLOUDFLARE_API_TOKEN}" ] && missing="${missing} CLOUDFLARE_API_TOKEN"
[ -z "${CLOUDFLARE_EMAIL}" ] && missing="${missing} CLOUDFLARE_EMAIL"
[ -z "${CLOUDFLARE_API_KEY}" ] && missing="${missing} CLOUDFLARE_API_KEY"
[ -z "${AWS_ACCESS_KEY_ID}" ] && missing="${missing} TF_STATE_R2_ACCESS_KEY_ID"
[ -z "${AWS_SECRET_ACCESS_KEY}" ] && missing="${missing} TF_STATE_R2_SECRET_ACCESS_KEY"
[ -z "${CF_ACCOUNT_ID}" ] && missing="${missing} CF_ACCOUNT_ID"
Expand All @@ -104,7 +109,7 @@ jobs:
echo "::error::See https://github.com/InstaNode-dev/infra/blob/master/terraform/cloudflare/README.md#bootstrap-one-time"
exit 1
fi
echo "all 4 operator secrets present"
echo "all 5 operator secrets present"

- name: terraform init
run: |
Expand Down
18 changes: 10 additions & 8 deletions terraform/cloudflare/dns.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# DNS records under management.
#
# Pre-cutover ritual (D-3): TTL must be 60s for ≥48h BEFORE any cut.
# Setting it that low here means terraform plan/apply itself satisfies
# the pre-step the first time we touch the record.
# That ONLY applies to grey-cloud (proxied=false) records — CF requires
# proxied=true records to have ttl=1 (CF manages TTL internally; setting
# 60 returns a 400 "ttl must be set to 1 when `proxied` is true").
#
# `proxied = true` = CF orange-cloud; `false` = grey-cloud (DNS only, no
# proxy). Today: marketing apex is orange (Phase 0 baseline), api is grey
# (becomes orange in Phase 4 — flip this flag in that phase's PR).
# `proxied = true` = CF orange-cloud (ttl=1); `false` = grey-cloud,
# DNS only (ttl=60 for cutover ramp). Today: marketing apex is orange
# (Phase 0 baseline), api is grey (becomes orange in Phase 4 — flip
# both the proxied flag AND ttl=60→1 in that phase's PR).

locals {
marketing_origin = "instanode-web.pages.dev" # set per environment in staging.tfvars / production.tfvars after Pages project is created
Expand All @@ -18,7 +20,7 @@ resource "cloudflare_dns_record" "apex" {
name = var.zone_name
type = "CNAME"
content = local.marketing_origin
ttl = 60
ttl = 1
proxied = true
comment = "marketing apex; CNAME-flattened to Pages project"
}
Expand All @@ -28,7 +30,7 @@ resource "cloudflare_dns_record" "www" {
name = "www.${var.zone_name}"
type = "CNAME"
content = var.zone_name
ttl = 60
ttl = 1
proxied = true
comment = "www → apex redirect handled by CF page rule"
}
Expand All @@ -49,7 +51,7 @@ resource "cloudflare_dns_record" "staging" {
name = "staging.${var.zone_name}"
type = "CNAME"
content = "instant-staging.${var.zone_name}.cdn.cloudflare.net" # Pages preview hostname; replaced after Pages project is up
ttl = 60
ttl = 1
proxied = true
comment = "staging mirror per D-2"
}
10 changes: 5 additions & 5 deletions terraform/cloudflare/staging.tf
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ resource "cloudflare_dns_record" "staging_wildcard" {
# regardless of what's here. A 404 sink is intentional — any unrouted
# subdomain hits CF's default 404 page.
content = local.staging_stem
ttl = 60
ttl = 1
proxied = true
comment = "wildcard for per-tenant CF Container services in staging; routed via cloudflare_workers_route below"
}
Expand All @@ -70,7 +70,7 @@ resource "cloudflare_dns_record" "staging_deployment_wildcard" {
name = "*.deployment.${local.staging_stem}"
type = "CNAME"
content = "deployment.${local.staging_stem}"
ttl = 60
ttl = 1
proxied = true
comment = "wildcard for /deploy/new staging apps (mirrors prod *.deployment.instanode.dev)"
}
Expand All @@ -83,7 +83,7 @@ resource "cloudflare_dns_record" "staging_deployment_anchor" {
name = "deployment.${local.staging_stem}"
type = "AAAA"
content = "100::" # IPv6 discard prefix — never reachable; CF proxied front-end terminates
ttl = 60
ttl = 1
proxied = true
comment = "anchor for deployment wildcard CNAME (CF requires a real record at the parent)"
}
Expand All @@ -102,7 +102,7 @@ resource "cloudflare_dns_record" "staging_webhook" {
name = "webhook.${local.staging_stem}"
type = "AAAA"
content = "100::" # placeholder; CF orange-cloud handles routing
ttl = 60
ttl = 1
proxied = true
comment = "staging /webhook/new receiver subdomain"
}
Expand All @@ -122,7 +122,7 @@ resource "cloudflare_dns_record" "staging_dashboard" {
name = "dashboard.${local.staging_stem}"
type = "CNAME"
content = "instanode-dashboard-staging.pages.dev" # set after dashboard Pages project is created
ttl = 60
ttl = 1
proxied = true
comment = "staging dashboard — QA-only; D-5 keeps prod dashboard off Pages"
}
Expand Down
Loading