├── modules ├── firebase.tf ├── variables.tf ├── service_account.tf ├── secret_manager.tf └── cloud_run.tf ├── variables.tf ├── versions.tf ├── README.md ├── main.tf ├── .gitignore └── Makefile /modules/firebase.tf: -------------------------------------------------------------------------------- 1 | resource "google_firebase_project" "default" { 2 | provider = google-beta 3 | 4 | project = var.project_id 5 | } 6 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "GCP_CREDENTIALS" { 2 | type = string 3 | } 4 | 5 | variable "GCP_PROJECT_ID" { 6 | type = string 7 | } 8 | 9 | variable "GCP_PROJECT_REGION" { 10 | type = string 11 | } 12 | -------------------------------------------------------------------------------- /modules/variables.tf: -------------------------------------------------------------------------------- 1 | variable "project_id" { 2 | type = string 3 | } 4 | 5 | variable "region" { 6 | type = string 7 | } 8 | 9 | variable "hasura_service_account_roles" { 10 | type = list(string) 11 | default = ["roles/secretmanager.secretAccessor"] 12 | } 13 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.3.3" 3 | required_providers { 4 | google = { 5 | source = "hashicorp/google" 6 | version = "~> 4.31.0" 7 | } 8 | google-beta = { 9 | source = "hashicorp/google-beta" 10 | version = "~> 4.31.0" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 個人開発用のインフラのテンプレート 2 | 3 | # リソース作成手順 4 | 5 | 1. GCPのプロジェクトを作成 6 | 1. gcloudコマンドの向き先を作成したプロジェクトにする 7 | 1. `make init` 8 | 1. `Makefile`の`GCP_PROJECT_ID`にGCPのプロジェクトIDを入れる 9 | 1. [Neon](https://neon.tech/)でDBを作成 10 | 1. 作成したDBのURLを、GCPのコンソール上からシークレットマネージャーに登録 11 | 1. Terraform CloudでWorkspacesを作成してApply 12 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | provider "google" { 2 | credentials = var.GCP_CREDENTIALS 3 | project = var.GCP_PROJECT_ID 4 | region = var.GCP_PROJECT_REGION 5 | } 6 | 7 | provider "google-beta" { 8 | credentials = var.GCP_CREDENTIALS 9 | project = var.GCP_PROJECT_ID 10 | region = var.GCP_PROJECT_REGION 11 | } 12 | 13 | module "modules" { 14 | source = "./modules" 15 | project_id = var.GCP_PROJECT_ID 16 | region = var.GCP_PROJECT_REGION 17 | } 18 | -------------------------------------------------------------------------------- /modules/service_account.tf: -------------------------------------------------------------------------------- 1 | resource "google_service_account" "hasura_service_account" { 2 | account_id = "hasura" 3 | display_name = "HasuraのCloud Run実行用" 4 | } 5 | 6 | # See: https://stackoverflow.com/questions/67863863/terraform-gcp-assign-iam-roles-to-service-account 7 | resource "google_project_iam_binding" "hasura_service_account" { 8 | project = var.project_id 9 | count = length(var.hasura_service_account_roles) 10 | role = var.hasura_service_account_roles[count.index] 11 | members = [ 12 | "serviceAccount:${google_service_account.hasura_service_account.email}" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /modules/secret_manager.tf: -------------------------------------------------------------------------------- 1 | resource "google_secret_manager_secret" "secret_hasura_graphql_admin_secret" { 2 | secret_id = "HASURA_GRAPHQL_ADMIN_SECRET" 3 | replication { 4 | automatic = true 5 | } 6 | } 7 | 8 | resource "google_secret_manager_secret_version" "secret_hasura_graphql_admin_secret" { 9 | secret = google_secret_manager_secret.secret_hasura_graphql_admin_secret.name 10 | secret_data = random_password.hasura_admin_secret.result 11 | } 12 | 13 | resource "random_password" "hasura_admin_secret" { 14 | length = 20 15 | special = true 16 | override_special = "!#$%&*()-_=+[]{}<>:?" 17 | } 18 | 19 | data "google_secret_manager_secret" "secret_hasura_graphql_database_url" { 20 | secret_id = "HASURA_GRAPHQL_DATABASE_URL" 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore//Terraform.gitignore 2 | 3 | # Local .terraform directories 4 | **/.terraform/* 5 | 6 | # .tfstate files 7 | *.tfstate 8 | *.tfstate.* 9 | 10 | # Crash log files 11 | crash.log 12 | 13 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 14 | # password, private keys, and other secrets. These should not be part of version 15 | # control as they are data points which are potentially sensitive and subject 16 | # to change depending on the environment. 17 | # 18 | *.tfvars 19 | 20 | # Ignore override files as they are usually used to override resources locally and so 21 | # are not checked in 22 | override.tf 23 | override.tf.json 24 | *_override.tf 25 | *_override.tf.json 26 | 27 | # Include override files you do wish to add to version control using negated pattern 28 | # 29 | # !example_override.tf 30 | 31 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 32 | # example: *tfplan* 33 | 34 | # Ignore CLI configuration files 35 | .terraformrc 36 | terraform.rc 37 | 38 | 39 | ### https://raw.github.com/github/gitignore//Global/VisualStudioCode.gitignore 40 | 41 | .vscode/* 42 | !.vscode/settings.json 43 | !.vscode/tasks.json 44 | !.vscode/launch.json 45 | !.vscode/extensions.json 46 | *.code-workspace 47 | 48 | # Local History for Visual Studio Code 49 | .history/ 50 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GCP_PROJECT_ID := "" 2 | REGISTRY_NAME := docker 3 | HASURA_VERSION := v2.16.0 4 | 5 | .PHONY: init 6 | init: 7 | make enable_googleapis 8 | make create_service_account 9 | make create_artifact_registry 10 | make create_secret_manager 11 | make push_hasura_image 12 | 13 | # 必要なAPIの有効化 14 | .PHONY: enable_googleapis 15 | enable_googleapis: 16 | gcloud services enable artifactregistry.googleapis.com 17 | gcloud services enable appengine.googleapis.com 18 | gcloud services enable iam.googleapis.com 19 | gcloud services enable run.googleapis.com 20 | gcloud services enable cloudresourcemanager.googleapis.com 21 | gcloud services enable firebase.googleapis.com 22 | gcloud services enable cloudbuild.googleapis.com 23 | gcloud services enable runtimeconfig.googleapis.com 24 | gcloud services enable cloudfunctions.googleapis.com 25 | gcloud services enable serviceusage.googleapis.com 26 | gcloud services enable secretmanager.googleapis.com 27 | 28 | # FIXME: 必要最低限の権限にする 29 | # Terraform用のサービスアカウントを作成 30 | .PHONY: create_service_account 31 | create_service_account: 32 | gcloud iam service-accounts create terraform --display-name="terraform" 33 | gcloud projects add-iam-policy-binding $(GCP_PROJECT_ID) \ 34 | --member serviceAccount:"terraform@$(GCP_PROJECT_ID).iam.gserviceaccount.com" \ 35 | --role "roles/owner" \ 36 | --no-user-output-enable 37 | 38 | # Hasuraのイメージを格納するartifact registryを作成 39 | .PHONY: create_artifact_registry 40 | create_artifact_registry: 41 | gcloud artifacts repositories create $(REGISTRY_NAME) --location=asia-northeast1 --repository-format=docker 42 | 43 | # 手動で登録する用のシークレットマネージャーの作成 44 | # NOTE: Neonでデータベースを作成してURLを手動でシークレットマネージャーに登録する 45 | .PHONY: create_secret_manager 46 | create_secret_manager: 47 | echo -n "" | gcloud secrets create HASURA_GRAPHQL_DATABASE_URL \ 48 | --replication-policy="automatic" \ 49 | --data-file=- 50 | 51 | # Hasuraのイメージをartifact registryにpush 52 | .PHONY: push_hasura_image 53 | push_hasura_image: 54 | docker pull hasura/graphql-engine:$(HASURA_VERSION) 55 | docker tag hasura/graphql-engine:$(HASURA_VERSION) asia-northeast1-docker.pkg.dev/$(GCP_PROJECT_ID)/$(REGISTRY_NAME)/hasura:latest 56 | docker push asia-northeast1-docker.pkg.dev/$(GCP_PROJECT_ID)/$(REGISTRY_NAME)/hasura:latest 57 | -------------------------------------------------------------------------------- /modules/cloud_run.tf: -------------------------------------------------------------------------------- 1 | resource "google_cloud_run_service" "hasura" { 2 | provider = google-beta 3 | 4 | name = "hasura" 5 | location = var.region 6 | autogenerate_revision_name = true 7 | 8 | template { 9 | metadata { 10 | annotations = { 11 | "autoscaling.knative.dev/minScale" = "0" 12 | "autoscaling.knative.dev/maxScale" = "5" 13 | } 14 | } 15 | 16 | spec { 17 | service_account_name = google_service_account.hasura_service_account.email 18 | 19 | containers { 20 | image = "${var.region}-docker.pkg.dev/${var.project_id}/docker/hasura:latest" 21 | 22 | resources { 23 | limits = { 24 | "memory" : "512Mi" 25 | "cpu" = "1000m" 26 | } 27 | } 28 | 29 | ports { 30 | container_port = 8080 31 | name = "http1" 32 | } 33 | 34 | env { 35 | name = "HASURA_GRAPHQL_DATABASE_URL" 36 | value_from { 37 | secret_key_ref { 38 | name = data.google_secret_manager_secret.secret_hasura_graphql_database_url.secret_id 39 | key = "latest" 40 | } 41 | } 42 | } 43 | 44 | env { 45 | name = "HASURA_GRAPHQL_ADMIN_SECRET" 46 | value_from { 47 | secret_key_ref { 48 | name = google_secret_manager_secret.secret_hasura_graphql_admin_secret.secret_id 49 | key = "latest" 50 | } 51 | } 52 | } 53 | 54 | env { 55 | name = "HASURA_GRAPHQL_ENABLE_CONSOLE" 56 | value = "true" 57 | } 58 | 59 | env { 60 | name = "HASURA_GRAPHQL_UNAUTHORIZED_ROLE" 61 | value = "anyone" 62 | } 63 | 64 | env { 65 | name = "HASURA_GRAPHQL_EXPERIMENTAL_FEATURES" 66 | value = "naming_convention" 67 | } 68 | } 69 | } 70 | } 71 | 72 | lifecycle { 73 | ignore_changes = [ 74 | template[0].metadata[0].annotations["client.knative.dev/user-image"], 75 | template[0].metadata[0].annotations["run.googleapis.com/client-name"], 76 | template[0].metadata[0].annotations["run.googleapis.com/client-version"], 77 | metadata[0].annotations["client.knative.dev/user-image"], 78 | metadata[0].annotations["run.googleapis.com/client-name"], 79 | metadata[0].annotations["run.googleapis.com/client-version"] 80 | ] 81 | } 82 | } 83 | 84 | resource "google_cloud_run_service_iam_member" "public_access_hasura" { 85 | location = google_cloud_run_service.hasura.location 86 | project = google_cloud_run_service.hasura.project 87 | service = google_cloud_run_service.hasura.name 88 | role = "roles/run.invoker" 89 | member = "allUsers" 90 | } 91 | --------------------------------------------------------------------------------