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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,8 @@ plan-output.txt
# Generated canonical pre-commit configuration
/.pre-commit-config.yaml
/.pre-commit-config.yaml.tmp

# Ignore plaintext credential files. Only the validated SOPS ciphertext path is tracked.
/secrets/*.env
/secrets/*.yaml
!/secrets/secrets.yaml
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

OpenTofu root for Make IT Work Cloud Twilio control-plane infrastructure.

This root owns only Twilio phone-number inventory and inbound messaging-webhook configuration. It must not own the OpenCode SMS bridge workload, Cloudflare workload route or DNS, number-to-agent mapping, approved-source allowlist, bridge credentials, or encryption material. Those runtime concerns belong to `kustomize-cluster`.
This root owns only Twilio phone-number inventory and inbound messaging-webhook configuration. It must not own the OpenCode SMS bridge workload, Cloudflare workload route or DNS, number-to-agent mapping, approved-source allowlist, bridge credentials, or runtime encryption material. Those runtime concerns belong to `kustomize-cluster`.

This bootstrap contains no Twilio resources, provider configuration, backend credentials, encrypted secrets, state, or number identifiers. Use GitHub MCP and pull-request CI plans as validation authority. `main` is an environment-gated apply path; use scoped branches and pull requests, never direct pushes. Do not run OpenTofu, SOPS, state, import, or apply commands from this server.
The root owns the SOPS-encrypted `secrets/secrets.yaml` provider credential file and no other secret material. It contains only the Twilio provider environment-variable names. The root contains no Twilio resources, provider configuration, state, or number identifiers. Use GitHub MCP and pull-request CI plans as validation authority. `main` is an environment-gated apply path; use scoped branches and pull requests, never direct pushes. Do not run OpenTofu, SOPS, state, import, or apply commands from this server.

The shared workflow is owned by `shared-workflows`; the runner image and canonical pre-commit configuration are owned by `images/tfroot-runner`. Keep any future SOPS data encrypted and never expose credentials, decrypted values, state, private keys, or sensitive plans.
17 changes: 13 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ TERRAFORM := $(shell which tofu)
S3_BUCKET := mitw-tf-twilio-infra
S3_REGION := us-west-2
S3_KEY := tofu/twilio/terraform.tfstate
TWILIO_CREDENTIALS := secrets/secrets.yaml

.PHONY: clean init plan apply test pre-commit-config pre-commit-check-deps pre-commit-install-hooks
.PHONY: clean init credentials-check plan apply test pre-commit-config pre-commit-check-deps pre-commit-install-hooks

clean:
@find . -name .terraform -type d | xargs -r rm -rf
Expand All @@ -18,12 +19,20 @@ init: clean
-backend-config="region=${S3_REGION}" \
-backend-config="use_lockfile=true"

plan: init
# The encrypted file is verified and exposed only to this short-lived child
# process. It does not configure the Twilio provider or call Twilio APIs.
credentials-check:
@test -f "${TWILIO_CREDENTIALS}"
@sops filestatus "${TWILIO_CREDENTIALS}" | jq -e '.encrypted == true' >/dev/null
@sops exec-env "${TWILIO_CREDENTIALS}" 'test -n "$$TWILIO_ACCOUNT_SID" && test -n "$$TWILIO_API_KEY" && test -n "$$TWILIO_API_SECRET"'

plan: init credentials-check
@${TERRAFORM} plan -refresh=false -input=false -compact-warnings

# There are intentionally no provider configurations or Twilio resources in
# this root, so backend selection is the only stateful behavior on main.
apply: init
# this root, so backend selection and encrypted-credential validation are the
# only stateful behaviors on main.
apply: init credentials-check
@${TERRAFORM} apply -auto-approve -refresh=false -input=false -compact-warnings

test: pre-commit-config pre-commit-install-hooks
Expand Down
10 changes: 6 additions & 4 deletions docs/bootstrap.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

## Scope

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.
This root validates the OpenTofu toolchain, remote state backend, and encrypted provider-credential delivery only. It creates, imports, updates, or deletes **no** Twilio resources. In particular, it does not purchase or configure phone numbers, webhooks, 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 root 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 validates SOPS credential delivery without performing a provider-side API call.

## Ownership boundary

The future root may own only Twilio phone-number inventory and inbound messaging-webhook configuration. `kustomize-cluster` remains the owner of the OpenCode bridge workload, workload `TunnelBinding`/DNS, fixed number-to-agent map, approved-source allowlist, runtime secrets, and state-encryption inputs. The root must never create a bridge-worker API key or duplicate a runtime owner.
The future root may own only Twilio phone-number inventory and inbound messaging-webhook configuration. `kustomize-cluster` remains the owner of the OpenCode bridge workload, workload `TunnelBinding`/DNS, fixed number-to-agent map, approved-source allowlist, runtime secrets, and runtime-encryption inputs. The root must never create a bridge-worker API key or duplicate a runtime owner.

## Backend and credential contract

[`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.

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.
The checked-in `.sops.yaml` identifies the approved encryption recipient. `secrets/secrets.yaml` is the only accepted provider credential file. It holds the encrypted `TWILIO_ACCOUNT_SID`, `TWILIO_API_KEY`, and `TWILIO_API_SECRET` values; it must never contain bridge runtime inputs. `make plan` and `make apply` first require SOPS to recognize the file as encrypted, then use `sops exec-env` to assert the three variables in a short-lived child process. They never write plaintext files, set static provider attributes, or use GitHub Actions secrets. The older `secrets/twilio.sops.env.example` placeholder is superseded and must not be used.

Only after the encrypted credential path 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

Expand Down
13 changes: 13 additions & 0 deletions secrets/secrets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
TWILIO_ACCOUNT_SID: ENC[AES256_GCM,data:1rwEFnR254orfuyd5oajxb7zlb93laTsMsMJLjIpjnBI5Q==,iv:5XcuMzThrHkJmDpAbLmyc5e6G+L3QTN1VzG6Qhjh368=,tag:g2jeVTbcdu5NUekvhXBeUw==,type:str]
TWILIO_API_KEY: ENC[AES256_GCM,data:dQUXkSVvrV6te+UGucxhFsZPV5EGMW/+OpaHsdHk4rGmKA==,iv:GqXYHPsPlK5gZAk340h01z9Vj2HAzNfMDCE7n1DVDoo=,tag:pkWjmFtSXWazYZ1XdYN71w==,type:str]
TWILIO_API_SECRET: ENC[AES256_GCM,data:zY6hExO4kYaz+epRpo5nfqTHIPrpVTu1DB2UbAO3fnE=,iv:lfPOnaegZz4zEBdOrPDWXAHJUCffEyXO5dxgPRScu3o=,tag:qAjtyATA7lxuY2sGq/S25A==,type:str]
sops:
kms:
- arn: arn:aws:kms:us-west-2:332355796717:key/0a45c0f6-71dc-4d54-ab33-9df4de1a9e91
created_at: "2026-09-04T18:56:10Z"
enc: AQICAHj1IggLFhM4nJnKEvmbEpk5E9RxZZoxpZYUW0taoyrz1AFIluGLSHyrmRFsHAf3aPP4AAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM7P1gO6LNa70z3QdJAgEQgDtBYYAcxnlG3JVNNFlGvf3pSIrw0YPoGhjCBbtZ8/yrdLmynNOYcn+4WLEXs9PEDHwQuWzYIpkQ/0PN0Q==
aws_profile: ""
lastmodified: "2026-09-04T18:56:10Z"
mac: ENC[AES256_GCM,data:XmZx/uuVBBXEAqngEeLPdwvoMSIpKDN5NlZ3lDwMbnRavRqtM0tUDKsRqjYLPrz07wjRou3VS5jNfDLwiyn6apcmSsvPsL5vxrIA7JZyGUEN4cpNmmSvH3VcJtkxdB+mpGv64uMgtm6yqwzlXYa8YRsXAU1cY4sfokzmIC3LyFg=,iv:cDQbhfpuWet961tRBUdcgWktgnpzZ9xC4wp6i/XTSC8=,tag:5U7DO6e9MtyvL+U6z1MOkA==,type:str]
unencrypted_suffix: _unencrypted
version: 3.10.2
3 changes: 3 additions & 0 deletions secrets/twilio.sops.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Superseded: do not use this path.
# The only accepted Twilio provider credential file is the SOPS-encrypted
# secrets/secrets.yaml document described in docs/bootstrap.md.
Loading