From 9f5d59748dec96994a6f9c9c8b23f062c3c2ed53 Mon Sep 17 00:00:00 2001 From: Miren Esnaola Date: Mon, 11 Apr 2022 10:52:51 +0200 Subject: [PATCH] Added example with GLB and Cloud Armor --- .../cloud-operations/glb_and_armor/README.md | 64 ++++ .../cloud-operations/glb_and_armor/main.tf | 308 ++++++++++++++++++ .../cloud-operations/glb_and_armor/outputs.tf | 26 ++ .../glb_and_armor/variables.tf | 41 +++ .../glb_and_armor/__init__.py | 13 + .../glb_and_armor/fixture/main.tf | 20 ++ .../glb_and_armor/fixture/variables.tf | 34 ++ .../glb_and_armor/test_plan.py | 19 ++ 8 files changed, 525 insertions(+) create mode 100644 examples/cloud-operations/glb_and_armor/README.md create mode 100644 examples/cloud-operations/glb_and_armor/main.tf create mode 100644 examples/cloud-operations/glb_and_armor/outputs.tf create mode 100644 examples/cloud-operations/glb_and_armor/variables.tf create mode 100644 tests/examples/cloud_operations/glb_and_armor/__init__.py create mode 100644 tests/examples/cloud_operations/glb_and_armor/fixture/main.tf create mode 100644 tests/examples/cloud_operations/glb_and_armor/fixture/variables.tf create mode 100644 tests/examples/cloud_operations/glb_and_armor/test_plan.py diff --git a/examples/cloud-operations/glb_and_armor/README.md b/examples/cloud-operations/glb_and_armor/README.md new file mode 100644 index 00000000..a8b73af8 --- /dev/null +++ b/examples/cloud-operations/glb_and_armor/README.md @@ -0,0 +1,64 @@ +# HTTP Load Balancer with Cloud Armor + +Google Cloud HTTP(S) load balancing is implemented at the edge of Google's network in Google's points of presence (POP) around the world. User traffic directed to an HTTP(S) load balancer enters the POP closest to the user and is then load balanced over Google's global network to the closest backend that has sufficient capacity available. + +Cloud Armor IP allowlist/denylist enable you to restrict or allow access to your HTTP(S) load balancer at the edge of the Google Cloud, as close as possible to the user and to malicious traffic. This prevents malicious users or traffic from consuming resources or entering your virtual private cloud (VPC) networks. + +In this lab, you configure an HTTP Load Balancer with global backends, as shown in the diagram below. Then, you stress test the Load Balancer and denylist the stress test IP with Cloud Armor. + +![Architecture](architecture.png) + +## Running the example + +Clone this repository or [open it in cloud shell](https://ssh.cloud.google.com/cloudshell/editor?cloudshell_git_repo=https%3A%2F%2Fgithub.com%2Fterraform-google-modules%2Fcloud-foundation-fabric&cloudshell_print=cloud-shell-readme.txt&cloudshell_working_dir=examples%2Fcloud-operations%2Fglb-and-armor), then go through the following steps to create resources: + +* `terraform init` +* `terraform apply -var project_id=my-project-id` + +The following outputs will be available once everything is deployed: + +* `glb_ip_address`, containing the IPv4 address of the HTTP Load Balancer +* `vm_siege_external_ip`, containing the external IPv4 address of the siege VM. + +Once done testing, you can clean up resources by running `terraform destroy`. + +## Testing the example + +1. Connect to the siege VM and run the following command + + siege -c 250 -t150s http://$LB_IP`ß + +2. In the Cloud Console, on the Navigation menu, click Network Services > Load balancing. +3. Click Backends. +4. Click http-backend. +5. Navigate to http-lb. +6. Click on the Monitoring tab. +7. Monitor the Frontend Location (Total inbound traffic) between North America and the two backends for 2 to 3 minutes. At first, traffic should just be directed to us-east1-mig but as the RPS increases, traffic is also directed to europe-west1-mig. This demonstrates that by default traffic is forwarded to the closest backend but if the load is very high, traffic can be distributed across the backends. +8. Re-run terraform as follows: + + terraform apply -var project_id=my-project-id -var enforce_security_policy=true + + Like this we have applied a security policy to denylist the IP address of the siege VM + +9. From the siege VM run the following command and verify that you get a 403 Forbidden error code back. + + curl http://$LB_IP + + +## Variables + +| name | description | type | required | default | +|---|---|:---:|:---:|:---:| +| [project_id](variables.tf#L26) | Identifier of the project. | string | ✓ | | +| [enforce_security_policy](variables.tf#L31) | Enforce security policy. | bool | | true | +| [prefix](variables.tf#L37) | Prefix used for created resources. | string | | null | +| [project_create](variables.tf#L17) | Parameters for the creation of the new project. | object({…}) | | null | + +## Outputs + +| name | description | sensitive | +|---|---|:---:| +| [glb_ip_address](outputs.tf#L18) | Load balancer IP address. | | +| [vm_siege_external_ip](outputs.tf#L23) | Siege VM external IP address. | | + + diff --git a/examples/cloud-operations/glb_and_armor/main.tf b/examples/cloud-operations/glb_and_armor/main.tf new file mode 100644 index 00000000..56dfac6f --- /dev/null +++ b/examples/cloud-operations/glb_and_armor/main.tf @@ -0,0 +1,308 @@ +/** + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +locals { + prefix = (var.prefix == null || var.prefix == "") ? "" : "${var.prefix}-" +} + +module "project" { + source = "../../../modules/project" + billing_account = (var.project_create != null + ? var.project_create.billing_account_id + : null + ) + parent = (var.project_create != null + ? var.project_create.parent + : null + ) + prefix = var.project_create == null ? null : var.prefix + name = var.project_id + services = [ + "compute.googleapis.com" + ] + service_config = { + disable_on_destroy = false + disable_dependent_services = false + } + project_create = var.project_create != null +} + + +module "vpc" { + source = "../../../modules/net-vpc" + project_id = module.project.project_id + name = "${local.prefix}vpc" + subnets = [ + { + ip_cidr_range = "10.0.1.0/24" + name = "subnet-ew1" + region = "europe-west1" + secondary_ip_range = null + }, + { + ip_cidr_range = "10.0.2.0/24" + name = "subnet-ue1" + region = "us-east1" + secondary_ip_range = null + }, + { + ip_cidr_range = "10.0.3.0/24" + name = "subnet-uw1" + region = "us-west1" + secondary_ip_range = null + } + ] +} + +module "firewall" { + source = "../../../modules/net-vpc-firewall" + project_id = module.project.project_id + network = module.vpc.name +} + +module "nat_ew1" { + source = "../../../modules/net-cloudnat" + project_id = module.project.project_id + region = "europe-west1" + name = "${local.prefix}nat-eu1" + router_network = module.vpc.name +} + +module "nat_ue1" { + source = "../../../modules/net-cloudnat" + project_id = module.project.project_id + region = "us-east1" + name = "${local.prefix}nat-ue1" + router_network = module.vpc.name +} + +module "instance_template_ew1" { + source = "../../../modules/compute-vm" + project_id = module.project.project_id + zone = "europe-west1-b" + name = "${local.prefix}europe-west1-template" + instance_type = "n1-standard-2" + network_interfaces = [{ + network = module.vpc.self_link + subnetwork = module.vpc.subnet_self_links["europe-west1/subnet-ew1"] + nat = false + addresses = null + }] + boot_disk = { + image = "projects/debian-cloud/global/images/family/debian-11" + type = "pd-ssd" + size = 10 + } + metadata = { + startup-script-url = "gs://cloud-training/gcpnet/httplb/startup.sh" + } + create_template = true + tags = [ + "http-server" + ] +} + +module "instance_template_ue1" { + source = "../../../modules/compute-vm" + project_id = module.project.project_id + zone = "us-east1-b" + name = "${local.prefix}us-east1-template" + network_interfaces = [{ + network = module.vpc.self_link + subnetwork = module.vpc.subnet_self_links["us-east1/subnet-ue1"] + nat = false + addresses = null + }] + boot_disk = { + image = "projects/debian-cloud/global/images/family/debian-11" + type = "pd-ssd" + size = 10 + } + metadata = { + startup-script-url = "gs://cloud-training/gcpnet/httplb/startup.sh" + } + create_template = true + tags = [ + "http-server" + ] +} + +module "vm_siege" { + source = "../../../modules/compute-vm" + project_id = module.project.project_id + zone = "us-west1-c" + name = "siege-vm" + instance_type = "n1-standard-2" + network_interfaces = [{ + network = module.vpc.self_link + subnetwork = module.vpc.subnet_self_links["us-west1/subnet-uw1"] + nat = true + addresses = null + }] + boot_disk = { + image = "projects/debian-cloud/global/images/family/debian-11" + type = "pd-ssd" + size = 10 + } + metadata = { + startup-script = <