cloud-run-django-terraform/main.tf (189 lines of code) (raw):
# Step 1: Activate Google Cloud
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 3.66"
}
}
}
# Step 2: Set up variables
provider "google" {
project = var.project
region = var.region
}
data "google_project" "project" {
project_id = var.project
}
variable "project" {
type = string
description = "Google Cloud Project ID"
}
variable "region" {
type = string
default = "us-central1"
description = "Google Cloud Region"
}
variable "service" {
type = string
default = "gametracker"
description = "The name of the service"
}
# Step 3: Activate service APIs
resource "google_project_service" "run" {
service = "run.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "sql-component" {
service = "sql-component.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "sqladmin" {
service = "sqladmin.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "compute" {
service = "compute.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "cloudbuild" {
service = "cloudbuild.googleapis.com"
disable_on_destroy = false
}
resource "google_project_service" "secretmanager" {
service = "secretmanager.googleapis.com"
disable_on_destroy = false
}
# Step 4: Create a custom Service Account
resource "google_service_account" "django" {
account_id = "django"
}
# Step 5: Create the database
resource "random_password" "database_password" {
length = 32
special = false
}
resource "google_sql_database_instance" "instance" {
name = "gametracker"
database_version = "POSTGRES_13"
region = "us-central1"
settings {
tier = "db-f1-micro"
}
deletion_protection = true
}
resource "google_sql_database" "database" {
name = "django"
instance = google_sql_database_instance.instance.name
}
resource "google_sql_user" "django" {
name = "django"
instance = google_sql_database_instance.instance.name
password = random_password.database_password.result
}
# Step 6: Create the secrets
resource "google_storage_bucket" "media" {
name = "${var.project}-images"
location = "US"
}
resource "random_password" "django_secret_key" {
special = false
length = 50
}
resource "google_secret_manager_secret" "django_settings" {
secret_id = "django_settings"
replication {
automatic = true
}
depends_on = [google_project_service.secretmanager]
}
# Step 7: Prepare the secrets for Django
resource "google_secret_manager_secret_version" "django_settings" {
secret = google_secret_manager_secret.django_settings.id
secret_data = templatefile("etc/env.tpl", {
bucket = google_storage_bucket.media.name
secret_key = random_password.django_secret_key.result
user = google_sql_user.django
instance = google_sql_database_instance.instance
database = google_sql_database.database
})
}
# Step 8: Expand Service Account permissions
resource "google_secret_manager_secret_iam_binding" "django_settings" {
secret_id = google_secret_manager_secret.django_settings.id
role = "roles/secretmanager.secretAccessor"
members = [local.cloudbuild_serviceaccount, local.django_serviceaccount]
}
locals {
cloudbuild_serviceaccount = "serviceAccount:${data.google_project.project.number}@cloudbuild.gserviceaccount.com"
django_serviceaccount = "serviceAccount:${google_service_account.django.email}"
}
# Step 9: Populate secrets
resource "random_password" "superuser_password" {
length = 32
special = false
}
resource "google_secret_manager_secret" "superuser_password" {
secret_id = "superuser_password"
replication {
automatic = true
}
depends_on = [google_project_service.secretmanager]
}
resource "google_secret_manager_secret_version" "superuser_password" {
secret = google_secret_manager_secret.superuser_password.id
secret_data = random_password.superuser_password.result
}
resource "google_secret_manager_secret_iam_binding" "superuser_password" {
secret_id = google_secret_manager_secret.superuser_password.id
role = "roles/secretmanager.secretAccessor"
members = [local.cloudbuild_serviceaccount]
}
# Step 10: Create Cloud Run service
resource "google_cloud_run_service" "service" {
name = var.service
location = var.region
autogenerate_revision_name = true
template {
spec {
service_account_name = google_service_account.django.email
containers {
image = "gcr.io/${var.project}/${var.service}"
}
}
metadata {
annotations = {
"autoscaling.knative.dev/maxScale" = "100"
"run.googleapis.com/cloudsql-instances" = google_sql_database_instance.instance.connection_name
"run.googleapis.com/client-name" = "terraform"
}
}
}
traffic {
percent = 100
latest_revision = true
}
}
# Step 11: Specify Cloud Run permissions
data "google_iam_policy" "noauth" {
binding {
role = "roles/run.invoker"
members = [
"allUsers",
]
}
}
resource "google_cloud_run_service_iam_policy" "noauth" {
location = google_cloud_run_service.service.location
project = google_cloud_run_service.service.project
service = google_cloud_run_service.service.name
policy_data = data.google_iam_policy.noauth.policy_data
}
# Step 12: Grant access to the database
resource "google_project_iam_binding" "service_permissions" {
for_each = toset([
"run.admin", "cloudsql.client"
])
role = "roles/${each.key}"
members = [local.cloudbuild_serviceaccount, local.django_serviceaccount]
}
resource "google_service_account_iam_binding" "cloudbuild_sa" {
service_account_id = google_service_account.django.name
role = "roles/iam.serviceAccountUser"
members = [local.cloudbuild_serviceaccount]
}
# Step 14: View final output
output "superuser_password" {
value = google_secret_manager_secret_version.superuser_password.secret_data
sensitive = true
}
output "service_url" {
value = google_cloud_run_service.service.status[0].url
}