diff --git a/.github/workflows/opentofu.yml b/.github/workflows/opentofu.yml index 098bcca..bcc2f47 100644 --- a/.github/workflows/opentofu.yml +++ b/.github/workflows/opentofu.yml @@ -19,5 +19,8 @@ jobs: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository uses: makeitworkcloud/shared-workflows/.github/workflows/opentofu.yml@main + with: + aws-region: us-west-2 + aws-role-to-assume: arn:aws:iam::332355796717:role/github-actions-twilio-state secrets: CHART_UPDATER_GITHUB_APP_PRIVATE_KEY: ${{ secrets.CHART_UPDATER_GITHUB_APP_PRIVATE_KEY }} diff --git a/Makefile b/Makefile index a8476b8..97e74e3 100644 --- a/Makefile +++ b/Makefile @@ -1,23 +1,30 @@ SHELL := /bin/bash TERRAFORM := $(shell which tofu) +S3_BUCKET := mitw-tf-twilio-infra +S3_REGION := us-west-2 +S3_KEY := tofu/twilio/terraform.tfstate .PHONY: clean init plan apply test pre-commit-config pre-commit-check-deps pre-commit-install-hooks clean: @find . -name .terraform -type d | xargs -r rm -rf -# Bootstrap deliberately uses no remote backend until the encrypted backend -# contract and least-privilege CI access are established in a later PR. +# tfroot-aws owns this private, versioned state bucket and the GitHub OIDC role +# that CI assumes. The backend needs no static AWS credentials. init: clean - @${TERRAFORM} init -backend=false -upgrade -input=false + @${TERRAFORM} init -reconfigure -upgrade -input=false \ + -backend-config="bucket=${S3_BUCKET}" \ + -backend-config="key=${S3_KEY}" \ + -backend-config="region=${S3_REGION}" \ + -backend-config="use_lockfile=true" plan: init - @${TERRAFORM} plan -refresh=false -input=false -lock=false -compact-warnings + @${TERRAFORM} plan -refresh=false -input=false -compact-warnings # There are intentionally no provider configurations or Twilio resources in -# this bootstrap, so the main-branch apply has no provider-side effect. +# this root, so backend selection is the only stateful behavior on main. apply: init - @${TERRAFORM} apply -auto-approve -refresh=false -input=false -lock=false -compact-warnings + @${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings test: pre-commit-config pre-commit-install-hooks @pre-commit run -a diff --git a/docs/bootstrap.md b/docs/bootstrap.md index eaf9785..5e18d1b 100644 --- a/docs/bootstrap.md +++ b/docs/bootstrap.md @@ -2,9 +2,9 @@ ## Scope -This initial root validates the OpenTofu toolchain and provider installation only. It creates, imports, updates, or deletes **no** Twilio resources. In particular, it does not purchase or configure phone numbers, webhooks, credentials, messaging services, or runtime routing. +This root validates the OpenTofu toolchain, remote state backend, and provider installation only. It creates, imports, updates, or deletes **no** Twilio resources. In particular, it does not purchase or configure phone numbers, webhooks, credentials, messaging services, or runtime routing. -The evaluated provider is `RJPearson94/twilio` `0.27.1`. Registry documentation confirms it supports Twilio phone-number resources and inbound `messaging` webhook fields, but it is community-maintained and requires existing account credentials. The bootstrap intentionally declares no provider configuration, so CI receives no Twilio credentials and performs no provider-side API call. +The evaluated provider is `RJPearson94/twilio` `0.27.1`. Registry documentation confirms it supports Twilio phone-number resources and inbound `messaging` webhook fields, but it is community-maintained and requires existing account credentials. The root intentionally declares no provider configuration, so CI receives no Twilio credentials and performs no provider-side API call. ## Ownership boundary @@ -12,13 +12,9 @@ The future root may own only Twilio phone-number inventory and inbound messaging ## Backend and credential contract -The checked-in `.sops.yaml` identifies the approved encryption recipient but no encrypted secret file exists yet. A later, separately reviewed change must: +[`tfroot-aws` PR #43](https://github.com/makeitworkcloud/tfroot-aws/pull/43) created the canonical backend producer: a dedicated private, encrypted, versioned bucket and an exact-repository GitHub OIDC role restricted to the state object, lockfile, and SOPS KMS decrypt/describe access. This root selects that backend through the reusable workflow's `aws-role-to-assume` input and uses S3 native locking. No static AWS backend credential is stored in source or GitHub Actions secrets. -1. establish least-privilege GitHub Actions OIDC access for this exact repository to decrypt SOPS material; -2. add an encrypted backend configuration for a dedicated Twilio state object; and -3. define an existing Twilio credential delivery path that cannot expose a token in source, CI logs, or OpenTofu state. - -Only after those prerequisites pass pull-request validation may a later root change add provider configuration or Twilio inventory. Any actual Twilio provisioning or webhook update still requires explicit owner confirmation before merge because `main` invokes the environment-gated apply path. +The checked-in `.sops.yaml` identifies the approved encryption recipient but no encrypted secret file exists yet. A later, separately reviewed change must define a Twilio credential delivery path that cannot expose a token in source, CI logs, or OpenTofu state. Only after that prerequisite passes pull-request validation may a later root change add provider configuration or Twilio inventory. Any actual Twilio provisioning or webhook update still requires explicit owner confirmation before merge because `main` invokes the environment-gated apply path. ## Central generated files diff --git a/main.tf b/main.tf index adbd32e..2f16480 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,4 @@ -# Bootstrap intentionally contains no Twilio resources, data sources, provider -# configuration, or secret material. The next root change must first establish -# the encrypted backend and credential-delivery contract described in docs/bootstrap.md. +# This root has a selected remote backend but intentionally contains no Twilio +# resources, data sources, provider configuration, or secret material. A later +# reviewed change must establish encrypted credential delivery before adding a +# provider block or managing Twilio inventory. diff --git a/providers.tf b/providers.tf index e580aec..1b1e825 100644 --- a/providers.tf +++ b/providers.tf @@ -1,6 +1,8 @@ terraform { required_version = "> 1.3" + backend "s3" {} + required_providers { twilio = { source = "RJPearson94/twilio" @@ -9,10 +11,5 @@ terraform { } } -# The permanent S3 backend is intentionally omitted until its encrypted -# contract and least-privilege CI access are reviewed in a follow-up PR. -# The bootstrap Makefile initializes with -backend=false. - -# No provider block is declared during bootstrap. The candidate provider is -# installed and syntax-validated without receiving credentials or managing -# Twilio resources. +# No provider block is declared. The selected backend is independent of Twilio +# credentials and resource management; those remain separate follow-up gates.