Skip to content

github-ci-bootstrap: create a bucket for Terraform binary plan files - #36

Merged
jwbron merged 1 commit into
mainfrom
jwies/ci-bootstrap-plans-bucket
Jul 20, 2026
Merged

github-ci-bootstrap: create a bucket for Terraform binary plan files#36
jwbron merged 1 commit into
mainfrom
jwies/ci-bootstrap-plans-bucket

Conversation

@jwbron

@jwbron jwbron commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Khan/actions#274 changes generate-terraform-plan/apply-terraform-plan to store the Terraform binary plan in GCS instead of committing it to git (a binary plan embeds a full copy of the Terraform state, including sensitive values in cleartext). Every consumer of those actions needs the same bucket with the same security posture, so this PR has the bootstrap module create it, next to the CI service accounts and WIF providers it belongs with, instead of each repo hand-rolling it.

What the module now creates (opt-out via create_terraform_plans_bucket = false)

  • Bucket terraform-plans-{org}-{repo}-{service} (same normalization as the state bucket; overridable via terraform_plans_bucket) in khan-internal-services, with uniform bucket-level access and public access prevention enforced.
  • Always per-service, never shared: plan files contain that service's state, so a shared bucket would let each service's CI read the others' state.
  • roles/storage.objectAdmin on the bucket for the read/write service account only (it uploads on plan, downloads and deletes on apply). The read-only account used for PR-branch plans gets no grant.
  • Lifecycle rule deleting objects after terraform_plans_expiration_days (default 30); applied plans are already deleted by the apply action, this catches superseded plan PRs.
  • New output terraform_plans_bucket to feed the actions' plan_bucket input.

Rollout

Additive and enabled by default: consumers get the bucket on their next module bump plus a local bootstrap terraform apply. For culture-cron, which already created khan-culture-cron-terraform-plans by hand in its bootstrap (Khan/culture-cron#28) during testing, adoption means passing terraform_plans_bucket = "khan-culture-cron-terraform-plans" and moving the two resources into the module in its bootstrap state:

terraform state mv google_storage_bucket.terraform_plans 'module.github_ci_bootstrap.google_storage_bucket.terraform_plans[0]'
terraform state mv google_storage_bucket_iam_member.ci_rw_terraform_plans_object_admin 'module.github_ci_bootstrap.google_storage_bucket_iam_member.ci_plans_bucket_access_rw[0]'

Related: #35 (make write_branch_patterns explicit); if both land together, tag a single github-ci-bootstrap-v2.0.0.

The generate-terraform-plan GitHub action (Khan/actions#274) uploads
binary plans to GCS instead of committing them, because a binary plan
embeds a full copy of the Terraform state including sensitive values.
Every consumer of the plan/apply actions needs the same bucket with the
same security posture, so create it here alongside the CI service
accounts it belongs to: per-service naming, uniform bucket-level
access, public access prevention, a lifecycle rule for plans that are
never applied, and object access for the rw service account only.

Opt out with create_terraform_plans_bucket = false for setups that do
not use the plan/apply actions.

@csilvers csilvers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense to me!

@jwbron
jwbron merged commit eec423f into main Jul 20, 2026
1 check passed
@jwbron
jwbron deleted the jwies/ci-bootstrap-plans-bucket branch July 20, 2026 23:42
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.

2 participants