diff --git a/terraform/environments/production/bi.tf b/terraform/environments/production/bi.tf new file mode 100644 index 000000000..8b57846f7 --- /dev/null +++ b/terraform/environments/production/bi.tf @@ -0,0 +1,174 @@ +# Deploy our Metabase instance + +locals { + metabase_region = local.region + metabase_zone = local.availability_zone +} + +resource "random_password" "metabase_db_password" { + length = 16 + + min_lower = 1 + min_upper = 1 + min_numeric = 1 + min_special = 1 +} + +# This user can also be used to connect to the Firezone database, +# but following SQL should be run manually using the Cloud SQL Proxy: +# +# GRANT SELECT ON ALL TABLES IN SCHEMA public TO metabase; +# GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO metabase; +# +resource "google_sql_user" "metabase" { + project = module.google-cloud-project.project.project_id + + instance = module.google-cloud-sql.master_instance_name + + name = "metabase" + password = random_password.metabase_db_password.result +} + +resource "google_sql_database" "metabase" { + project = module.google-cloud-project.project.project_id + + name = "metabase" + instance = module.google-cloud-sql.master_instance_name +} + +module "metabase" { + source = "../../modules/metabase-app" + project_id = module.google-cloud-project.project.project_id + + compute_network = module.google-cloud-vpc.id + compute_subnetwork = google_compute_subnetwork.tools.self_link + + compute_instance_type = "n1-standard-1" + compute_region = local.metabase_region + compute_instance_availability_zone = local.metabase_zone + + image_repo = "metabase" + image = "metabase" + image_tag = var.metabase_image_tag + + application_name = "metabase" + application_version = replace(replace(var.metabase_image_tag, ".", "-"), "v", "") + + application_environment_variables = [ + { + name = "MB_DB_TYPE" + value = "postgres" + }, + { + name = "MB_DB_TYPE" + value = "postgres" + }, + { + name = "MB_DB_DBNAME" + value = google_sql_database.metabase.name + }, + { + name = "MB_DB_PORT" + value = "5432" + }, + { + name = "MB_DB_USER" + value = google_sql_user.metabase.name + }, + { + name = "MB_DB_PASS" + value = random_password.metabase_db_password.result + }, + { + # TODO: create a read replica for analytics + name = "MB_DB_HOST" + value = module.google-cloud-sql.bi_instance_ip_address + }, + { + name = "MB_SITE_NAME" + value = module.google-cloud-project.project.project_id + }, + { + name = "MB_ANON_TRACKING_ENABLED" + value = "false" + }, + # { + # name = "MB_JETTY_PORT" + # value = "80" + # } + ] + + health_check = { + name = "health" + protocol = "TCP" + port = 3000 + + initial_delay_sec = 60 + + check_interval_sec = 15 + timeout_sec = 10 + healthy_threshold = 1 + unhealthy_threshold = 3 + + http_health_check = { + request_path = "/healthz" + } + } +} + +# Allow outbound traffic +resource "google_compute_firewall" "egress-ipv4" { + project = module.google-cloud-project.project.project_id + + name = "metabase-egress-ipv4" + network = module.google-cloud-vpc.id + direction = "EGRESS" + + target_tags = module.metabase.target_tags + destination_ranges = ["0.0.0.0/0"] + + allow { + protocol = "udp" + } +} + +resource "google_compute_firewall" "egress-ipv6" { + project = module.google-cloud-project.project.project_id + + name = "metabase-egress-ipv6" + network = module.google-cloud-vpc.id + direction = "EGRESS" + + target_tags = module.metabase.target_tags + destination_ranges = ["::/0"] + + allow { + protocol = "udp" + } +} + +resource "google_compute_firewall" "metabase-ssh-ipv4" { + project = module.google-cloud-project.project.project_id + + name = "metabase-ssh-ipv4" + network = module.google-cloud-vpc.id + + allow { + protocol = "tcp" + ports = [22] + } + + allow { + protocol = "udp" + ports = [22] + } + + allow { + protocol = "sctp" + ports = [22] + } + + # Only allows connections using IAP + source_ranges = local.iap_ipv4_ranges + target_tags = module.metabase.target_tags +} diff --git a/terraform/environments/production/gateways.tf b/terraform/environments/production/gateways.tf index 9ae917e18..9bb175ab8 100644 --- a/terraform/environments/production/gateways.tf +++ b/terraform/environments/production/gateways.tf @@ -1,34 +1,7 @@ # Deploy our dogfood gateways locals { - gateways_region = "us-central1" - gateways_zones = ["us-central1-b"] -} - -resource "google_compute_network" "gateways" { - project = module.google-cloud-project.project.project_id - name = "gateways" - - routing_mode = "GLOBAL" - - auto_create_subnetworks = false - - depends_on = [ - module.api - ] -} - -resource "google_compute_subnetwork" "gateways" { - project = module.google-cloud-project.project.project_id - - name = "gateways" - region = local.gateways_region - - network = google_compute_network.gateways.self_link - - stack_type = "IPV4_IPV6" - ip_cidr_range = "10.101.0.0/24" - ipv6_access_type = "EXTERNAL" - private_ip_google_access = true + gateways_region = local.region + gateways_zones = [local.availability_zone] } module "gateways" { @@ -37,8 +10,8 @@ module "gateways" { source = "../../modules/gateway-google-cloud-compute" project_id = module.google-cloud-project.project.project_id - compute_network = google_compute_network.gateways.self_link - compute_subnetwork = google_compute_subnetwork.gateways.self_link + compute_network = module.google-cloud-vpc.id + compute_subnetwork = google_compute_subnetwork.tools.self_link compute_instance_type = "n1-standard-1" compute_region = local.gateways_region @@ -78,50 +51,34 @@ module "gateways" { token = var.gateway_token } +# Allow gateways to access the Metabase +resource "google_compute_firewall" "gateways-metabase-access" { + count = var.gateway_token != null ? 1 : 0 -# Allow inbound traffic -# resource "google_compute_firewall" "ingress-ipv4" { -# count = var.gateway_token != null ? 1 : 0 + project = module.google-cloud-project.project.project_id -# project = module.google-cloud-project.project.project_id + name = "gateways-metabase-access" + network = module.google-cloud-vpc.id + direction = "INGRESS" -# name = "gateways-ingress-ipv4" -# network = google_compute_network.network.self_link -# direction = "INGRESS" + source_tags = module.gateways[0].target_tags + target_tags = module.metabase.target_tags -# target_tags = module.gateways[0].target_tags -# source_ranges = ["0.0.0.0/0"] + allow { + protocol = "tcp" + } +} -# allow { -# protocol = "udp" -# } -# } - -# resource "google_compute_firewall" "ingress-ipv6" { -# count = var.gateway_token != null ? 1 : 0 - -# project = module.google-cloud-project.project.project_id - -# name = "gateways-ingress-ipv6" -# network = google_compute_network.network.self_link -# direction = "INGRESS" - -# target_tags = module.gateways[0].target_tags -# source_ranges = ["::/0"] - -# allow { -# protocol = "udp" -# } -# } +# curl "http://metabase.c.firezone-prod.internal:3000/" -v # Allow outbound traffic -resource "google_compute_firewall" "egress-ipv4" { +resource "google_compute_firewall" "gateways-egress-ipv4" { count = var.gateway_token != null ? 1 : 0 project = module.google-cloud-project.project.project_id name = "gateways-egress-ipv4" - network = google_compute_network.gateways.self_link + network = module.google-cloud-vpc.id direction = "EGRESS" target_tags = module.gateways[0].target_tags @@ -132,13 +89,13 @@ resource "google_compute_firewall" "egress-ipv4" { } } -resource "google_compute_firewall" "egress-ipv6" { +resource "google_compute_firewall" "gateways-egress-ipv6" { count = var.gateway_token != null ? 1 : 0 project = module.google-cloud-project.project.project_id name = "gateways-egress-ipv6" - network = google_compute_network.gateways.self_link + network = module.google-cloud-vpc.id direction = "EGRESS" target_tags = module.gateways[0].target_tags @@ -155,7 +112,7 @@ resource "google_compute_firewall" "gateways-ssh-ipv4" { project = module.google-cloud-project.project.project_id name = "gateways-ssh-ipv4" - network = google_compute_network.gateways.self_link + network = module.google-cloud-vpc.id allow { protocol = "tcp" @@ -173,6 +130,6 @@ resource "google_compute_firewall" "gateways-ssh-ipv4" { } # Only allows connections using IAP - source_ranges = ["35.235.240.0/20"] + source_ranges = local.iap_ipv4_ranges target_tags = module.gateways[0].target_tags } diff --git a/terraform/environments/production/main.tf b/terraform/environments/production/main.tf index a0d40bd69..8b2c65fd7 100644 --- a/terraform/environments/production/main.tf +++ b/terraform/environments/production/main.tf @@ -11,6 +11,10 @@ locals { availability_zone = "us-east1-d" tld = "firezone.dev" + + iap_ipv4_ranges = [ + "35.235.240.0/20" + ] } terraform { @@ -206,6 +210,23 @@ resource "google_compute_subnetwork" "apps" { private_ip_google_access = true } +# Create VPN subnet for tooling instances +resource "google_compute_subnetwork" "tools" { + project = module.google-cloud-project.project.project_id + + name = "tooling" + + stack_type = "IPV4_IPV6" + + ip_cidr_range = "10.129.0.0/20" + region = local.region + network = module.google-cloud-vpc.id + + ipv6_access_type = "EXTERNAL" + + private_ip_google_access = true +} + # Create SQL user and database resource "random_password" "firezone_db_password" { length = 16 @@ -753,7 +774,7 @@ resource "google_compute_firewall" "portal-ssh-ipv4" { } # Only allows connections using IAP - source_ranges = ["35.235.240.0/20"] + source_ranges = local.iap_ipv4_ranges target_tags = concat(module.web.target_tags, module.api.target_tags) } @@ -781,7 +802,7 @@ resource "google_compute_firewall" "relays-ssh-ipv4" { } # Only allows connections using IAP - source_ranges = ["35.235.240.0/20"] + source_ranges = local.iap_ipv4_ranges target_tags = module.relays[0].target_tags } diff --git a/terraform/environments/production/variables.tf b/terraform/environments/production/variables.tf index c15f17827..18363cec4 100644 --- a/terraform/environments/production/variables.tf +++ b/terraform/environments/production/variables.tf @@ -3,6 +3,11 @@ variable "image_tag" { description = "Image tag for all services. Notice: we assume all services are deployed with the same version" } +variable "metabase_image_tag" { + type = string + default = "v0.47.6" +} + variable "relay_token" { type = string default = null