This Terraform setup will create a new GCP project and arrange the necessary API services. It creates a Virtual Private Cloud (VPC), a default Firestore database, configures firewall rules, and creates required service accounts, such as the Firebase Admin SDK, and sets up the service account's IAM permissions.
We are looking for the community to verify this configuration (even though we have already tested it) and create configurations for other terraform providers (e.g., AWS, Azure, Kubernetes, Oracle Cloud, Alibaba Cloud ) to build a similar setup, enabling cloud-agnostic capabilities.
This Terraform configuration will enable the following GCP services:
Compute Engine APICloud Key Management Service (KMS) APICompute EngineSecret ManagerService AccountsCloud StorageCloud BuildCloud Resource Manager APIService Usage APIIAM APIFirestore API
This configuration uses a GCS backend to store the Terraform state. Before you can use this configuration, you need to create a GCS bucket.
-
Create the GCS bucket:
gsutil mb gs://a-unique-name-gcp-terraform
-
Enable versioning for the bucket:
gsutil versioning set on gs://a-unique-name-gcp-terraform
-
Authenticate with Google Cloud:
gcloud auth application-default login
-
Initialize Terraform:
terraform init
-
Create a
terraform.tfvarsfile with the following content:project_id = "your-gcp-project-id" billing_account = "your-billing-account-id" org_id = "your-organization-id-numbers"Replace the values with your GCP project ID, billing account ID, and organization ID. You can also customize the
network_nameandsubnet_cidrvariables in this file. -
Apply the Terraform configuration:
terraform apply
Terraform will show you a plan of the resources to be created. Type
yesto approve the plan.
Before you can use Cloud Build to deploy the Terraform configuration, you need to create a secret in Google Secret Manager to hold your GitHub Personal Access Token (PAT). This allows Cloud Build to access your repository.
-
Create a GitHub Personal Access Token (PAT):
- Go to https://github.com/settings/tokens and generate a new token.
- The token must have the
reposcope to allow Cloud Build to access your repository.
-
Create the secret in Google Secret Manager:
export GITHUB_TOKEN="your-github-pat" gcloud secrets create github-token-secret-name --data-file=- <<< "$GITHUB_TOKEN"
-
Ensure the Cloud Build service account has the necessary permissions: The service account that runs your Cloud Build trigger will need the
Secret Manager Secret Accessorrole to access thegithub-tokensecret. It will also need the roles listed in the "Cloud Build Deployment" section below.
-
Enable the Cloud Build API for your project.
-
Create a secret in Secret Manager with your GitHub SSH key.
-
Create a service account for Cloud Build with the following roles:
Cloud Build Service AccountCloud Build WorkerPool ownerCloud Build WorkerPool userCloud Deployment Manager Service AgentCloud KMS CryptoKey DecrypterCompute AdminCompute Engine Service AgentCompute Instance Admin (v1)Compute Network AdminIAP-secured Tunnel UserSecret Manager Secret AccessorService Account Token CreatorService Account UserService Usage AdminStorage AdminStorage Bucket ViewerViewerResourcemanager.projectCreator
The service account email should be
svc-terraform-your-gcp-project-id@your-gcp-project-id.iam.gserviceaccount.com. -
Grant the Cloud Build service account the
Secret Manager Secret Accessorrole for the secret. -
Update the
cloudbuild.yamlfile with your project ID in theavailableSecretssection. -
Create a Cloud Build trigger:
- In the Google Cloud Console, go to Cloud Build > Triggers.
- Click Create trigger.
- Name:
ans-terraform-pr - Event:
Pull request - Source: Select your repository and the base branch (e.g.,
main). - Configuration:
Cloud Build configuration file (yaml or json) - Location:
/terraform/cloudbuild.yaml - Click Create.
-
Trigger the build:
- Create a pull request to the base branch.
After the apply is complete, Terraform will output the following:
project_id: The ID of the created GCP project.cloud_run_service_account_email: The email of the Cloud Run service account.network_name: The name of the VPC network.
To destroy the resources created by this Terraform configuration, you can either push to the destroy branch or run the following command:
terraform destroyEnable it by visiting https://console.developers.google.com/apis/api/cloudbilling.googleapis.com/overview?project=... then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
Error: failed pre-requisites: missing permission on "billingAccounts/01466A-729CFD-658D6D": billing.resourceAssociations.create
│
│ with google_project.project,
│ on main.tf line 23, in resource "google_project" "project":
│ 23: resource "google_project" "project" {
BILLING_ACCOUNT_ID="1111-1111-1111"service account is from the cloud build deployment configuration. Step 3
gcloud billing accounts add-iam-policy-binding "${BILLING_ACCOUNT_ID}" \
--member="serviceAccount:<service_account_name>@<gcp_project>.iam.gserviceaccount.com" \
--role="roles/billing.user"Grant the Organization-level IAM role roles/resourcemanager.projectCreator to your service account so it can create new GCP projects. Run once (replace ORG_ID and the service-account e-mail):
gcloud organizations add-iam-policy-binding ORG_ID \
--member="serviceAccount:<service_account_name>@<gcp_project>.iam.gserviceaccount.com" \
--role="roles/resourcemanager.projectCreator"Find your ORG_ID quickly:
gcloud organizations list│ Error: error creating project your-gcp-project-id: googleapi: Error 403: Cloud Resource Manager API has not been used in project before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudresourcemanager.googleapis.com/overview?project=<project_id> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
│ Error: error creating project googleapi: Error 400: field [parent] has issue [Parent id must be numeric.]
│ Details:
│ [
│ {
│ "@type": "type.googleapis.com/google.rpc.BadRequest",
│ "fieldViolations": [
│ {
│ "description": "Parent id must be numeric.",
│ "field": "parent"
│ }
│ ]
│ },
│ {
│ "@type": "type.googleapis.com/google.rpc.Help",
│ "links": [
│ {
│ "url": "https://cloud.google.com/resource-manager/reference/rest/v1/projects"
│ }
│ ]
│ }
Find your numeric org ID
gcloud organizations listOutput
DISPLAY_NAME ID
example.com 123456789Use the numeric ID in your variables or .tfvars:
org_id = "123456789"google_project.project: Creating...
╷
│ Error: error creating project your-gcp-project-id: googleapi: Error 409: Requested entity already exists, alreadyExists.
If you ever created your GCP project manually then you will receive this error. Change the project id in yout .tfvars
project_id = "a-unique-project-id-random-number"Error: Error creating Network: googleapi: Error 403: Compute Engine API has not been used in newly created project before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=<project_id> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
│ Details:
│ [
│ {
│ "@type": "type.googleapis.com/google.rpc.ErrorInfo",
│ "domain": "googleapis.com",
│ "metadata": {
│ "activationUrl": "https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=<project_id>",
│ ...
│ "service": "compute.googleapis.com",
│ "serviceTitle": "Compute Engine API"
│ },
│ "reason": "SERVICE_DISABLED"
│ },
│ {
│ "@type": "type.googleapis.com/google.rpc.LocalizedMessage",
│ "locale": "en-US",
│ "message": "Compute Engine API has not been used in project <peoject_id> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=<peoject_id> then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry."
│ },
│ {
│ "@type": "type.googleapis.com/google.rpc.Help",
│ "links": [
│ {
│ "description": "Google developers console API activation",
│ "url": "https://console.developers.google.com/apis/api/compute.googleapis.com/overview?project=<project_id>"
│ }
│ ]
│ }
│ ]
add a dependency to the resource in your main.tf
depends_on = [google_project_service.project_services]Create a branch called "destroy" and raise a PR.
Minimal checklist: google_project.project
deletion_policy = "DELETE"Firestore database
deletion_policy = "DELETE"
delete_protection_state = "DELETE_PROTECTION_DISABLED"Any Cloud Storage buckets
force_destroy = trueso objects are wiped on destroy.
Any other resources that have prevent_destroy or deletion_protection Remove or disable those flags.
Service-account keys (if you generated any) Terraform will delete the keys automatically when the SA is destroyed.
IAM / billing permissions
Ensure the Terraform service account still has
roles/resourcemanager.projectCreator
roles/billing.user (or billing.admin)
roles/compute.admin (or the specific roles)
so it can both create and destroy.