diff --git a/0-bootstrap/README.md b/0-bootstrap/README.md index c3d10381d..21c7dabf0 100644 --- a/0-bootstrap/README.md +++ b/0-bootstrap/README.md @@ -523,12 +523,14 @@ The following steps will guide you through deploying without using Cloud Build. | default\_region\_2 | Secondary default region to create resources where applicable. | `string` | `"us-west1"` | no | | default\_region\_gcs | Case-Sensitive default region to create gcs resources where applicable. | `string` | `"US"` | no | | default\_region\_kms | Secondary default region to create kms resources where applicable. | `string` | `"us"` | no | +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | folder\_prefix | Name prefix to use for folders created. Should be the same in all steps. | `string` | `"fldr"` | no | | groups | Contain the details of the Groups to be created. |
object({
create_required_groups = optional(bool, false)
create_optional_groups = optional(bool, false)
billing_project = optional(string, null)
required_groups = object({
group_org_admins = string
group_billing_admins = string
billing_data_users = string
audit_data_users = string
})
optional_groups = optional(object({
gcp_security_reviewer = optional(string, "")
gcp_network_viewer = optional(string, "")
gcp_scc_admin = optional(string, "")
gcp_global_secrets_admin = optional(string, "")
gcp_kms_admin = optional(string, "")
}), {})
})
| n/a | yes | | initial\_group\_config | Define the group configuration when it is initialized. Valid values are: WITH\_INITIAL\_OWNER, EMPTY and INITIAL\_GROUP\_CONFIG\_UNSPECIFIED. | `string` | `"WITH_INITIAL_OWNER"` | no | | org\_id | GCP Organization ID | `string` | n/a | yes | | org\_policy\_admin\_role | Additional Org Policy Admin role for admin group. You can use this for testing purposes. | `bool` | `false` | no | | parent\_folder | Optional - for an organization with existing projects or for development/validation. It will place all the example foundation resources under the provided folder instead of the root organization. The value is the numeric folder ID. The folder must already exist. | `string` | `""` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | project\_prefix | Name prefix to use for projects created. Should be the same in all steps. Max size is 3 characters. | `string` | `"prj"` | no | ## Outputs diff --git a/0-bootstrap/cb.tf b/0-bootstrap/cb.tf index 86c94540d..27ca53163 100644 --- a/0-bootstrap/cb.tf +++ b/0-bootstrap/cb.tf @@ -66,9 +66,25 @@ resource "random_string" "suffix" { upper = false } +module "gcp_projects_state_bucket" { + source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" + version = "~> 8.0" + + name = "${var.bucket_prefix}-${module.seed_bootstrap.seed_project_id}-gcp-projects-tfstate" + project_id = module.seed_bootstrap.seed_project_id + location = var.default_region + force_destroy = var.bucket_force_destroy + + encryption = { + default_kms_key_name = local.state_bucket_kms_key + } + + depends_on = [module.seed_bootstrap.gcs_bucket_tfstate] +} + module "tf_source" { source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_source" - version = "~> 8.0" + version = "~> 9.0" org_id = var.org_id folder_id = google_folder.bootstrap.id @@ -78,6 +94,8 @@ module "tf_source" { group_org_admins = var.groups.required_groups.group_org_admins buckets_force_destroy = var.bucket_force_destroy + project_deletion_policy = var.project_deletion_policy + activate_apis = [ "serviceusage.googleapis.com", "servicenetworking.googleapis.com", @@ -116,6 +134,15 @@ module "tf_source" { depends_on = [module.seed_bootstrap] } +resource "google_project_service_identity" "workflows_identity" { + provider = google-beta + + project = module.tf_source.cloudbuild_project_id + service = "workflows.googleapis.com" + + depends_on = [module.tf_source] +} + module "tf_private_pool" { source = "./modules/cb-private-pool" @@ -137,7 +164,7 @@ module "tf_private_pool" { module "tf_cloud_builder" { source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_builder" - version = "~> 8.0" + version = "~> 9.0" project_id = module.tf_source.cloudbuild_project_id dockerfile_repo_uri = module.tf_source.csr_repos[local.cloudbuilder_repo].url @@ -188,7 +215,7 @@ module "build_terraform_image" { module "tf_workspace" { source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace" - version = "~> 8.0" + version = "~> 9.0" for_each = local.granular_sa project_id = module.tf_source.cloudbuild_project_id diff --git a/0-bootstrap/github.tf.example b/0-bootstrap/github.tf.example index 7f5a0e3f3..df996af94 100644 --- a/0-bootstrap/github.tf.example +++ b/0-bootstrap/github.tf.example @@ -70,7 +70,7 @@ locals { module "gh_cicd" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" name = "${var.project_prefix}-b-cicd-wif-gh" random_project_id = true @@ -87,6 +87,8 @@ module "gh_cicd" { "cloudresourcemanager.googleapis.com", "iamcredentials.googleapis.com", ] + + deletion_policy = var.project_deletion_policy } module "gh_oidc" { diff --git a/0-bootstrap/gitlab.tf.example b/0-bootstrap/gitlab.tf.example index 579e84b21..1f0346cfc 100644 --- a/0-bootstrap/gitlab.tf.example +++ b/0-bootstrap/gitlab.tf.example @@ -81,7 +81,7 @@ provider "gitlab" { module "gitlab_cicd" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" name = "${var.project_prefix}-b-cicd-wif-gl" random_project_id = true @@ -100,8 +100,9 @@ module "gitlab_cicd" { "sts.googleapis.com", "dns.googleapis.com", "secretmanager.googleapis.com", - ] + + deletion_policy = var.project_deletion_policy } module "gitlab_oidc" { diff --git a/0-bootstrap/groups.tf b/0-bootstrap/groups.tf index 6f9a8d160..aadb18ece 100644 --- a/0-bootstrap/groups.tf +++ b/0-bootstrap/groups.tf @@ -34,7 +34,7 @@ data "google_organization" "org" { module "required_group" { source = "terraform-google-modules/group/google" - version = "~> 0.6" + version = "~> 0.7" for_each = local.required_groups_to_create id = each.value @@ -46,7 +46,7 @@ module "required_group" { module "optional_group" { source = "terraform-google-modules/group/google" - version = "~> 0.6" + version = "~> 0.7" for_each = local.optional_groups_to_create id = each.value diff --git a/0-bootstrap/jenkins.tf.example b/0-bootstrap/jenkins.tf.example index 7e9413ffb..8a17ad374 100644 --- a/0-bootstrap/jenkins.tf.example +++ b/0-bootstrap/jenkins.tf.example @@ -46,6 +46,7 @@ module "jenkins_bootstrap" { tunnel0_bgp_session_range = var.tunnel0_bgp_session_range tunnel1_bgp_peer_address = var.tunnel1_bgp_peer_address tunnel1_bgp_session_range = var.tunnel1_bgp_session_range + project_deletion_policy = var.project_deletion_policy } resource "google_organization_iam_member" "org_jenkins_sa_browser" { diff --git a/0-bootstrap/main.tf b/0-bootstrap/main.tf index 7dbf89534..17bc985e5 100644 --- a/0-bootstrap/main.tf +++ b/0-bootstrap/main.tf @@ -38,13 +38,14 @@ locals { } resource "google_folder" "bootstrap" { - display_name = "${var.folder_prefix}-bootstrap" - parent = local.parent + display_name = "${var.folder_prefix}-bootstrap" + parent = local.parent + deletion_protection = var.folder_deletion_protection } module "seed_bootstrap" { source = "terraform-google-modules/bootstrap/google" - version = "~> 8.0" + version = "~> 9.0" org_id = var.org_id folder_id = google_folder.bootstrap.id @@ -64,6 +65,7 @@ module "seed_bootstrap" { encrypt_gcs_bucket_tfstate = true key_rotation_period = "7776000s" kms_prevent_destroy = !var.bucket_tfstate_kms_force_destroy + project_deletion_policy = var.project_deletion_policy project_labels = { environment = "bootstrap" @@ -104,19 +106,3 @@ module "seed_bootstrap" { depends_on = [module.required_group] } - -module "gcp_projects_state_bucket" { - source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" - version = "~> 6.0" - - name = "${var.bucket_prefix}-${module.seed_bootstrap.seed_project_id}-gcp-projects-tfstate" - project_id = module.seed_bootstrap.seed_project_id - location = var.default_region - force_destroy = var.bucket_force_destroy - - encryption = { - default_kms_key_name = local.state_bucket_kms_key - } - - depends_on = [module.seed_bootstrap.gcs_bucket_tfstate] -} diff --git a/0-bootstrap/modules/gitlab-oidc/versions.tf b/0-bootstrap/modules/gitlab-oidc/versions.tf index dc2e4b617..0d9e65818 100644 --- a/0-bootstrap/modules/gitlab-oidc/versions.tf +++ b/0-bootstrap/modules/gitlab-oidc/versions.tf @@ -20,7 +20,7 @@ terraform { google = { source = "hashicorp/google" - version = ">= 3.64, < 6" + version = ">= 3.64, < 7" } } diff --git a/0-bootstrap/modules/jenkins-agent/README.md b/0-bootstrap/modules/jenkins-agent/README.md index 09f72a5aa..10c713ea4 100644 --- a/0-bootstrap/modules/jenkins-agent/README.md +++ b/0-bootstrap/modules/jenkins-agent/README.md @@ -68,6 +68,7 @@ module "jenkins_bootstrap" { | on\_prem\_vpn\_public\_ip\_address | The public IP Address of the Jenkins Controller. | `string` | n/a | yes | | on\_prem\_vpn\_public\_ip\_address2 | The secondpublic IP Address of the Jenkins Controller. | `string` | n/a | yes | | org\_id | GCP Organization ID | `string` | n/a | yes | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | project\_labels | Labels to apply to the project. | `map(string)` | `{}` | no | | project\_prefix | Name prefix to use for projects created. | `string` | `"prj"` | no | | router\_asn | BGP ASN for cloud routes. | `number` | `"64515"` | no | diff --git a/0-bootstrap/modules/jenkins-agent/main.tf b/0-bootstrap/modules/jenkins-agent/main.tf index d18397c6b..c9651b743 100644 --- a/0-bootstrap/modules/jenkins-agent/main.tf +++ b/0-bootstrap/modules/jenkins-agent/main.tf @@ -29,7 +29,7 @@ resource "random_id" "suffix" { *******************************************/ module "cicd_project" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" name = local.cicd_project_name random_project_id = true @@ -40,6 +40,8 @@ module "cicd_project" { billing_account = var.billing_account activate_apis = local.activate_apis labels = var.project_labels + + deletion_policy = var.project_deletion_policy } /****************************************** diff --git a/0-bootstrap/modules/jenkins-agent/variables.tf b/0-bootstrap/modules/jenkins-agent/variables.tf index 13c90a059..80b1f53db 100644 --- a/0-bootstrap/modules/jenkins-agent/variables.tf +++ b/0-bootstrap/modules/jenkins-agent/variables.tf @@ -39,6 +39,12 @@ variable "default_region" { default = "us-central1" } +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + /* ---------------------------------------- Specific to CICD Project ---------------------------------------- */ diff --git a/0-bootstrap/modules/tfc-agent-gke/main.tf b/0-bootstrap/modules/tfc-agent-gke/main.tf index 4100c3611..2e631e3fd 100644 --- a/0-bootstrap/modules/tfc-agent-gke/main.tf +++ b/0-bootstrap/modules/tfc-agent-gke/main.tf @@ -96,7 +96,7 @@ resource "google_service_account" "tfc_agent_service_account" { module "tfc_agent_cluster" { source = "terraform-google-modules/kubernetes-engine/google//modules/beta-autopilot-private-cluster/" - version = "~> 31.0" + version = "~> 34.0" project_id = var.project_id region = var.region @@ -394,7 +394,7 @@ resource "google_dns_policy" "default_policy" { module "hub" { source = "terraform-google-modules/kubernetes-engine/google//modules/fleet-membership" - version = "~> 31.0" + version = "~> 34.0" project_id = var.project_id location = var.region diff --git a/0-bootstrap/modules/tfc-agent-gke/versions.tf b/0-bootstrap/modules/tfc-agent-gke/versions.tf index 2ccf6ddc9..c3c6eeced 100644 --- a/0-bootstrap/modules/tfc-agent-gke/versions.tf +++ b/0-bootstrap/modules/tfc-agent-gke/versions.tf @@ -20,7 +20,7 @@ terraform { google = { source = "hashicorp/google" - version = ">= 4.3.0, < 6" + version = ">= 4.3.0, < 7" } kubernetes = { diff --git a/0-bootstrap/terraform_cloud.tf.example b/0-bootstrap/terraform_cloud.tf.example index ab999e239..27d9e05a8 100644 --- a/0-bootstrap/terraform_cloud.tf.example +++ b/0-bootstrap/terraform_cloud.tf.example @@ -230,7 +230,7 @@ resource "tfe_run_trigger" "projects_bu2_shared_production" { module "tfc_cicd" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" name = "${var.project_prefix}-b-cicd-wif-tfc" random_project_id = true @@ -251,6 +251,8 @@ module "tfc_cicd" { "gkehub.googleapis.com", "connectgateway.googleapis.com" ] + + deletion_policy = var.project_deletion_policy } module "tfc-oidc" { diff --git a/0-bootstrap/variables.tf b/0-bootstrap/variables.tf index 39b993abb..db7e27c65 100644 --- a/0-bootstrap/variables.tf +++ b/0-bootstrap/variables.tf @@ -90,6 +90,18 @@ variable "bucket_tfstate_kms_force_destroy" { default = false } +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} + /* ---------------------------------------- Specific to Groups creation ---------------------------------------- */ diff --git a/0-bootstrap/versions.tf b/0-bootstrap/versions.tf index ee8f24e58..17dac8a60 100644 --- a/0-bootstrap/versions.tf +++ b/0-bootstrap/versions.tf @@ -20,7 +20,13 @@ terraform { google = { // version 4.31.0 removed because of issue https://github.com/hashicorp/terraform-provider-google/issues/12226 source = "hashicorp/google" - version = ">= 3.50, != 4.31.0" + version = ">= 3.50, != 4.31.0, <= 6.10" + } + + google-beta = { + // version 4.31.0 removed because of issue https://github.com/hashicorp/terraform-provider-google/issues/12226 + source = "hashicorp/google-beta" + version = ">= 3.50, != 4.31.0, <= 6.10" } // Un-comment gitlab required_providers when using gitlab CI/CD diff --git a/1-org/envs/shared/README.md b/1-org/envs/shared/README.md index e260c67ca..e12dc5bcf 100644 --- a/1-org/envs/shared/README.md +++ b/1-org/envs/shared/README.md @@ -12,12 +12,14 @@ | enforce\_allowed\_worker\_pools | Whether to enforce the organization policy restriction on allowed worker pools for Cloud Build. | `bool` | `false` | no | | essential\_contacts\_domains\_to\_allow | The list of domains that email addresses added to Essential Contacts can have. | `list(string)` | n/a | yes | | essential\_contacts\_language | Essential Contacts preferred language for notifications, as a ISO 639-1 language code. See [Supported languages](https://cloud.google.com/resource-manager/docs/managing-notification-contacts#supported-languages) for a list of supported languages. | `string` | `"en"` | no | +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | gcp\_groups | Groups to grant specific roles in the Organization.
platform\_viewer: Google Workspace or Cloud Identity group that have the ability to view resource information across the Google Cloud organization.
security\_reviewer: Google Workspace or Cloud Identity group that members are part of the security team responsible for reviewing cloud security
network\_viewer: Google Workspace or Cloud Identity group that members are part of the networking team and review network configurations.
scc\_admin: Google Workspace or Cloud Identity group that can administer Security Command Center.
audit\_viewer: Google Workspace or Cloud Identity group that members are part of an audit team and view audit logs in the logging project.
global\_secrets\_admin: Google Workspace or Cloud Identity group that members are responsible for putting secrets into Secrets Manage |
object({
audit_viewer = optional(string, null)
security_reviewer = optional(string, null)
network_viewer = optional(string, null)
scc_admin = optional(string, null)
global_secrets_admin = optional(string, null)
kms_admin = optional(string, null)
})
| `{}` | no | | log\_export\_storage\_force\_destroy | (Optional) If set to true, delete all contents when destroying the resource; otherwise, destroying the resource will fail if contents are present. | `bool` | `false` | no | | log\_export\_storage\_location | The location of the storage bucket used to export logs. | `string` | `null` | no | | log\_export\_storage\_retention\_policy | Configuration of the bucket's data retention policy for how long objects in the bucket should be retained. |
object({
is_locked = bool
retention_period_days = number
})
| `null` | no | | log\_export\_storage\_versioning | (Optional) Toggles bucket versioning, ability to retain a non-current object version when the live object version gets replaced or deleted. | `bool` | `false` | no | | project\_budget | Budget configuration for projects.
budget\_amount: The amount to use as the budget.
alert\_spent\_percents: A list of percentages of the budget to alert on when threshold is exceeded.
alert\_pubsub\_topic: The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}`.
alert\_spend\_basis: The type of basis used to determine if spend has passed the threshold. Possible choices are `CURRENT_SPEND` or `FORECASTED_SPEND` (default). |
object({
dns_hub_budget_amount = optional(number, 1000)
dns_hub_alert_spent_percents = optional(list(number), [1.2])
dns_hub_alert_pubsub_topic = optional(string, null)
dns_hub_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
base_net_hub_budget_amount = optional(number, 1000)
base_net_hub_alert_spent_percents = optional(list(number), [1.2])
base_net_hub_alert_pubsub_topic = optional(string, null)
base_net_hub_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
base_network_budget_amount = optional(number, 1000)
base_network_alert_spent_percents = optional(list(number), [1.2])
base_network_alert_pubsub_topic = optional(string, null)
base_network_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
restricted_net_hub_budget_amount = optional(number, 1000)
restricted_net_hub_alert_spent_percents = optional(list(number), [1.2])
restricted_net_hub_alert_pubsub_topic = optional(string, null)
restricted_net_hub_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
restricted_network_budget_amount = optional(number, 1000)
restricted_network_alert_spent_percents = optional(list(number), [1.2])
restricted_network_alert_pubsub_topic = optional(string, null)
restricted_network_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
interconnect_budget_amount = optional(number, 1000)
interconnect_alert_spent_percents = optional(list(number), [1.2])
interconnect_alert_pubsub_topic = optional(string, null)
interconnect_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
org_secrets_budget_amount = optional(number, 1000)
org_secrets_alert_spent_percents = optional(list(number), [1.2])
org_secrets_alert_pubsub_topic = optional(string, null)
org_secrets_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
org_billing_export_budget_amount = optional(number, 1000)
org_billing_export_alert_spent_percents = optional(list(number), [1.2])
org_billing_export_alert_pubsub_topic = optional(string, null)
org_billing_export_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
org_audit_logs_budget_amount = optional(number, 1000)
org_audit_logs_alert_spent_percents = optional(list(number), [1.2])
org_audit_logs_alert_pubsub_topic = optional(string, null)
org_audit_logs_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
common_kms_budget_amount = optional(number, 1000)
common_kms_alert_spent_percents = optional(list(number), [1.2])
common_kms_alert_pubsub_topic = optional(string, null)
common_kms_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
scc_notifications_budget_amount = optional(number, 1000)
scc_notifications_alert_spent_percents = optional(list(number), [1.2])
scc_notifications_alert_pubsub_topic = optional(string, null)
scc_notifications_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
})
| `{}` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | scc\_notification\_filter | Filter used to create the Security Command Center Notification, you can see more details on how to create filters in https://cloud.google.com/security-command-center/docs/how-to-api-filter-notifications#create-filter | `string` | `"state = \"ACTIVE\""` | no | | scc\_notification\_name | Name of the Security Command Center Notification. It must be unique in the organization. Run `gcloud scc notifications describe --organization=org_id` to check if it already exists. | `string` | n/a | yes | diff --git a/1-org/envs/shared/folders.tf b/1-org/envs/shared/folders.tf index eff64af4e..90c69454a 100644 --- a/1-org/envs/shared/folders.tf +++ b/1-org/envs/shared/folders.tf @@ -21,9 +21,11 @@ resource "google_folder" "common" { display_name = "${local.folder_prefix}-common" parent = local.parent + # deletion_protection = var.folder_deletion_protection // uncommnet after updating "GoogleCloudPlatform/cloud-functions/google" to provider v6 } resource "google_folder" "network" { display_name = "${local.folder_prefix}-network" parent = local.parent + # deletion_protection = var.folder_deletion_protection // uncommnet after updating "GoogleCloudPlatform/cloud-functions/google" to provider v6 } diff --git a/1-org/envs/shared/projects.tf b/1-org/envs/shared/projects.tf index 60e9e9e87..2cf27b963 100644 --- a/1-org/envs/shared/projects.tf +++ b/1-org/envs/shared/projects.tf @@ -34,7 +34,7 @@ locals { module "org_audit_logs" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -43,6 +43,7 @@ module "org_audit_logs" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.common.id + deletion_policy = var.project_deletion_policy activate_apis = ["logging.googleapis.com", "bigquery.googleapis.com", "billingbudgets.googleapis.com"] labels = { @@ -67,7 +68,7 @@ module "org_audit_logs" { module "org_billing_export" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -76,6 +77,7 @@ module "org_billing_export" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.common.id + deletion_policy = var.project_deletion_policy activate_apis = ["logging.googleapis.com", "bigquery.googleapis.com", "billingbudgets.googleapis.com"] labels = { @@ -100,7 +102,7 @@ module "org_billing_export" { module "common_kms" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -109,6 +111,7 @@ module "common_kms" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.common.id + deletion_policy = var.project_deletion_policy activate_apis = ["logging.googleapis.com", "cloudkms.googleapis.com", "billingbudgets.googleapis.com"] labels = { @@ -134,7 +137,7 @@ module "common_kms" { module "org_secrets" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -143,6 +146,7 @@ module "org_secrets" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.common.id + deletion_policy = var.project_deletion_policy activate_apis = ["logging.googleapis.com", "secretmanager.googleapis.com", "billingbudgets.googleapis.com"] labels = { @@ -167,7 +171,7 @@ module "org_secrets" { module "interconnect" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -176,6 +180,7 @@ module "interconnect" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.network.id + deletion_policy = var.project_deletion_policy activate_apis = ["billingbudgets.googleapis.com", "compute.googleapis.com"] labels = { @@ -200,7 +205,7 @@ module "interconnect" { module "scc_notifications" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -209,6 +214,7 @@ module "scc_notifications" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.common.id + deletion_policy = var.project_deletion_policy activate_apis = ["logging.googleapis.com", "pubsub.googleapis.com", "securitycenter.googleapis.com", "billingbudgets.googleapis.com", "cloudkms.googleapis.com"] labels = { @@ -233,7 +239,7 @@ module "scc_notifications" { module "dns_hub" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -242,6 +248,7 @@ module "dns_hub" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.network.id + deletion_policy = var.project_deletion_policy activate_apis = [ "compute.googleapis.com", @@ -274,7 +281,7 @@ module "dns_hub" { module "base_network_hub" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" count = var.enable_hub_and_spoke ? 1 : 0 random_project_id = true @@ -284,6 +291,7 @@ module "base_network_hub" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.network.id + deletion_policy = var.project_deletion_policy activate_apis = [ "compute.googleapis.com", @@ -324,7 +332,7 @@ resource "google_project_iam_member" "network_sa_base" { module "restricted_network_hub" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" count = var.enable_hub_and_spoke ? 1 : 0 random_project_id = true @@ -334,6 +342,7 @@ module "restricted_network_hub" { org_id = local.org_id billing_account = local.billing_account folder_id = google_folder.network.id + deletion_policy = var.project_deletion_policy activate_apis = [ "compute.googleapis.com", @@ -373,6 +382,8 @@ module "base_restricted_environment_network" { project_prefix = local.project_prefix folder_id = google_folder.network.id + project_deletion_policy = var.project_deletion_policy + env = each.key env_code = each.value diff --git a/1-org/envs/shared/variables.tf b/1-org/envs/shared/variables.tf index 01ba2a832..b39073d7d 100644 --- a/1-org/envs/shared/variables.tf +++ b/1-org/envs/shared/variables.tf @@ -193,3 +193,15 @@ variable "tfc_org_name" { type = string default = "" } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/1-org/modules/cai-monitoring/main.tf b/1-org/modules/cai-monitoring/main.tf index 22d6425ff..8a76ab17d 100644 --- a/1-org/modules/cai-monitoring/main.tf +++ b/1-org/modules/cai-monitoring/main.tf @@ -71,10 +71,10 @@ data "archive_file" "function_source_zip" { module "cloudfunction_source_bucket" { source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" - version = "~> 6.0" + version = "~> 8.0" project_id = var.project_id - name = "bkt-cai-monitoring-${random_id.suffix.hex}-sources-${data.google_project.project.number}-${var.location}" + name = "bkt-cai-monitoring-${random_id.suffix.hex}-sources-${data.google_project.project.number}" location = var.location storage_class = "REGIONAL" force_destroy = true @@ -121,7 +121,7 @@ resource "google_cloud_asset_organization_feed" "organization_feed" { module "pubsub_cai_feed" { source = "terraform-google-modules/pubsub/google" - version = "~> 6.0" + version = "~> 7.0" topic = "top-cai-monitoring-${random_id.suffix.hex}-event" project_id = var.project_id diff --git a/1-org/modules/centralized-logging/main.tf b/1-org/modules/centralized-logging/main.tf index 58bebc7c5..75cad1c1d 100644 --- a/1-org/modules/centralized-logging/main.tf +++ b/1-org/modules/centralized-logging/main.tf @@ -83,7 +83,7 @@ resource "random_string" "suffix" { module "log_export" { source = "terraform-google-modules/log-export/google" - version = "~> 8.0" + version = "~> 10.0" for_each = local.log_exports @@ -98,7 +98,7 @@ module "log_export" { module "log_export_billing" { source = "terraform-google-modules/log-export/google" - version = "~> 8.0" + version = "~> 10.0" for_each = var.enable_billing_account_sink ? local.destination_resource_name : {} @@ -123,7 +123,7 @@ resource "time_sleep" "wait_sa_iam_membership" { module "destination_project" { source = "terraform-google-modules/log-export/google//modules/project" - version = "~> 8.0" + version = "~> 10.0" count = var.project_options != null ? 1 : 0 project_id = var.logging_destination_project_id @@ -151,7 +151,7 @@ resource "google_project_iam_member" "project_sink_member" { module "internal_project_log_export" { source = "terraform-google-modules/log-export/google" - version = "~> 8.0" + version = "~> 10.0" count = var.project_options != null ? 1 : 0 destination_uri = "logging.googleapis.com/projects/${var.logging_destination_project_id}/locations/${var.project_options.location}/buckets/${coalesce(var.project_options.log_bucket_id, "AggregatedLogs")}" @@ -164,7 +164,7 @@ module "internal_project_log_export" { module "destination_aggregated_logs" { source = "terraform-google-modules/log-export/google//modules/logbucket" - version = "~> 8.0" + version = "~> 10.0" count = var.project_options != null ? 1 : 0 project_id = var.logging_destination_project_id @@ -238,7 +238,7 @@ resource "google_project_iam_member" "project_sink_member_billing" { #----------------------# module "destination_storage" { source = "terraform-google-modules/log-export/google//modules/storage" - version = "~> 8.0" + version = "~> 10.0" count = var.storage_options != null ? 1 : 0 @@ -289,7 +289,7 @@ resource "google_storage_bucket_iam_member" "storage_sink_member_billing" { #----------------------# module "destination_pubsub" { source = "terraform-google-modules/log-export/google//modules/pubsub" - version = "~> 8.0" + version = "~> 10.0" count = var.pubsub_options != null ? 1 : 0 diff --git a/1-org/modules/network/main.tf b/1-org/modules/network/main.tf index 15c771d00..d1b22bd52 100644 --- a/1-org/modules/network/main.tf +++ b/1-org/modules/network/main.tf @@ -20,7 +20,7 @@ module "base_shared_vpc_host_project" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -29,6 +29,7 @@ module "base_shared_vpc_host_project" { billing_account = var.billing_account folder_id = var.folder_id disable_services_on_destroy = false + deletion_policy = var.project_deletion_policy activate_apis = [ "compute.googleapis.com", @@ -56,7 +57,7 @@ module "base_shared_vpc_host_project" { module "restricted_shared_vpc_host_project" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -65,6 +66,7 @@ module "restricted_shared_vpc_host_project" { billing_account = var.billing_account folder_id = var.folder_id disable_services_on_destroy = false + deletion_policy = var.project_deletion_policy activate_apis = [ "compute.googleapis.com", diff --git a/1-org/modules/network/variables.tf b/1-org/modules/network/variables.tf index 9de1cfc26..32887bad5 100644 --- a/1-org/modules/network/variables.tf +++ b/1-org/modules/network/variables.tf @@ -45,6 +45,12 @@ variable "env_code" { description = "A short form of the environment to prepare within the Google Cloud organization (ex. d)." } +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + variable "project_budget" { description = < enabled: If the assured workload should be created.
location: The location where the workload will be created.
display\_name: User-assigned resource display name.
compliance\_regime: Supported Compliance Regimes. See https://cloud.google.com/assured-workloads/docs/reference/rest/Shared.Types/ComplianceRegime .
resource\_type: The type of resource. One of CONSUMER\_FOLDER, KEYRING, or ENCRYPTION\_KEYS\_PROJECT. |
object({
enabled = optional(bool, false)
location = optional(string, "us-central1")
display_name = optional(string, "FEDRAMP-MODERATE")
compliance_regime = optional(string, "FEDRAMP_MODERATE")
resource_type = optional(string, "CONSUMER_FOLDER")
})
| `{}` | no | | env | The environment to prepare (ex. development) | `string` | n/a | yes | | environment\_code | A short form of the folder level resources (environment) within the Google Cloud organization (ex. d). | `string` | n/a | yes | +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | project\_budget | Budget configuration for projects.
budget\_amount: The amount to use as the budget.
alert\_spent\_percents: A list of percentages of the budget to alert on when threshold is exceeded.
alert\_pubsub\_topic: The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}`.
alert\_spend\_basis: The type of basis used to determine if spend has passed the threshold. Possible choices are `CURRENT_SPEND` or `FORECASTED_SPEND` (default). |
object({
base_network_budget_amount = optional(number, 1000)
base_network_alert_spent_percents = optional(list(number), [1.2])
base_network_alert_pubsub_topic = optional(string, null)
base_network_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
restricted_network_budget_amount = optional(number, 1000)
restricted_network_alert_spent_percents = optional(list(number), [1.2])
restricted_network_alert_pubsub_topic = optional(string, null)
restricted_network_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
secret_budget_amount = optional(number, 1000)
secret_alert_spent_percents = optional(list(number), [1.2])
secret_alert_pubsub_topic = optional(string, null)
secret_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
kms_budget_amount = optional(number, 1000)
kms_alert_spent_percents = optional(list(number), [1.2])
kms_alert_pubsub_topic = optional(string, null)
kms_budget_alert_spend_basis = optional(string, "FORECASTED_SPEND")
})
| `{}` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | tfc\_org\_name | Name of the TFC organization | `string` | n/a | yes | diff --git a/2-environments/modules/env_baseline/folders.tf b/2-environments/modules/env_baseline/folders.tf index 7e05471ce..61c8f6c64 100644 --- a/2-environments/modules/env_baseline/folders.tf +++ b/2-environments/modules/env_baseline/folders.tf @@ -19,8 +19,9 @@ *****************************************/ resource "google_folder" "env" { - display_name = "${local.folder_prefix}-${var.env}" - parent = local.parent + display_name = "${local.folder_prefix}-${var.env}" + parent = local.parent + deletion_protection = var.folder_deletion_protection } resource "time_sleep" "wait_60_seconds" { diff --git a/2-environments/modules/env_baseline/kms.tf b/2-environments/modules/env_baseline/kms.tf index e6e4d992f..01dc42f26 100644 --- a/2-environments/modules/env_baseline/kms.tf +++ b/2-environments/modules/env_baseline/kms.tf @@ -21,7 +21,7 @@ module "env_kms" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -33,6 +33,7 @@ module "env_kms" { disable_services_on_destroy = false depends_on = [time_sleep.wait_60_seconds] activate_apis = ["logging.googleapis.com", "cloudkms.googleapis.com", "billingbudgets.googleapis.com"] + deletion_policy = var.project_deletion_policy labels = { environment = var.env diff --git a/2-environments/modules/env_baseline/secrets.tf b/2-environments/modules/env_baseline/secrets.tf index fa875c67a..6ff24a4ec 100644 --- a/2-environments/modules/env_baseline/secrets.tf +++ b/2-environments/modules/env_baseline/secrets.tf @@ -21,7 +21,7 @@ module "env_secrets" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -33,6 +33,7 @@ module "env_secrets" { disable_services_on_destroy = false depends_on = [time_sleep.wait_60_seconds] activate_apis = ["logging.googleapis.com", "secretmanager.googleapis.com"] + deletion_policy = var.project_deletion_policy labels = { environment = var.env diff --git a/2-environments/modules/env_baseline/variables.tf b/2-environments/modules/env_baseline/variables.tf index 400479c0e..81ab12a83 100644 --- a/2-environments/modules/env_baseline/variables.tf +++ b/2-environments/modules/env_baseline/variables.tf @@ -81,3 +81,15 @@ variable "assured_workload_configuration" { }) default = {} } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/3-networks-hub-and-spoke/modules/transitivity/main.tf b/3-networks-hub-and-spoke/modules/transitivity/main.tf index 92cafdf2f..f2e0cff90 100644 --- a/3-networks-hub-and-spoke/modules/transitivity/main.tf +++ b/3-networks-hub-and-spoke/modules/transitivity/main.tf @@ -37,7 +37,7 @@ module "service_account" { module "templates" { source = "terraform-google-modules/vm/google//modules/instance_template" - version = "~> 11.0" + version = "~> 12.0" for_each = toset(var.regions) can_ip_forward = true @@ -65,7 +65,7 @@ module "templates" { module "migs" { source = "terraform-google-modules/vm/google//modules/mig" - version = "~> 11.1" + version = "~> 12.1" for_each = toset(var.regions) project_id = var.project_id @@ -91,7 +91,7 @@ module "migs" { module "ilbs" { source = "GoogleCloudPlatform/lb-internal/google" - version = "~> 6.0" + version = "~> 7.0" for_each = toset(var.regions) region = each.key @@ -108,7 +108,10 @@ module "ilbs" { target_tags = null create_backend_firewall = false backends = [ - { group = module.migs[each.key].instance_group, description = "" }, + { + group = module.migs[each.key].instance_group, + description = "" + }, ] health_check = { diff --git a/4-projects/business_unit_1/development/README.md b/4-projects/business_unit_1/development/README.md index e1fa6e324..9d723d711 100644 --- a/4-projects/business_unit_1/development/README.md +++ b/4-projects/business_unit_1/development/README.md @@ -3,11 +3,13 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | gcs\_custom\_placement\_config | Configuration of the bucket's custom location in a dual-region bucket setup. If the bucket is designated a single or multi-region, the variable are null. |
object({
data_locations = list(string)
})
| `null` | no | | instance\_region | Region which the peered subnet will be created (Should be same region as the VM that will be created on step 5-app-infra on the peering project). | `string` | `null` | no | | location\_gcs | Case-Sensitive Location for GCS Bucket (Should be same region as the KMS Keyring) | `string` | `null` | no | | location\_kms | Case-Sensitive Location for KMS Keyring (Should be same region as the GCS Bucket) | `string` | `null` | no | | peering\_module\_depends\_on | List of modules or resources peering module depends on. | `list(any)` | `[]` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | tfc\_org\_name | Name of the TFC organization. | `string` | `""` | no | diff --git a/4-projects/business_unit_1/development/main.tf b/4-projects/business_unit_1/development/main.tf index e03ab8209..e06845839 100644 --- a/4-projects/business_unit_1/development/main.tf +++ b/4-projects/business_unit_1/development/main.tf @@ -35,4 +35,6 @@ module "env" { peering_iap_fw_rules_enabled = true subnet_region = coalesce(var.instance_region, local.default_region) subnet_ip_range = "10.3.64.0/21" + project_deletion_policy = var.project_deletion_policy + folder_deletion_protection = var.folder_deletion_protection } diff --git a/4-projects/business_unit_1/development/variables.tf b/4-projects/business_unit_1/development/variables.tf index 0b055e98f..7add57dfc 100644 --- a/4-projects/business_unit_1/development/variables.tf +++ b/4-projects/business_unit_1/development/variables.tf @@ -56,3 +56,15 @@ variable "instance_region" { type = string default = null } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/4-projects/business_unit_1/nonproduction/README.md b/4-projects/business_unit_1/nonproduction/README.md index e1fa6e324..9d723d711 100644 --- a/4-projects/business_unit_1/nonproduction/README.md +++ b/4-projects/business_unit_1/nonproduction/README.md @@ -3,11 +3,13 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | gcs\_custom\_placement\_config | Configuration of the bucket's custom location in a dual-region bucket setup. If the bucket is designated a single or multi-region, the variable are null. |
object({
data_locations = list(string)
})
| `null` | no | | instance\_region | Region which the peered subnet will be created (Should be same region as the VM that will be created on step 5-app-infra on the peering project). | `string` | `null` | no | | location\_gcs | Case-Sensitive Location for GCS Bucket (Should be same region as the KMS Keyring) | `string` | `null` | no | | location\_kms | Case-Sensitive Location for KMS Keyring (Should be same region as the GCS Bucket) | `string` | `null` | no | | peering\_module\_depends\_on | List of modules or resources peering module depends on. | `list(any)` | `[]` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | tfc\_org\_name | Name of the TFC organization. | `string` | `""` | no | diff --git a/4-projects/business_unit_1/nonproduction/main.tf b/4-projects/business_unit_1/nonproduction/main.tf index b16bd8a4c..2086a4494 100644 --- a/4-projects/business_unit_1/nonproduction/main.tf +++ b/4-projects/business_unit_1/nonproduction/main.tf @@ -35,4 +35,6 @@ module "env" { peering_iap_fw_rules_enabled = true subnet_region = coalesce(var.instance_region, local.default_region) subnet_ip_range = "10.3.128.0/21" + project_deletion_policy = var.project_deletion_policy + folder_deletion_protection = var.folder_deletion_protection } diff --git a/4-projects/business_unit_1/nonproduction/variables.tf b/4-projects/business_unit_1/nonproduction/variables.tf index 0b055e98f..7add57dfc 100644 --- a/4-projects/business_unit_1/nonproduction/variables.tf +++ b/4-projects/business_unit_1/nonproduction/variables.tf @@ -56,3 +56,15 @@ variable "instance_region" { type = string default = null } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/4-projects/business_unit_1/production/README.md b/4-projects/business_unit_1/production/README.md index e1fa6e324..9d723d711 100644 --- a/4-projects/business_unit_1/production/README.md +++ b/4-projects/business_unit_1/production/README.md @@ -3,11 +3,13 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | gcs\_custom\_placement\_config | Configuration of the bucket's custom location in a dual-region bucket setup. If the bucket is designated a single or multi-region, the variable are null. |
object({
data_locations = list(string)
})
| `null` | no | | instance\_region | Region which the peered subnet will be created (Should be same region as the VM that will be created on step 5-app-infra on the peering project). | `string` | `null` | no | | location\_gcs | Case-Sensitive Location for GCS Bucket (Should be same region as the KMS Keyring) | `string` | `null` | no | | location\_kms | Case-Sensitive Location for KMS Keyring (Should be same region as the GCS Bucket) | `string` | `null` | no | | peering\_module\_depends\_on | List of modules or resources peering module depends on. | `list(any)` | `[]` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | tfc\_org\_name | Name of the TFC organization. | `string` | `""` | no | diff --git a/4-projects/business_unit_1/production/main.tf b/4-projects/business_unit_1/production/main.tf index fab79745d..68d2a73ad 100644 --- a/4-projects/business_unit_1/production/main.tf +++ b/4-projects/business_unit_1/production/main.tf @@ -35,4 +35,6 @@ module "env" { peering_iap_fw_rules_enabled = true subnet_region = coalesce(var.instance_region, local.default_region) subnet_ip_range = "10.3.192.0/21" + project_deletion_policy = var.project_deletion_policy + folder_deletion_protection = var.folder_deletion_protection } diff --git a/4-projects/business_unit_1/production/variables.tf b/4-projects/business_unit_1/production/variables.tf index 0b055e98f..7add57dfc 100644 --- a/4-projects/business_unit_1/production/variables.tf +++ b/4-projects/business_unit_1/production/variables.tf @@ -56,3 +56,15 @@ variable "instance_region" { type = string default = null } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/4-projects/business_unit_1/shared/README.md b/4-projects/business_unit_1/shared/README.md index 9515329eb..011c44625 100644 --- a/4-projects/business_unit_1/shared/README.md +++ b/4-projects/business_unit_1/shared/README.md @@ -5,6 +5,7 @@ |------|-------------|------|---------|:--------:| | default\_region | Default region to create resources where applicable. | `string` | `"us-central1"` | no | | project\_budget | Budget configuration.
budget\_amount: The amount to use as the budget.
alert\_spent\_percents: A list of percentages of the budget to alert on when threshold is exceeded.
alert\_pubsub\_topic: The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}`.
alert\_spend\_basis: The type of basis used to determine if spend has passed the threshold. Possible choices are `CURRENT_SPEND` or `FORECASTED_SPEND` (default). |
object({
budget_amount = optional(number, 1000)
alert_spent_percents = optional(list(number), [1.2])
alert_pubsub_topic = optional(string, null)
alert_spend_basis = optional(string, "FORECASTED_SPEND")
})
| `{}` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | tfc\_org\_name | Name of the TFC organization | `string` | `""` | no | diff --git a/4-projects/business_unit_1/shared/example_infra_pipeline.tf b/4-projects/business_unit_1/shared/example_infra_pipeline.tf index 7b09e6cd6..013b80bd4 100644 --- a/4-projects/business_unit_1/shared/example_infra_pipeline.tf +++ b/4-projects/business_unit_1/shared/example_infra_pipeline.tf @@ -28,6 +28,9 @@ module "app_infra_cloudbuild_project" { environment = "common" project_budget = var.project_budget project_prefix = local.project_prefix + + project_deletion_policy = var.project_deletion_policy + activate_apis = [ "cloudbuild.googleapis.com", "sourcerepo.googleapis.com", diff --git a/4-projects/business_unit_1/shared/variables.tf b/4-projects/business_unit_1/shared/variables.tf index 5f08bcddf..b372391ef 100644 --- a/4-projects/business_unit_1/shared/variables.tf +++ b/4-projects/business_unit_1/shared/variables.tf @@ -47,3 +47,9 @@ variable "tfc_org_name" { type = string default = "" } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} diff --git a/4-projects/modules/base_env/README.md b/4-projects/modules/base_env/README.md index 70d08bc55..25653ac3c 100644 --- a/4-projects/modules/base_env/README.md +++ b/4-projects/modules/base_env/README.md @@ -7,6 +7,7 @@ | business\_unit | The business (ex. business\_unit\_1). | `string` | n/a | yes | | env | The environment to prepare (ex. development). | `string` | n/a | yes | | firewall\_enable\_logging | Toggle firewall logging for VPC Firewalls. | `bool` | `true` | no | +| folder\_deletion\_protection | Prevent Terraform from destroying or recreating the folder. | `string` | `true` | no | | folder\_prefix | Name prefix to use for folders created. Should be the same in all steps. | `string` | `"fldr"` | no | | gcs\_bucket\_prefix | Name prefix to be used for GCS Bucket | `string` | `"bkt"` | no | | gcs\_custom\_placement\_config | Configuration of the bucket's custom location in a dual-region bucket setup. If the bucket is designated a single or multi-region, the variable are null. |
object({
data_locations = list(string)
})
| n/a | yes | @@ -20,6 +21,7 @@ | peering\_iap\_fw\_rules\_enabled | Toggle creation of optional IAP firewall rules: SSH, RDP. | `bool` | `false` | no | | peering\_module\_depends\_on | List of modules or resources peering module depends on. | `list(any)` | `[]` | no | | project\_budget | Budget configuration.
budget\_amount: The amount to use as the budget.
alert\_spent\_percents: A list of percentages of the budget to alert on when threshold is exceeded.
alert\_pubsub\_topic: The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}`.
alert\_spend\_basis: The type of basis used to determine if spend has passed the threshold. Possible choices are `CURRENT_SPEND` or `FORECASTED_SPEND` (default). |
object({
budget_amount = optional(number, 1000)
alert_spent_percents = optional(list(number), [1.2])
alert_pubsub_topic = optional(string, null)
alert_spend_basis = optional(string, "FORECASTED_SPEND")
})
| `{}` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | remote\_state\_bucket | Backend bucket to load Terraform Remote State Data from previous steps. | `string` | n/a | yes | | subnet\_ip\_range | IP range for the peered subnetwork. If "peering\_iap\_fw\_rules\_enabled" is true, this field should not be null. | `string` | `null` | no | | subnet\_region | Region which the peered subnet will be created. If "peering\_iap\_fw\_rules\_enabled" is true, this field should not be null. | `string` | `null` | no | diff --git a/4-projects/modules/base_env/business_unit_folder.tf b/4-projects/modules/base_env/business_unit_folder.tf index 68a98ea2f..a379e82d9 100644 --- a/4-projects/modules/base_env/business_unit_folder.tf +++ b/4-projects/modules/base_env/business_unit_folder.tf @@ -19,6 +19,7 @@ locals { } resource "google_folder" "env_business_unit" { - display_name = local.env_business_unit_folder_name - parent = local.env_folder_name + display_name = local.env_business_unit_folder_name + parent = local.env_folder_name + deletion_protection = var.folder_deletion_protection } diff --git a/4-projects/modules/base_env/example_base_shared_vpc_project.tf b/4-projects/modules/base_env/example_base_shared_vpc_project.tf index 2b7c5e7ba..03741b6a2 100644 --- a/4-projects/modules/base_env/example_base_shared_vpc_project.tf +++ b/4-projects/modules/base_env/example_base_shared_vpc_project.tf @@ -29,6 +29,8 @@ module "base_shared_vpc_project" { enable_cloudbuild_deploy = local.enable_cloudbuild_deploy app_infra_pipeline_service_accounts = local.app_infra_pipeline_service_accounts + project_deletion_policy = var.project_deletion_policy + // The roles defined in "sa_roles" will be used to grant the necessary permissions // to deploy the resources, a Compute Engine instance for each environment, defined // in 5-app-infra step (5-app-infra/modules/env_base/main.tf). @@ -47,7 +49,8 @@ module "base_shared_vpc_project" { activate_apis = [ "iam.googleapis.com", - "cloudresourcemanager.googleapis.com" + "cloudresourcemanager.googleapis.com", + "storage.googleapis.com" ] # Metadata @@ -58,5 +61,3 @@ module "base_shared_vpc_project" { secondary_contact = "example2@example.com" business_code = var.business_code } - - diff --git a/4-projects/modules/base_env/example_floating_project.tf b/4-projects/modules/base_env/example_floating_project.tf index d3188c7af..e8bbe7406 100644 --- a/4-projects/modules/base_env/example_floating_project.tf +++ b/4-projects/modules/base_env/example_floating_project.tf @@ -24,6 +24,8 @@ module "floating_project" { project_budget = var.project_budget project_prefix = local.project_prefix + project_deletion_policy = var.project_deletion_policy + # Metadata project_suffix = "sample-floating" application_name = "${var.business_code}-sample-application" diff --git a/4-projects/modules/base_env/example_peering_project.tf b/4-projects/modules/base_env/example_peering_project.tf index e0e387abf..862836007 100644 --- a/4-projects/modules/base_env/example_peering_project.tf +++ b/4-projects/modules/base_env/example_peering_project.tf @@ -40,6 +40,8 @@ module "peering_project" { project_budget = var.project_budget project_prefix = local.project_prefix + project_deletion_policy = var.project_deletion_policy + // Enabling Cloud Build Deploy to use Service Accounts during the build and give permissions to the SA. // The permissions will be the ones necessary for the deployment of the step 5-app-infra enable_cloudbuild_deploy = local.enable_cloudbuild_deploy diff --git a/4-projects/modules/base_env/example_restricted_shared_vpc_project.tf b/4-projects/modules/base_env/example_restricted_shared_vpc_project.tf index 252d4ec70..5244a53b7 100644 --- a/4-projects/modules/base_env/example_restricted_shared_vpc_project.tf +++ b/4-projects/modules/base_env/example_restricted_shared_vpc_project.tf @@ -27,6 +27,7 @@ module "restricted_shared_vpc_project" { project_budget = var.project_budget project_prefix = local.project_prefix + project_deletion_policy = var.project_deletion_policy activate_apis = ["accesscontextmanager.googleapis.com"] vpc_service_control_attach_enabled = local.enforce_vpcsc ? "true" : "false" diff --git a/4-projects/modules/base_env/example_storage_cmek.tf b/4-projects/modules/base_env/example_storage_cmek.tf index 8b40250a7..f9a77c08b 100644 --- a/4-projects/modules/base_env/example_storage_cmek.tf +++ b/4-projects/modules/base_env/example_storage_cmek.tf @@ -20,7 +20,7 @@ data "google_storage_project_service_account" "gcs_account" { module "kms" { source = "terraform-google-modules/kms/google" - version = "~> 2.1" + version = "~> 3.2" project_id = local.kms_project_id keyring = var.keyring_name @@ -44,11 +44,11 @@ resource "random_string" "bucket_name" { module "gcs_buckets" { source = "terraform-google-modules/cloud-storage/google//modules/simple_bucket" - version = "~> 6.0" + version = "~> 8.0" project_id = module.base_shared_vpc_project.project_id location = var.location_gcs - name = "${var.gcs_bucket_prefix}-${module.base_shared_vpc_project.project_id}-${lower(var.location_gcs)}-cmek-encrypted-${random_string.bucket_name.result}" + name = "${var.gcs_bucket_prefix}-${module.base_shared_vpc_project.project_id}-cmek-encrypted-${random_string.bucket_name.result}" bucket_policy_only = true custom_placement_config = var.gcs_custom_placement_config diff --git a/4-projects/modules/base_env/variables.tf b/4-projects/modules/base_env/variables.tf index 384d35d05..a734b678e 100644 --- a/4-projects/modules/base_env/variables.tf +++ b/4-projects/modules/base_env/variables.tf @@ -180,3 +180,15 @@ variable "vpc_service_control_attach_dry_run" { type = bool default = false } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder." + type = string + default = true +} diff --git a/4-projects/modules/infra_pipelines/main.tf b/4-projects/modules/infra_pipelines/main.tf index 036ff505e..123b5514b 100644 --- a/4-projects/modules/infra_pipelines/main.tf +++ b/4-projects/modules/infra_pipelines/main.tf @@ -54,12 +54,14 @@ resource "google_storage_bucket" "cloudbuild_bucket" { } module "tf_workspace" { - source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace" - version = "~> 8.0" + source = "terraform-google-modules/bootstrap/google//modules/tf_cloudbuild_workspace" + version = "~> 9.0" + for_each = toset(var.app_infra_repos) - project_id = var.cloudbuild_project_id - location = var.default_region + project_id = var.cloudbuild_project_id + location = var.default_region + trigger_location = var.default_region # using bucket custom names for compliance with bucket naming conventions create_state_bucket = true @@ -76,6 +78,8 @@ module "tf_workspace" { diff_sa_project = true buckets_force_destroy = true + + substitutions = { "_BILLING_ID" = var.billing_account "_GAR_REGION" = local.gar_region diff --git a/4-projects/modules/single_project/README.md b/4-projects/modules/single_project/README.md index b92f4b388..80758abb9 100644 --- a/4-projects/modules/single_project/README.md +++ b/4-projects/modules/single_project/README.md @@ -15,6 +15,7 @@ | org\_id | The organization id for the associated services | `string` | n/a | yes | | primary\_contact | The primary email contact for the project | `string` | n/a | yes | | project\_budget | Budget configuration.
budget\_amount: The amount to use as the budget.
alert\_spent\_percents: A list of percentages of the budget to alert on when threshold is exceeded.
alert\_pubsub\_topic: The name of the Cloud Pub/Sub topic where budget related messages will be published, in the form of `projects/{project_id}/topics/{topic_id}`.
alert\_spend\_basis: The type of basis used to determine if spend has passed the threshold. Possible choices are `CURRENT_SPEND` or `FORECASTED_SPEND` (default). |
object({
budget_amount = optional(number, 1000)
alert_spent_percents = optional(list(number), [1.2])
alert_pubsub_topic = optional(string, null)
alert_spend_basis = optional(string, "FORECASTED_SPEND")
})
| `{}` | no | +| project\_deletion\_policy | The deletion policy for the project created. | `string` | `"PREVENT"` | no | | project\_prefix | Name prefix to use for projects created. | `string` | `"prj"` | no | | project\_suffix | The name of the GCP project. Max 16 characters with 3 character business unit code. | `string` | n/a | yes | | sa\_roles | A list of roles to give the Service Account from App Infra Pipeline. | `map(list(string))` | `{}` | no | diff --git a/4-projects/modules/single_project/main.tf b/4-projects/modules/single_project/main.tf index 529eb24a9..eda1b55f5 100644 --- a/4-projects/modules/single_project/main.tf +++ b/4-projects/modules/single_project/main.tf @@ -46,7 +46,7 @@ locals { module "project" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" random_project_id = true random_project_id_length = 4 @@ -55,6 +55,7 @@ module "project" { org_id = var.org_id billing_account = var.billing_account folder_id = var.folder_id + deletion_policy = var.project_deletion_policy svpc_host_project_id = var.shared_vpc_host_project_id shared_vpc_subnets = var.shared_vpc_subnets # Optional: To enable subnetting, replace to "module.networking_project.subnetwork_self_link" diff --git a/4-projects/modules/single_project/variables.tf b/4-projects/modules/single_project/variables.tf index 429f6d08f..00d68d1de 100644 --- a/4-projects/modules/single_project/variables.tf +++ b/4-projects/modules/single_project/variables.tf @@ -160,3 +160,9 @@ variable "enable_cloudbuild_deploy" { type = bool default = false } + +variable "project_deletion_policy" { + description = "The deletion policy for the project created." + type = string + default = "PREVENT" +} diff --git a/5-app-infra/business_unit_1/development/versions.tf b/5-app-infra/business_unit_1/development/versions.tf index baa38abbc..bbf8d82ce 100644 --- a/5-app-infra/business_unit_1/development/versions.tf +++ b/5-app-infra/business_unit_1/development/versions.tf @@ -21,12 +21,12 @@ terraform { google = { source = "hashicorp/google" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } google-beta = { source = "hashicorp/google-beta" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } null = { diff --git a/5-app-infra/business_unit_1/nonproduction/versions.tf b/5-app-infra/business_unit_1/nonproduction/versions.tf index baa38abbc..bbf8d82ce 100644 --- a/5-app-infra/business_unit_1/nonproduction/versions.tf +++ b/5-app-infra/business_unit_1/nonproduction/versions.tf @@ -21,12 +21,12 @@ terraform { google = { source = "hashicorp/google" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } google-beta = { source = "hashicorp/google-beta" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } null = { diff --git a/5-app-infra/business_unit_1/production/versions.tf b/5-app-infra/business_unit_1/production/versions.tf index baa38abbc..bbf8d82ce 100644 --- a/5-app-infra/business_unit_1/production/versions.tf +++ b/5-app-infra/business_unit_1/production/versions.tf @@ -21,12 +21,12 @@ terraform { google = { source = "hashicorp/google" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } google-beta = { source = "hashicorp/google-beta" - version = ">= 3.77, < 6" + version = ">= 3.77, < 7" } null = { diff --git a/5-app-infra/modules/env_base/main.tf b/5-app-infra/modules/env_base/main.tf index 6d7821183..078743720 100644 --- a/5-app-infra/modules/env_base/main.tf +++ b/5-app-infra/modules/env_base/main.tf @@ -39,6 +39,7 @@ locals { env_project_id = local.env_project_ids[var.project_suffix] subnetwork_self_link = local.env_project_subnets[var.project_suffix] + subnetwork_project = element(split("/", local.subnetwork_self_link), index(split("/", local.subnetwork_self_link), "projects") + 1, ) resource_manager_tags = local.env_project_resource_manager_tags[var.project_suffix] } @@ -61,7 +62,7 @@ resource "google_service_account" "compute_engine_service_account" { module "instance_template" { source = "terraform-google-modules/vm/google//modules/instance_template" - version = "~> 11.0" + version = "~> 12.0" machine_type = var.machine_type region = var.region @@ -80,10 +81,11 @@ module "instance_template" { module "compute_instance" { source = "terraform-google-modules/vm/google//modules/compute_instance" - version = "~> 11.0" + version = "~> 12.0" region = var.region subnetwork = local.subnetwork_self_link + subnetwork_project = local.subnetwork_project num_instances = var.num_instances hostname = var.hostname instance_template = module.instance_template.self_link diff --git a/helpers/foundation-deployer/README.md b/helpers/foundation-deployer/README.md index dc60a66a4..6c5cc1048 100644 --- a/helpers/foundation-deployer/README.md +++ b/helpers/foundation-deployer/README.md @@ -11,6 +11,7 @@ Helper tool to deploy the Terraform example foundation using Cloud Build and Clo - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) version 2.28.0 or later - [Terraform](https://www.terraform.io/downloads.html) version 1.5.7 or later - See `0-bootstrap` README for additional IAM [requirements](../../0-bootstrap/README.md#prerequisites) on the user deploying the Foundation. +- To enable Security Command Center, choose a Security Command Center tier and create and grant permissions for the Security Command Center service account as described in [Setting up Security Command Center](https://cloud.google.com/security-command-center/docs/quickstart-security-command-center). Your environment need to use the same [Terraform](https://www.terraform.io/downloads.html) version used on the build pipeline. Otherwise, you might experience Terraform state snapshot lock errors. diff --git a/helpers/foundation-deployer/global.tfvars.example b/helpers/foundation-deployer/global.tfvars.example index 0347e625e..b9ab862de 100644 --- a/helpers/foundation-deployer/global.tfvars.example +++ b/helpers/foundation-deployer/global.tfvars.example @@ -27,6 +27,8 @@ foundation_code_path = "FULL_PATH_TO_FOLDER_WHERE_THE_EXAMPLE_FOUNDATION_CODE_WA // See https://cloud.google.com/sdk/gcloud/reference/config/set#EXAMPLES validator_project_id = "EXISTING_PROJECT_ID" +project_deletion_policy = "DELETE" +folder_deletion_protection = false // 0-bootstrap inputs // https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/0-bootstrap/README.md#inputs @@ -142,5 +144,5 @@ target_name_server_addresses = [ // Can be used to override the default region set in 0-bootstrap // See https://github.com/terraform-google-modules/terraform-example-foundation/blob/master/4-projects/business_unit_1/production/README.md#outputs -gcs_location = "US" -kms_location = "us" +location_kms = "us" +location_gcs = "US" diff --git a/helpers/foundation-deployer/stages/apply.go b/helpers/foundation-deployer/stages/apply.go index 90b6a9537..d48083083 100644 --- a/helpers/foundation-deployer/stages/apply.go +++ b/helpers/foundation-deployer/stages/apply.go @@ -45,6 +45,8 @@ func DeployBootstrapStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, c Co BucketTfstateKmsForceDestroy: tfvars.BucketTfstateKmsForceDestroy, Groups: tfvars.Groups, InitialGroupConfig: tfvars.InitialGroupConfig, + FolderDeletionProtection: tfvars.FolderDeletionProtection, + ProjectDeletionPolicy: tfvars.ProjectDeletionPolicy, } err := utils.WriteTfvars(filepath.Join(c.FoundationPath, BootstrapStep, "terraform.tfvars"), bootstrapTfvars) @@ -205,6 +207,8 @@ func DeployOrgStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, outputs Bo LogExportStorageForceDestroy: tfvars.LogExportStorageForceDestroy, LogExportStorageLocation: tfvars.LogExportStorageLocation, BillingExportDatasetLocation: tfvars.BillingExportDatasetLocation, + FolderDeletionProtection: tfvars.FolderDeletionProtection, + ProjectDeletionPolicy: tfvars.ProjectDeletionPolicy, } orgTfvars.GcpGroups = GcpGroups{} if tfvars.HasOptionalGroupsCreation() { @@ -247,7 +251,9 @@ func DeployOrgStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, outputs Bo func DeployEnvStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, outputs BootstrapOutputs, c CommonConf) error { envsTfvars := EnvsTfvars{ - RemoteStateBucket: outputs.RemoteStateBucket, + RemoteStateBucket: outputs.RemoteStateBucket, + FolderDeletionProtection: tfvars.FolderDeletionProtection, + ProjectDeletionPolicy: tfvars.ProjectDeletionPolicy, } err := utils.WriteTfvars(filepath.Join(c.FoundationPath, EnvironmentsStep, "terraform.tfvars"), envsTfvars) if err != nil { @@ -338,8 +344,10 @@ func DeployProjectsStage(t testing.TB, s steps.Steps, tfvars GlobalTFVars, outpu } //for each environment envTfvars := ProjEnvTfvars{ - ProjectsKMSLocation: tfvars.ProjectsKMSLocation, - ProjectsGCSLocation: tfvars.ProjectsGCSLocation, + LocationKMS: tfvars.LocationKMS, + LocationGCS: tfvars.LocationGCS, + FolderDeletionProtection: tfvars.FolderDeletionProtection, + ProjectDeletionPolicy: tfvars.ProjectDeletionPolicy, } for _, envfile := range []string{ "development.auto.tfvars", diff --git a/helpers/foundation-deployer/stages/data.go b/helpers/foundation-deployer/stages/data.go index 6a40fed9f..a3b64687c 100644 --- a/helpers/foundation-deployer/stages/data.go +++ b/helpers/foundation-deployer/stages/data.go @@ -152,13 +152,15 @@ type GlobalTFVars struct { EnableHubAndSpoke bool `hcl:"enable_hub_and_spoke"` EnableHubAndSpokeTransitivity bool `hcl:"enable_hub_and_spoke_transitivity"` CreateUniqueTagKey bool `hcl:"create_unique_tag_key"` - ProjectsKMSLocation string `hcl:"projects_kms_location"` - ProjectsGCSLocation string `hcl:"projects_gcs_location"` + LocationKMS string `hcl:"location_kms"` + LocationGCS string `hcl:"location_gcs"` CodeCheckoutPath string `hcl:"code_checkout_path"` FoundationCodePath string `hcl:"foundation_code_path"` ValidatorProjectId *string `hcl:"validator_project_id"` Groups Groups `hcl:"groups"` InitialGroupConfig *string `hcl:"initial_group_config"` + FolderDeletionProtection bool `hcl:"folder_deletion_protection"` + ProjectDeletionPolicy string `hcl:"project_deletion_policy"` } // HasValidatorProj checks if a Validator Project was provided @@ -205,6 +207,8 @@ type BootstrapTfvars struct { BucketTfstateKmsForceDestroy *bool `hcl:"bucket_tfstate_kms_force_destroy"` Groups Groups `hcl:"groups"` InitialGroupConfig *string `hcl:"initial_group_config"` + FolderDeletionProtection bool `hcl:"folder_deletion_protection"` + ProjectDeletionPolicy string `hcl:"project_deletion_policy"` } type OrgTfvars struct { @@ -220,10 +224,14 @@ type OrgTfvars struct { LogExportStorageLocation string `hcl:"log_export_storage_location"` BillingExportDatasetLocation string `hcl:"billing_export_dataset_location"` GcpGroups GcpGroups `hcl:"gcp_groups"` + FolderDeletionProtection bool `hcl:"folder_deletion_protection"` + ProjectDeletionPolicy string `hcl:"project_deletion_policy"` } type EnvsTfvars struct { - RemoteStateBucket string `hcl:"remote_state_bucket"` + RemoteStateBucket string `hcl:"remote_state_bucket"` + FolderDeletionProtection bool `hcl:"folder_deletion_protection"` + ProjectDeletionPolicy string `hcl:"project_deletion_policy"` } type NetCommonTfvars struct { @@ -250,8 +258,10 @@ type ProjSharedTfvars struct { } type ProjEnvTfvars struct { - ProjectsKMSLocation string `hcl:"projects_kms_location"` - ProjectsGCSLocation string `hcl:"projects_gcs_location"` + LocationKMS string `hcl:"location_kms"` + LocationGCS string `hcl:"location_gcs"` + FolderDeletionProtection bool `hcl:"folder_deletion_protection"` + ProjectDeletionPolicy string `hcl:"project_deletion_policy"` } type AppInfraCommonTfvars struct { diff --git a/test/integration/bootstrap/bootstrap_test.go b/test/integration/bootstrap/bootstrap_test.go index 41e46466b..aef67be44 100644 --- a/test/integration/bootstrap/bootstrap_test.go +++ b/test/integration/bootstrap/bootstrap_test.go @@ -49,6 +49,8 @@ func TestBootstrap(t *testing.T) { vars := map[string]interface{}{ "bucket_force_destroy": true, "bucket_tfstate_kms_force_destroy": true, + "folder_deletion_protection": false, + "project_deletion_policy": "DELETE", } temp := tft.NewTFBlueprintTest(t, diff --git a/test/integration/envs/envs_test.go b/test/integration/envs/envs_test.go index ed06d1786..15de28f31 100644 --- a/test/integration/envs/envs_test.go +++ b/test/integration/envs/envs_test.go @@ -40,7 +40,9 @@ func TestEnvs(t *testing.T) { backend_bucket := bootstrap.GetStringOutput("gcs_bucket_tfstate") vars := map[string]interface{}{ - "remote_state_bucket": backend_bucket, + "remote_state_bucket": backend_bucket, + "folder_deletion_protection": false, + "project_deletion_policy": "DELETE", } backendConfig := map[string]interface{}{ diff --git a/test/integration/org/org_test.go b/test/integration/org/org_test.go index 00c6b7b85..8b4b942cc 100644 --- a/test/integration/org/org_test.go +++ b/test/integration/org/org_test.go @@ -41,6 +41,8 @@ func TestOrg(t *testing.T) { vars := map[string]interface{}{ "remote_state_bucket": backend_bucket, "log_export_storage_force_destroy": "true", + "folder_deletion_protection": false, + "project_deletion_policy": "DELETE", } backendConfig := map[string]interface{}{ diff --git a/test/integration/projects/projects_test.go b/test/integration/projects/projects_test.go index 27cb910be..f630045d5 100644 --- a/test/integration/projects/projects_test.go +++ b/test/integration/projects/projects_test.go @@ -128,7 +128,9 @@ func TestProjects(t *testing.T) { sharedCloudBuildSA := terraform.OutputMap(t, shared.GetTFOptions(), "terraform_service_accounts")[tt.repo] vars := map[string]interface{}{ - "remote_state_bucket": backend_bucket, + "remote_state_bucket": backend_bucket, + "folder_deletion_protection": false, + "project_deletion_policy": "DELETE", } projects := tft.NewTFBlueprintTest(t, diff --git a/test/setup/main.tf b/test/setup/main.tf index 7b85df91d..976fba60b 100644 --- a/test/setup/main.tf +++ b/test/setup/main.tf @@ -40,13 +40,14 @@ resource "random_string" "two_alphanumeric" { } resource "google_folder" "test_folder" { - display_name = "test_foundation_folder_${random_string.suffix.result}" - parent = "folders/${var.folder_id}" + display_name = "test_foundation_folder_${random_string.suffix.result}" + parent = "folders/${var.folder_id}" + deletion_protection = false } module "project" { source = "terraform-google-modules/project-factory/google" - version = "~> 15.0" + version = "~> 17.0" name = "ci-foundation-${random_string.suffix.result}" random_project_id = true @@ -54,6 +55,7 @@ module "project" { org_id = var.org_id folder_id = var.folder_id billing_account = var.billing_account + deletion_policy = "DELETE" activate_apis = [ "cloudresourcemanager.googleapis.com", diff --git a/test/setup/outputs.tf b/test/setup/outputs.tf index bff0125e8..121f8560e 100644 --- a/test/setup/outputs.tf +++ b/test/setup/outputs.tf @@ -109,3 +109,14 @@ output "create_unique_tag_key" { description = "Set to true to avoid tag key name colision during integrated tests. Tag keys are organization-wide unique names." value = true } + +output "project_deletion_policy" { + description = "The deletion policy for the project created. Set to `DELETE` during integrated tests so that projects can be destroyed." + value = "DELETE" +} + +variable "folder_deletion_protection" { + description = "Prevent Terraform from destroying or recreating the folder. Set to `false` during integrated tests so that folders can be destroyed." + type = bool + default = false +}