Skip to content
68 changes: 49 additions & 19 deletions examples/cross-regional-failover-with-rxlb/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ resource "google_compute_region_security_policy" "armor" {
for_each = var.regions
name = "regional-${each.key}-armor"
region = each.key
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add type = "CLOUD_ARMOR" here as well. In my testing, not having this caused the resource to be destroyed and recreated even with no changes, because it thought the type was null.

type = "CLOUD_ARMOR"

rules {
priority = 1000
Expand Down Expand Up @@ -58,6 +59,10 @@ resource "google_compute_instance_template" "tmpl" {
name_prefix = "regional-${each.key}-tmpl"
machine_type = var.instance_machine_type

lifecycle {
create_before_destroy = true
}

disk {
source_image = var.instance_image
auto_delete = true
Expand All @@ -66,8 +71,9 @@ resource "google_compute_instance_template" "tmpl" {

network_interface {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that without

access_config {}

The VMs won't get an external IP address. This could work, but not without some more configuration. For one, I think this causes the startup script to fail because apt-get doesn't work with cloud nat. Also, in order to allow SSH into that machines, you'd need to configure IAP tunneling. Not sure what we usually do with these templates, but I think you either need to make sure that this works correctly without an external IP, or just enable an external IP for the VMs.

subnetwork = google_compute_subnetwork.vm[each.key].self_link
access_config {}
}

metadata_startup_script = <<-EOT
#!/bin/bash
apt-get update -y
Expand Down Expand Up @@ -147,14 +153,20 @@ resource "google_compute_region_target_http_proxy" "http" {
}

resource "google_compute_region_target_https_proxy" "https" {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm getting an error during resource creation here, which I don't fully understand

╷
│ Error: Error creating RegionTargetHttpsProxy: googleapi: Error 400: Invalid value for field 'resource.sslCertificates': ''. The URL is malformed., invalid
│
│   with google_compute_region_target_https_proxy.https["us-central1"],
│   on main.tf line 164, in resource "google_compute_region_target_https_proxy" "https":
│  164: resource "google_compute_region_target_https_proxy" "https" {
│
╵
╷
│ Error: Error creating RegionTargetHttpsProxy: googleapi: Error 400: Invalid value for field 'resource.sslCertificates': ''. The URL is malformed., invalid
│
│   with google_compute_region_target_https_proxy.https["us-west1"],
│   on main.tf line 164, in resource "google_compute_region_target_https_proxy" "https":
│  164: resource "google_compute_region_target_https_proxy" "https" {
│
╵

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still getting this same error when testing.

provider = "google-beta"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got a deprecation warning here

Warning: Quoted references are deprecated
│
│   on main.tf line 170, in resource "google_compute_region_target_https_proxy" "https":
│  170:   provider = "google-beta"
│
│ In this context, references are expected literally rather than in quotes. Terraform 0.11 and earlier required quotes, but quoted references are now deprecated and will be
│ removed in a future version of Terraform. Remove the quotes surrounding this reference to silence this warning.
╵

so I think you can just make provider = google-beta

for_each = var.regions
name = "regional-${each.key}-https-proxy"
region = each.key
url_map = google_compute_region_url_map.um[each.key].self_link

certificate_manager_certificates = [
google_certificate_manager_certificate.cert[each.key].id
google_certificate_manager_certificate.cert[each.key].id
]

depends_on = [
google_certificate_manager_certificate.cert
]

}

resource "google_compute_address" "addr" {
Expand Down Expand Up @@ -192,14 +204,20 @@ resource "google_compute_forwarding_rule" "https" {
}

resource "google_dns_record_set" "regional_geo_a" {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This resource should also have --enable-health-check set, correct? That is, the health checking feature should be enabled so that failover from to the other can happen, right?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you still need --enable-health-check set, correct? So that healthchecking in DNS can failover from one region to another if one of the LBs goes down?

count = var.enable_dns_records && length(local.dns_managed_zone_name) > 0 ? 1 : 0
count = var.enable_dns_records && length(local.ordered_regions) > 0 ? 1 : 0

lifecycle {
replace_triggered_by = [google_compute_address.addr]
ignore_changes = [rrdatas]
}

managed_zone = local.dns_managed_zone_name
name = "${var.regional_hostname}."
type = "A"
ttl = 60

routing_policy {
enable_geo_fencing = false
dynamic "geo" {
for_each = var.regions
content {
Expand All @@ -209,6 +227,7 @@ resource "google_dns_record_set" "regional_geo_a" {
}
}
}

resource "google_certificate_manager_dns_authorization" "auth" {
for_each = var.regions
provider = google-beta
Expand All @@ -218,27 +237,36 @@ resource "google_certificate_manager_dns_authorization" "auth" {
}

locals {
dns_managed_zone_name = var.create_public_zone && var.enable_dns_records ? google_dns_managed_zone.public_new[0].name : var.public_zone_name
ordered_regions = sort(keys(var.regions))
dns_managed_zone_name = coalesce(
try(google_dns_managed_zone.public_new[0].name, null),
var.public_zone_name
)
}

resource "google_dns_record_set" "acme_txt" {
for_each = (var.enable_dns_records && length(local.dns_managed_zone_name) > 0) ? google_certificate_manager_dns_authorization.auth : {}
for_each = (var.enable_dns_records && length(local.ordered_regions) > 0) ? google_certificate_manager_dns_authorization.auth : {}
managed_zone = local.dns_managed_zone_name
name = each.value.dns_resource_record[0].name
type = "TXT"
ttl = 60
rrdatas = [each.value.dns_resource_record[0].data]
}


resource "google_certificate_manager_certificate" "cert" {
for_each = var.regions
provider = google-beta
name = "regional-${each.key}-cm-cert"
location = each.key
location = each.key

managed {
domains = [var.regional_hostname]
dns_authorizations = [google_certificate_manager_dns_authorization.auth[each.key].id]
}
depends_on = [
google_dns_record_set.acme_txt
]
}

resource "google_dns_managed_zone" "public_new" {
Expand All @@ -248,19 +276,6 @@ resource "google_dns_managed_zone" "public_new" {
description = "Public zone for ${var.regional_hostname}"
}

resource "google_dns_record_set" "regional_a" {
count = var.enable_dns_records && length(var.regions) > 0 ? 1 : 0

managed_zone = local.dns_managed_zone_name
name = "${var.regional_hostname}."
type = "A"
ttl = 60

rrdatas = [
for r in keys(var.regions) : google_compute_address.addr[r].address
]
}

resource "google_compute_firewall" "allow_hc" {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need a firewall rule covering traffic from the proxy to the backend, no? For instance, the google_compute_firewall on https://docs.cloud.google.com/load-balancing/docs/l7-internal/int-https-lb-tf-examples

name = "allow-hc"
network = google_compute_network.auto.name
Expand All @@ -272,3 +287,18 @@ resource "google_compute_firewall" "allow_hc" {
source_ranges = ["130.211.0.0/22", "35.191.0.0/16"]
target_tags = ["allow-hc"]
}

resource "google_compute_firewall" "allow_proxy_to_backend" {
name = "allow-proxy-to-backend"
network = google_compute_network.auto.name

direction = "INGRESS"
priority = 1000
source_ranges = ["35.191.0.0/16", "130.211.0.0/22"]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source range here should be the source range of the proxy subnet (the proxy_only resource), since that is the address range the LBs will be using to send traffic to the backends.

target_tags = ["allow-proxy"]

allow {
protocol = "tcp"
ports = ["80", "443"]
}
}
5 changes: 0 additions & 5 deletions examples/cross-regional-failover-with-rxlb/variables.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
variable "project_id" {
description = "GCP project ID"
type = string
}

variable "project" {
description = "GCP project ID (alias used in some places)"
type = string
Expand Down