{"id":13574635,"url":"https://github.com/mharrvic/backstage-cloudrun-terraform","last_synced_at":"2026-02-19T02:02:15.284Z","repository":{"id":124061532,"uuid":"576551006","full_name":"mharrvic/backstage-cloudrun-terraform","owner":"mharrvic","description":"Backstage deploy with Cloud Run via Terraform","archived":false,"fork":false,"pushed_at":"2022-12-27T11:04:02.000Z","size":451,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-12T13:07:52.725Z","etag":null,"topics":["backstage","cloudrun","terraform"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mharrvic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-12-10T07:37:43.000Z","updated_at":"2024-01-14T14:23:00.000Z","dependencies_parsed_at":"2023-07-07T04:46:51.375Z","dependency_job_id":null,"html_url":"https://github.com/mharrvic/backstage-cloudrun-terraform","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mharrvic/backstage-cloudrun-terraform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mharrvic%2Fbackstage-cloudrun-terraform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mharrvic%2Fbackstage-cloudrun-terraform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mharrvic%2Fbackstage-cloudrun-terraform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mharrvic%2Fbackstage-cloudrun-terraform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mharrvic","download_url":"https://codeload.github.com/mharrvic/backstage-cloudrun-terraform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mharrvic%2Fbackstage-cloudrun-terraform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29600845,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T00:59:38.239Z","status":"online","status_checked_at":"2026-02-19T02:00:07.702Z","response_time":117,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backstage","cloudrun","terraform"],"created_at":"2024-08-01T15:00:53.217Z","updated_at":"2026-02-19T02:02:15.246Z","avatar_url":"https://github.com/mharrvic.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# [Terraform with CloudRun backstage](https://www.mharrvic.com/notes/backstage-deploy-with-cloudrun-via-terraform)\n\n## Requirements\n\n- Terraform CLI - [https://developer.hashicorp.com/terraform/cli/commands](https://developer.hashicorp.com/terraform/cli/commands)\n  - If you are using M1 mac and having a trouble setting up, you can follow this GIST [https://gist.github.com/mharrvic/12b46934c608b0e21d6dd3e9fdeb1669](https://gist.github.com/mharrvic/12b46934c608b0e21d6dd3e9fdeb1669)\n- GCLOUD CLI - [https://cloud.google.com/sdk/gcloud](https://cloud.google.com/sdk/gcloud)\n\n## Get Started\n\nSetup backstage app to your local machine [https://backstage.io/docs/getting-started/create-an-app](https://backstage.io/docs/getting-started/create-an-app)\n\n1. Set Variables (for a more readable command), paste this to your terminal\n\n   ```bash\n   export PROJECT_ID=your-gcp-project-id\n   export REGION=us-west1\n   export REPO_NAME=backstage\n   ```\n\n2. Enable GCloud API Services\n\n   ```bash\n   gcloud services enable \\\n   \tartifactregistry.googleapis.com/ \\\n   \trun.googleapis.com/ \\\n   \tcompute.googleapis.com/ \\\n   \tvpcaccess.googleapis.com/ \\\n   \tservicenetworking.googleapis.com/ \\\n   \tsecretmanager.googleapis.com/ \\\n   \tsqladmin.googleapis.com/ \\\n   \tcloudbuild.googleapis.com/\n   ```\n\n3. Create artifact registry (to store the backstage docker image)\n\n   ```bash\n   gcloud artifacts repositories create ${REPO_NAME} --repository-format=docker \\\n   --location=${REGION} --description=\"Docker image for backstage\"\n   ```\n\n4. Create a secret value for environment variables\n\n   ```bash\n   gcloud secrets create POSTGRES_PASSWORD \\\n       --replication-policy=\"automatic\"\n   echo -n \"your-db-password-here\" | \\\n       gcloud secrets versions add POSTGRES_PASSWORD --data-file=-\n   ```\n\n5. Authenticate Docker config\n\n   ```bash\n   gcloud auth configure-docker ${REGION}-docker.pkg.dev\n   ```\n\n6. Build and Push the docker image to the artifact registry (locally)\n\n   ```bash\n   # From root folder\n\n   # Build the backstage application first\n   yarn build:all\n\n   # Build the docker image and tag it to the artifact repository\n   docker build . -f packages/backend/Dockerfile --tag ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${REPO_NAME}:dev\n\n   #  Push the docker image\n   docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${REPO_NAME}:dev\n   ```\n\n7. Optional: Docker build and push using cloudbuild. Make sure to do `yarn build:all` first\n\n   ```bash\n   # Create a new file: cloudbuild.yaml and paste this:\n\n   steps:\n     # Docker Build\n     - name: 'gcr.io/cloud-builders/docker'\n       args: ['pull', 'docker/dockerfile:experimental']\n     - name: 'gcr.io/cloud-builders/docker'\n       args:\n         [\n           'build',\n           '.',\n           '-f',\n           'packages/backend/Dockerfile',\n           '-t',\n           'us-west1-docker.pkg.dev/your-project-id/your-repository/your-repository:dev',\n         ]\n       env:\n         - 'DOCKER_BUILDKIT=1'\n\n       # Docker Push\n     - name: 'gcr.io/cloud-builders/docker'\n       args:\n         [\n           'push',\n           'us-west1-docker.pkg.dev/your-project-id/your-repository/your-repository:dev',\n         ]\n\n   # Sumbit the config using gcloud cli:\n   gcloud builds submit --config cloudbuild.yaml\n   ```\n\n   I preferred this one since it does the build and push directly from google cloud, with lesser bandwidth usage when used locally. Win-win if you have a slow internet connection or your docker is fucking you up haha.\n\n## Terraform\n\nNow that we already have an artifact registry repository with backstage image, we can now start working with Infrastructure as Code with Terraform.\n\nLet’s create a `deployment` folder to our root directory, and create `environments/dev` and `modules` folder.\n\nUnder `environments/dev`, create `terraform.tfvars` file to store our local variables and add these:\n\n```bash\nproject                      = \"your-gcp-project-id\"\nregion                       = \"us-west1\"\nzone                         = \"us-west1-a\"\nartifact_registry_url        = \"us-west1-docker.pkg.dev\"\nartifact_registry_repository = \"backstage\"\n```\n\nCreate `variables.tf` file for our input variables to be passed to our module\n\n```bash\nvariable \"project\" {\n  type        = string\n  description = \"The project ID to deploy to\"\n}\n\nvariable \"region\" {\n  type        = string\n  description = \"The region to deploy to\"\n}\n\nvariable \"zone\" {\n  type        = string\n  description = \"The zone to deploy to\"\n}\n\nvariable \"artifact_registry_url\" {\n  type        = string\n  description = \"The URL of the Artifact Registry repository\"\n}\n\nvariable \"artifact_registry_repository\" {\n  type        = string\n  description = \"The name of the Artifact Registry repository\"\n}\n```\n\nCreate `main.tf` file to describe our main infrastructure\n\n```bash\nprovider \"google\" {\n  project = var.project\n}\n\n# Modules will be here\n```\n\nThe current folder tree should look something like this:\n\n```bash\n├── environments\n│   └── dev\n│       ├── main.tf\n│       ├── terraform.tfvars\n│       └── variables.tf\n└── modules\n```\n\n### VPC Module\n\nWe will use [VPC](https://cloud.google.com/vpc) to secure our resources and data, and isolate our network from the public internet.\n\nCreate `vpc` folder under `modules` directory and create three files: `main.tf` `outputs.tf` `variables.tf`\n\n```bash\n└── modules\n    └── vpc\n        ├── main.tf\n        ├── outputs.tf\n        └── variables.tf\n```\n\nOpen the `variables.tf` and add these(feel free to update some of the IP ranges):\n\n```bash\nvariable \"region\" {\n  type        = string\n  description = \"The region to deploy to\"\n}\n\nvariable \"project_id\" {\n  type        = string\n  description = \"The project ID to deploy to\"\n}\n\nvariable \"subnet_ip\" {\n  type        = string\n  description = \"The IP and CIDR range of the subnet being created\"\n  default     = \"10.0.0.0/16\"\n}\n\nvariable \"serverless_vpc_ip_cidr_range\" {\n  type        = string\n  description = \"Serverless VPC Connector IP CIDR range\"\n  default     = \"10.8.0.0/28\"\n}\n\nvariable \"network_name\" {\n  type        = string\n  description = \"Network name\"\n  default     = \"backstage-main\"\n}\n```\n\nOpen the `[main.tf](http://main.tf)` let’s leverage the vpc module from google\n\n```bash\nmodule \"vpc_network\" {\n  source  = \"terraform-google-modules/network/google\"\n  version = \"~\u003e 6.0\"\n\n  network_name = var.network_name\n  project_id   = var.project_id\n\n  subnets = [\n      {\n        subnet_name           = \"${module.vpc_network.network_name}-subnetwork\"\n        subnet_ip             = var.subnet_ip\n        subnet_region         = var.region\n        subnet_private_access = \"true\"\n        subnet_flow_logs      = \"false\"\n      }\n    ]\n}\n```\n\nLet’s add a GCE global address resource. This resource represents a static IP address that can be used to communicate with resources with our VPC network.\n\n```bash\nresource \"google_compute_global_address\" \"backstage_private_ip_address\" {\n  provider = google-beta\n\n  project       = var.project_id\n  name          = \"backstage-private-ip-address\"\n  purpose       = \"VPC_PEERING\"\n  address_type  = \"INTERNAL\"\n  prefix_length = 16\n  network       = \"projects/${var.project_id}/global/networks/${module.vpc_network.network_name}\"\n}\n```\n\nLet’s add a Google Service Networking connection resource. This connection will allow resources in our VPC network to communicate with the service using the reserved peering ranges.\n\n```bash\nresource \"google_service_networking_connection\" \"backstage_private_vpc_connection\" {\n  provider = google-beta\n\n  network                 = \"projects/${var.project_id}/global/networks/${module.vpc_network.network_name}\"\n  service                 = \"servicenetworking.googleapis.com\"\n  reserved_peering_ranges = [google_compute_global_address.backstage_private_ip_address.name]\n}\n```\n\nLet's add a Serverless VPC Connector. This resource creates a connection between our VPC network and Google's Cloud Run(serverless) service, for our use case.\n\n```bash\nresource \"google_vpc_access_connector\" \"connector\" {\n  name          = \"backstage-connector\"\n  project       = var.project_id\n  region        = var.region\n  ip_cidr_range = var.serverless_vpc_ip_cidr_range\n  network       = module.vpc_network.network_name\n}\n```\n\nOur `main.tf` should look something like this:\n\n```bash\nmodule \"vpc_network\" {\n  source  = \"terraform-google-modules/network/google\"\n  version = \"~\u003e 6.0\"\n\n  network_name = var.network_name\n  project_id   = var.project_id\n\n  subnets = [\n      {\n        subnet_name           = \"${module.vpc_network.network_name}-subnetwork\"\n        subnet_ip             = var.subnet_ip\n        subnet_region         = var.region\n        subnet_private_access = \"true\"\n        subnet_flow_logs      = \"false\"\n      }\n    ]\n}\n\nresource \"google_compute_global_address\" \"backstage_private_ip_address\" {\n  provider = google-beta\n\n  project       = var.project_id\n  name          = \"backstage-private-ip-address\"\n  purpose       = \"VPC_PEERING\"\n  address_type  = \"INTERNAL\"\n  prefix_length = 16\n  network       = \"projects/${var.project_id}/global/networks/${module.vpc_network.network_name}\"\n}\n\nresource \"google_service_networking_connection\" \"backstage_private_vpc_connection\" {\n  provider = google-beta\n\n  network                 = \"projects/${var.project_id}/global/networks/${module.vpc_network.network_name}\"\n  service                 = \"servicenetworking.googleapis.com\"\n  reserved_peering_ranges = [google_compute_global_address.backstage_private_ip_address.name]\n}\n\nresource \"google_vpc_access_connector\" \"connector\" {\n  name          = \"backstage-connector\"\n  project       = var.project_id\n  region        = var.region\n  ip_cidr_range = var.serverless_vpc_ip_cidr_range\n  network       = module.vpc_network.network_name\n}\n```\n\nFinally, let's create an `outputs.tf` file to make our infrastructure configuration available to other Terraform configurations.\n\n```bash\noutput \"vpc_network\" {\n  value       = module.vpc_network\n  description = \"Backstage VPC Network\"\n}\n\noutput \"backstage_serverless_vpc_connector_name\" {\n  value       = google_vpc_access_connector.connector.name\n  description = \"Backstage Serverless VPC Connector\"\n}\n\noutput \"backstage_private_vpc_connection\" {\n  value       = google_service_networking_connection.backstage_private_vpc_connection\n  description = \"Backstage Private VPC Connection\"\n}\n```\n\n### CloudSQL Module\n\nWe will be using Cloud SQL postgres for our database\n\nCreate `cloudsql` folder under `modules` directory and create three files: `main.tf` `outputs.tf` `variables.tf`\n\n```bash\n└── modules\n    └── cloudsql\n        ├── main.tf\n        ├── outputs.tf\n        └── variables.tf\n```\n\nOpen the `variables.tf` and add these:\n\n```bash\nvariable \"project_id\" {\n  type        = string\n  description = \"GCP Project for Backstage\"\n}\n\nvariable \"region\" {\n  type = string\n}\n\nvariable \"network_id\" {\n  type = string\n}\n\nvariable \"deletion_protection\" {\n  type        = bool\n  description = \"Sets delete_protection of the Instance\"\n  default     = false\n}\n\nvariable \"user_password\" {\n  type        = string\n  description = \"The password for the default user. If not set, a random one will be generated and available in the generated_user_password output variable.\"\n}\n```\n\nOpen the `main.tf` and add this Postgres resource with a private network connected to our VPC:\n\n```bash\nresource \"google_sql_database_instance\" \"backstage\" {\n  provider         = google-beta\n  project          = var.project_id\n  name             = \"backstage-db\"\n  database_version = \"POSTGRES_14\"\n  region           = var.region\n\n  settings {\n    tier = \"db-g1-small\"\n    ip_configuration {\n      ipv4_enabled    = false\n      private_network = var.network_id\n      require_ssl     = true\n    }\n  }\n\n  deletion_protection = var.deletion_protection\n}\n```\n\nCreate a database and database user and password\n\n```bash\nresource \"random_id\" \"user-password\" {\n  byte_length = 8\n}\n\nresource \"google_sql_database\" \"backstage_db\" {\n  project  = var.project_id\n  name     = google_sql_database_instance.backstage.name\n  instance = google_sql_database_instance.backstage.name\n}\n\nresource \"google_sql_user\" \"backstage_user\" {\n  name     = \"postgres\"\n  instance = google_sql_database_instance.backstage.name\n  password = var.user_password == \"\" ? random_id.user-password.hex : var.user_password\n}\n```\n\nFinally, let's create an `outputs.tf` file to make our infrastructure configuration available to other Terraform configurations.\n\n```bash\noutput \"sql_instance_name\" {\n  value       = google_sql_database_instance.backstage.name\n  description = \"Backstage sql instance name\"\n}\n\noutput \"sql_instance_connection_name\" {\n  value       = google_sql_database_instance.backstage.connection_name\n  description = \"Backstage sql instance connection name\"\n}\n\noutput \"generated_user_password\" {\n  description = \"The auto generated default user password if no input password was provided\"\n  value       = random_id.user-password.hex\n  sensitive   = true\n}\n```\n\n### Secrets Module\n\nWe will securely store the postgres password with Secrets Manager\n\nCreate `secrets` folder under `modules` directory and create three files: `main.tf` `variables.tf`\n\n```bash\n└── modules\n    └── secrets\n        ├── main.tf\n        └── variables.tf\n```\n\nOpen the `variables.tf` and add the postgres_password variable\n\n```bash\nvariable \"postgres_password\" {\n  type        = string\n  description = \"Cloud SQL Postgres password\"\n}\n```\n\nOpen the `main.tf` and add the secrets manager resource with the password generated from cloud SQL module\n\n```bash\nresource \"google_secret_manager_secret\" \"postgres_password\" {\n  secret_id = \"postgres-password\"\n\n  labels = {\n    label = \"postgres-password\"\n  }\n\n  replication {\n    automatic = true\n  }\n}\n\nresource \"google_secret_manager_secret_version\" \"postgres_password\" {\n  secret = google_secret_manager_secret.postgres_password.id\n\n  secret_data = var.postgres_password\n}\n```\n\n### IAM Module\n\nWe will create a service account for Cloud Run\n\nCreate `iam` folder under `modules` directory and create three files: `main.tf` `outputs.tf` `variables.tf`\n\n```bash\n└── modules\n    └── iam\n        ├── main.tf\n\t\t\t\t├── outputs.tf\n        └── variables.tf\n```\n\nOpen the `variables.tf` and add the project_id variable\n\n```bash\nvariable \"project_id\" {\n  type        = string\n  description = \"The project id for the Backstage\"\n}\n```\n\nOpen the `main.tf` and add these service account resource together with each role\n\n```bash\nresource \"google_service_account\" \"backstage\" {\n  project      = var.project_id\n  account_id   = \"backstage\"\n  display_name = \"Backstage\"\n}\n\nresource \"google_project_iam_member\" \"backstage\" {\n  project = var.project_id\n  for_each = toset([\n    \"roles/cloudsql.admin\",\n    \"roles/run.admin\",\n    \"roles/serviceusage.serviceUsageAdmin\",\n    \"roles/iam.serviceAccountUser\",\n    \"roles/secretmanager.secretAccessor\",\n  ])\n  role   = each.key\n  member = \"serviceAccount:${google_service_account.backstage.email}\"\n}\n```\n\nOpen the `outputs.tf` and add expose the service account email and id\n\n```bash\noutput \"backstage_service_account_email\" {\n  value       = google_service_account.backstage.email\n  description = \"Backstage service account email\"\n}\n\noutput \"backstage_service_account_id\" {\n  value       = google_service_account.backstage.id\n  description = \"Backstage service account id\"\n}\n```\n\n### CloudRun Module\n\nWe will create a Cloud Run resource that is publicly available.\n\nCreate `cloudrun` folder under `modules` directory and create three files: `main.tf` `variables.tf`\n\n```bash\n└── modules\n    └── cloudrun\n        ├── main.tf\n        └── variables.tf\n```\n\nOpen the `variables.tf` and add the incoming variables\n\n```bash\nvariable \"project_id\" {\n  type        = string\n  description = \"GCP Project for Backstage\"\n}\n\nvariable \"region\" {\n  type = string\n}\n\nvariable \"vpc_connector_name\" {\n  type        = string\n  description = \"Serverless VPC Connector\"\n}\n\nvariable \"cloudsql_instance_name\" {\n  type        = string\n  description = \"Cloud SQL Instance Name\"\n}\n\nvariable \"cloudsql_instance_connection_name\" {\n  type        = string\n  description = \"Cloud SQL Instance Connection Name\"\n}\n\nvariable \"artifact_registry_url\" {\n  type        = string\n  description = \"Artifact Registry URL\"\n}\n\nvariable \"artifact_repo\" {\n  type        = string\n  description = \"Artifact Registry Repo\"\n}\n\nvariable \"service_account_email\" {\n  type        = string\n  description = \"Service Account Email\"\n\n}\n```\n\nOpen `main.tf` and add the Cloud Run resource, together with the previously pushed Backstage image artifact. Our Cloud Run service is connected to Cloud SQL in a private connection. We can connect to our own VPC network, thanks to the Serverless VPC Connector. We are also securely connected to our Cloud SQL instance with Cloud SQL Proxy, without setting up an SSL certificate.\n\n```bash\nresource \"google_cloud_run_service\" \"backstage\" {\n  provider = google-beta\n\n  name     = \"backstage\"\n  location = var.region\n  project  = var.project_id\n\n  template {\n    spec {\n      containers {\n        image = \"${var.artifact_registry_url}/${var.project_id}/${var.artifact_repo}/${var.artifact_repo}:dev\"\n        env {\n          name  = \"BACKSTAGE_BASE_URL\"\n          value = \"\"\n        }\n        env {\n          name  = \"POSTGRES_HOST\"\n          value = \"/cloudsql/${var.cloudsql_instance_connection_name}\"\n        }\n        env {\n          name  = \"POSTGRES_USER\"\n          value = \"postgres\"\n        }\n        env {\n          name  = \"POSTGRES_PORT\"\n          value = \"5432\"\n        }\n        env {\n          name = \"POSTGRES_PASSWORD\"\n          value_from {\n            secret_key_ref {\n              name = \"postgres-password\"\n              key  = \"latest\"\n            }\n          }\n        }\n      }\n\n      service_account_name = var.service_account_email\n    }\n\n    metadata {\n      annotations = {\n        \"run.googleapis.com/cloudsql-instances\"   = var.cloudsql_instance_connection_name\n        \"run.googleapis.com/client-name\"          = \"terraform\"\n        \"run.googleapis.com/vpc-access-connector\" = \"projects/${var.project_id}/locations/${var.region}/connectors/${var.vpc_connector_name}\"\n        \"run.googleapis.com/vpc-access-egress\"    = \"all-traffic\"\n      }\n    }\n  }\n\n  traffic {\n    percent         = 100\n    latest_revision = true\n  }\n\n  autogenerate_revision_name = true\n}\n```\n\nLet's add a publicly accessible IAM policy resource to enable us to access the Backstage service.\n\n```bash\ndata \"google_iam_policy\" \"noauth\" {\n  binding {\n    role = \"roles/run.invoker\"\n    members = [\n      \"allUsers\",\n    ]\n  }\n}\n\nresource \"google_cloud_run_service_iam_policy\" \"noauth\" {\n  location = var.region\n  project  = var.project_id\n  service  = google_cloud_run_service.backstage.name\n\n  policy_data = data.google_iam_policy.noauth.policy_data\n}\n```\n\n### Final Config\n\nLet’s go back to our `main.tf` from `deployment/environment/dev` directory and add the modules.\n\n```bash\nprovider \"google\" {\n  project = var.project\n}\n\nmodule \"vpc\" {\n  source     = \"../../modules/vpc\"\n  region     = var.region\n  project_id = var.project\n}\n\nmodule \"cloudsql\" {\n  source        = \"../../modules/cloudsql\"\n  region        = var.region\n  project_id    = var.project\n  network_id    = \"projects/${var.project}/global/networks/${module.vpc.vpc_network.network_name}\"\n  user_password = \"\"\n  depends_on = [\n    module.vpc, module.vpc.backstage_private_vpc_connection\n  ]\n}\n\nmodule \"secrets\" {\n  source            = \"../../modules/secrets\"\n  postgres_password = module.cloudsql.generated_user_password\n  depends_on = [\n    module.cloudsql\n  ]\n}\n\nmodule \"iam\" {\n  source     = \"../../modules/iam\"\n  project_id = var.project\n}\nmodule \"cloudrun\" {\n  source                            = \"../../modules/cloudrun\"\n  project_id                        = var.project\n  region                            = var.region\n  vpc_connector_name                = module.vpc.backstage_serverless_vpc_connector_name\n  artifact_registry_url             = var.artifact_registry_url\n  artifact_repo                     = var.artifact_registry_repository\n  cloudsql_instance_name            = module.cloudsql.sql_instance_name\n  cloudsql_instance_connection_name = module.cloudsql.sql_instance_connection_name\n  service_account_email             = module.iam.backstage_service_account_email\n\n  depends_on = [\n    module.cloudsql, module.vpc, module.secrets\n  ]\n}\n```\n\nOur final folder tree should look something like this:\n\n```bash\n├── deployment\n│   ├── environments\n│   │   └── dev\n│   │       ├── main.tf\n│   │       ├── terraform.tfvars\n│   │       └── variables.tf\n│   └── modules\n│       ├── cloudrun\n│       │   ├── main.tf\n│       │   └── variables.tf\n│       ├── cloudsql\n│       │   ├── main.tf\n│       │   ├── outputs.tf\n│       │   └── variables.tf\n│       ├── iam\n│       │   ├── main.tf\n│       │   ├── outputs.tf\n│       │   └── variables.tf\n│       ├── secrets\n│       │   ├── main.tf\n│       │   └── variables.tf\n│       └── vpc\n│           ├── main.tf\n│           ├── outputs.tf\n│           └── variables.tf\n```\n\nInitialize our Terraform config\n\n```bash\ncd deployment/environments/dev/\n\nterraform init\n```\n\nRun **`terraform plan -out tfplan`**  to generate the execution plan\n\nRun **`terraform apply tfplan`** to create or update infrastructure according to the execution plan\n\nYou should now be able to deploy your Backstage with Cloud Run via Terraform! Yey!\n\n## CI/CD with Github Action (soon)\n\n## External Techdocs (soon)\n\n## Source Code\n\n[Github Repo](https://github.com/mharrvic/backstage-cloudrun-terraform)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmharrvic%2Fbackstage-cloudrun-terraform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmharrvic%2Fbackstage-cloudrun-terraform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmharrvic%2Fbackstage-cloudrun-terraform/lists"}