diff --git a/.github/workflows/documentation.yaml b/.github/workflows/documentation.yaml index 16d12334..3041b949 100644 --- a/.github/workflows/documentation.yaml +++ b/.github/workflows/documentation.yaml @@ -13,6 +13,7 @@ jobs: - authorize-private-service - cloudevent-broker - cloudevent-trigger + - networking steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/cloudevent-broker/README.md b/cloudevent-broker/README.md index 3ed55b8b..b4e2ad75 100644 --- a/cloudevent-broker/README.md +++ b/cloudevent-broker/README.md @@ -6,18 +6,27 @@ This module provisions a regionalizied Broker abstraction akin to the Knative events is something like this: ```hcl +// Create a network with several regional subnets +module "networking" { + source = "chainguard-dev/glue/cloudrun//networking" + + name = "my-networking" + project_id = var.project_id + regions = [...] +} + // Create the Broker abstraction. module "cloudevent-broker" { source = "chainguard-dev/glue/cloudrun//cloudevent-broker" name = "my-broker" project_id = var.project_id - regions = local.region-to-networking + regions = module.networking.regional-networks } // Authorize the "foo" service account to publish events. module "foo-emits-events" { - for_each = local.region-to-networking + for_each = module.networking.regional-networks source = "chainguard-dev/glue/cloudrun//authorize-private-service" @@ -31,7 +40,7 @@ module "foo-emits-events" { // Run a cloud run service as the "foo" service account, and pass in the address // of the regional ingress endpoint. resource "google_cloud_run_v2_service" "foo-service" { - for_each = local.region-to-networking + for_each = module.networking.regional-networks project = var.project_id name = "foo" @@ -62,9 +71,6 @@ resource "google_cloud_run_v2_service" "foo-service" { } } } - -// TODO(mattmoor): Put together an example showing how to set up -// local.region-to-networking with the appropriate pieces. ``` diff --git a/cloudevent-trigger/README.md b/cloudevent-trigger/README.md index f8093abe..5dc279f4 100644 --- a/cloudevent-trigger/README.md +++ b/cloudevent-trigger/README.md @@ -6,18 +6,27 @@ is captured by the sibling `cloudevent-broker` module. The intended usage of this module for consuming events is something like this: ```hcl +// Create a network with several regional subnets +module "networking" { + source = "chainguard-dev/glue/cloudrun//networking" + + name = "my-networking" + project_id = var.project_id + regions = [...] +} + // Create the Broker abstraction. module "cloudevent-broker" { source = "chainguard-dev/glue/cloudrun//cloudevent-broker" name = "my-broker" project_id = var.project_id - regions = local.region-to-networking + regions = module.networking.regional-networks } // Run a cloud run service "bar" to consume events from the Broker above. resource "google_cloud_run_v2_service" "bar-service" { - for_each = local.region-to-networking + for_each = module.networking.regional-networks project = var.project_id name = "bar" @@ -49,7 +58,7 @@ resource "google_cloud_run_v2_service" "bar-service" { // Set up regionalized triggers to deliver filtered events from our regionalized // brokers to our regionalized consumer services. module "cloudevent-trigger" { - for_each = var.regions + for_each = module.networking.regional-networks source = "chainguard-dev/glue/cloudrun//cloudevent-trigger" diff --git a/networking/README.md b/networking/README.md new file mode 100644 index 00000000..15c8b074 --- /dev/null +++ b/networking/README.md @@ -0,0 +1,71 @@ +# `networking` + +This module sets up GCP networking suitable for operating Cloud Run services +utilizing the preview [Direct VPC egress](https://cloud.google.com/run/docs/configuring/vpc-direct-vpc) +feature to talk to other "internal ingress" Cloud Run services, and access other +GCP resources that live within or are accessible via the provisioned network. +The intended usage of this module: + +```hcl +// Create a network with several regional subnets +module "networking" { + source = "chainguard-dev/glue/cloudrun//networking" + + name = "my-networking" + project_id = var.project_id + + // These are all of the regions where direct VPC egress is + // supported in preview. + regions = [ + "us-east1", + "us-central1", + "europe-west1", + "europe-west3", + "asia-northeast1", + ] +} +``` + + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | n/a | +| [google-beta](#provider\_google-beta) | n/a | +| [random](#provider\_random) | n/a | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [authorize-delivery](#module\_authorize-delivery) | ../authorize-private-service | n/a | + +## Resources + +| Name | Type | +|------|------| +| [google-beta_google_project_service_identity.pubsub](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_project_service_identity) | resource | +| [google_pubsub_subscription.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription) | resource | +| [google_service_account.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | +| [google_service_account_iam_binding.allow-pubsub-to-mint-tokens](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account_iam_binding) | resource | +| [random_string.suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [broker](#input\_broker) | The name of the pubsub topic we are using as a broker. | `string` | n/a | yes | +| [filter](#input\_filter) | A Knative Trigger-style filter over the cloud event attributes. | `map(string)` | n/a | yes | +| [name](#input\_name) | n/a | `string` | n/a | yes | +| [private-service](#input\_private-service) | The private cloud run service that is subscribing to these events. |
object({
name = string
region = string
})
| n/a | yes | +| [project\_id](#input\_project\_id) | n/a | `string` | n/a | yes | + +## Outputs + +No outputs. + diff --git a/networking/dns.tf b/networking/dns.tf new file mode 100644 index 00000000..20806a4d --- /dev/null +++ b/networking/dns.tf @@ -0,0 +1,60 @@ +// Create a special DNS zone attached to the network in which +// we will operate our services that reroutes *.run.app to records +// that we control. +resource "google_dns_managed_zone" "cloud-run-internal" { + project = var.project_id + name = "cloud-run-internal" + dns_name = "run.app." + description = "This reroutes run.app requests to private.googleapis.com" + + visibility = "private" + + private_visibility_config { + networks { + network_url = google_compute_network.this.id + } + } +} + +// Create a record for *.run.app that points to private.googleapis.com +resource "google_dns_record_set" "cloud-run-cname" { + project = var.project_id + name = "*.run.app." + managed_zone = google_dns_managed_zone.cloud-run-internal.name + type = "CNAME" + ttl = 60 + + rrdatas = ["private.googleapis.com."] +} + +// Create a special DNS zone attached to the network in which +// we will operate our services that reroutes private.googleapis.com +// to records that we control. +resource "google_dns_managed_zone" "private-google-apis" { + project = var.project_id + name = "private-google-apis" + dns_name = "private.googleapis.com." + description = "This maps DNS for private.googleapis.com" + + visibility = "private" + + private_visibility_config { + networks { + network_url = google_compute_network.this.id + } + } +} + +// Create a record for private.googleapis.com that points to +// the documented internal IP addresses for the Google APIs. +resource "google_dns_record_set" "private-googleapis-a-record" { + project = var.project_id + name = "private.googleapis.com." + managed_zone = google_dns_managed_zone.private-google-apis.name + type = "A" + ttl = 60 + + // This IP range is documented here: + // https://cloud.google.com/vpc/docs/configure-private-google-access-hybrid + rrdatas = [for x in range(8, 12) : "199.36.153.${x}"] +} diff --git a/networking/main.tf b/networking/main.tf new file mode 100644 index 00000000..3487816e --- /dev/null +++ b/networking/main.tf @@ -0,0 +1,25 @@ +// Create a global network in which to place our resources. +resource "google_compute_network" "this" { + name = var.name + auto_create_subnetworks = false + routing_mode = "GLOBAL" + project = var.project_id + delete_default_routes_on_create = true +} + +// Create regional subnets in each of the specified regions, +// which we will use to operate Cloud Run services. +resource "google_compute_subnetwork" "regional" { + for_each = { + for region in var.regions : region => 1 + index(var.regions, region) + } + + name = "${var.name}-${each.key}" + + // This is needed in order to interact with Google APIs like Pub/Sub. + private_ip_google_access = true + + network = google_compute_network.this.id + region = each.key + ip_cidr_range = cidrsubnet(var.cidr, 8, each.value) +} diff --git a/networking/outputs.tf b/networking/outputs.tf new file mode 100644 index 00000000..5a4f3ce5 --- /dev/null +++ b/networking/outputs.tf @@ -0,0 +1,12 @@ +output "network_id" { + value = google_compute_network.this.id +} + +output "regional-networks" { + value = { + for region in var.regions : region => { + network = google_compute_network.this.id + subnet = google_compute_subnetwork.regional[region].name + } + } +} diff --git a/networking/variables.tf b/networking/variables.tf new file mode 100644 index 00000000..f7b0f3de --- /dev/null +++ b/networking/variables.tf @@ -0,0 +1,16 @@ +variable "name" { + type = string +} + +variable "project_id" { + type = string +} + +variable "regions" { + type = list(string) + description = "The list of regions in which to provision subnets suitable for use with Cloud Run direct VPC egress." +} + +variable "cidr" { + default = "10.0.0.0/8" +}