Skip to content

Repository files navigation

terraform-google-project

CI Terraform Registry

Terraform module that provisions one or more Google Cloud projects from a single map(object) input. For each entry it:

  • creates the project with a generated project ID (<name>-<random suffix>),
  • enables the requested APIs,
  • applies your labels, always merging managed = "terraform".

⚠️ Breaking change in v2.0.0 — API resource addresses changed

Prior versions keyed the google_project_service resources with a positional index ("<project>-<api>-<index>"). Because the index was derived from the flattened project/API list, adding or removing any project or API shifted the index of every subsequent entry, causing Terraform to destroy and recreate unrelated google_project_service resources — and, with disable_on_destroy = true, to disable and re-enable those APIs on live projects.

v2.0.0 drops the index: keys are now "<project>-<api>", which is stable and unique. Duplicate entries in an apis list are now deduplicated.

Migrating from v1.x

The key change means existing state entries no longer match the new resource addresses. Do not apply the upgrade blindly — an unmigrated plan will propose destroying and recreating every enabled API. Instead, move the state entries first:

# After bumping the module version, before plan/apply.
# Strips the trailing "-<index>" from every google_project_service key.
terraform state list | grep 'google_project_service\.main\[' | while read -r addr; do
  new=$(echo "$addr" | sed -E 's/-[0-9]+"\]$/"]/')
  terraform state mv "$addr" "$new"
done

A subsequent terraform plan should show no changes for google_project_service resources. (moved blocks cannot express this migration because the addresses are dynamic for_each keys.)

Usage

module "project" {
  source  = "FFerrinho/project/google"
  version = "~> 2.0"

  projects = {
    "my-project" = {
      org_id          = "1234567890"
      billing_account = "ABCD-EFGH-IJKL-MNOP"
      deletion_policy = "DELETE"
      apis = [
        "compute.googleapis.com",
        "container.googleapis.com",
      ]
      labels = {
        environment = "development"
      }
    }
  }
}

See examples/ for a minimal (simple) and a multi-project (full) configuration.

Behaviour notes

  • Project ID generation: the project ID is <map key>-<random decimal suffix>. One random_id (2 bytes) is shared by all projects in the map, so all generated IDs carry the same suffix. Keep map keys ≤ 24 characters so the resulting ID stays within GCP's 30-character limit.
  • Parenting: set org_id or folder_id per project to choose where it lives.
  • API management: enabled services use disable_dependent_services = true and disable_on_destroy = true — removing an API from the list (or destroying the project resource) actively disables that API. Treat API removals as deliberate, reviewed changes.
  • Labels: managed = "terraform" is always merged into the labels you provide.

Testing

The module ships a native terraform test suite in tests/ that runs entirely against mocked providers — no GCP credentials or real infrastructure required:

terraform init -backend=false
terraform test

CI runs fmt, validate, the test suite, and example validation on every push and pull request. See CONTRIBUTING.md for the full development workflow and CHANGELOG.md for release history.

Requirements

Name Version
terraform >= 1.5
google ~> 6
random ~> 3

Providers

Name Version
google 6.50.0
random 3.9.0

Modules

No modules.

Resources

Name Type
google_project.main resource
google_project_service.main resource
random_id.random resource

Inputs

Name Description Type Default Required
projects A map of projects to create, keyed by project name. Per project: org_id or folder_id (parent), billing_account, deletion_policy (PREVENT, ABANDON or DELETE), labels, auto_create_network, and apis (list of service endpoints to enable).
map(object({
project_id = optional(string)
org_id = optional(string)
folder_id = optional(string)
billing_account = optional(string)
deletion_policy = optional(string)
labels = optional(map(string))
auto_create_network = optional(bool)
apis = optional(list(string))
}))
n/a yes

Outputs

Name Description
project_info Map of created projects, keyed by project name, with the generated project ID, display name and project number.

About

This Terraform module creates and manages Google Cloud Platform (GCP) projects. It supports configuring project settings, enabling APIs, and managing labels. The module also includes options for auto-creating networks and handling project deletion policies.

Topics

Resources

Contributing

Stars

0 stars

Watchers

1 watching

Forks

Contributors

Languages