diff --git a/examples/autoscale/README.md b/examples/autoscale/README.md deleted file mode 100644 index 1dc17374..00000000 --- a/examples/autoscale/README.md +++ /dev/null @@ -1,365 +0,0 @@ ---- -short_title: Common Firewall Option with Autoscaling -type: refarch -show_in_hub: false ---- -# Deployment of Palo Alto Networks VM-Series Firewalls with Autoscaling - -## Overview -This example deploys VM-Series firewalls withing a Managed Instance Group (MIG). The MIG enables the VM-Series to horizontally scale (i.e. do autoscaling) based on custom PAN-OS metrics that Panorama delivers to Google Cloud Monitoring. There are 10 custom metric that are delivered: -- VMSeries/DataPlaneCPUUtilizationPct -- VMSeries/panSessionConnectionsPerSecond -- VMSeries/panSessionThroughputKbps -- VMSeries/panSessionThroughputPps -- VMSeries/DataPlanePacketBufferUtilization -- VMSeries/panGPGatewayUtilizationPct -- VMSeries/panGPGWUtilizationActiveTunnels -- VMSeries/panSessionActive -- VMSeries/panSessionSslProxyUtilization -- VMSeries/panSessionUtilization - -GCP Autoscaler adds or deletes VM instances from a managed instance group based on the group's autoscaling policy that is applied in `autoscale` module - -``` -resource "google_compute_autoscaler" "zonal" { - for_each = var.regional_mig ? {} : var.zones - ... - - autoscaling_policy { - min_replicas = var.min_vmseries_replicas - max_replicas = var.max_vmseries_replicas - cooldown_period = var.cooldown_period - - dynamic "metric" { - for_each = var.autoscaler_metrics - content { - name = metric.key - type = try(metric.value.type, "GAUGE") - target = metric.value.target - } - } - - scale_in_control { - time_window_sec = var.scale_in_control_time_window_sec - max_scaled_in_replicas { - fixed = var.scale_in_control_replicas_fixed - } - } - } -} -``` - -### VM-Series licensing -When doing autoscaling there are at least 2 options for VM-Series licensing. These options are different in the way how you can free up licenses (delicense) when MIG scales in. -1. An authcode is set in VM-Series bootstrap parameters. [Delicesing can be done manually](https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/license-the-vm-series-firewall/vm-series-models/deactivate-the-licenses/deactivate-vm) -2. An authcode is assigned to Device Group through [Panorama Software Firewall License Plugin](https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management). Delicensing can happen automatically according to Software Firewall License Plugin settings. However due to how Software Firewall License Plugin works after scale-in event there is at least 1h delay before delicensing is actually happening. - -To speed up delicensing, `autoscale` module and this example introduce optional delicensing Cloud Function that works in conjunction with Software Firewall License Plugin. The Cloud Function is triggered on MIG scale-in event via pub/sub event, connects to Panorama and requests the plugin to delicense deleted VM-Series instance without any delay. - -To enable the Cloud Function use instructions below to set `delicensing_cloud_function_config`. - -### Resources created in this example - -Created resources include: -* 3 x VPC Networks (`mgmt`, `untrust/public`, and `trust/hub` VPC networks). -* 1 x Service Account -* 1 x Managed Instance Group. -* 1 x Internal TCP/UDP load balancer to distribute egress traffic to VM-Series trust/hub interfaces. -* 1 x External TCP/UDP load balancer to distribute internet inbound traffic to VM-Series untrust/public interfaces. -* 1 x Pub/Sub Topic and Subscription - - -![image](https://user-images.githubusercontent.com/2110772/188896518-1fe5abd2-1887-4c2f-bc63-95c6a03bbb4e.png) - -(Optional) Delicensing Cloud Function: - -* 1 x Log router -* 1 x Pub/Sub Topic -* 1 x Service Account -* 1 x Storage Bucket -* 1 x Serverless VPC Access connector -* 1 x Secret Manager secret -* 1 x Cloud Function - -(Optional) Test VMs: - -* N x Compute Engine VMs - -## Requirements - -1. A Panorama appliance with network connectivity over `TCP/443` & `TCP/3978` from the VM-Series MGMT interfaces. This example assumes VM-Series instances connect to Panorama over the internet. - -> If you do not have a Panorama appliance, please see `examples/panorama` to deploy Panorama on Google Cloud. - -2. A Panorama `Device Group`, `Template Stack`, and [`VM Authorization Key`](https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/bootstrap-the-vm-series-firewall/generate-the-vm-auth-key-on-panorama). These values are required to bootstrap the VM-Series firewalls to Panorama. -3. (For BYOL VM-Series licensing only) An authcode is assigned to Device Group through [Panorama Software Firewall License Plugin](https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management). - If delicensing Cloud Function is used it requires that VM-Series use Panorama Software Firewall License Plugin for licensing. - -> For information on staging Panorama for VM-Series MIGs, see: -> * [Panorama Staging for VM-Series MIGs](docs/panorama-staging-vmseries-migs.md) -> * [Autoscaling Components for Google Cloud](https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/set-up-the-vm-series-firewall-on-google-cloud-platform/autoscaling-on-google-cloud-platform/autoscaling-components-for-gcp#id17COG5060BX) - - -## Deploy - -1. Access a machine with Terraform installed or click **Open in Google Cloud Shell**. - -

- - -

- -2. Enable the required APIs, clone the Github repository, and change directories to the example build. - -``` -gcloud services enable compute.googleapis.com -git clone https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules -cd terraform-google-vmseries-modules/examples/autoscale -``` - -3. Create a file named `terraform.tfvars` in a text editor of your choice (i.e. Cloud Shell Editor, `vim`, or `nano`) or copy an existing sample `example.tfvars` file. - -4. If created from scratch, paste the variables below into your `terraform.tfvars`. Modify the values to match your environment. A description of each variable can be found in [variables.tf](variables.tf). -``` -project_id = "my-project-id" -name_prefix = "example-" -region = "us-central1" - -cidr_mgmt = "10.0.0.0/28" -cidr_untrust = "10.0.1.0/28" -cidr_trust = "10.0.2.0/28" -allowed_sources = ["0.0.0.0/0"] - -vmseries_image_name = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/vmseries-flex-byol-1023" -vmseries_instances_min = 1 -vmseries_instances_max = 2 - -panorama_address = "1.1.1.1" -panorama_device_group = "autoscale-device-group" -panorama_template_stack = "autoscale-template-stack" -panorama_vm_auth_key = "01234567890123456789" -``` -5. (Optional) If you would like to deploy zonal MIGs instead of regional MIGs, make the following changes in [`main.tf`](main.tf). - * Within `module "autoscale"`, add the `zones` parameter and set `regional_mig=false`. - * Within `module "intlb"`, configure backends parameter to use each output for `zonal_instance_group_ids`. - -
-module "autoscale" {
-  source = "PaloAltoNetworks/vmseries-modules/google//modules/autoscale"
-
-  name             = "${local.prefix}vmseries"
-  region           = "us-central1"
-  regional_mig = false
-  zones = {
-    zone1 = "us-central1-a"
-    zone2 = "us-central1-b"
-  }
-  ...
-  ...
-}
-...
-...
-module "intlb" {
-  source = "PaloAltoNetworks/vmseries-modules/google//modules/lb_internal"
-
-  name              = "${local.prefix}internal-lb"
-  network           = data.google_compute_subnetwork.trust.network
-  subnetwork        = data.google_compute_subnetwork.trust.self_link
-  all_ports         = true
-  health_check_port = 80
-  backends = {
-    backend1 = module.autoscale.zonal_instance_group_ids["zone1"]
-    backend2 = module.autoscale.zonal_instance_group_ids["zone2"]
-  }
-  allow_global_access = true
-}
-
- -6. (Optional) Configure [Panorama Software Firewall License Plugin](https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management) - -> **Note:** For delicensing Cloud Function to work it is required that -`License manager` name is exactly the same as VM-Series MIG name. - -Make sure you are using `panorama_auth_key` from Panorama Software Firewall License Plugin in `terraform.tfvars`. `panorama_vm_auth_key` should NOT be used (commented out or deleted). - -``` -# panorama_vm_auth_key = "01234567890123456789" -panorama_auth_key = "_XX__0qweryQWERTYqwertyQWERTGrp" -``` - -7. (Optional) If you would like to configure Cloud Function for VM-Series delicensing on MIG scale-in event add `delicensing_cloud_function_config` to `terraform.tfvars`. - -``` -delicensing_cloud_function_config = { - name_prefix = "abc-" - function_name = "delicensing-cfn" - panorama_address = "1.1.1.1" - panorama2_address = null - vpc_connector_network = "panorama-vpc" - vpc_connector_cidr = "10.254.190.64/28" - region = "us-central1" - bucket_location = "US" -} -``` - -> If Panorama in HA mode is used set 2nd Panorama address in `panorama2_address` parameter. - -8. (Optional) If you would like to have VMs to test autoscaling add `test_vms` to `terraform.tfvars`. - -``` - test_vms = { - "vm1" = { - "zone" : "us-central1-a" - "machine_type": "e2-micro" - } - } -``` - -9. Save your `terraform.tfvars` and deploy. - -``` -terraform init -terraform apply -``` -> **Note:** The health probes on the external load balancer be down. This is because a service must be configured behind the firewall to respond to the load balancer's health probes. - -10. (Optional) If you are using delicensing Cloud Function remember to set Panorama credentials in the Secret Manager secret created by Terraform. -Credentials use `|` as delimiter. Example: `admin|password` - -11. (Optional) Configure Security policies and NAT Run hping3 utility from test VM to generate sessions to trigger scale-out event. - -``` -hping3 -1 -i u10000 -``` - -## Reference - -### Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.3, < 2.0 | -| [google](#requirement\_google) | ~> 4.58 | - -### Providers - -| Name | Version | -|------|---------| -| [google](#provider\_google) | ~> 4.58 | - -### Modules - -| Name | Source | Version | -|------|--------|---------| -| [autoscale](#module\_autoscale) | ../../modules/autoscale/ | n/a | -| [extlb](#module\_extlb) | ../../modules/lb_external/ | n/a | -| [iam\_service\_account](#module\_iam\_service\_account) | ../../modules/iam_service_account/ | n/a | -| [intlb](#module\_intlb) | ../../modules/lb_internal/ | n/a | -| [mgmt\_cloud\_nat](#module\_mgmt\_cloud\_nat) | terraform-google-modules/cloud-nat/google | =1.2 | -| [vpc\_mgmt](#module\_vpc\_mgmt) | terraform-google-modules/network/google | ~> 4.0 | -| [vpc\_trust](#module\_vpc\_trust) | terraform-google-modules/network/google | ~> 4.0 | -| [vpc\_untrust](#module\_vpc\_untrust) | terraform-google-modules/network/google | ~> 4.0 | - -### Resources - -| Name | Type | -|------|------| -| [google_compute_instance.test_vm](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance) | resource | -| [google_service_account.test_vm](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | -| [google_compute_image.ubuntu](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_image) | data source | - -### Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [allowed\_sources](#input\_allowed\_sources) | A list of IP addresses to be added to the management network's ingress firewall rule. The IP addresses will be able to access to the VM-Series management interface. | `list(string)` | n/a | yes | -| [authcodes](#input\_authcodes) | VM-Series authcodes. | `string` | `null` | no | -| [autoscaler\_metrics](#input\_autoscaler\_metrics) | The map with the keys being metrics identifiers (e.g. custom.googleapis.com/VMSeries/panSessionUtilization).
Each of the contained objects has attribute `target` which is a numerical threshold for a scale-out or a scale-in.
Each zonal group grows until it satisfies all the targets.

Additional optional attribute `type` defines the metric as either `GAUGE` (the default), `DELTA_PER_SECOND`, or `DELTA_PER_MINUTE`.
For full specification, see the `metric` inside the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_autoscaler). | `map` |
{
"custom.googleapis.com/VMSeries/panSessionActive": {
"target": 100
}
}
| no | -| [cidr\_mgmt](#input\_cidr\_mgmt) | The CIDR range of the management subnetwork. | `string` | `"10.0.0.0/28"` | no | -| [cidr\_trust](#input\_cidr\_trust) | The CIDR range of the trust subnetwork. | `string` | `"10.0.2.0/28"` | no | -| [cidr\_untrust](#input\_cidr\_untrust) | The CIDR range of the untrust subnetwork. | `string` | `"10.0.1.0/28"` | no | -| [delicensing\_cloud\_function\_config](#input\_delicensing\_cloud\_function\_config) | Defining `delicensing_cloud_function_config` enables creation of delicesing cloud function and related resources.
The variable contains the following configuration parameters that are related to Cloud Function:
- `name_prefix` - Resource name prefix
- `function_name` - Cloud Function base name
- `region` - Cloud Function region
- `bucket_location` - Cloud Function source code bucket location
- `panorama_address` - Panorama IP address/FQDN
- `vpc_connector_network` - Panorama VPC network Name
- `vpc_connector_cidr` - VPC connector /28 CIDR.
VPC connector will be user for delicensing CFN to access Panorama VPC network.

Example:
{
name_prefix = "abc-"
function_name = "delicensing-cfn"
region = "us-central1"
bucket_location = "US"
panorama_address = "1.1.1.1"
panorama2_address = null
vpc_connector_network = "panorama-vpc"
vpc_connector_cidr = "10.10.190.0/28"
}
|
object({
name_prefix = string
function_name = string
region = string
bucket_location = string
panorama_address = string
panorama2_address = string
vpc_connector_network = string
vpc_connector_cidr = string
})
| `null` | no | -| [name\_prefix](#input\_name\_prefix) | Prefix to prepend the resource names. This is useful for identifing the created resources. | `string` | `""` | no | -| [panorama\_address](#input\_panorama\_address) | The Panorama IP address/FQDN. The Panorama must be reachable from the management VPC. This build assumes Panorama is reachable via the internet. The management VPC network uses a NAT gateway to communicate to Panorama's external IP addresses. | `string` | n/a | yes | -| [panorama\_auth\_key](#input\_panorama\_auth\_key) | Panorama authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management | `string` | `null` | no | -| [panorama\_device\_group](#input\_panorama\_device\_group) | The name of the Panorama device group that will bootstrap the VM-Series firewalls. | `string` | n/a | yes | -| [panorama\_template\_stack](#input\_panorama\_template\_stack) | The name of the Panorama template stack that will bootstrap the VM-Series firewalls. | `string` | n/a | yes | -| [panorama\_vm\_auth\_key](#input\_panorama\_vm\_auth\_key) | Panorama VM authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/bootstrap-the-vm-series-firewall/generate-the-vm-auth-key-on-panorama.html | `string` | `null` | no | -| [project\_id](#input\_project\_id) | GCP Project ID to contain the created cloud resources. | `string` | n/a | yes | -| [region](#input\_region) | GCP region | `string` | n/a | yes | -| [ssh\_keys](#input\_ssh\_keys) | VM-Series SSH keys. Format: 'admin:' | `string` | `""` | no | -| [test\_vms](#input\_test\_vms) | Test VMs

Example:
{
"vm1" = {
"zone" : "us-central1-a"
"machine_type": "e2-micro"
}
}
|
map(object({
zone = string
machine_type = string
}))
| `{}` | no | -| [vmseries\_image\_name](#input\_vmseries\_image\_name) | Link to VM-Series PAN-OS image. Can be either a full self\_link, or one of the shortened forms per the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#image). | `string` | n/a | yes | -| [vmseries\_instances\_max](#input\_vmseries\_instances\_max) | The maximum number of VM-Series that the autoscaler can scale up to. This is required when creating or updating an autoscaler. The maximum number of VM-Series should not be lower than minimal number of VM-Series. | `number` | `5` | no | -| [vmseries\_instances\_min](#input\_vmseries\_instances\_min) | The minimum number of VM-Series that the autoscaler can scale down to. This cannot be less than 0. | `number` | `2` | no | -| [vmseries\_machine\_type](#input\_vmseries\_machine\_type) | (Optional) The instance type for the VM-Series firewalls. | `string` | `"n2-standard-4"` | no | - -### Outputs - -No outputs. - - - -## Requirements - -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | >= 1.2, < 2.0 | -| [google](#requirement\_google) | ~> 4.58 | - -## Providers - -| Name | Version | -|------|---------| -| [google](#provider\_google) | 4.73.1 | - -## Modules - -| Name | Source | Version | -|------|--------|---------| -| [autoscale](#module\_autoscale) | ../../modules/autoscale/ | n/a | -| [extlb](#module\_extlb) | ../../modules/lb_external/ | n/a | -| [iam\_service\_account](#module\_iam\_service\_account) | ../../modules/iam_service_account/ | n/a | -| [intlb](#module\_intlb) | ../../modules/lb_internal/ | n/a | -| [mgmt\_cloud\_nat](#module\_mgmt\_cloud\_nat) | terraform-google-modules/cloud-nat/google | =1.2 | -| [vpc\_mgmt](#module\_vpc\_mgmt) | terraform-google-modules/network/google | ~> 4.0 | -| [vpc\_trust](#module\_vpc\_trust) | terraform-google-modules/network/google | ~> 4.0 | -| [vpc\_untrust](#module\_vpc\_untrust) | terraform-google-modules/network/google | ~> 4.0 | - -## Resources - -| Name | Type | -|------|------| -| [google_compute_instance.test_vm](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance) | resource | -| [google_compute_image.ubuntu](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_image) | data source | - -## Inputs - -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [allowed\_sources](#input\_allowed\_sources) | A list of IP addresses to be added to the management network's ingress firewall rule. The IP addresses will be able to access to the VM-Series management interface. | `list(string)` | n/a | yes | -| [autoscaler\_metrics](#input\_autoscaler\_metrics) | The map with the keys being metrics identifiers (e.g. custom.googleapis.com/VMSeries/panSessionUtilization).
Each of the contained objects has attribute `target` which is a numerical threshold for a scale-out or a scale-in.
Each zonal group grows until it satisfies all the targets.

Additional optional attribute `type` defines the metric as either `GAUGE` (the default), `DELTA_PER_SECOND`, or `DELTA_PER_MINUTE`.
For full specification, see the `metric` inside the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_autoscaler). | `map` |
{
"custom.googleapis.com/VMSeries/panSessionActive": {
"target": 100
}
}
| no | -| [cidr\_mgmt](#input\_cidr\_mgmt) | The CIDR range of the management subnetwork. | `string` | `"10.0.0.0/28"` | no | -| [cidr\_trust](#input\_cidr\_trust) | The CIDR range of the trust subnetwork. | `string` | `"10.0.2.0/28"` | no | -| [cidr\_untrust](#input\_cidr\_untrust) | The CIDR range of the untrust subnetwork. | `string` | `"10.0.1.0/28"` | no | -| [delicensing\_cloud\_function\_config](#input\_delicensing\_cloud\_function\_config) | Defining `delicensing_cloud_function_config` enables creation of delicesing cloud function and related resources.
The variable contains the following configuration parameters that are related to Cloud Function:
- name\_prefix - Resource name prefix
- function\_name - Cloud Function base name
- region - Cloud Function region
- bucket\_location - Cloud Function source code bucket location
- panorama\_ip - Panorama IP address
- vpc\_connector\_network - Panorama VPC network Name
- vpc\_connector\_cidr - VPC connector /28 CIDR.
VPC connector will be user for delicensing CFN to access Panorama VPC network.


Example:
{
name_prefix = "abc-"
function_name = "delicensing-cfn"
region = "europe-central1"
bucket_location = "EU"
panorama_ip = "1.1.1.1"
vpc_connector_network = "panorama-vpc"
vpc_connector_cidr = "10.10.190.0/28"
}
| `any` | `null` | no | -| [name\_prefix](#input\_name\_prefix) | Prefix to prepend the resource names. This is useful for identifing the created resources. | `string` | `""` | no | -| [panorama\_address](#input\_panorama\_address) | The Panorama IP/Domain address. The Panorama address must be reachable from the management VPC. This build assumes Panorama is reachable via the internet. The management VPC network uses a NAT gateway to communicate to Panorama's external IP addresses. | `string` | n/a | yes | -| [panorama\_auth\_key](#input\_panorama\_auth\_key) | Panorama authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management | `string` | `null` | no | -| [panorama\_device\_group](#input\_panorama\_device\_group) | The name of the Panorama device group that will bootstrap the VM-Series firewalls. | `string` | n/a | yes | -| [panorama\_template\_stack](#input\_panorama\_template\_stack) | The name of the Panorama template stack that will bootstrap the VM-Series firewalls. | `string` | n/a | yes | -| [panorama\_vm\_auth\_key](#input\_panorama\_vm\_auth\_key) | Panorama VM authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/bootstrap-the-vm-series-firewall/generate-the-vm-auth-key-on-panorama.html | `string` | `null` | no | -| [project\_id](#input\_project\_id) | GCP Project ID to contain the created cloud resources. | `string` | n/a | yes | -| [region](#input\_region) | GCP region | `string` | n/a | yes | -| [ssh\_keys](#input\_ssh\_keys) | VM-Series SSH keys. Format: 'admin:' | `string` | `""` | no | -| [test\_vm\_zone](#input\_test\_vm\_zone) | n/a | `string` | `""` | no | -| [test\_vms](#input\_test\_vms) | List ot test VM names | `list(string)` | `[]` | no | -| [vmseries\_image\_name](#input\_vmseries\_image\_name) | Link to VM-Series PAN-OS image. Can be either a full self\_link, or one of the shortened forms per the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#image). | `string` | n/a | yes | -| [vmseries\_instances\_max](#input\_vmseries\_instances\_max) | The maximum number of VM-Series that the autoscaler can scale up to. This is required when creating or updating an autoscaler. The maximum number of VM-Series should not be lower than minimal number of VM-Series. | `number` | `5` | no | -| [vmseries\_instances\_min](#input\_vmseries\_instances\_min) | The minimum number of VM-Series that the autoscaler can scale down to. This cannot be less than 0. | `number` | `2` | no | -| [vmseries\_machine\_type](#input\_vmseries\_machine\_type) | (Optional) The instance type for the VM-Series firewalls. | `string` | `"n2-standard-4"` | no | - -## Outputs - -No outputs. - \ No newline at end of file diff --git a/examples/autoscale/docs/panorama-staging-vmseries-migs.md b/examples/autoscale/docs/panorama-staging-vmseries-migs.md deleted file mode 100644 index 22419d7a..00000000 --- a/examples/autoscale/docs/panorama-staging-vmseries-migs.md +++ /dev/null @@ -1,359 +0,0 @@ -# Panorama Staging for VM-Series MIGs - -## Overview - -This guide describes how to configure a Panorama Device Group and Template Stack to secure the traditional hub-and-spoke network design in Google Cloud. The Device Group and Template Stack can be used to automatically bootstrap the VM-Series firewalls that are scaled through either a regional or zonal Managed Instance Group (MIG). - -Panorama is required for managing autoscaled firewalls because as firewalls are scaled, the VM-Series metadata (defined within the MIG's instance template) bootstrap the VM-Series to a Panorama Device Group and Template Stack. From there, Panorama automatically pushes the device group and template stack to the VM-Series so it is configured to handle traffic. - -

- -## Requirements - -* A Panorama appliance with PAN-OS 9.1, 10.1, or 10.2. If you do not have a Panorama appliance, consider using `examples/panorama`. - -## Create a Panorama Template & Template Stack - -In this section, we will create a Panorama template and template stack. - -1. Log into your Panorama appliance. Navigate to **Panorama → Templates → Add**. - -

- -2. Enter a name for your template. - -

- -3. Click **Add Stack** to create a template stack. - -

- -4. Enter a name for the template stack. In the **TEMPLATES** window, add the template you created in the previous step. - -

- -> **_Note:_** Template Stacks are a collection of layered templates. The VM-Series metadata field, `tplname`, must reference the name of the **template stack**, not the name of an individual template. - -## Configure Template - -In this section, we will configure the Panorama template to enable the firewalls to publish VM-Series metrics to [Cloud Monitoring](https://cloud.google.com/monitoring/docs/monitoring-overview). Then, we will configure interfaces and the Virtual Router to secure spoke networks that are within the RFC1918 address space. - -### Publish PAN-OS Metrics to Google Cloud Monitoring - -1. Click the **Device** tab. From the **Template** drop down, select the template you created in the previous step. - -

- -2. Navigate to **VM-Series → Google**. Click the gear icon. - -

- -3. Check *ON* **Publish PAN-OS metrics to Stackdriver**. Set the update interval between `1` and `5` minutes. - -

- -### Create Security Zones - -1. Click the **Network** tab. Select the template you created in the previous step from the **Template** dropdown menu. - -

- -2. Click **Zones → Add**. - -

- -3. Enter `untrust` for the zone name. Select `Layer3` for the interface type. - -

- -4. Create a second zone. Enter `trust` for the zone name. Select `Layer3` for the interface type. - -

- -### Create Virtual Router - -1. Click **Virtual Routers → Add**. Enter `VR1` for the Virtual Router name. - -

- -### Configure Untrust Interface - -1. Create the untrust dataplane interface (`ethernet1/1`). Click **Interfaces → Add Interface**. - -

- -2. Click the **Config** tab. Set the untrust interface as follows: - * **Slot** - `Slot 1` - * **Interface Name** - `ethernet1/1` - * **Interface Type** - `Layer3` - * **Virtual Router** - `VR1` - * **Security Zone** - `untrust` - -

- -3. Click the **IPv4** tab. Select **DHCP Client**. **_Check ON_** the automatic default route generation box. - -

- -### Configure Trust Interface - -1. Click **Add Interface**. - -

- -2. Click the **Config** tab. Set the trust interface as follows: - * **Slot** - `Slot 1` - * **Interface Name** - `ethernet1/2` - * **Interface Type** - `Layer3` - * **Virtual Router** - `VR1` - * **Security Zone** - `trust` - -

- -3. Click the **IPv4** tab. Select `DHCP Client`. **_Check OFF_** the automatic default route generation box. - -

- -### Configure Loopback Interface - -Google Cloud load balancers distribute traffic to the VM-Series instance group. Here we will configure a loopback interface that will handle the incoming load balancer health probes. - -1. Click **Loopback → Add**. - -

- -2. Click the **Config** tab, set the numeric suffix (i.e. `1`). Set the Virtual Router to `VR1` and the Security Zone to `trust`. - -

- -3. Click the **IPv4** tab, set a "dummy" /32 IP address (i.e. `100.64.0.1/32`). - -

- -4. Click the **Advanced** tab. Select the **Management Profile** dropdown, click **New Management Profile**. - -

- -5. Enter a name for the Management Profile. Check on the service that corresponds to your health probes port (recommended `TCP/80` or `TCP/443`). Set the **Permitted IP Addresses** to Google Cloud's dedicated health probe ranges: `35.191.0.0/16` & `130.211.0.0/22`. - -

- -6. Click **OK** on the Loopback interface creation window. Click **OK** on the security warning prompt. - -

- -### Create Static Routes on Virtual Router - -Now, we will configure the virtual router to correctly route traffic for spoke networks within the RFC1918 address space. We will also configure static routes to handle health probes from the internal load balancer. - -> **_Note:_** This guide assumes the trust subnetwork's default gateway is `10.0.2.1`. Please verify you are using the correct default gateway before proceeding. - -1. Go to **Virtual Routers → VR1 → Static Routes → Add**. - -

- -2. Configure 2 static route as follows. The routes hairpin the internal load balancer's health probe ranges (`35.191.0.0/16` & `130.211.0.0/22`) through the VM-Series trust interface `ethernet1/2` which has a default gateway of `10.0.2.1`. - -

- -3. Configure 3 static routes as follows. The routes hairpin spoke VPC traffic (within the RFC1918 space) through the VM-Series trust interface `ethernet1/2` which has a default gateway of `10.0.2.1`. - -

- -4. Your static routes should look like the image below before proceeding. - -

- -## Create a Panorama Device Group - -In this section, we will create a Panorama device group. - -1. Click **Panorama → Device Groups → Add**. - -

- -2. Enter a name for the device group. In the **REFERENCE TEMPLATES** window, add the _template stack_ you created previously. Record the name of the device group and template stack. They will be used in the VM-Series deployment to bootstrap the VM-Series to Panorama. - -

- -## Configure Device Group - -In this section, we will configure the device group's security policies to allow the load balancer's health probes and to deny all other traffic. We will then configure NAT policies to translate outbound internet traffic from the spoke networks and to translate the internal load balancer's health probes. - -### Create Health Probe Security Policy - -1. Click the **Policies** tab. Select the device group you created in the previous step from the **Device Group** dropdown menu. On the left menu, go to to **Security → Pre Rules → Add**. - -

- -2. Enter a name for the security policy. - -

- -3. Click the **Source** tab. Set the **source zone** to `Any`. Set the **source address** to `35.191.0.0/16` & `130.211.0.0/22`. - -

- -4. Click the **Destination** tab. Set the **destination zone** to `Any`. - -

- -5. Click the **Actions** tab. Set **action** to `Allow`. Set the log settings to `Log at Session End` and select your log forwarding profile (optional). - -

- -### Create Destination NAT for Internal Load Balancer Health Probes - -1. Go to **Policies → NAT → Pre Rules → Add**. Verify you are modifying the device group you previously created. - -

- -2. Enter a name for the NAT rule. - -

- -3. **_Original Packet Tab_** - * **Source Zone** - `trust` - * **Destination Zone** - `trust` - * **Destination Interface** - `ethernet1/2` (trust interface) - * **Source Address** - `35.191.0.0/16` & `130.211.0.0/22` (health-probe range) - -

- -4. **_Translated Packet Tab_** - * Source Address Translation - * **Translation Type -** `None` - * Destination Address Translation - * **Translation Type -** `Dynamic IP (with session distribution)` - * **Translated Address -** `100.64.0.1` (IP address of the loopback interface that we created previously) - -

- -### Set Predefined Security Rules to Deny and Log - -In this section, we will configure the predefined security polices to deny and log all traffic. It is important to set the intrazone-default rule to deny because all VPC to VPC traffic traverses through the same zone. - -1. Go to **Policies → Security → Default Rules**. -2. _Highlight_ the intrazone-default security policy. Click **Override**. - -

- -3. Click the **Actions** tab. Set the Action to `Deny`. Check on **Log at Session End** and select your log forwarding profile. - -

- -4. Repeat the process for the **interzone-default** rule. - - -## Commit the Changes - -1. Commit the changes to Panorama. **Commit → Commit to Panorama → Commit**. - -

- -## Gather information to bootstrap the VM-Series MIG - -In this section, we will gather information to bootstrap the VM-Series managed instance group. This information will be passed as metadata parameters within the MIG's instance template. - -1. Record the name of the **Device Group** (metadata field `dgname`) and **Template Stack** (metadata field `tplname`). -2. Generate & record a vm-auth-key. This key is authenticates newly deployed VM-Series to Panorama and enables the firewalls to be added as a managed device. - - * Log into the Terminal console/CLI of your Panorama appliance. - * Enter the following command to generate a VM Auth Key. The key lifetime can vary between 1 and 8760 hours. - -``` -request bootstrap vm-auth-key generate lifetime <1-8760> -``` - -3. Record the vm-auth-key value. This value is assigned to the vm-auth-key metadata field within the MIG's instance template. - -

- -## Configure Autoscale Module with Bootstrap to Panorama - -Below is an example of how to deploy the VM-Series MIG. The `metadata` variable is configured to bootstrap to the VM-Series firewall we just created. - -``` -data "google_compute_subnetwork" "mgmt" { - name = "mgmt-subnet" - region = "us-central1" -} - -data "google_compute_subnetwork" "untrust" { - name = "untrust-subnet" - region = "us-central1" -} - -data "google_compute_subnetwork" "trust" { - name = "trust-subnet" - region = "us-central1" -} - -module "autoscale" { - source = "PaloAltoNetworks/vmseries-modules/google//modules/autoscale" - - name = "vmseries" - region = "us-central1" - regional_mig = true - min_vmseries_replicas = 2 - max_vmseries_replicas = 5 - image = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/vmseries-flex-bundle2-1014" - create_pubsub_topic = true - service_account_email = "vmseries-sa@someproject.iam.gserviceaccount.com" - autoscaler_metrics = { - "custom.googleapis.com/VMSeries/panSessionActive" = { - target = 100 - } - } - - network_interfaces = [ - { - subnetwork = data.google_compute_subnetwork.untrust.self_link - create_public_ip = true - }, - { - subnetwork = data.google_compute_subnetwork.mgmt.self_link - create_public_ip = true - }, - { - subnetwork = data.google_compute_subnetwork.trust.self_link - create_public_ip = false - } - ] - - metadata = { - type = "dhcp-client" - op-command-modes = "mgmt-interface-swap" - vm-auth-key = "8**************2" - panorama-server = "20.4.3.65" - dgname = "google-autoscale-dg" - tplname = "google-autoscale_stack" - dhcp-send-hostname = "yes" - dhcp-send-client-id = "yes" - dhcp-accept-server-hostname = "yes" - dhcp-accept-server-domain = "yes" - dns-primary = "169.254.169.254" - dns-secondary = "8.8.8.8" - } -} -``` - -Once the deployment finishes, the bootstrapped VM-Series will appear on Panorama under **Managed Devices → Summary**. - -

- -## Community Supported - -The software and templates in the repo are released under an as-is, best effort, -support policy. This software should be seen as community supported and Palo -Alto Networks will contribute our expertise as and when possible. We do not -provide technical support or help in using or troubleshooting the components of -the project through our normal support options such as Palo Alto Networks -support teams, or ASC (Authorized Support Centers) partners and backline support -options. The underlying product used (the VM-Series firewall) by the scripts or -templates are still supported, but the support is only for the product -functionality and not for help in deploying or using the template or script -itself. Unless explicitly tagged, all projects or work posted in our GitHub -repository (at https://github.com/PaloAltoNetworks) or sites other than our -official Downloads page on https://support.paloaltonetworks.com are provided -under the best effort policy. diff --git a/examples/autoscale/example.tfvars b/examples/autoscale/example.tfvars deleted file mode 100644 index d0427603..00000000 --- a/examples/autoscale/example.tfvars +++ /dev/null @@ -1,47 +0,0 @@ -project_id = "my-project-id" -name_prefix = "example-" -region = "us-central1" - -cidr_mgmt = "10.0.0.0/28" -cidr_untrust = "10.0.1.0/28" -cidr_trust = "10.0.2.0/28" -allowed_sources = ["0.0.0.0/0"] - -vmseries_image_name = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/vmseries-flex-byol-1023" -vmseries_instances_min = 1 -vmseries_instances_max = 2 - -panorama_address = "1.1.1.1" -panorama_device_group = "autoscale-device-group" -panorama_template_stack = "autoscale-template-stack" -panorama_vm_auth_key = "01234567890123456789" - -#--------------------------------------------------------------------------------- -# (Optional) Panorama Software Firewall License Plugin - -# panorama_auth_key = "_XX__0qweryQWERTYqwertyQWERTGrp" - -#--------------------------------------------------------------------------------- -# (Optional) Delicensing Cloud Function - -# delicensing_cloud_function_config = { -# name_prefix = "abc-" -# function_name = "delicensing-cfn" -# region = "us-central1" -# bucket_location = "US" -# panorama_address = "1.1.1.1" -# panorama2_address = "2.2.2.2" -# vpc_connector_network = "panorama-vpc" -# vpc_connector_cidr = "10.10.190.0/28" -# } - -#--------------------------------------------------------------------------------- -# (Optional) Test VMs - -# test_vms = { -# "vm1" = { -# "zone" : "us-central1-a" -# "machine_type": "e2-micro" -# } -# } - diff --git a/examples/autoscale/main.tf b/examples/autoscale/main.tf deleted file mode 100644 index bf855c78..00000000 --- a/examples/autoscale/main.tf +++ /dev/null @@ -1,254 +0,0 @@ -# Create mgmt, untrust, and trust VPC networks. -# It is recommended to have the management network preconfigured with network access -# to Panorama. All autoscale deployments require Panorama. -module "vpc_mgmt" { - source = "terraform-google-modules/network/google" - version = "~> 4.0" - project_id = var.project_id - network_name = "${var.name_prefix}mgmt-vpc" - routing_mode = "GLOBAL" - - subnets = [ - { - subnet_name = "${var.name_prefix}${var.region}-mgmt" - subnet_ip = var.cidr_mgmt - subnet_region = var.region - } - ] - - firewall_rules = [ - { - name = "${var.name_prefix}vmseries-mgmt" - direction = "INGRESS" - priority = "100" - description = "Allow ingress access to VM-Series management interface" - ranges = var.allowed_sources - allow = [ - { - protocol = "tcp" - ports = ["22", "443", "3978"] - } - ] - } - ] -} - -module "vpc_untrust" { - source = "terraform-google-modules/network/google" - version = "~> 4.0" - project_id = var.project_id - network_name = "${var.name_prefix}untrust-vpc" - routing_mode = "GLOBAL" - - subnets = [ - { - subnet_name = "${var.name_prefix}${var.region}-untrust" - subnet_ip = var.cidr_untrust - subnet_region = var.region - } - ] - - firewall_rules = [ - { - name = "${var.name_prefix}allow-all-untrust" - direction = "INGRESS" - priority = "100" - ranges = ["0.0.0.0/0"] - allow = [ - { - protocol = "all" - ports = [] - } - ] - } - ] -} - -module "vpc_trust" { - source = "terraform-google-modules/network/google" - version = "~> 4.0" - project_id = var.project_id - network_name = "${var.name_prefix}trust-vpc" - routing_mode = "GLOBAL" - delete_default_internet_gateway_routes = true - - subnets = [ - { - subnet_name = "${var.name_prefix}${var.region}-trust" - subnet_ip = var.cidr_trust - subnet_region = var.region - } - ] - - firewall_rules = [ - { - name = "${var.name_prefix}allow-all-trust" - direction = "INGRESS" - priority = "100" - ranges = ["0.0.0.0/0"] - allow = [ - { - protocol = "all" - ports = [] - } - ] - } - ] - - routes = [ - { - name = "default-trust" - destination_range = "0.0.0.0/0" - next_hop_ilb = module.intlb.forwarding_rule - } - ] -} - -# IAM service account for running GCP instances of Palo Alto Networks VM-Series and their GCP plugin access. -module "iam_service_account" { - source = "../../modules/iam_service_account/" - - project_id = var.project_id - service_account_id = "${var.name_prefix}vmseries-mig-sa" -} - -# Create VM-Series managed instance group for autoscaling -module "autoscale" { - source = "../../modules/autoscale/" - - project_id = var.project_id - name = "${var.name_prefix}vmseries" - region = var.region - regional_mig = true - create_pubsub_topic = true - autoscaler_metrics = var.autoscaler_metrics - min_vmseries_replicas = var.vmseries_instances_min # min firewalls per region. - max_vmseries_replicas = var.vmseries_instances_max # max firewalls per region. - image = var.vmseries_image_name - machine_type = var.vmseries_machine_type - service_account_email = module.iam_service_account.email - target_pools = [module.extlb.target_pool] - - delicensing_cloud_function_config = try(var.delicensing_cloud_function_config, null) - - network_interfaces = [ - { - subnetwork = module.vpc_untrust.subnets_self_links[0] - create_public_ip = true - }, - { - subnetwork = module.vpc_mgmt.subnets_self_links[0] - create_public_ip = true - }, - { - subnetwork = module.vpc_trust.subnets_self_links[0] - create_public_ip = false - } - ] - - metadata = { - type = "dhcp-client" - op-command-modes = "mgmt-interface-swap" - panorama-server = var.panorama_address - dgname = var.panorama_device_group - tplname = var.panorama_template_stack - dhcp-send-hostname = "yes" - dhcp-send-client-id = "yes" - dhcp-accept-server-hostname = "yes" - dhcp-accept-server-domain = "yes" - dns-primary = "169.254.169.254" # Google DNS required to deliver PAN-OS metrics to Cloud Monitoring - ssh-keys = var.ssh_keys - vm-auth-key = var.panorama_vm_auth_key - authcodes = var.authcodes - auth-key = var.panorama_auth_key - plugin-op-commands = var.panorama_auth_key != null ? "panorama-licensing-mode-on" : null - } - - depends_on = [ - module.mgmt_cloud_nat - ] -} - -# Internal Network Load Balancer to distribute traffic to VM-Series trust interfaces -module "intlb" { - source = "../../modules/lb_internal/" - - name = "${var.name_prefix}internal-lb" - region = var.region - network = module.vpc_trust.network_id - subnetwork = module.vpc_trust.subnets_self_links[0] - all_ports = true - health_check_port = 80 - backends = { - backend = module.autoscale.regional_instance_group_id - } - allow_global_access = true -} - -# External Network Load Balancer to distribute traffic to VM-Series untrust interfaces -module "extlb" { - source = "../../modules/lb_external/" - - name = "${var.name_prefix}external-lb" - rules = { ("${var.name_prefix}rule0") = { port_range = 80 } } - - health_check_http_port = 80 - health_check_http_request_path = "/" -} - -# Cloud NAT for the management interfaces. It is required in the management network to provide -# connectivity to Cortex Data Lakeand to license the VM-Series from the PANW licensing servers. -module "mgmt_cloud_nat" { - source = "terraform-google-modules/cloud-nat/google" - version = "=1.2" - - name = "${var.name_prefix}mgmt-nat" - project_id = var.project_id - region = var.region - create_router = true - router = "${var.name_prefix}mgmt-router" - network = module.vpc_mgmt.network_id -} - - -#--------------------------------------------------------------------------------- -# The following VM(s) emulate clients - -data "google_compute_image" "ubuntu" { - family = "ubuntu-pro-2204-lts" - project = "ubuntu-os-pro-cloud" -} - -resource "google_service_account" "test_vm" { - count = length(var.test_vms) > 0 ? 1 : 0 - account_id = "${var.name_prefix}test-vm-sa" - display_name = "Test VM Service Account" -} - -resource "google_compute_instance" "test_vm" { - for_each = var.test_vms - - name = "${var.name_prefix}${each.key}" - machine_type = each.value.machine_type - zone = each.value.zone - - boot_disk { - initialize_params { - image = data.google_compute_image.ubuntu.id - size = "10" - } - } - - network_interface { - subnetwork = module.vpc_trust.subnets_self_links[0] - } - - metadata = { - enable-oslogin = true - } - - service_account { - email = google_service_account.test_vm[0].email - scopes = ["cloud-platform"] - } -} \ No newline at end of file diff --git a/examples/autoscale/outputs.tf b/examples/autoscale/outputs.tf deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/autoscale/variables.tf b/examples/autoscale/variables.tf deleted file mode 100644 index 44479052..00000000 --- a/examples/autoscale/variables.tf +++ /dev/null @@ -1,186 +0,0 @@ -variable "project_id" { - description = "GCP Project ID to contain the created cloud resources." - type = string -} - -variable "name_prefix" { - description = "Prefix to prepend the resource names. This is useful for identifing the created resources." - type = string - default = "" -} - -variable "region" { - description = "GCP region" - type = string -} - -variable "allowed_sources" { - description = "A list of IP addresses to be added to the management network's ingress firewall rule. The IP addresses will be able to access to the VM-Series management interface." - type = list(string) -} - -variable "vmseries_image_name" { - description = " Link to VM-Series PAN-OS image. Can be either a full self_link, or one of the shortened forms per the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance#image)." - type = string - #default = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/vmseries-flex-bundle2-1014" -} - -variable "vmseries_instances_min" { - description = "The minimum number of VM-Series that the autoscaler can scale down to. This cannot be less than 0." - type = number - default = 2 -} - -variable "vmseries_instances_max" { - description = "The maximum number of VM-Series that the autoscaler can scale up to. This is required when creating or updating an autoscaler. The maximum number of VM-Series should not be lower than minimal number of VM-Series." - type = number - default = 5 -} - -variable "ssh_keys" { - type = string - default = "" - description = "VM-Series SSH keys. Format: 'admin:'" -} - -variable "panorama_address" { - description = "The Panorama IP address/FQDN. The Panorama must be reachable from the management VPC. This build assumes Panorama is reachable via the internet. The management VPC network uses a NAT gateway to communicate to Panorama's external IP addresses." - type = string -} - -variable "panorama_device_group" { - description = "The name of the Panorama device group that will bootstrap the VM-Series firewalls." - type = string -} - -variable "panorama_template_stack" { - description = "The name of the Panorama template stack that will bootstrap the VM-Series firewalls." - type = string -} - -variable "panorama_vm_auth_key" { - description = "Panorama VM authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/10-1/vm-series-deployment/bootstrap-the-vm-series-firewall/generate-the-vm-auth-key-on-panorama.html" - type = string - default = null -} - -variable "authcodes" { - description = "VM-Series authcodes." - type = string - default = null -} - -variable "panorama_auth_key" { - description = "Panorama authorization key. To generate, follow this guide https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management" - type = string - default = null -} - -variable "vmseries_machine_type" { - description = "(Optional) The instance type for the VM-Series firewalls." - type = string - default = "n2-standard-4" -} - -variable "autoscaler_metrics" { - description = <<-EOF - The map with the keys being metrics identifiers (e.g. custom.googleapis.com/VMSeries/panSessionUtilization). - Each of the contained objects has attribute `target` which is a numerical threshold for a scale-out or a scale-in. - Each zonal group grows until it satisfies all the targets. - - Additional optional attribute `type` defines the metric as either `GAUGE` (the default), `DELTA_PER_SECOND`, or `DELTA_PER_MINUTE`. - For full specification, see the `metric` inside the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_autoscaler). - EOF - default = { - "custom.googleapis.com/VMSeries/panSessionActive" = { - target = 100 - } - } -} - -variable "cidr_mgmt" { - description = "The CIDR range of the management subnetwork." - type = string - default = "10.0.0.0/28" -} - -variable "cidr_untrust" { - description = "The CIDR range of the untrust subnetwork." - type = string - default = "10.0.1.0/28" -} - -variable "cidr_trust" { - description = "The CIDR range of the trust subnetwork." - type = string - default = "10.0.2.0/28" -} - -#--------------------------------------------------------------------------------- -# The following variables are used for delicensing Cloud Function - -variable "delicensing_cloud_function_config" { - description = <<-EOF - Defining `delicensing_cloud_function_config` enables creation of delicesing cloud function and related resources. - The variable contains the following configuration parameters that are related to Cloud Function: - - `name_prefix` - Resource name prefix - - `function_name` - Cloud Function base name - - `region` - Cloud Function region - - `bucket_location` - Cloud Function source code bucket location - - `panorama_address` - Panorama IP address/FQDN - - `vpc_connector_network` - Panorama VPC network Name - - `vpc_connector_cidr` - VPC connector /28 CIDR. - VPC connector will be user for delicensing CFN to access Panorama VPC network. - - Example: - - ``` - { - name_prefix = "abc-" - function_name = "delicensing-cfn" - region = "us-central1" - bucket_location = "US" - panorama_address = "1.1.1.1" - panorama2_address = null - vpc_connector_network = "panorama-vpc" - vpc_connector_cidr = "10.10.190.0/28" - } - ``` - EOF - type = object({ - name_prefix = string - function_name = string - region = string - bucket_location = string - panorama_address = string - panorama2_address = string - vpc_connector_network = string - vpc_connector_cidr = string - }) - default = null -} - -#--------------------------------------------------------------------------------- -# The following variables are used for test VMs - -variable "test_vms" { - description = <<-EOF - Test VMs - - Example: - - ``` - { - "vm1" = { - "zone" : "us-central1-a" - "machine_type": "e2-micro" - } - } - ``` - EOF - type = map(object({ - zone = string - machine_type = string - })) - default = {} -} \ No newline at end of file diff --git a/examples/vpc_peering_common_with_autoscale/README.md b/examples/vpc_peering_common_with_autoscale/README.md new file mode 100644 index 00000000..9eac31e1 --- /dev/null +++ b/examples/vpc_peering_common_with_autoscale/README.md @@ -0,0 +1,215 @@ +--- +show_in_hub: false +--- +# Reference Architecture with Terraform: VM-Series in GCP, Centralized Architecture, Common NGFW with autoscale Option + +Palo Alto Networks produces several [validated reference architecture design and deployment documentation guides](https://www.paloaltonetworks.com/resources/reference-architectures), which describe well-architected and tested deployments. When deploying VM-Series in a public cloud, the reference architectures guide users toward the best security outcomes, whilst reducing rollout time and avoiding common integration efforts. +The Terraform code presented here will deploy Palo Alto Networks VM-Series firewalls in GCP based on a centralized design with common VM-Series and autoscaling capabilities for all traffic; for a discussion of other options, please see the design guide from [the reference architecture guides](https://www.paloaltonetworks.com/resources/reference-architectures). + +## Detailed Architecture and Design + +### Centralized Design + +This design uses a VPC Peering. Application functions are distributed across multiple projects that are connected in a logical hub-and-spoke topology. A security project acts as the hub, providing centralized connectivity and control for multiple application projects. You deploy all VM-Series firewalls within the security project. The spoke projects contain the workloads and necessary services to support the application deployment. +This design model integrates multiple methods to interconnect and control your application project VPC networks with resources in the security project. VPC Peering enables the private VPC network in the security project to peer with, and share routing information to, each application project VPC network. Using Shared VPC, the security project administrators create and share VPC network resources from within the security project to the application projects. The application project administrators can select the network resources and deploy the application workloads. + +### Common Option with autoscaling + +The common firewall option with autoscaling leverages a single set autoscale group of VM-Series firewalls. Compared to the standard common firewall option - the autoscaling solved the issue of resource bottleneck given by a single set of firewalls, being able to scale horizontally based on configurable metrics. + +![VM-Series-Common-Firewall-Option-With-Autoscaling](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/assets/43091730/ca675535-d8d9-44f1-af75-2558afa4621d) + +The scope of this code is to deploy an example of the [VM-Series Common Firewall Option](https://www.paloaltonetworks.com/apps/pan/public/downloadResource?pagePath=/content/pan/en_US/resources/guides/gcp-architecture-guide#Design%20Model) architecture within a GCP project, but using an autoscaling group of instances instead of a single pair of firewall. + +The example makes use of VM-Series basic [bootstrap process](https://docs.paloaltonetworks.com/vm-series/10-2/vm-series-deployment/bootstrap-the-vm-series-firewall/bootstrap-the-vm-series-firewall-on-google) using metadata information to pass bootstrap parameters to the autoscale instances. + +With default variable values the topology consists of : + - 5 VPC networks : + - Management VPC + - Untrust (outside) VPC + - Trust (inside/security) VPC + - Spoke-1 VPC + - Spoke-2 VPC + - 1 Autoscaling Group + - 2 Linux Ubuntu VMs (inside Spoke VPCs - for testing purposes) + - one internal network loadbalancer (for outbound/east-west traffic) + - one external regional network loadbalancer (for inbound traffic) + +## Prerequisites + +The following steps should be followed before deploying the Terraform code presented here. + +1. Prepare [VM-Series licenses](https://support.paloaltonetworks.com/) +2. Configure the terraform [google provider](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#authentication-configuration) + +## Usage + +1. Access Google Cloud Shell or any other environment that has access to your GCP project + +2. Clone the repository: + +``` +git clone https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules +cd terraform-google-vmseries-modules/examples/vpc_peering_common_with_autoscale +``` + +3. Copy the `example.tfvars` to `terraform.tfvars`. + +`project`, `ssh_keys` and management network `source_ranges` firewall rule should be modified for successful deployment and access to the instance. + +There are also a few variables that have some default values but which should also be changed as per deployment requirements + + - `region` + - `autoscale_common.bootstrap_options` + - `autoscale..bootstrap_options` + - `linux_vms..linux_disk_size` + +1. Apply the terraform code: + +``` +terraform init +terraform apply +``` + +4. Check the output plan and confirm the apply. + +5. Check the successful application and outputs of the resulting infrastructure: + +``` +Apply complete! Resources: 48 added, 0 changed, 0 destroyed. + +Outputs: + +lbs_external_ips = { + "external-lb" = { + "all-ports" = "" + } +} +lbs_internal_ips = { + "internal-lb" = "10.10.12.4" +} +linux_vm_ips = { + "spoke1-vm" = "192.168.1.2" + "spoke2-vm" = "192.168.2.2" +} +pubsub_subscription_id = { + "fw-autoscale-common" = "projects//subscriptions/fw-autoscale-common-mig" +} +pubsub_topic_id = { + "fw-autoscale-common" = "projects//topics/fw-autoscale-common-mig" +} + +``` + + +## Post build + +Usually autoscale groups are managed by Panorama - but they can also be accessed directly via the public/private IP address like any other VM within GCP. + +Connect to the VM-Series instance(s) via SSH using your associated private key and set a password : + +``` +ssh admin@x.x.x.x -i /PATH/TO/YOUR/KEY/id_rsa +Welcome admin. + +admin@PA-VM> configure +Entering configuration mode +[edit] +admin@PA-VM# set mgt-config users admin password +Enter password : +Confirm password : + +[edit] +admin@PA-VM# commit +Configuration committed successfully +``` + +## Check access via web UI + +Use a web browser to access `https://` (these can be obtained via the GCP console/API) and login with admin and your previously configured password. + +## Change the public Loopback public IP Address + +For the VM-Series that are backend instance group members of the public-facing loadbalancer - go to Network -> Interfaces -> Loopback and add the value of `1.1.1.1` with the value from the `EXTERNAL_LB_PUBLIC_IP` from the terraform outputs. + +## Check traffic from spoke VMs + +After you do some basic configuration on the autoscaling group vmseries - you can try to check connectivity via the spoke VMs (the following tests presume that the autoscale group has been configured to process east - west traffic). + +SSH to one of the spoke VMs using GCP IAP and gcloud command and test connectivity : + + +``` +$ gcloud compute ssh spoke1-vm +No zone specified. Using zone [us-east1-b] for instance: [spoke1-vm]. +External IP address was not found; defaulting to using IAP tunneling. +WARNING: + +To increase the performance of the tunnel, consider installing NumPy. For instructions, +please see https://cloud.google.com/iap/docs/using-tcp-forwarding#increasing_the_tcp_upload_bandwidth + +@spoke1-vm:~$ping 8.8.8.8 +@spoke1-vm:~$ping 192.168.2.2 +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3, < 2.0 | + +### Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | n/a | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [autoscale](#module\_autoscale) | ../../modules/autoscale/ | n/a | +| [iam\_service\_account](#module\_iam\_service\_account) | ../../modules/iam_service_account | n/a | +| [lb\_external](#module\_lb\_external) | ../../modules/lb_external | n/a | +| [lb\_internal](#module\_lb\_internal) | ../../modules/lb_internal | n/a | +| [vpc](#module\_vpc) | ../../modules/vpc | n/a | +| [vpc\_peering](#module\_vpc\_peering) | ../../modules/vpc-peering | n/a | + +### Resources + +| Name | Type | +|------|------| +| [google_compute_instance.linux_vm](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance) | resource | +| [google_compute_route.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_route) | resource | +| [google_compute_image.my_image](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_image) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [autoscale](#input\_autoscale) | A map containing each vmseries autoscale setting.
Zonal or regional managed instance group type is controolled from the `autoscale_regional_mig` variable for all autoscale instances.

Example of variable deployment :
autoscale = {
fw-autoscale-common = {
name = "fw-autoscale-common"
zones = {
zone1 = "us-east4-b"
zone2 = "us-east4-c"
}
named_ports = [
{
name = "http"
port = 80
},
{
name = "https"
port = 443
}
]
service_account_key = "sa-vmseries-01"
min_vmseries_replicas = 2
max_vmseries_replicas = 4
create_pubsub_topic = true
autoscaler_metrics = {
"custom.googleapis.com/VMSeries/panSessionUtilization" = {
target = 70
}
"custom.googleapis.com/VMSeries/panSessionThroughputKbps" = {
target = 700000
}
}
bootstrap_options = {
type = "dhcp-client"
dhcp-send-hostname = "yes"
dhcp-send-client-id = "yes"
dhcp-accept-server-hostname = "yes"
dhcp-accept-server-domain = "yes"
mgmt-interface-swap = "enable"
panorama-server = "1.1.1.1"
ssh-keys = "admin:" # Replace this value with client data
}
network_interfaces = [
{
vpc_network_key = "fw-untrust-vpc"
subnetwork_key = "fw-untrust-sub"
create_public_ip = true
},
{
vpc_network_key = "fw-mgmt-vpc"
subnetwork_key = "fw-mgmt-sub"
create_public_ip = true
},
{
vpc_network_key = "fw-trust-vpc"
subnetwork_key = "fw-trust-sub"
}
]
}
}
| `any` | `{}` | no | +| [autoscale\_common](#input\_autoscale\_common) | A map containing common vmseries autoscale setting.
Bootstrap options can be moved between vmseries autoscale individual instances variable (`autoscale`) and this common vmseries autoscale variable (`autoscale_common`).

Example of variable deployment :
autoscale_common = {
image = "vmseries-flex-byol-1110"
machine_type = "n2-standard-4"
min_cpu_platform = "Intel Cascade Lake"
disk_type = "pd-ssd"
scopes = [
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud.useraccounts.readonly",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
]
tags = ["vmseries-autoscale"]
update_policy_type = "OPPORTUNISTIC"
cooldown_period = 480
bootstrap_options = [
panorama_server = "1.1.1.1"
]
}
| `any` | `{}` | no | +| [autoscale\_regional\_mig](#input\_autoscale\_regional\_mig) | Sets the managed instance group type to either a regional (if `true`) or a zonal (if `false`).
For more information please see [About regional MIGs](https://cloud.google.com/compute/docs/instance-groups/regional-migs#why_choose_regional_managed_instance_groups). | `bool` | `true` | no | +| [lbs\_external](#input\_lbs\_external) | A map containing each external loadbalancer setting.

Example of variable deployment :
lbs_external = {
"external-lb" = {
name = "external-lb"
backends = ["fw-vmseries-01", "fw-vmseries-02"]
rules = {
"all-ports" = {
ip_protocol = "L3_DEFAULT"
}
}
http_health_check_port = "80"
http_health_check_request_path = "/php/login.php"
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_external#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [lbs\_internal](#input\_lbs\_internal) | A map containing each internal loadbalancer setting.
Note : private IP reservation is not by default within the example as it may overlap with autoscale IP allocation.

Example of variable deployment :
lbs_internal = {
"internal-lb" = {
name = "internal-lb"
health_check_port = "80"
backends = ["fw-vmseries-01", "fw-vmseries-02"]
subnetwork_key = "fw-trust-sub"
vpc_network_key = "fw-trust-vpc"
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_internal#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [linux\_vms](#input\_linux\_vms) | A map containing each Linux VM configuration that will be placed in SPOKE VPCs for testing purposes.

Example of varaible deployment:
linux_vms = {
spoke1-vm = {
linux_machine_type = "n2-standard-4"
zone = "us-east1-b"
linux_disk_size = "50" # Modify this value as per deployment requirements
vpc_network_key = "fw-spoke1-vpc"
subnetwork_key = "fw-spoke1-sub"
private_ip = "192.168.1.2"
scopes = [
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud.useraccounts.readonly",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
]
service_account_key = "sa-linux-01"
}
}
| `map(any)` | `{}` | no | +| [name\_prefix](#input\_name\_prefix) | A string to prefix resource namings. | `string` | `"example-"` | no | +| [networks](#input\_networks) | A map containing each network setting.

Example of variable deployment :
networks = {
fw-mgmt-vpc = {
vpc_name = "fw-mgmt-vpc"
create_network = true
delete_default_routes_on_create = false
mtu = "1460"
routing_mode = "REGIONAL"
subnetworks = {
fw-mgmt-sub = {
name = "fw-mgmt-sub"
create_subnetwork = true
ip_cidr_range = "10.10.10.0/28"
region = "us-east1"
}
}
firewall_rules = {
allow-mgmt-ingress = {
name = "allow-mgmt-vpc"
source_ranges = ["10.10.10.0/24", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes.
priority = "1000"
allowed_protocol = "all"
allowed_ports = []
}
}
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc#input_networks)

Multiple keys can be added and will be deployed by the code. | `any` | `{}` | no | +| [project](#input\_project) | The project name to deploy the infrastructure in to. | `string` | `null` | no | +| [region](#input\_region) | The region into which to deploy the infrastructure in to. | `string` | `"us-central1"` | no | +| [routes](#input\_routes) | A map containing each route setting. Note that you can only add routes using a next-hop type of internal load-balance rule.

Example of variable deployment :
routes = {
"default-route-trust" = {
name = "fw-default-trust"
destination_range = "0.0.0.0/0"
vpc_network_key = "fw-trust-vpc"
lb_internal_name = "internal-lb"
}
}
Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [service\_accounts](#input\_service\_accounts) | A map containing each service account setting.

Example of variable deployment :
service_accounts = {
"sa-vmseries-01" = {
service_account_id = "sa-vmseries-01"
display_name = "VM-Series SA"
roles = [
"roles/compute.networkViewer",
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
"roles/monitoring.viewer",
"roles/viewer"
]
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/iam_service_account#Inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [vpc\_peerings](#input\_vpc\_peerings) | A map containing each VPC peering setting.

Example of variable deployment :
vpc_peerings = {
"trust-to-spoke1" = {
local_network_key = "fw-trust-vpc"
peer_network_key = "fw-spoke1-vpc"

local_export_custom_routes = true
local_import_custom_routes = true
local_export_subnet_routes_with_public_ip = true
local_import_subnet_routes_with_public_ip = true

peer_export_custom_routes = true
peer_import_custom_routes = true
peer_export_subnet_routes_with_public_ip = true
peer_import_subnet_routes_with_public_ip = true
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc-peering#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [lbs\_external\_ips](#output\_lbs\_external\_ips) | Public IP addresses of external network loadbalancers. | +| [lbs\_internal\_ips](#output\_lbs\_internal\_ips) | Private IP addresses of internal network loadbalancers. | +| [linux\_vm\_ips](#output\_linux\_vm\_ips) | Private IP addresses of Linux VMs. | +| [pubsub\_subscription\_id](#output\_pubsub\_subscription\_id) | The resource ID of the Pub/Sub Subscription. | +| [pubsub\_topic\_id](#output\_pubsub\_topic\_id) | The resource ID of the Pub/Sub Topic. | + diff --git a/examples/vpc_peering_common_with_autoscale/example.tfvars b/examples/vpc_peering_common_with_autoscale/example.tfvars new file mode 100644 index 00000000..2573804c --- /dev/null +++ b/examples/vpc_peering_common_with_autoscale/example.tfvars @@ -0,0 +1,340 @@ +# General +project = "" +region = "us-east4" +name_prefix = "" + +# Service accounts + +service_accounts = { + sa-vmseries-01 = { + service_account_id = "sa-vmseries-01" + display_name = "VM-Series SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + }, + sa-linux-01 = { + service_account_id = "sa-linux-01" + display_name = "Linux VMs SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + } +} + +# VPC + +networks = { + fw-mgmt-vpc = { + vpc_name = "fw-mgmt-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-mgmt-sub = { + name = "fw-mgmt-sub" + create_subnetwork = true + ip_cidr_range = "10.10.10.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-mgmt-ingress = { + name = "allow-mgmt-vpc" + source_ranges = ["1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-untrust-vpc = { + vpc_name = "fw-untrust-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-untrust-sub = { + name = "fw-untrust-sub" + create_subnetwork = true + ip_cidr_range = "10.10.11.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-untrust-ingress = { + name = "allow-untrust-vpc" + source_ranges = ["35.191.0.0/16", "209.85.152.0/22", "209.85.204.0/22", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-trust-vpc = { + vpc_name = "fw-trust-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-trust-sub = { + name = "fw-trust-sub" + create_subnetwork = true + ip_cidr_range = "10.10.12.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-trust-ingress = { + name = "allow-trust-vpc" + source_ranges = ["192.168.0.0/16", "35.191.0.0/16", "130.211.0.0/22"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-spoke1-vpc = { + vpc_name = "fw-spoke1-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-spoke1-sub = { + name = "fw-spoke1-sub" + create_subnetwork = true + ip_cidr_range = "192.168.1.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-spoke1-ingress = { + name = "allow-spoke1-vpc" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-spoke2-vpc = { + vpc_name = "fw-spoke2-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-spoke2-sub = { + name = "fw-spoke2-sub" + create_subnetwork = true + ip_cidr_range = "192.168.2.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-spoke2-ingress = { + name = "allow-spoke2-vpc" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + } +} + +# VPC Peerings + +vpc_peerings = { + trust-to-spoke1 = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke1-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + }, + trust-to-spoke2 = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke2-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + } +} + +# Static routes +routes = { + fw-default-trust = { + name = "fw-default-trust" + destination_range = "0.0.0.0/0" + vpc_network_key = "fw-trust-vpc" + lb_internal_key = "internal-lb" + } +} + +# Autoscale +autoscale_regional_mig = true + +autoscale_common = { + image = "vmseries-flex-byol-1110" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + disk_type = "pd-ssd" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + tags = ["vmseries-autoscale"] + update_policy_type = "OPPORTUNISTIC" + cooldown_period = 480 +} + +autoscale = { + fw-autoscale-common = { + name = "fw-autoscale-common" + zones = { + zone1 = "us-east4-b" + zone2 = "us-east4-c" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + service_account_key = "sa-vmseries-01" + min_vmseries_replicas = 2 + max_vmseries_replicas = 4 + create_pubsub_topic = true + autoscaler_metrics = { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + } + bootstrap_options = { + type = "dhcp-client" + dhcp-send-hostname = "yes" + dhcp-send-client-id = "yes" + dhcp-accept-server-hostname = "yes" + dhcp-accept-server-domain = "yes" + mgmt-interface-swap = "enable" + panorama-server = "1.1.1.1" + ssh-keys = "admin:" # Replace this value with client data + } + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } + ] + } +} + +# Spoke Linux VMs +linux_vms = { + spoke1-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east4-b" + linux_disk_size = "50" + vpc_network_key = "fw-spoke1-vpc" + subnetwork_key = "fw-spoke1-sub" + private_ip = "192.168.1.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + }, + spoke2-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east4-b" + linux_disk_size = "50" + vpc_network_key = "fw-spoke2-vpc" + subnetwork_key = "fw-spoke2-sub" + private_ip = "192.168.2.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + } +} + +# Internal Network Loadbalancer +lbs_internal = { + internal-lb = { + name = "internal-lb" + health_check_port = "80" + backends = ["fw-autoscale-common"] + subnetwork = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } +} + +# External Network Loadbalancer +lbs_external = { + external-lb = { + name = "external-lb" + backends = ["fw-autoscale-common"] + rules = { + all-ports = { + ip_protocol = "L3_DEFAULT" + } + } + http_health_check_port = "80" + http_health_check_request_path = "/php/login.php" + } +} \ No newline at end of file diff --git a/examples/vpc_peering_common_with_autoscale/main.tf b/examples/vpc_peering_common_with_autoscale/main.tf new file mode 100644 index 00000000..1309eec1 --- /dev/null +++ b/examples/vpc_peering_common_with_autoscale/main.tf @@ -0,0 +1,183 @@ +module "iam_service_account" { + source = "../../modules/iam_service_account" + + for_each = var.service_accounts + + service_account_id = "${var.name_prefix}${each.value.service_account_id}" + display_name = "${var.name_prefix}${each.value.display_name}" + roles = each.value.roles + project_id = var.project +} + +module "vpc" { + source = "../../modules/vpc" + + for_each = var.networks + + project_id = var.project + name = "${var.name_prefix}${each.value.vpc_name}" + create_network = each.value.create_network + delete_default_routes_on_create = each.value.delete_default_routes_on_create + mtu = each.value.mtu + routing_mode = each.value.routing_mode + subnetworks = { for k, v in each.value.subnetworks : k => merge(v, { + name = "${var.name_prefix}${v.name}" + }) + } + firewall_rules = try({ for k, v in each.value.firewall_rules : k => merge(v, { + name = "${var.name_prefix}${v.name}" + }) + }, {}) +} + +resource "google_compute_route" "this" { + + for_each = var.routes + + name = "${var.name_prefix}${each.value.name}" + dest_range = each.value.destination_range + network = module.vpc[each.value.vpc_network_key].network.self_link + next_hop_ilb = module.lb_internal[each.value.lb_internal_key].forwarding_rule + priority = 100 +} + +module "vpc_peering" { + source = "../../modules/vpc-peering" + + for_each = var.vpc_peerings + + local_network = module.vpc[each.value.local_network_key].network.id + peer_network = module.vpc[each.value.peer_network_key].network.id + + local_export_custom_routes = each.value.local_export_custom_routes + local_import_custom_routes = each.value.local_import_custom_routes + local_export_subnet_routes_with_public_ip = each.value.local_export_subnet_routes_with_public_ip + local_import_subnet_routes_with_public_ip = each.value.local_import_subnet_routes_with_public_ip + + peer_export_custom_routes = each.value.peer_export_custom_routes + peer_import_custom_routes = each.value.peer_import_custom_routes + peer_export_subnet_routes_with_public_ip = each.value.peer_export_subnet_routes_with_public_ip + peer_import_subnet_routes_with_public_ip = each.value.peer_import_subnet_routes_with_public_ip +} + +module "autoscale" { + source = "../../modules/autoscale/" + + for_each = var.autoscale + + name = "${var.name_prefix}${each.value.name}" + region = var.region + project_id = var.project + regional_mig = try(var.autoscale_regional_mig, true) + zones = try(each.value.zones, {}) + image = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/${try(each.value.image, var.autoscale_common.image)}" + named_ports = try(each.value.named_ports, var.autoscale_common.named_ports) + machine_type = try(each.value.machine_type, var.autoscale_common.machine_type) + min_cpu_platform = try(each.value.min_cpu_platform, var.autoscale_common.min_cpu_platform, "Intel Cascade Lake") + disk_type = try(each.value.disk_type, var.autoscale_common.disk_type, "pd-ssd") + service_account_email = try(module.iam_service_account[each.value.service_account_key].email, module.iam_service_account[var.autoscale_common.service_account_key].email) + scopes = try(each.value.scopes, var.autoscale_common.scopes, []) + tags = try(each.value.tags, var.autoscale_common.tags, []) + update_policy_type = try(each.value.update_policy_type, var.autoscale_common.update_policy_type, "OPPORTUNISTIC") + min_vmseries_replicas = try(each.value.min_vmseries_replicas, var.autoscale_common.min_vmseries_replicas) + max_vmseries_replicas = try(each.value.max_vmseries_replicas, var.autoscale_common.max_vmseries_replicas) + cooldown_period = try(each.value.cooldown_period, var.autoscale_common.cooldown_period, 480) + scale_in_control_time_window_sec = try(each.value.scale_in_control_time_window_sec, var.autoscale_common.scale_in_control_time_window_sec, 1800) + scale_in_control_replicas_fixed = try(each.value.scale_in_control_replicas_fixed, var.autoscale_common.scale_in_control_replicas_fixed, 1) + create_pubsub_topic = try(each.value.create_pubsub_topic, var.autoscale_common.create_pubsub_topic) + autoscaler_metrics = try(each.value.autoscaler_metrics, var.autoscale_common.autoscaler_metrics, + { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + }) + + network_interfaces = [for v in each.value.network_interfaces : + { + subnetwork = module.vpc[v.vpc_network_key].subnetworks[v.subnetwork_key].self_link + create_public_ip = try(v.create_public_ip, false) + }] + metadata = merge( + try(each.value.bootstrap_options, {}), + try(var.autoscale_common.bootstrap_options, {}) + ) +} + +data "google_compute_image" "my_image" { + family = "ubuntu-pro-2204-lts" + project = "ubuntu-os-pro-cloud" +} + +resource "google_compute_instance" "linux_vm" { + for_each = var.linux_vms + + name = "${var.name_prefix}${each.key}" + machine_type = each.value.linux_machine_type + zone = each.value.zone + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.id + size = each.value.linux_disk_size + } + } + + network_interface { + subnetwork = module.vpc[each.value.vpc_network_key].subnetworks[each.value.subnetwork_key].self_link + network_ip = each.value.private_ip + } + + metadata = { + enable-oslogin = true + } + + + service_account { + email = module.iam_service_account[each.value.service_account_key].email + scopes = each.value.scopes + } +} + +module "lb_internal" { + source = "../../modules/lb_internal" + + for_each = var.lbs_internal + + name = "${var.name_prefix}${each.value.name}" + region = var.region + health_check_port = try(each.value.health_check_port, "80") + backends = var.autoscale_regional_mig ? { for v in each.value.backends : v => module.autoscale[v].regional_instance_group_id } : merge([ + for v in each.value.backends : + { + for z_k, z_v in var.autoscale[v].zones : + "${v}_${z_k}" => module.autoscale[v].zonal_instance_group_ids[z_k] + } + ]...) + subnetwork = module.vpc[each.value.vpc_network_key].subnetworks[each.value.subnetwork_key].self_link + network = module.vpc[each.value.vpc_network_key].network.self_link + all_ports = true +} + +module "lb_external" { + source = "../../modules/lb_external" + + for_each = var.lbs_external + + project = var.project + + name = "${var.name_prefix}${each.value.name}" + backend_instance_groups = var.autoscale_regional_mig ? { for v in each.value.backends : v => module.autoscale[v].regional_instance_group_id } : merge([ + for v in each.value.backends : + { + for z_k, z_v in var.autoscale[v].zones : + "${v}_${z_k}" => module.autoscale[v].zonal_instance_group_ids[z_k] + } + ]...) + rules = each.value.rules + + health_check_http_port = each.value.http_health_check_port + health_check_http_request_path = try(each.value.http_health_check_request_path, "/php/login.php") +} \ No newline at end of file diff --git a/examples/autoscale/main_test.go b/examples/vpc_peering_common_with_autoscale/main_test.go similarity index 95% rename from examples/autoscale/main_test.go rename to examples/vpc_peering_common_with_autoscale/main_test.go index 9e129279..9e6dbfa3 100644 --- a/examples/autoscale/main_test.go +++ b/examples/vpc_peering_common_with_autoscale/main_test.go @@ -1,4 +1,4 @@ -package autoscale +package vpc_peering_common_with_autoscale import ( "testing" @@ -22,7 +22,7 @@ func CreateTerraformOptions(t *testing.T) *terraform.Options { VarFiles: []string{"example.tfvars"}, Vars: map[string]interface{}{ "name_prefix": varsInfo.NamePrefix, - "project_id": varsInfo.GoogleProjectId, + "project": varsInfo.GoogleProjectId, }, Logger: logger.Default, Lock: true, @@ -62,4 +62,4 @@ func TestIdempotence(t *testing.T) { assertList := []testskeleton.AssertExpression{} // deploy test infrastructure and verify outputs and check if there are no planned changes after deployment testskeleton.DeployInfraCheckOutputsVerifyChanges(t, terraformOptions, assertList) -} \ No newline at end of file +} diff --git a/examples/vpc_peering_common_with_autoscale/outputs.tf b/examples/vpc_peering_common_with_autoscale/outputs.tf new file mode 100644 index 00000000..eec4859c --- /dev/null +++ b/examples/vpc_peering_common_with_autoscale/outputs.tf @@ -0,0 +1,24 @@ +output "pubsub_topic_id" { + description = "The resource ID of the Pub/Sub Topic." + value = try({ for k, v in module.autoscale : k => v.pubsub_topic_id }, null) +} + +output "pubsub_subscription_id" { + description = "The resource ID of the Pub/Sub Subscription." + value = try({ for k, v in module.autoscale : k => v.pubsub_subscription_id }, null) +} + +output "lbs_internal_ips" { + description = "Private IP addresses of internal network loadbalancers." + value = { for k, v in module.lb_internal : k => v.address } +} + +output "lbs_external_ips" { + description = "Public IP addresses of external network loadbalancers." + value = { for k, v in module.lb_external : k => v.ip_addresses } +} + +output "linux_vm_ips" { + description = "Private IP addresses of Linux VMs." + value = { for k, v in resource.google_compute_instance.linux_vm : k => v.network_interface[0].network_ip } +} \ No newline at end of file diff --git a/examples/vpc_peering_common_with_autoscale/variables.tf b/examples/vpc_peering_common_with_autoscale/variables.tf new file mode 100644 index 00000000..d3089ea8 --- /dev/null +++ b/examples/vpc_peering_common_with_autoscale/variables.tf @@ -0,0 +1,349 @@ +# General +variable "project" { + description = "The project name to deploy the infrastructure in to." + type = string + default = null +} +variable "region" { + description = "The region into which to deploy the infrastructure in to." + type = string + default = "us-central1" +} +variable "name_prefix" { + description = "A string to prefix resource namings." + type = string + default = "example-" +} + +#Service Account + +variable "service_accounts" { + description = <<-EOF + A map containing each service account setting. + + Example of variable deployment : + ``` + service_accounts = { + "sa-vmseries-01" = { + service_account_id = "sa-vmseries-01" + display_name = "VM-Series SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/iam_service_account#Inputs) + + Multiple keys can be added and will be deployed by the code. + + EOF + type = map(any) + default = {} +} + +#VPC + +variable "networks" { + description = <<-EOF + A map containing each network setting. + + Example of variable deployment : + + ``` + networks = { + fw-mgmt-vpc = { + vpc_name = "fw-mgmt-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-mgmt-sub = { + name = "fw-mgmt-sub" + create_subnetwork = true + ip_cidr_range = "10.10.10.0/28" + region = "us-east1" + } + } + firewall_rules = { + allow-mgmt-ingress = { + name = "allow-mgmt-vpc" + source_ranges = ["10.10.10.0/24", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + } + } + ``` + + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc#input_networks) + + Multiple keys can be added and will be deployed by the code. + EOF + type = any + default = {} +} + +variable "vpc_peerings" { + description = <<-EOF + A map containing each VPC peering setting. + + Example of variable deployment : + + ``` + vpc_peerings = { + "trust-to-spoke1" = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke1-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc-peering#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +variable "routes" { + description = <<-EOF + A map containing each route setting. Note that you can only add routes using a next-hop type of internal load-balance rule. + + Example of variable deployment : + + ``` + routes = { + "default-route-trust" = { + name = "fw-default-trust" + destination_range = "0.0.0.0/0" + vpc_network_key = "fw-trust-vpc" + lb_internal_name = "internal-lb" + } + } + ``` + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +#Autoscale +variable "autoscale_regional_mig" { + description = <<-EOF + Sets the managed instance group type to either a regional (if `true`) or a zonal (if `false`). + For more information please see [About regional MIGs](https://cloud.google.com/compute/docs/instance-groups/regional-migs#why_choose_regional_managed_instance_groups). + EOF + type = bool + default = true +} +variable "autoscale_common" { + description = <<-EOF + A map containing common vmseries autoscale setting. + Bootstrap options can be moved between vmseries autoscale individual instances variable (`autoscale`) and this common vmseries autoscale variable (`autoscale_common`). + + Example of variable deployment : + + ``` + autoscale_common = { + image = "vmseries-flex-byol-1110" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + disk_type = "pd-ssd" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + tags = ["vmseries-autoscale"] + update_policy_type = "OPPORTUNISTIC" + cooldown_period = 480 + bootstrap_options = [ + panorama_server = "1.1.1.1" + ] + } + ``` + EOF + type = any + default = {} +} + +variable "autoscale" { + description = <<-EOF + A map containing each vmseries autoscale setting. + Zonal or regional managed instance group type is controolled from the `autoscale_regional_mig` variable for all autoscale instances. + + Example of variable deployment : + + ``` + autoscale = { + fw-autoscale-common = { + name = "fw-autoscale-common" + zones = { + zone1 = "us-east4-b" + zone2 = "us-east4-c" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + service_account_key = "sa-vmseries-01" + min_vmseries_replicas = 2 + max_vmseries_replicas = 4 + create_pubsub_topic = true + autoscaler_metrics = { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + } + bootstrap_options = { + type = "dhcp-client" + dhcp-send-hostname = "yes" + dhcp-send-client-id = "yes" + dhcp-accept-server-hostname = "yes" + dhcp-accept-server-domain = "yes" + mgmt-interface-swap = "enable" + panorama-server = "1.1.1.1" + ssh-keys = "admin:" # Replace this value with client data + } + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } + ] + } + } + ``` + EOF + type = any + default = {} +} + +#Load Balancers + +variable "lbs_internal" { + description = <<-EOF + A map containing each internal loadbalancer setting. + Note : private IP reservation is not by default within the example as it may overlap with autoscale IP allocation. + + Example of variable deployment : + + ``` + lbs_internal = { + "internal-lb" = { + name = "internal-lb" + health_check_port = "80" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + subnetwork_key = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_internal#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} +variable "lbs_external" { + description = <<-EOF + A map containing each external loadbalancer setting. + + Example of variable deployment : + + ``` + lbs_external = { + "external-lb" = { + name = "external-lb" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + rules = { + "all-ports" = { + ip_protocol = "L3_DEFAULT" + } + } + http_health_check_port = "80" + http_health_check_request_path = "/php/login.php" + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_external#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +#Spoke VPCs Linux VMs + +variable "linux_vms" { + description = <<-EOF + A map containing each Linux VM configuration that will be placed in SPOKE VPCs for testing purposes. + + Example of varaible deployment: + + ``` + linux_vms = { + spoke1-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east1-b" + linux_disk_size = "50" # Modify this value as per deployment requirements + vpc_network_key = "fw-spoke1-vpc" + subnetwork_key = "fw-spoke1-sub" + private_ip = "192.168.1.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + } + } + ``` + EOF + type = map(any) + default = {} +} diff --git a/examples/autoscale/versions.tf b/examples/vpc_peering_common_with_autoscale/versions.tf similarity index 55% rename from examples/autoscale/versions.tf rename to examples/vpc_peering_common_with_autoscale/versions.tf index b9f6089a..785e9269 100644 --- a/examples/autoscale/versions.tf +++ b/examples/vpc_peering_common_with_autoscale/versions.tf @@ -1,16 +1,13 @@ terraform { required_version = ">= 1.3, < 2.0" - required_providers { - google = { version = "~> 4.58" } - } } provider "google" { - project = var.project_id + project = var.project region = var.region } provider "google-beta" { - project = var.project_id + project = var.project region = var.region } diff --git a/examples/vpc_peering_dedicated_with_autoscale/README.md b/examples/vpc_peering_dedicated_with_autoscale/README.md new file mode 100644 index 00000000..f2e0662f --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/README.md @@ -0,0 +1,219 @@ +--- +show_in_hub: false +--- +# Reference Architecture with Terraform: VM-Series in GCP, Centralized Architecture, Dedicated inbound NGFW with autoscale Option + +Palo Alto Networks produces several [validated reference architecture design and deployment documentation guides](https://www.paloaltonetworks.com/resources/reference-architectures), which describe well-architected and tested deployments. When deploying VM-Series in a public cloud, the reference architectures guide users toward the best security outcomes, whilst reducing rollout time and avoiding common integration efforts. +The Terraform code presented here will deploy Palo Alto Networks VM-Series firewalls in GCP based on a centralized design with dedicated inbound VM-Series and autoscaling capabilities for all traffic; for a discussion of other options, please see the design guide from [the reference architecture guides](https://www.paloaltonetworks.com/resources/reference-architectures). + +## Detailed Architecture and Design + +### Centralized Design + +This design uses a VPC Peering. Application functions are distributed across multiple projects that are connected in a logical hub-and-spoke topology. A security project acts as the hub, providing centralized connectivity and control for multiple application projects. You deploy all VM-Series firewalls within the security project. The spoke projects contain the workloads and necessary services to support the application deployment. +This design model integrates multiple methods to interconnect and control your application project VPC networks with resources in the security project. VPC Peering enables the private VPC network in the security project to peer with, and share routing information to, each application project VPC network. Using Shared VPC, the security project administrators create and share VPC network resources from within the security project to the application projects. The application project administrators can select the network resources and deploy the application workloads. + +### Dedicated inbound Option with autoscaling + +The dedicated inbound firewall option with autoscaling leverages a single set autoscale group of VM-Series firewalls. Compared to the standard dedicated inbound firewall option - the autoscaling solved the issue of resource bottleneck given by a single set of firewalls, being able to scale horizontally based on configurable metrics. + +![VM-Series-Dedicated-Firewall-Option-With-Autoscaling](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/assets/43091730/41e95242-eaf1-4850-b563-df17d138bef9) + + +The scope of this code is to deploy an example of the [VM-Series Dedicated Inbound Firewall Option](https://www.paloaltonetworks.com/apps/pan/public/downloadResource?pagePath=/content/pan/en_US/resources/guides/gcp-architecture-guide#Design%20Model) architecture within a GCP project, but using an autoscaling group of instances instead of a single pair of firewall. + +The example makes use of VM-Series basic [bootstrap process](https://docs.paloaltonetworks.com/vm-series/10-2/vm-series-deployment/bootstrap-the-vm-series-firewall/bootstrap-the-vm-series-firewall-on-google) using metadata information to pass bootstrap parameters to the autoscale instances. + +With default variable values the topology consists of : + - 5 VPC networks : + - Management VPC + - Untrust (outside) VPC + - Trust (inside/security) VPC + - Spoke-1 VPC + - Spoke-2 VPC + - 2 Autoscaling Group + - 2 Linux Ubuntu VMs (inside Spoke VPCs - for testing purposes) + - one internal network loadbalancer (for outbound/east-west traffic) + - one external regional network loadbalancer (for inbound traffic) + +## Prerequisites + +The following steps should be followed before deploying the Terraform code presented here. + +1. Prepare [VM-Series licenses](https://support.paloaltonetworks.com/) +2. Configure the terraform [google provider](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#authentication-configuration) + +## Usage + +1. Access Google Cloud Shell or any other environment that has access to your GCP project + +2. Clone the repository: + +``` +git clone https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules +cd terraform-google-vmseries-modules/examples/vpc_peering_dedicated_with_autoscale +``` + +3. Copy the `example.tfvars` to `terraform.tfvars`. + +`project`, `ssh_keys` and management network `source_ranges` firewall rule should be modified for successful deployment and access to the instance. + +There are also a few variables that have some default values but which should also be changed as per deployment requirements + + - `region` + - `autoscale_common.bootstrap_options` + - `autoscale..bootstrap_options` + - `linux_vms..linux_disk_size` + +1. Apply the terraform code: + +``` +terraform init +terraform apply +``` + +4. Check the output plan and confirm the apply. + +5. Check the successful application and outputs of the resulting infrastructure: + +``` +Apply complete! Resources: 55 added, 0 changed, 0 destroyed. + +Outputs: + +lbs_external_ips = { + "external-lb" = { + "all-portsss" = "" + } +} +lbs_internal_ips = { + "internal-lb" = "10.10.12.4" +} +linux_vm_ips = { + "spoke1-vm" = "192.168.1.2" + "spoke2-vm" = "192.168.2.2" +} +pubsub_subscription_id = { + "fw-autoscale-inbound" = "projects/gcp-gcs-pso/subscriptions/hgu-asi-ref-fw-autoscale-inbound-mig" + "fw-autoscale-obew" = "projects/gcp-gcs-pso/subscriptions/hgu-asi-ref-fw-autoscale-obew-mig" +} +pubsub_topic_id = { + "fw-autoscale-inbound" = "projects/gcp-gcs-pso/topics/hgu-asi-ref-fw-autoscale-inbound-mig" + "fw-autoscale-obew" = "projects/gcp-gcs-pso/topics/hgu-asi-ref-fw-autoscale-obew-mig" +} + + +``` + + +## Post build + +Usually autoscale groups are managed by Panorama - but they can also be accessed directly via the public/private IP address like any other VM within GCP. + +Connect to the VM-Series instance(s) via SSH using your associated private key and set a password : + +``` +ssh admin@x.x.x.x -i /PATH/TO/YOUR/KEY/id_rsa +Welcome admin. + +admin@PA-VM> configure +Entering configuration mode +[edit] +admin@PA-VM# set mgt-config users admin password +Enter password : +Confirm password : + +[edit] +admin@PA-VM# commit +Configuration committed successfully +``` + +## Check access via web UI + +Use a web browser to access `https://` (these can be obtained via the GCP console/API) and login with admin and your previously configured password. + +## Change the public Loopback public IP Address + +For the VM-Series that are backend instance group members of the public-facing loadbalancer - go to Network -> Interfaces -> Loopback and change the value of `1.1.1.1` with the value from the `EXTERNAL_LB_PUBLIC_IP` from the terraform outputs. + +## Check traffic from spoke VMs + +After you do some basic configuration on the autoscaling group vmseries - you can try to check connectivity via the spoke VMs (the following tests presume that the autoscale group has been configured to process east - west traffic). + +SSH to one of the spoke VMs using GCP IAP and gcloud command and test connectivity : + + +``` +$ gcloud compute ssh spoke1-vm +No zone specified. Using zone [us-east1-b] for instance: [spoke1-vm]. +External IP address was not found; defaulting to using IAP tunneling. +WARNING: + +To increase the performance of the tunnel, consider installing NumPy. For instructions, +please see https://cloud.google.com/iap/docs/using-tcp-forwarding#increasing_the_tcp_upload_bandwidth + +@spoke1-vm:~$ping 8.8.8.8 +@spoke1-vm:~$ping 192.168.2.2 +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3, < 2.0 | + +### Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | n/a | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [autoscale](#module\_autoscale) | ../../modules/autoscale/ | n/a | +| [iam\_service\_account](#module\_iam\_service\_account) | ../../modules/iam_service_account | n/a | +| [lb\_external](#module\_lb\_external) | ../../modules/lb_external | n/a | +| [lb\_internal](#module\_lb\_internal) | ../../modules/lb_internal | n/a | +| [vpc](#module\_vpc) | ../../modules/vpc | n/a | +| [vpc\_peering](#module\_vpc\_peering) | ../../modules/vpc-peering | n/a | + +### Resources + +| Name | Type | +|------|------| +| [google_compute_instance.linux_vm](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance) | resource | +| [google_compute_route.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_route) | resource | +| [google_compute_image.my_image](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_image) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [autoscale](#input\_autoscale) | A map containing each vmseries autoscale setting.
Zonal or regional managed instance group type is controolled from the `autoscale_regional_mig` variable for all autoscale instances.

Example of variable deployment :
autoscale = {
fw-autoscale-common = {
name = "fw-autoscale-common"
zones = {
zone1 = "us-east4-b"
zone2 = "us-east4-c"
}
named_ports = [
{
name = "http"
port = 80
},
{
name = "https"
port = 443
}
]
service_account_key = "sa-vmseries-01"
min_vmseries_replicas = 2
max_vmseries_replicas = 4
create_pubsub_topic = true
autoscaler_metrics = {
"custom.googleapis.com/VMSeries/panSessionUtilization" = {
target = 70
}
"custom.googleapis.com/VMSeries/panSessionThroughputKbps" = {
target = 700000
}
}
bootstrap_options = {
type = "dhcp-client"
dhcp-send-hostname = "yes"
dhcp-send-client-id = "yes"
dhcp-accept-server-hostname = "yes"
dhcp-accept-server-domain = "yes"
mgmt-interface-swap = "enable"
panorama-server = "1.1.1.1"
ssh-keys = "admin:" # Replace this value with client data
}
network_interfaces = [
{
vpc_network_key = "fw-untrust-vpc"
subnetwork_key = "fw-untrust-sub"
create_public_ip = true
},
{
vpc_network_key = "fw-mgmt-vpc"
subnetwork_key = "fw-mgmt-sub"
create_public_ip = true
},
{
vpc_network_key = "fw-trust-vpc"
subnetwork_key = "fw-trust-sub"
}
]
}
}
| `any` | `{}` | no | +| [autoscale\_common](#input\_autoscale\_common) | A map containing common vmseries autoscale setting.
Bootstrap options can be moved between vmseries autoscale individual instances variable (`autoscale`) and this common vmseries autoscale variable (`autoscale_common`).

Example of variable deployment :
autoscale_common = {
image = "vmseries-flex-byol-1110"
machine_type = "n2-standard-4"
min_cpu_platform = "Intel Cascade Lake"
disk_type = "pd-ssd"
scopes = [
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud.useraccounts.readonly",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
]
tags = ["vmseries-autoscale"]
update_policy_type = "OPPORTUNISTIC"
cooldown_period = 480
bootstrap_options = [
panorama_server = "1.1.1.1"
]
}
| `any` | `{}` | no | +| [autoscale\_regional\_mig](#input\_autoscale\_regional\_mig) | Sets the managed instance group type to either a regional (if `true`) or a zonal (if `false`).
For more information please see [About regional MIGs](https://cloud.google.com/compute/docs/instance-groups/regional-migs#why_choose_regional_managed_instance_groups). | `bool` | `true` | no | +| [lbs\_external](#input\_lbs\_external) | A map containing each external loadbalancer setting.

Example of variable deployment :
lbs_external = {
"external-lb" = {
name = "external-lb"
backends = ["fw-vmseries-01", "fw-vmseries-02"]
rules = {
"all-ports" = {
ip_protocol = "L3_DEFAULT"
}
}
http_health_check_port = "80"
http_health_check_request_path = "/php/login.php"
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_external#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [lbs\_internal](#input\_lbs\_internal) | A map containing each internal loadbalancer setting.
Note : private IP reservation is not by default within the example as it may overlap with autoscale IP allocation.

Example of variable deployment :
lbs_internal = {
"internal-lb" = {
name = "internal-lb"
health_check_port = "80"
backends = ["fw-vmseries-01", "fw-vmseries-02"]
subnetwork_key = "fw-trust-sub"
vpc_network_key = "fw-trust-vpc"
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_internal#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [linux\_vms](#input\_linux\_vms) | A map containing each Linux VM configuration that will be placed in SPOKE VPCs for testing purposes.

Example of varaible deployment:
linux_vms = {
spoke1-vm = {
linux_machine_type = "n2-standard-4"
zone = "us-east1-b"
linux_disk_size = "50" # Modify this value as per deployment requirements
vpc_network_key = "fw-spoke1-vpc"
subnetwork_key = "fw-spoke1-sub"
private_ip = "192.168.1.2"
scopes = [
"https://www.googleapis.com/auth/compute.readonly",
"https://www.googleapis.com/auth/cloud.useraccounts.readonly",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
]
service_account_key = "sa-linux-01"
}
}
| `map(any)` | `{}` | no | +| [name\_prefix](#input\_name\_prefix) | A string to prefix resource namings. | `string` | `"example-"` | no | +| [networks](#input\_networks) | A map containing each network setting.

Example of variable deployment :
networks = {
fw-mgmt-vpc = {
vpc_name = "fw-mgmt-vpc"
create_network = true
delete_default_routes_on_create = false
mtu = "1460"
routing_mode = "REGIONAL"
subnetworks = {
fw-mgmt-sub = {
name = "fw-mgmt-sub"
create_subnetwork = true
ip_cidr_range = "10.10.10.0/28"
region = "us-east1"
}
}
firewall_rules = {
allow-mgmt-ingress = {
name = "allow-mgmt-vpc"
source_ranges = ["10.10.10.0/24", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes.
priority = "1000"
allowed_protocol = "all"
allowed_ports = []
}
}
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc#input_networks)

Multiple keys can be added and will be deployed by the code. | `any` | `{}` | no | +| [project](#input\_project) | The project name to deploy the infrastructure in to. | `string` | `null` | no | +| [region](#input\_region) | The region into which to deploy the infrastructure in to. | `string` | `"us-central1"` | no | +| [routes](#input\_routes) | A map containing each route setting. Note that you can only add routes using a next-hop type of internal load-balance rule.

Example of variable deployment :
routes = {
"default-route-trust" = {
name = "fw-default-trust"
destination_range = "0.0.0.0/0"
vpc_network_key = "fw-trust-vpc"
lb_internal_name = "internal-lb"
}
}
Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [service\_accounts](#input\_service\_accounts) | A map containing each service account setting.

Example of variable deployment :
service_accounts = {
"sa-vmseries-01" = {
service_account_id = "sa-vmseries-01"
display_name = "VM-Series SA"
roles = [
"roles/compute.networkViewer",
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
"roles/monitoring.viewer",
"roles/viewer"
]
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/iam_service_account#Inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [vpc\_peerings](#input\_vpc\_peerings) | A map containing each VPC peering setting.

Example of variable deployment :
vpc_peerings = {
"trust-to-spoke1" = {
local_network_key = "fw-trust-vpc"
peer_network_key = "fw-spoke1-vpc"

local_export_custom_routes = true
local_import_custom_routes = true
local_export_subnet_routes_with_public_ip = true
local_import_subnet_routes_with_public_ip = true

peer_export_custom_routes = true
peer_import_custom_routes = true
peer_export_subnet_routes_with_public_ip = true
peer_import_subnet_routes_with_public_ip = true
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc-peering#inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [lbs\_external\_ips](#output\_lbs\_external\_ips) | Public IP addresses of external network loadbalancers. | +| [lbs\_internal\_ips](#output\_lbs\_internal\_ips) | Private IP addresses of internal network loadbalancers. | +| [linux\_vm\_ips](#output\_linux\_vm\_ips) | Private IP addresses of Linux VMs. | +| [pubsub\_subscription\_id](#output\_pubsub\_subscription\_id) | The resource ID of the Pub/Sub Subscription. | +| [pubsub\_topic\_id](#output\_pubsub\_topic\_id) | The resource ID of the Pub/Sub Topic. | + diff --git a/examples/vpc_peering_dedicated_with_autoscale/example.tfvars b/examples/vpc_peering_dedicated_with_autoscale/example.tfvars new file mode 100644 index 00000000..17708c02 --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/example.tfvars @@ -0,0 +1,395 @@ +# General +project = "" +region = "us-east4" +name_prefix = "" + +# Service accounts + +service_accounts = { + sa-vmseries-01 = { + service_account_id = "sa-vmseries-01" + display_name = "VM-Series SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + }, + sa-linux-01 = { + service_account_id = "sa-linux-01" + display_name = "Linux VMs SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + } +} + +# VPC + +networks = { + fw-mgmt-vpc = { + vpc_name = "fw-mgmt-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-mgmt-sub = { + name = "fw-mgmt-sub" + create_subnetwork = true + ip_cidr_range = "10.10.10.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-mgmt-ingress = { + name = "allow-mgmt-vpc" + source_ranges = ["1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-untrust-vpc = { + vpc_name = "fw-untrust-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-untrust-sub = { + name = "fw-untrust-sub" + create_subnetwork = true + ip_cidr_range = "10.10.11.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-untrust-ingress = { + name = "allow-untrust-vpc" + source_ranges = ["35.191.0.0/16", "209.85.152.0/22", "209.85.204.0/22", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-trust-vpc = { + vpc_name = "fw-trust-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-trust-sub = { + name = "fw-trust-sub" + create_subnetwork = true + ip_cidr_range = "10.10.12.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-trust-ingress = { + name = "allow-trust-vpc" + source_ranges = ["192.168.0.0/16", "35.191.0.0/16", "130.211.0.0/22"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-spoke1-vpc = { + vpc_name = "fw-spoke1-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-spoke1-sub = { + name = "fw-spoke1-sub" + create_subnetwork = true + ip_cidr_range = "192.168.1.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-spoke1-ingress = { + name = "allow-spoke1-vpc" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + }, + fw-spoke2-vpc = { + vpc_name = "fw-spoke2-vpc" + create_network = true + delete_default_routes_on_create = true + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-spoke2-sub = { + name = "fw-spoke2-sub" + create_subnetwork = true + ip_cidr_range = "192.168.2.0/28" + region = "us-east4" + } + } + firewall_rules = { + allow-spoke2-ingress = { + name = "allow-spoke2-vpc" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + } +} + +# VPC Peerings + +vpc_peerings = { + trust-to-spoke1 = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke1-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + }, + trust-to-spoke2 = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke2-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + } +} + +# Static routes +routes = { + fw-default-trust = { + name = "fw-default-trust" + destination_range = "0.0.0.0/0" + vpc_network_key = "fw-trust-vpc" + lb_internal_key = "internal-lb" + } +} + +# Autoscale +autoscale_regional_mig = true + +autoscale_common = { + image = "vmseries-flex-byol-1110" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + disk_type = "pd-ssd" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + tags = ["vmseries-autoscale"] + update_policy_type = "OPPORTUNISTIC" + cooldown_period = 480 +} + +autoscale = { + fw-autoscale-obew = { + name = "fw-autoscale-obew" + zones = { + zone1 = "us-east4-b" + zone2 = "us-east4-c" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + service_account_key = "sa-vmseries-01" + min_vmseries_replicas = 2 + max_vmseries_replicas = 4 + create_pubsub_topic = true + autoscaler_metrics = { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + } + bootstrap_options = { + type = "dhcp-client" + dhcp-send-hostname = "yes" + dhcp-send-client-id = "yes" + dhcp-accept-server-hostname = "yes" + dhcp-accept-server-domain = "yes" + mgmt-interface-swap = "enable" + panorama-server = "1.1.1.1" + ssh-keys = "admin:" # Replace this value with client data + } + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } + ] + }, + fw-autoscale-inbound = { + name = "fw-autoscale-inbound" + zones = { + zone1 = "us-east4-b" + zone2 = "us-east4-c" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + service_account_key = "sa-vmseries-01" + min_vmseries_replicas = 2 + max_vmseries_replicas = 4 + create_pubsub_topic = true + autoscaler_metrics = { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + } + bootstrap_options = { + type = "dhcp-client" + dhcp-send-hostname = "yes" + dhcp-send-client-id = "yes" + dhcp-accept-server-hostname = "yes" + dhcp-accept-server-domain = "yes" + mgmt-interface-swap = "enable" + panorama-server = "1.1.1.1" + ssh-keys = "admin:" # Replace this value with client data + } + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } + ] + } +} + +# Spoke Linux VMs +linux_vms = { + spoke1-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east4-b" + linux_disk_size = "50" + vpc_network_key = "fw-spoke1-vpc" + subnetwork_key = "fw-spoke1-sub" + private_ip = "192.168.1.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + }, + spoke2-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east4-b" + linux_disk_size = "50" + vpc_network_key = "fw-spoke2-vpc" + subnetwork_key = "fw-spoke2-sub" + private_ip = "192.168.2.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + } +} + +# Internal Network Loadbalancer +lbs_internal = { + internal-lb = { + name = "internal-lb" + health_check_port = "80" + backends = ["fw-autoscale-obew"] + subnetwork = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } +} + +# External Network Loadbalancer +lbs_external = { + external-lb = { + name = "external-lb" + backends = ["fw-autoscale-inbound"] + rules = { + all-ports = { + ip_protocol = "L3_DEFAULT" + } + } + http_health_check_port = "80" + http_health_check_request_path = "/php/login.php" + } +} \ No newline at end of file diff --git a/examples/vpc_peering_dedicated_with_autoscale/main.tf b/examples/vpc_peering_dedicated_with_autoscale/main.tf new file mode 100644 index 00000000..1309eec1 --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/main.tf @@ -0,0 +1,183 @@ +module "iam_service_account" { + source = "../../modules/iam_service_account" + + for_each = var.service_accounts + + service_account_id = "${var.name_prefix}${each.value.service_account_id}" + display_name = "${var.name_prefix}${each.value.display_name}" + roles = each.value.roles + project_id = var.project +} + +module "vpc" { + source = "../../modules/vpc" + + for_each = var.networks + + project_id = var.project + name = "${var.name_prefix}${each.value.vpc_name}" + create_network = each.value.create_network + delete_default_routes_on_create = each.value.delete_default_routes_on_create + mtu = each.value.mtu + routing_mode = each.value.routing_mode + subnetworks = { for k, v in each.value.subnetworks : k => merge(v, { + name = "${var.name_prefix}${v.name}" + }) + } + firewall_rules = try({ for k, v in each.value.firewall_rules : k => merge(v, { + name = "${var.name_prefix}${v.name}" + }) + }, {}) +} + +resource "google_compute_route" "this" { + + for_each = var.routes + + name = "${var.name_prefix}${each.value.name}" + dest_range = each.value.destination_range + network = module.vpc[each.value.vpc_network_key].network.self_link + next_hop_ilb = module.lb_internal[each.value.lb_internal_key].forwarding_rule + priority = 100 +} + +module "vpc_peering" { + source = "../../modules/vpc-peering" + + for_each = var.vpc_peerings + + local_network = module.vpc[each.value.local_network_key].network.id + peer_network = module.vpc[each.value.peer_network_key].network.id + + local_export_custom_routes = each.value.local_export_custom_routes + local_import_custom_routes = each.value.local_import_custom_routes + local_export_subnet_routes_with_public_ip = each.value.local_export_subnet_routes_with_public_ip + local_import_subnet_routes_with_public_ip = each.value.local_import_subnet_routes_with_public_ip + + peer_export_custom_routes = each.value.peer_export_custom_routes + peer_import_custom_routes = each.value.peer_import_custom_routes + peer_export_subnet_routes_with_public_ip = each.value.peer_export_subnet_routes_with_public_ip + peer_import_subnet_routes_with_public_ip = each.value.peer_import_subnet_routes_with_public_ip +} + +module "autoscale" { + source = "../../modules/autoscale/" + + for_each = var.autoscale + + name = "${var.name_prefix}${each.value.name}" + region = var.region + project_id = var.project + regional_mig = try(var.autoscale_regional_mig, true) + zones = try(each.value.zones, {}) + image = "https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/${try(each.value.image, var.autoscale_common.image)}" + named_ports = try(each.value.named_ports, var.autoscale_common.named_ports) + machine_type = try(each.value.machine_type, var.autoscale_common.machine_type) + min_cpu_platform = try(each.value.min_cpu_platform, var.autoscale_common.min_cpu_platform, "Intel Cascade Lake") + disk_type = try(each.value.disk_type, var.autoscale_common.disk_type, "pd-ssd") + service_account_email = try(module.iam_service_account[each.value.service_account_key].email, module.iam_service_account[var.autoscale_common.service_account_key].email) + scopes = try(each.value.scopes, var.autoscale_common.scopes, []) + tags = try(each.value.tags, var.autoscale_common.tags, []) + update_policy_type = try(each.value.update_policy_type, var.autoscale_common.update_policy_type, "OPPORTUNISTIC") + min_vmseries_replicas = try(each.value.min_vmseries_replicas, var.autoscale_common.min_vmseries_replicas) + max_vmseries_replicas = try(each.value.max_vmseries_replicas, var.autoscale_common.max_vmseries_replicas) + cooldown_period = try(each.value.cooldown_period, var.autoscale_common.cooldown_period, 480) + scale_in_control_time_window_sec = try(each.value.scale_in_control_time_window_sec, var.autoscale_common.scale_in_control_time_window_sec, 1800) + scale_in_control_replicas_fixed = try(each.value.scale_in_control_replicas_fixed, var.autoscale_common.scale_in_control_replicas_fixed, 1) + create_pubsub_topic = try(each.value.create_pubsub_topic, var.autoscale_common.create_pubsub_topic) + autoscaler_metrics = try(each.value.autoscaler_metrics, var.autoscale_common.autoscaler_metrics, + { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + }) + + network_interfaces = [for v in each.value.network_interfaces : + { + subnetwork = module.vpc[v.vpc_network_key].subnetworks[v.subnetwork_key].self_link + create_public_ip = try(v.create_public_ip, false) + }] + metadata = merge( + try(each.value.bootstrap_options, {}), + try(var.autoscale_common.bootstrap_options, {}) + ) +} + +data "google_compute_image" "my_image" { + family = "ubuntu-pro-2204-lts" + project = "ubuntu-os-pro-cloud" +} + +resource "google_compute_instance" "linux_vm" { + for_each = var.linux_vms + + name = "${var.name_prefix}${each.key}" + machine_type = each.value.linux_machine_type + zone = each.value.zone + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.id + size = each.value.linux_disk_size + } + } + + network_interface { + subnetwork = module.vpc[each.value.vpc_network_key].subnetworks[each.value.subnetwork_key].self_link + network_ip = each.value.private_ip + } + + metadata = { + enable-oslogin = true + } + + + service_account { + email = module.iam_service_account[each.value.service_account_key].email + scopes = each.value.scopes + } +} + +module "lb_internal" { + source = "../../modules/lb_internal" + + for_each = var.lbs_internal + + name = "${var.name_prefix}${each.value.name}" + region = var.region + health_check_port = try(each.value.health_check_port, "80") + backends = var.autoscale_regional_mig ? { for v in each.value.backends : v => module.autoscale[v].regional_instance_group_id } : merge([ + for v in each.value.backends : + { + for z_k, z_v in var.autoscale[v].zones : + "${v}_${z_k}" => module.autoscale[v].zonal_instance_group_ids[z_k] + } + ]...) + subnetwork = module.vpc[each.value.vpc_network_key].subnetworks[each.value.subnetwork_key].self_link + network = module.vpc[each.value.vpc_network_key].network.self_link + all_ports = true +} + +module "lb_external" { + source = "../../modules/lb_external" + + for_each = var.lbs_external + + project = var.project + + name = "${var.name_prefix}${each.value.name}" + backend_instance_groups = var.autoscale_regional_mig ? { for v in each.value.backends : v => module.autoscale[v].regional_instance_group_id } : merge([ + for v in each.value.backends : + { + for z_k, z_v in var.autoscale[v].zones : + "${v}_${z_k}" => module.autoscale[v].zonal_instance_group_ids[z_k] + } + ]...) + rules = each.value.rules + + health_check_http_port = each.value.http_health_check_port + health_check_http_request_path = try(each.value.http_health_check_request_path, "/php/login.php") +} \ No newline at end of file diff --git a/examples/vpc_peering_dedicated_with_autoscale/main_test.go b/examples/vpc_peering_dedicated_with_autoscale/main_test.go new file mode 100644 index 00000000..6986c898 --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/main_test.go @@ -0,0 +1,65 @@ +package vpc_peering_dedicated_with_autoscale + +import ( + "testing" + "log" + + "github.com/PaloAltoNetworks/terraform-modules-vmseries-tests-skeleton/pkg/testskeleton" + "github.com/gruntwork-io/terratest/modules/logger" + "github.com/gruntwork-io/terratest/modules/terraform" +) + +func CreateTerraformOptions(t *testing.T) *terraform.Options { + varsInfo, err := testskeleton.GenerateTerraformVarsInfo("gcp") + if err != nil { + // Handle the error + log.Fatalf("Error generating terraform vars info: %v", err) + } + + // define options for Terraform + terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ + TerraformDir: ".", + VarFiles: []string{"example.tfvars"}, + Vars: map[string]interface{}{ + "name_prefix": varsInfo.NamePrefix, + "project": varsInfo.GoogleProjectId, + }, + Logger: logger.Default, + Lock: true, + Upgrade: true, + SetVarsAfterVarFiles: true, + }) + + return terraformOptions +} + +func TestValidate(t *testing.T) { + testskeleton.ValidateCode(t, nil) +} + +func TestPlan(t *testing.T) { + // define options for Terraform + terraformOptions := CreateTerraformOptions(t) + // prepare list of items to check + assertList := []testskeleton.AssertExpression{} + // plan test infrastructure and verify outputs + testskeleton.PlanInfraCheckErrors(t, terraformOptions, assertList, "No errors are expected") +} + +func TestApply(t *testing.T) { + // define options for Terraform + terraformOptions := CreateTerraformOptions(t) + // prepare list of items to check + assertList := []testskeleton.AssertExpression{} + // deploy test infrastructure and verify outputs and check if there are no planned changes after deployment + testskeleton.DeployInfraCheckOutputs(t, terraformOptions, assertList) +} + +func TestIdempotence(t *testing.T) { + // define options for Terraform + terraformOptions := CreateTerraformOptions(t) + // prepare list of items to check + assertList := []testskeleton.AssertExpression{} + // deploy test infrastructure and verify outputs and check if there are no planned changes after deployment + testskeleton.DeployInfraCheckOutputsVerifyChanges(t, terraformOptions, assertList) +} diff --git a/examples/vpc_peering_dedicated_with_autoscale/outputs.tf b/examples/vpc_peering_dedicated_with_autoscale/outputs.tf new file mode 100644 index 00000000..eec4859c --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/outputs.tf @@ -0,0 +1,24 @@ +output "pubsub_topic_id" { + description = "The resource ID of the Pub/Sub Topic." + value = try({ for k, v in module.autoscale : k => v.pubsub_topic_id }, null) +} + +output "pubsub_subscription_id" { + description = "The resource ID of the Pub/Sub Subscription." + value = try({ for k, v in module.autoscale : k => v.pubsub_subscription_id }, null) +} + +output "lbs_internal_ips" { + description = "Private IP addresses of internal network loadbalancers." + value = { for k, v in module.lb_internal : k => v.address } +} + +output "lbs_external_ips" { + description = "Public IP addresses of external network loadbalancers." + value = { for k, v in module.lb_external : k => v.ip_addresses } +} + +output "linux_vm_ips" { + description = "Private IP addresses of Linux VMs." + value = { for k, v in resource.google_compute_instance.linux_vm : k => v.network_interface[0].network_ip } +} \ No newline at end of file diff --git a/examples/vpc_peering_dedicated_with_autoscale/variables.tf b/examples/vpc_peering_dedicated_with_autoscale/variables.tf new file mode 100644 index 00000000..d3089ea8 --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/variables.tf @@ -0,0 +1,349 @@ +# General +variable "project" { + description = "The project name to deploy the infrastructure in to." + type = string + default = null +} +variable "region" { + description = "The region into which to deploy the infrastructure in to." + type = string + default = "us-central1" +} +variable "name_prefix" { + description = "A string to prefix resource namings." + type = string + default = "example-" +} + +#Service Account + +variable "service_accounts" { + description = <<-EOF + A map containing each service account setting. + + Example of variable deployment : + ``` + service_accounts = { + "sa-vmseries-01" = { + service_account_id = "sa-vmseries-01" + display_name = "VM-Series SA" + roles = [ + "roles/compute.networkViewer", + "roles/logging.logWriter", + "roles/monitoring.metricWriter", + "roles/monitoring.viewer", + "roles/viewer" + ] + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/iam_service_account#Inputs) + + Multiple keys can be added and will be deployed by the code. + + EOF + type = map(any) + default = {} +} + +#VPC + +variable "networks" { + description = <<-EOF + A map containing each network setting. + + Example of variable deployment : + + ``` + networks = { + fw-mgmt-vpc = { + vpc_name = "fw-mgmt-vpc" + create_network = true + delete_default_routes_on_create = false + mtu = "1460" + routing_mode = "REGIONAL" + subnetworks = { + fw-mgmt-sub = { + name = "fw-mgmt-sub" + create_subnetwork = true + ip_cidr_range = "10.10.10.0/28" + region = "us-east1" + } + } + firewall_rules = { + allow-mgmt-ingress = { + name = "allow-mgmt-vpc" + source_ranges = ["10.10.10.0/24", "1.1.1.1/32"] # Replace 1.1.1.1/32 with your own souurce IP address for management purposes. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + } + } + } + ``` + + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc#input_networks) + + Multiple keys can be added and will be deployed by the code. + EOF + type = any + default = {} +} + +variable "vpc_peerings" { + description = <<-EOF + A map containing each VPC peering setting. + + Example of variable deployment : + + ``` + vpc_peerings = { + "trust-to-spoke1" = { + local_network_key = "fw-trust-vpc" + peer_network_key = "fw-spoke1-vpc" + + local_export_custom_routes = true + local_import_custom_routes = true + local_export_subnet_routes_with_public_ip = true + local_import_subnet_routes_with_public_ip = true + + peer_export_custom_routes = true + peer_import_custom_routes = true + peer_export_subnet_routes_with_public_ip = true + peer_import_subnet_routes_with_public_ip = true + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc-peering#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +variable "routes" { + description = <<-EOF + A map containing each route setting. Note that you can only add routes using a next-hop type of internal load-balance rule. + + Example of variable deployment : + + ``` + routes = { + "default-route-trust" = { + name = "fw-default-trust" + destination_range = "0.0.0.0/0" + vpc_network_key = "fw-trust-vpc" + lb_internal_name = "internal-lb" + } + } + ``` + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +#Autoscale +variable "autoscale_regional_mig" { + description = <<-EOF + Sets the managed instance group type to either a regional (if `true`) or a zonal (if `false`). + For more information please see [About regional MIGs](https://cloud.google.com/compute/docs/instance-groups/regional-migs#why_choose_regional_managed_instance_groups). + EOF + type = bool + default = true +} +variable "autoscale_common" { + description = <<-EOF + A map containing common vmseries autoscale setting. + Bootstrap options can be moved between vmseries autoscale individual instances variable (`autoscale`) and this common vmseries autoscale variable (`autoscale_common`). + + Example of variable deployment : + + ``` + autoscale_common = { + image = "vmseries-flex-byol-1110" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + disk_type = "pd-ssd" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + tags = ["vmseries-autoscale"] + update_policy_type = "OPPORTUNISTIC" + cooldown_period = 480 + bootstrap_options = [ + panorama_server = "1.1.1.1" + ] + } + ``` + EOF + type = any + default = {} +} + +variable "autoscale" { + description = <<-EOF + A map containing each vmseries autoscale setting. + Zonal or regional managed instance group type is controolled from the `autoscale_regional_mig` variable for all autoscale instances. + + Example of variable deployment : + + ``` + autoscale = { + fw-autoscale-common = { + name = "fw-autoscale-common" + zones = { + zone1 = "us-east4-b" + zone2 = "us-east4-c" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + service_account_key = "sa-vmseries-01" + min_vmseries_replicas = 2 + max_vmseries_replicas = 4 + create_pubsub_topic = true + autoscaler_metrics = { + "custom.googleapis.com/VMSeries/panSessionUtilization" = { + target = 70 + } + "custom.googleapis.com/VMSeries/panSessionThroughputKbps" = { + target = 700000 + } + } + bootstrap_options = { + type = "dhcp-client" + dhcp-send-hostname = "yes" + dhcp-send-client-id = "yes" + dhcp-accept-server-hostname = "yes" + dhcp-accept-server-domain = "yes" + mgmt-interface-swap = "enable" + panorama-server = "1.1.1.1" + ssh-keys = "admin:" # Replace this value with client data + } + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + } + ] + } + } + ``` + EOF + type = any + default = {} +} + +#Load Balancers + +variable "lbs_internal" { + description = <<-EOF + A map containing each internal loadbalancer setting. + Note : private IP reservation is not by default within the example as it may overlap with autoscale IP allocation. + + Example of variable deployment : + + ``` + lbs_internal = { + "internal-lb" = { + name = "internal-lb" + health_check_port = "80" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + subnetwork_key = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_internal#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} +variable "lbs_external" { + description = <<-EOF + A map containing each external loadbalancer setting. + + Example of variable deployment : + + ``` + lbs_external = { + "external-lb" = { + name = "external-lb" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + rules = { + "all-ports" = { + ip_protocol = "L3_DEFAULT" + } + } + http_health_check_port = "80" + http_health_check_request_path = "/php/login.php" + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_external#inputs) + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +#Spoke VPCs Linux VMs + +variable "linux_vms" { + description = <<-EOF + A map containing each Linux VM configuration that will be placed in SPOKE VPCs for testing purposes. + + Example of varaible deployment: + + ``` + linux_vms = { + spoke1-vm = { + linux_machine_type = "n2-standard-4" + zone = "us-east1-b" + linux_disk_size = "50" # Modify this value as per deployment requirements + vpc_network_key = "fw-spoke1-vpc" + subnetwork_key = "fw-spoke1-sub" + private_ip = "192.168.1.2" + scopes = [ + "https://www.googleapis.com/auth/compute.readonly", + "https://www.googleapis.com/auth/cloud.useraccounts.readonly", + "https://www.googleapis.com/auth/devstorage.read_only", + "https://www.googleapis.com/auth/logging.write", + "https://www.googleapis.com/auth/monitoring.write", + ] + service_account_key = "sa-linux-01" + } + } + ``` + EOF + type = map(any) + default = {} +} diff --git a/examples/vpc_peering_dedicated_with_autoscale/versions.tf b/examples/vpc_peering_dedicated_with_autoscale/versions.tf new file mode 100644 index 00000000..785e9269 --- /dev/null +++ b/examples/vpc_peering_dedicated_with_autoscale/versions.tf @@ -0,0 +1,13 @@ +terraform { + required_version = ">= 1.3, < 2.0" +} + +provider "google" { + project = var.project + region = var.region +} + +provider "google-beta" { + project = var.project + region = var.region +}