From 49d897533bfda8d96a8d0e80ba1ee37d9c38641f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 19 Oct 2023 06:29:50 +0200 Subject: [PATCH 1/7] feat: allow metrics to be exposed publicly --- README.md | 1 + main.tf | 10 ++++++++++ variables.tf | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/README.md b/README.md index a99778d..8bb8938 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,7 @@ You can check the status of the certificate in the Google Cloud Console. | [domain](#input\_domain) | Domain to associate Atlantis with and to request a managed SSL certificate for. Without `https://` | `string` | n/a | yes | | [enable\_oslogin](#input\_enable\_oslogin) | Enables OS Login service on the VM | `bool` | `false` | no | | [env\_vars](#input\_env\_vars) | Key-value pairs representing environment variables and their respective values | `map(any)` | n/a | yes | +| [expose\_metrics\_publicly](#input\_expose\_metrics\_publicly) | Exposes the /metrics endpoint publicly even if Atlantis is protected by IAP | `bool` | `false` | no | | [iap](#input\_iap) | Settings for enabling Cloud Identity Aware Proxy to protect the Atlantis UI |
object({
oauth2_client_id = string
oauth2_client_secret = string
})
| `null` | no | | [image](#input\_image) | Docker image. This is most often a reference to a container located in a container registry | `string` | `"ghcr.io/runatlantis/atlantis:latest"` | no | | [labels](#input\_labels) | Key-value pairs representing labels attaching to instance & instance template | `map(any)` | `{}` | no | diff --git a/main.tf b/main.tf index 5193d79..d8c2653 100644 --- a/main.tf +++ b/main.tf @@ -362,6 +362,16 @@ resource "google_compute_url_map" "default" { } } + # As Atlantis uses the `/metrics` path to expose certain metrics + # we should make it possible to access it without IAP. + dynamic "host_rule" { + for_each = var.iap != null && var.expose_metrics_publicly ? [1] : [] + content { + hosts = [var.domain] + path_matcher = "metrics" + } + } + dynamic "path_matcher" { for_each = var.iap != null ? [1] : [] content { diff --git a/variables.tf b/variables.tf index 265c7b8..9ff201a 100644 --- a/variables.tf +++ b/variables.tf @@ -140,6 +140,12 @@ variable "project" { default = null } +variable "expose_metrics_publicly" { + type = bool + description = "Exposes the /metrics endpoint publicly even if Atlantis is protected by IAP" + default = false +} + variable "labels" { type = map(any) description = "Key-value pairs representing labels attaching to instance & instance template" From 5366367fd7f476e5992b446d713b12a4f9eb92b4 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 19 Oct 2023 06:31:32 +0200 Subject: [PATCH 2/7] feat: add path matcher for `/metrics` --- main.tf | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index d8c2653..ba95716 100644 --- a/main.tf +++ b/main.tf @@ -362,6 +362,18 @@ resource "google_compute_url_map" "default" { } } + dynamic "path_matcher" { + for_each = var.iap != null ? [1] : [] + content { + name = "events" + default_service = google_compute_backend_service.iap[0].id + path_rule { + paths = ["/events"] + service = google_compute_backend_service.default.id + } + } + } + # As Atlantis uses the `/metrics` path to expose certain metrics # we should make it possible to access it without IAP. dynamic "host_rule" { @@ -375,10 +387,10 @@ resource "google_compute_url_map" "default" { dynamic "path_matcher" { for_each = var.iap != null ? [1] : [] content { - name = "events" + name = "metrics" default_service = google_compute_backend_service.iap[0].id path_rule { - paths = ["/events"] + paths = ["/metrics"] service = google_compute_backend_service.default.id } } From a931761e47f2615d1d7323849281b95b2cbfd7e8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Wed, 25 Oct 2023 21:38:17 +0200 Subject: [PATCH 3/7] chore: add condition to metrics path matcher too --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index ba95716..a4fa41b 100644 --- a/main.tf +++ b/main.tf @@ -385,7 +385,7 @@ resource "google_compute_url_map" "default" { } dynamic "path_matcher" { - for_each = var.iap != null ? [1] : [] + for_each = var.iap != null && var.expose_metrics_publicly ? [1] : [] content { name = "metrics" default_service = google_compute_backend_service.iap[0].id From 6d4893e10c70b2bb6e1b8a5f3a4ee02c5b0fcd4c Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Wed, 25 Oct 2023 21:48:07 +0200 Subject: [PATCH 4/7] feat: merge path matchers and use a single host rule - API was complaining --- main.tf | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/main.tf b/main.tf index a4fa41b..8bc3c6a 100644 --- a/main.tf +++ b/main.tf @@ -358,40 +358,26 @@ resource "google_compute_url_map" "default" { for_each = var.iap != null ? [1] : [] content { hosts = [var.domain] - path_matcher = "events" + path_matcher = "public" } } dynamic "path_matcher" { for_each = var.iap != null ? [1] : [] content { - name = "events" + name = "public" default_service = google_compute_backend_service.iap[0].id path_rule { paths = ["/events"] service = google_compute_backend_service.default.id } - } - } - - # As Atlantis uses the `/metrics` path to expose certain metrics - # we should make it possible to access it without IAP. - dynamic "host_rule" { - for_each = var.iap != null && var.expose_metrics_publicly ? [1] : [] - content { - hosts = [var.domain] - path_matcher = "metrics" - } - } - dynamic "path_matcher" { - for_each = var.iap != null && var.expose_metrics_publicly ? [1] : [] - content { - name = "metrics" - default_service = google_compute_backend_service.iap[0].id - path_rule { - paths = ["/metrics"] - service = google_compute_backend_service.default.id + dynamic "path_rule" { + for_each = var.expose_metrics_publicly ? [1] : [] + content { + paths = ["/metrics"] + service = google_compute_backend_service.default.id + } } } } From b556e7131d963d2d258120f75eb03c8aab20d0b5 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 19 Oct 2023 06:16:35 +0200 Subject: [PATCH 5/7] chore: bump google cloud provider version to 4.79.0 and add the google-beta provider --- README.md | 5 +++-- versions.tf | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0c5c76..60bcbdd 100644 --- a/README.md +++ b/README.md @@ -179,7 +179,8 @@ You can check the status of the certificate in the Google Cloud Console. |------|---------| | [terraform](#requirement\_terraform) | >= 0.13.0 | | [cloudinit](#requirement\_cloudinit) | >=2.2.0 | -| [google](#requirement\_google) | >=4.47.0 | +| [google](#requirement\_google) | >=4.79.0 | +| [google-beta](#requirement\_google-beta) | >=4.79.0 | | [random](#requirement\_random) | >=3.4.3 | ## Providers @@ -187,7 +188,7 @@ You can check the status of the certificate in the Google Cloud Console. | Name | Version | |------|---------| | [cloudinit](#provider\_cloudinit) | >=2.2.0 | -| [google](#provider\_google) | >=4.47.0 | +| [google](#provider\_google) | >=4.79.0 | | [random](#provider\_random) | >=3.4.3 | ## Modules diff --git a/versions.tf b/versions.tf index 64b8914..d184637 100644 --- a/versions.tf +++ b/versions.tf @@ -4,7 +4,11 @@ terraform { required_providers { google = { source = "hashicorp/google" - version = ">=4.47.0" + version = ">=4.79.0" + } + google-beta = { + source = "hashicorp/google-beta" + version = ">=4.79.0" } cloudinit = { source = "hashicorp/cloudinit" From d5d6d9ee21f2e3716ed30d10a0760ba1b2633104 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 19 Oct 2023 06:17:15 +0200 Subject: [PATCH 6/7] chore: refactor locals and add labels (using the beta provider too) --- README.md | 3 ++- main.tf | 54 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 60bcbdd..5acd35e 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ You can check the status of the certificate in the Google Cloud Console. |------|---------| | [cloudinit](#provider\_cloudinit) | >=2.2.0 | | [google](#provider\_google) | >=4.79.0 | +| [google-beta](#provider\_google-beta) | >=4.79.0 | | [random](#provider\_random) | >=3.4.3 | ## Modules @@ -201,6 +202,7 @@ You can check the status of the certificate in the Google Cloud Console. | Name | Type | |------|------| +| [google-beta_google_compute_instance_group_manager.default](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_compute_instance_group_manager) | resource | | [google_compute_backend_service.default](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_backend_service) | resource | | [google_compute_backend_service.iap](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_backend_service) | resource | | [google_compute_firewall.lb_health_check](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_firewall) | resource | @@ -208,7 +210,6 @@ You can check the status of the certificate in the Google Cloud Console. | [google_compute_global_forwarding_rule.https](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_global_forwarding_rule) | resource | | [google_compute_health_check.default](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_health_check) | resource | | [google_compute_health_check.default_instance_group_manager](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_health_check) | resource | -| [google_compute_instance_group_manager.default](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_group_manager) | resource | | [google_compute_instance_template.default](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_template) | resource | | [google_compute_managed_ssl_certificate.default](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_managed_ssl_certificate) | resource | | [google_compute_route.public_internet](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_route) | resource | diff --git a/main.tf b/main.tf index 8bc3c6a..4a3bed4 100644 --- a/main.tf +++ b/main.tf @@ -1,11 +1,16 @@ locals { - # The default port that Atlantis runs on is 4141. + # The default port that Atlantis runs on is 4141, we default to this. atlantis_port = lookup(var.env_vars, "ATLANTIS_PORT", 4141) - # Atlantis its home directory is "/home/atlantis". - atlantis_data_dir = lookup(var.env_vars, "ATLANTIS_DATA_DIR", "/home/atlantis") - port_name = "atlantis" - network_traffic_tags = ["atlantis-${random_string.random.result}"] - labels = merge(var.labels, { "container-vm" = module.container.vm_container_label }) + # Atlantis its home directory is "/home/atlantis", we default to this. + atlantis_data_dir = lookup(var.env_vars, "ATLANTIS_DATA_DIR", "/home/atlantis") + atlantis_port_name = "atlantis" + atlantis_network_traffic_tags = ["atlantis-${random_string.random.result}"] + atlantis_labels = merge( + var.labels, + module.container.container_vm.labels, + { "vm" = module.container.container_vm.name }, + { "app" = "atlantis" } + ) } resource "random_string" "random" { @@ -146,7 +151,12 @@ resource "google_compute_instance_template" "default" { boot = true disk_type = "pd-ssd" disk_size_gb = 10 - labels = local.labels + labels = merge( + local.atlantis_labels, + { + "disk-type" = "boot" + }, + ) dynamic "disk_encryption_key" { for_each = var.disk_kms_key_self_link != null ? [1] : [] @@ -163,7 +173,12 @@ resource "google_compute_instance_template" "default" { mode = "READ_WRITE" disk_size_gb = var.persistent_disk_size_gb auto_delete = false - labels = local.labels + labels = merge( + local.atlantis_labels, + { + "disk-type" = "data" + }, + ) dynamic "disk_encryption_key" { for_each = var.disk_kms_key_self_link != null ? [1] : [] @@ -189,10 +204,8 @@ resource "google_compute_instance_template" "default" { scopes = var.service_account.scopes } - tags = concat(local.network_traffic_tags, var.tags) - - labels = local.labels - + tags = concat(local.atlantis_network_traffic_tags, var.tags) + labels = local.atlantis_labels project = var.project # Instance Templates cannot be updated after creation with the Google Cloud Platform API. @@ -239,8 +252,12 @@ resource "google_compute_instance_group_manager" "default" { instance_template = google_compute_instance_template.default.id } + all_instances_config { + labels = local.atlantis_labels + } + named_port { - name = local.port_name + name = local.atlantis_port_name port = local.atlantis_port } @@ -264,7 +281,8 @@ resource "google_compute_instance_group_manager" "default" { max_unavailable_fixed = 1 replacement_method = "RECREATE" } - project = var.project + project = var.project + provider = google-beta } resource "google_compute_global_address" "default" { @@ -283,7 +301,7 @@ resource "google_compute_managed_ssl_certificate" "default" { resource "google_compute_backend_service" "default" { name = var.name protocol = "HTTP" - port_name = local.port_name + port_name = local.atlantis_port_name timeout_sec = 10 connection_draining_timeout_sec = 5 load_balancing_scheme = "EXTERNAL_MANAGED" @@ -306,7 +324,7 @@ resource "google_compute_backend_service" "iap" { count = var.iap != null ? 1 : 0 name = "${var.name}-iap" protocol = "HTTP" - port_name = local.port_name + port_name = local.atlantis_port_name timeout_sec = 10 connection_draining_timeout_sec = 5 load_balancing_scheme = "EXTERNAL_MANAGED" @@ -411,7 +429,7 @@ resource "google_compute_route" "public_internet" { next_hop_gateway = "default-internet-gateway" priority = 0 project = var.project - tags = local.network_traffic_tags + tags = local.atlantis_network_traffic_tags } # This firewall rule allows Google Cloud to issue the health checks @@ -430,5 +448,5 @@ resource "google_compute_firewall" "lb_health_check" { data.google_netblock_ip_ranges.this["legacy-health-checkers"].cidr_blocks_ipv4, )) project = var.project - target_tags = local.network_traffic_tags + target_tags = local.atlantis_network_traffic_tags } From 74bedd3a1251eb5f1f9234fab3d56b344ca940cf Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen <58337159+bschaatsbergen@users.noreply.github.com> Date: Thu, 19 Oct 2023 11:36:03 +0200 Subject: [PATCH 7/7] Update main.tf Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 4a3bed4..48e05ce 100644 --- a/main.tf +++ b/main.tf @@ -1,7 +1,7 @@ locals { # The default port that Atlantis runs on is 4141, we default to this. atlantis_port = lookup(var.env_vars, "ATLANTIS_PORT", 4141) - # Atlantis its home directory is "/home/atlantis", we default to this. + # Atlantis' home directory is "/home/atlantis", we default to this. atlantis_data_dir = lookup(var.env_vars, "ATLANTIS_DATA_DIR", "/home/atlantis") atlantis_port_name = "atlantis" atlantis_network_traffic_tags = ["atlantis-${random_string.random.result}"]