Skip to content

Create a GCP project with org/gcp/project-factory

Purpose: Create (or converge) a GCP project using the Terraform Google Project Factory module via HyOps. Owner: Platform operations Trigger: First-time GCP bootstrap for an environment; new project required. Impact: Creates cloud resources and links billing; may incur cost. Severity: P2 Pre-reqs: hyops init gcp completed for the environment; gcloud installed and authenticated (ADC); Terraform Cloud token available (recommended: run hyops init terraform-cloud --env <env>), unless you run with local state (HYOPS_TERRAFORM_BACKEND_MODE=local). Rollback strategy: Use hyops destroy only if you intentionally want to delete the project. Note: the upstream module defaults deletion_policy=PREVENT, so destroy will fail unless you first apply with deletion_policy: "DELETE" (see Destroy / purge).


Context

This runbook covers the project creation step. It assumes you have already initialised GCP credentials with:

  • Runbook: RB-026-hyops-init-gcp.md

org/gcp/project-factory runs via:

  • Driver: iac/terragrunt
  • Profile: gcp@v1.0
  • Pack: gcp/org/00-project-factory@v1.0

After apply, re-run hyops init gcp --force so HyOps can auto-derive the Terraform impersonation target (service account email) from module state and validate it.

In the preferred GCP operating model, this project is the env-scoped control project by default. That makes it the clean place for:

  • GCP Secret Manager
  • env-scoped backup bucket modules
  • other env-scoped control services

It does not need to be the same project that owns the Shared VPC, Cloud NAT, or runner VM placement.


State backend (cloud vs local)

By default, the gcp@v1.0 Terragrunt profile uses HCP Terraform (Terraform Cloud) backend for state (cloud state, local execution).

  • Default: HYOPS_TERRAFORM_BACKEND_MODE=cloud
  • Local state (for offline/dev): HYOPS_TERRAFORM_BACKEND_MODE=local (writes tfstate under <root>/state/terraform/)

Example:

# recommended for cloud provider stacks
export HYOPS_TERRAFORM_BACKEND_MODE=cloud

# or: local state backend
export HYOPS_TERRAFORM_BACKEND_MODE=local

Preconditions and safety checks

  • Ensure you are targeting the correct environment:

    echo "HYOPS_ENV=$HYOPS_ENV"
    

  • Confirm you have a billing account:

    gcloud beta billing accounts list
    

  • (Optional) Check if you have an Organization:

    gcloud organizations list
    
    Notes:

  • Personal/trial accounts often show Listed 0 items. This is OK. In that case, omit org_id and folder_id in inputs.

Inputs

Create a local inputs file (do not commit it to a public repo if it contains real billing/org identifiers).

Minimal example (trial/personal accounts, no Organization)

project_id: hybridops-pf-dev
region: europe-west2
billing_account_id: "01B1FD-FAC417-423408"
activate_apis:
  - cloudresourcemanager.googleapis.com
  - iam.googleapis.com
  - secretmanager.googleapis.com
labels:
  owner: hybridops
  env: dev

Enterprise example (Organization or Folder)

name_prefix: platform
context_id: dev
project_id: hybridops-pf-dev
region: europe-west2
billing_account_id: "01B1FD-FAC417-423408"
org_id: "123456789012"      # OR folder_id: "123456789012"
activate_apis:
  - cloudresourcemanager.googleapis.com
  - iam.googleapis.com
  - secretmanager.googleapis.com
labels:
  owner: hybridops
  env: dev

Notes: - HyOps accepts billing_account_id (legacy alias) and will map it to the upstream input billing_account. - org_id / folder_id are optional (recommended for enterprise governance). - secretmanager.googleapis.com should be enabled by default if you plan to use GCP Secret Manager as the external secret authority for runner-driven DR.


Steps

1) Preflight

INPUTS=/tmp/hyops-gcp-project-factory.dev.yml
hyops preflight --env dev --strict --module org/gcp/project-factory --inputs "$INPUTS"

2) Apply

hyops apply --env dev --module org/gcp/project-factory --inputs "$INPUTS"

3) Re-run GCP init to validate impersonation

hyops init gcp --env dev --force

4) Destroy / purge (optional)

By default, the upstream Project Factory module sets deletion_policy=PREVENT. That is a safe default, but it means hyops destroy cannot delete the project.

To intentionally delete the project:

# 1) converge deletion_policy into state
#    (edit your inputs file and add: deletion_policy: "DELETE")
hyops apply --env dev --module org/gcp/project-factory --inputs "$INPUTS"

# 2) destroy using the same inputs
hyops destroy --env dev --module org/gcp/project-factory --inputs "$INPUTS"

Notes: - GCP project deletion is asynchronous. A deleted project ID may remain reserved for a period of time, so immediate re-create with the same project_id can fail with 409 alreadyExists. - For iterative testing, prefer a new project_id per run (for example hybridops-pf-dev2).


Verification

  • Confirm module state exists:

    ls -la ~/.hybridops/envs/dev/state/modules/org__gcp__project-factory/latest.json
    

  • Confirm GCP readiness marker includes impersonation_validated=true:

    cat ~/.hybridops/envs/dev/meta/gcp.ready.json
    


Troubleshooting

  • If apply fails with permission errors:
  • Use an existing project and skip project-factory, or
  • Ask an admin to create the project / grant permissions (project create + billing link).

  • If you have no Organization (gcloud organizations list is empty):

  • Omit org_id/folder_id and proceed only if your account can create projects under “No organization”.

Maintainer: HybridOps.Studio License: MIT-0 for code, CC-BY-4.0 for documentation