Skip to content

Commit 63906d8

Browse files
daniel-citgtsorbo
andauthored
feat!: Enable CMEK for Terraform state buckets (#1030)
Co-authored-by: Grant Sorbo <[email protected]>
1 parent 15bab38 commit 63906d8

File tree

10 files changed

+55
-27
lines changed

10 files changed

+55
-27
lines changed

0-bootstrap/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ Each step has instructions for this change.
288288
| billing\_account | The ID of the billing account to associate projects with. | `string` | n/a | yes |
289289
| bucket\_force\_destroy | When deleting a bucket, this boolean option will delete all contained objects. If false, Terraform will fail to delete buckets which contain objects. | `bool` | `false` | no |
290290
| bucket\_prefix | Name prefix to use for state bucket created. | `string` | `"bkt"` | no |
291+
| bucket\_tfstate\_kms\_force\_destroy | When deleting a bucket, this boolean option will delete the KMS keys used for the Terraform state bucket. | `bool` | `false` | no |
291292
| default\_region | Default region to create resources where applicable. | `string` | `"us-central1"` | no |
292293
| folder\_prefix | Name prefix to use for folders created. Should be the same in all steps. | `string` | `"fldr"` | no |
293294
| group\_billing\_admins | Google Group for GCP Billing Administrators | `string` | n/a | yes |

0-bootstrap/cb.tf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ locals {
2222

2323
cicd_project_id = module.tf_source.cloudbuild_project_id
2424

25+
state_bucket_kms_key = "projects/${module.seed_bootstrap.seed_project_id}/locations/${var.default_region}/keyRings/${var.project_prefix}-keyring/cryptoKeys/${var.project_prefix}-key"
26+
2527
bucket_self_link_prefix = "https://www.googleapis.com/storage/v1/b/"
2628
default_state_bucket_self_link = "${local.bucket_self_link_prefix}${module.seed_bootstrap.gcs_bucket_tfstate}"
2729
gcp_projects_state_bucket_self_link = module.gcp_projects_state_bucket.bucket.self_link
@@ -74,6 +76,12 @@ module "gcp_projects_state_bucket" {
7476
project_id = module.seed_bootstrap.seed_project_id
7577
location = var.default_region
7678
force_destroy = var.bucket_force_destroy
79+
80+
encryption = {
81+
default_kms_key_name = local.state_bucket_kms_key
82+
}
83+
84+
depends_on = [module.seed_bootstrap.gcs_bucket_tfstate]
7785
}
7886

7987
module "tf_source" {

0-bootstrap/main.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ module "seed_bootstrap" {
6161
parent_folder = var.parent_folder == "" ? "" : local.parent
6262
org_admins_org_iam_permissions = local.org_admins_org_iam_permissions
6363
project_prefix = var.project_prefix
64+
encrypt_gcs_bucket_tfstate = true
65+
key_rotation_period = "7776000s"
66+
kms_prevent_destroy = !var.bucket_tfstate_kms_force_destroy
6467

6568
project_labels = {
6669
environment = "bootstrap"

0-bootstrap/sa.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ locals {
9898
"roles/storage.admin",
9999
"roles/iam.serviceAccountAdmin",
100100
"roles/resourcemanager.projectDeleter",
101+
"roles/cloudkms.admin",
101102
],
102103
"org" = [
103104
"roles/storage.objectAdmin",

0-bootstrap/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ variable "bucket_force_destroy" {
8282
default = false
8383
}
8484

85+
variable "bucket_tfstate_kms_force_destroy" {
86+
description = "When deleting a bucket, this boolean option will delete the KMS keys used for the Terraform state bucket."
87+
type = bool
88+
default = false
89+
}
90+
8591
/* ----------------------------------------
8692
Specific to Groups creation
8793
---------------------------------------- */

helpers/foundation-deployer/global.tfvars.example

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ group_org_admins = "REPLACE_ME" # "[email protected]"
3939
group_billing_admins = "REPLACE_ME" # "[email protected]"
4040
org_project_creators = []
4141

42-
bucket_force_destroy = false
43-
project_prefix = "prj"
44-
folder_prefix = "fldr"
42+
bucket_force_destroy = false
43+
bucket_tfstate_kms_force_destroy = false
44+
45+
project_prefix = "prj"
46+
folder_prefix = "fldr"
4547

4648
// Optional - for an organization with existing projects or for development/validation.
4749
// Uncomment this variable to place all the example foundation resources under

helpers/foundation-deployer/stages/apply.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ import (
3232

3333
func DeployBootstrapStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, c CommonConf) error {
3434
bootstrapTfvars := BootstrapTfvars{
35-
OrgID: tfvars.OrgID,
36-
DefaultRegion: tfvars.DefaultRegion,
37-
BillingAccount: tfvars.BillingAccount,
38-
GroupOrgAdmins: tfvars.GroupOrgAdmins,
39-
GroupBillingAdmins: tfvars.GroupBillingAdmins,
40-
OrgProjectCreators: tfvars.OrgProjectCreators,
41-
ParentFolder: tfvars.ParentFolder,
42-
ProjectPrefix: tfvars.ProjectPrefix,
43-
FolderPrefix: tfvars.FolderPrefix,
44-
BucketForceDestroy: tfvars.BucketForceDestroy,
45-
Groups: tfvars.Groups,
46-
InitialGroupConfig: tfvars.InitialGroupConfig,
35+
OrgID: tfvars.OrgID,
36+
DefaultRegion: tfvars.DefaultRegion,
37+
BillingAccount: tfvars.BillingAccount,
38+
GroupOrgAdmins: tfvars.GroupOrgAdmins,
39+
GroupBillingAdmins: tfvars.GroupBillingAdmins,
40+
OrgProjectCreators: tfvars.OrgProjectCreators,
41+
ParentFolder: tfvars.ParentFolder,
42+
ProjectPrefix: tfvars.ProjectPrefix,
43+
FolderPrefix: tfvars.FolderPrefix,
44+
BucketForceDestroy: tfvars.BucketForceDestroy,
45+
BucketTfstateKmsForceDestroy: tfvars.BucketTfstateKmsForceDestroy,
46+
Groups: tfvars.Groups,
47+
InitialGroupConfig: tfvars.InitialGroupConfig,
4748
}
4849

4950
err := utils.WriteTfvars(filepath.Join(c.FoundationPath, BootstrapStep, "terraform.tfvars"), bootstrapTfvars)

helpers/foundation-deployer/stages/data.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ type GlobalTFVars struct {
156156
FolderPrefix *string `hcl:"folder_prefix"`
157157
CaiMonitoringKmsForceDestroy *bool `hcl:"cai_monitoring_kms_force_destroy"`
158158
BucketForceDestroy *bool `hcl:"bucket_force_destroy"`
159+
BucketTfstateKmsForceDestroy *bool `hcl:"bucket_tfstate_kms_force_destroy"`
159160
AuditLogsTableDeleteContentsOnDestroy *bool `hcl:"audit_logs_table_delete_contents_on_destroy"`
160161
LogExportStorageForceDestroy *bool `hcl:"log_export_storage_force_destroy"`
161162
LogExportStorageLocation string `hcl:"log_export_storage_location"`
@@ -193,18 +194,19 @@ func (g GlobalTFVars) CheckString(s string) {
193194
}
194195

195196
type BootstrapTfvars struct {
196-
OrgID string `hcl:"org_id"`
197-
BillingAccount string `hcl:"billing_account"`
198-
GroupOrgAdmins string `hcl:"group_org_admins"`
199-
GroupBillingAdmins string `hcl:"group_billing_admins"`
200-
DefaultRegion string `hcl:"default_region"`
201-
ParentFolder *string `hcl:"parent_folder"`
202-
ProjectPrefix *string `hcl:"project_prefix"`
203-
FolderPrefix *string `hcl:"folder_prefix"`
204-
BucketForceDestroy *bool `hcl:"bucket_force_destroy"`
205-
OrgProjectCreators []string `hcl:"org_project_creators"`
206-
Groups *Groups `hcl:"groups"`
207-
InitialGroupConfig *string `hcl:"initial_group_config"`
197+
OrgID string `hcl:"org_id"`
198+
BillingAccount string `hcl:"billing_account"`
199+
GroupOrgAdmins string `hcl:"group_org_admins"`
200+
GroupBillingAdmins string `hcl:"group_billing_admins"`
201+
DefaultRegion string `hcl:"default_region"`
202+
ParentFolder *string `hcl:"parent_folder"`
203+
ProjectPrefix *string `hcl:"project_prefix"`
204+
FolderPrefix *string `hcl:"folder_prefix"`
205+
BucketForceDestroy *bool `hcl:"bucket_force_destroy"`
206+
BucketTfstateKmsForceDestroy *bool `hcl:"bucket_tfstate_kms_force_destroy"`
207+
OrgProjectCreators []string `hcl:"org_project_creators"`
208+
Groups *Groups `hcl:"groups"`
209+
InitialGroupConfig *string `hcl:"initial_group_config"`
208210
}
209211

210212
type OrgTfvars struct {

helpers/foundation-deployer/stages/validate.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ func ValidateDestroyFlags(t testing.TB, g GlobalTFVars) {
105105
if g.LogExportStorageForceDestroy == nil || !*g.LogExportStorageForceDestroy {
106106
flags = append(flags, "log_export_storage_force_destroy")
107107
}
108+
if g.BucketTfstateKmsForceDestroy == nil || !*g.BucketTfstateKmsForceDestroy {
109+
flags = append(flags, "bucket_tfstate_kms_force_destroy")
110+
}
108111
if g.CaiMonitoringKmsForceDestroy == nil || !*g.CaiMonitoringKmsForceDestroy {
109112
flags = append(flags, "cai_monitoring_kms_force_destroy")
110113
}

test/integration/bootstrap/bootstrap_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ func TestBootstrap(t *testing.T) {
4848

4949
vars := map[string]interface{}{
5050
"bucket_force_destroy": true,
51+
"bucket_tfstate_kms_force_destroy": true,
5152
}
5253

5354
temp := tft.NewTFBlueprintTest(t,

0 commit comments

Comments
 (0)