Added example with GLB and Cloud Armor
This commit is contained in:
parent
22d0506f4d
commit
9f5d59748d
|
@ -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
|
||||
<!-- BEGIN TFDOC -->
|
||||
|
||||
## Variables
|
||||
|
||||
| name | description | type | required | default |
|
||||
|---|---|:---:|:---:|:---:|
|
||||
| [project_id](variables.tf#L26) | Identifier of the project. | <code>string</code> | ✓ | |
|
||||
| [enforce_security_policy](variables.tf#L31) | Enforce security policy. | <code>bool</code> | | <code>true</code> |
|
||||
| [prefix](variables.tf#L37) | Prefix used for created resources. | <code>string</code> | | <code>null</code> |
|
||||
| [project_create](variables.tf#L17) | Parameters for the creation of the new project. | <code title="object({ billing_account_id = string parent = string })">object({…})</code> | | <code>null</code> |
|
||||
|
||||
## 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. | |
|
||||
|
||||
<!-- END TFDOC -->
|
|
@ -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 = <<EOT
|
||||
#!/bin/bash
|
||||
|
||||
apt update -y
|
||||
apt install -y siege
|
||||
EOT
|
||||
}
|
||||
tags = [
|
||||
"ssh"
|
||||
]
|
||||
}
|
||||
|
||||
module "mig_ew1" {
|
||||
source = "../../../modules/compute-mig"
|
||||
project_id = module.project.project_id
|
||||
location = "europe-west1"
|
||||
name = "${local.prefix}europe-west1-mig"
|
||||
regional = true
|
||||
default_version = {
|
||||
instance_template = module.instance_template_ew1.template.self_link
|
||||
name = "default"
|
||||
}
|
||||
autoscaler_config = {
|
||||
max_replicas = 5
|
||||
min_replicas = 1
|
||||
cooldown_period = 45
|
||||
cpu_utilization_target = 0.8
|
||||
load_balancing_utilization_target = null
|
||||
metric = null
|
||||
}
|
||||
named_ports = {
|
||||
http = 80
|
||||
}
|
||||
depends_on = [
|
||||
module.nat_ew1
|
||||
]
|
||||
}
|
||||
|
||||
module "mig_ue1" {
|
||||
source = "../../../modules/compute-mig"
|
||||
project_id = module.project.project_id
|
||||
location = "us-east1"
|
||||
name = "${local.prefix}us-east1-mig"
|
||||
regional = true
|
||||
default_version = {
|
||||
instance_template = module.instance_template_ue1.template.self_link
|
||||
name = "default"
|
||||
}
|
||||
autoscaler_config = {
|
||||
max_replicas = 5
|
||||
min_replicas = 1
|
||||
cooldown_period = 45
|
||||
cpu_utilization_target = 0.8
|
||||
load_balancing_utilization_target = null
|
||||
metric = null
|
||||
}
|
||||
named_ports = {
|
||||
http = 80
|
||||
}
|
||||
depends_on = [
|
||||
module.nat_ue1
|
||||
]
|
||||
}
|
||||
|
||||
module "glb" {
|
||||
source = "../../../modules/net-glb"
|
||||
name = "${local.prefix}http-lb"
|
||||
project_id = module.project.project_id
|
||||
backend_services_config = {
|
||||
http-backend = {
|
||||
bucket_config = null
|
||||
enable_cdn = false
|
||||
cdn_config = null
|
||||
group_config = {
|
||||
backends = [
|
||||
{
|
||||
group = module.mig_ew1.group_manager.instance_group
|
||||
options = null
|
||||
},
|
||||
{
|
||||
group = module.mig_ue1.group_manager.instance_group
|
||||
options = null
|
||||
}
|
||||
],
|
||||
health_checks = ["hc"]
|
||||
log_config = {
|
||||
enable = true
|
||||
sample_rate = 1
|
||||
}
|
||||
options = {
|
||||
affinity_cookie_ttl_sec = null
|
||||
custom_request_headers = null
|
||||
custom_response_headers = null
|
||||
connection_draining_timeout_sec = null
|
||||
load_balancing_scheme = null
|
||||
locality_lb_policy = null
|
||||
port_name = "http"
|
||||
security_policy = try(google_compute_security_policy.policy[0].name, null)
|
||||
session_affinity = null
|
||||
timeout_sec = null
|
||||
circuits_breakers = null
|
||||
consistent_hash = null
|
||||
iap = null
|
||||
protocol = "HTTP"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
health_checks_config = {
|
||||
hc = {
|
||||
type = "http"
|
||||
logging = true
|
||||
options = null
|
||||
check = {
|
||||
port_name = "http"
|
||||
port_specification = "USE_NAMED_PORT"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_security_policy" "policy" {
|
||||
count = var.enforce_security_policy ? 1 : 0
|
||||
name = "${local.prefix}denylist-siege"
|
||||
project = module.project.project_id
|
||||
rule {
|
||||
action = "deny(403)"
|
||||
priority = "1000"
|
||||
match {
|
||||
versioned_expr = "SRC_IPS_V1"
|
||||
config {
|
||||
src_ip_ranges = [module.vm_siege.external_ip]
|
||||
}
|
||||
}
|
||||
description = "Deny access to siege VM IP"
|
||||
}
|
||||
rule {
|
||||
action = "allow"
|
||||
priority = "2147483647"
|
||||
match {
|
||||
versioned_expr = "SRC_IPS_V1"
|
||||
config {
|
||||
src_ip_ranges = ["*"]
|
||||
}
|
||||
}
|
||||
description = "default rule"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
output "glb_ip_address" {
|
||||
description = "Load balancer IP address."
|
||||
value = module.glb.global_forwarding_rule.ip_address
|
||||
}
|
||||
|
||||
output "vm_siege_external_ip" {
|
||||
description = "Siege VM external IP address."
|
||||
value = module.vm_siege.external_ip
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
variable "project_create" {
|
||||
description = "Parameters for the creation of the new project."
|
||||
type = object({
|
||||
billing_account_id = string
|
||||
parent = string
|
||||
})
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
description = "Identifier of the project."
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "enforce_security_policy" {
|
||||
description = "Enforce security policy."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "prefix" {
|
||||
description = "Prefix used for created resources."
|
||||
type = string
|
||||
default = null
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
# 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.
|
|
@ -0,0 +1,20 @@
|
|||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
module "test" {
|
||||
source = "../../../../../examples/cloud-operations/glb_and_armor"
|
||||
project_create = var.project_create
|
||||
project_id = var.project_id
|
||||
enforce_security_policy = var.enforce_security_policy
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
variable "project_create" {
|
||||
type = object({
|
||||
billing_account_id = string
|
||||
parent = string
|
||||
})
|
||||
default = {
|
||||
billing_account_id = "123456789"
|
||||
parent = "organizations/123456789"
|
||||
}
|
||||
}
|
||||
|
||||
variable "project_id" {
|
||||
type = string
|
||||
default = "project-1"
|
||||
}
|
||||
|
||||
variable "enforce_security_policy" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# 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.
|
||||
|
||||
def test_resources(e2e_plan_runner):
|
||||
"Test that plan works and the numbers of resources is as expected."
|
||||
modules, resources = e2e_plan_runner()
|
||||
assert len(modules) == 11
|
||||
assert len(resources) == 25
|
Loading…
Reference in New Issue