diff --git a/examples/vpc_peering_common_dual_stack/README.md b/examples/vpc_peering_common_dual_stack/README.md new file mode 100644 index 0000000..59d86fa --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/README.md @@ -0,0 +1,318 @@ +--- +short_title: Common Firewall Option - IPv4/IPv6 Dual Stack +type: refarch +show_in_hub: false +--- +# Reference Architecture with Terraform: VM-Series in GCP, Centralized Architecture, Common NGFW Option - IPv4/IPv6 Dual Stack + +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 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). + +## Reference Architecture Design + +![simple](https://github.com/PaloAltoNetworks/terraform-google-swfw-modules/assets/2110772/9530fc51-7267-4b74-a996-a522b97f0996) + +This code implements: +- a _centralized design_, a hub-and-spoke topology with a shared VPC containing VM-Series to inspect all inbound, outbound, east-west, and enterprise traffic +- the _common option_, which routes all traffic flows onto a single set of VM-Series + +## 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 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 + +The common firewall option leverages a single set of VM-Series firewalls. The sole set of firewalls operates as a shared resource and may present scale limitations with all traffic flowing through a single set of firewalls due to the performance degradation that occurs when traffic crosses virtual routers. This option is suitable for proof-of-concepts and smaller scale deployments because the number of firewalls is low. However, the technical integration complexity is high. + +![VM-Series-Common-Firewall-Option-Dual-Stack](https://github.com/user-attachments/assets/427a318e-5288-456f-ab3f-72a7cad73ba2) + +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. + +The example makes use of VM-Series full [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 XML templates to properly parametrize the initial Day 0 configuration. + +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 VM-Series firewalls + - 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) + +## IPv4/IPv6 Dual Stack + +This example implements end-to-end IPv6 connectivity (alongside with IPv4 connectivity, in dual stack fashion) for data VPCs: + - Untrust (outside) VPC + - Trust (inside/security) VPC + - Spoke-1 VPC + - Spoke-2 VPC + +Untrust VPC is assigned with IPv6 adresses from an external IPv6 address range, while other VPCs (Trust, Spoke-1, Spoke-2) are utilizing private IPv6 ULA address range. + +Management VPC connectivity is IPv4 only. + +>**Note**: VM-Series must run PAN-OS version `>=11` to provide IPv6 support. + +### IPv6 Routing + +As of September 2024 there is a cloud provider [limitation](https://cloud.google.com/vpc/docs/static-routes#static-route-next-hops) that a static IPv6 route can't have a passthrough Network Load Balancer as the next hop. + +To enable outbound routing from Spoke-1 and Spoke-2 VPCs a policy based route is used to forward traffic to the Internal Load Balancer and then VM-Series. + +As of September 2024 `terraform-provider-google` supports `google_network_connectivity_policy_based_route` resources only for IPv4 protocol version. To overcome this limitation a `local-exec` provisioner running `gcloud beta network-connectivity policy-based-routes create <...>` is used to manage policy based routes. + +>**Note**: `local-exec` requires `gcloud` beta components. To install the components run `gcloud components install beta`. + +## 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) +3. Install `gcloud` beta components: `gcloud components install beta` + +## 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-swfw-modules +cd terraform-google-swfw-modules/examples/vpc_peering_common_dual_stack +``` + +3. Copy the `example.tfvars` to `terraform.tfvars`. + +`project`, `ssh_keys` and `source_ranges` 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` + - `vmseries..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: 92 added, 0 changed, 0 destroyed. (Number of resources can vary based on how many instances you push through tfvars) + +Outputs: + +lbs_external_ips = [ + { + "example-ipv6-all-ports-ipv4" = "" + }, + { + "example-ipv6-all-ports-ipv6" = "EXTERNAL_LB_PUBLIC_IPV6_ADDRESS" + }, +] +lbs_internal_ips = { + "internal-lb-ipv4" = "10.10.12.5" + "internal-lb-ipv6" = "" +} +linux_vm_ips = { + "spoke1-vm" = "192.168.1.2" + "spoke2-vm" = "192.168.2.2" +} +vmseries_ipv6_private_ips = { + "fw-vmseries-01" = { + "0" = "" + "1" = "" + "2" = "" + } + "fw-vmseries-02" = { + "0" = "" + "1" = "" + "2" = "" + } +} +vmseries_ipv6_public_ips = { + "fw-vmseries-01" = { + "0" = "" + } + "fw-vmseries-02" = { + "0" = "" + } +} +vmseries_private_ips = { + "fw-vmseries-01" = { + "0" = "10.10.11.2" + "1" = "10.10.10.2" + "2" = "10.10.12.2" + } + "fw-vmseries-02" = { + "0" = "10.10.11.3" + "1" = "10.10.10.3" + "2" = "10.10.12.3" + } +} +vmseries_public_ips = { + "fw-vmseries-01" = { + "0" = "" + "1" = "" + } + "fw-vmseries-02" = { + "0" = "" + "1" = "" + } +} +``` + +## Post build + +Connect to the VM-Series instance(s) via SSH using your associated private key and check if the bootstrap process if finished successfuly and then set a password : + - Please allow for up to 10-15 minutes for the bootstrap process to finish + - The key output you should check for is "Auto-commit Successful" + +``` +ssh admin@x.x.x.x -i /PATH/TO/YOUR/KEY/id_rsa +Welcome admin. +admin@PA-VM> show system bootstrap status + +Bootstrap Phase Status Details +=============== ====== ======= +Media Detection Success Media detected successfully +Media Sanity Check Success Media sanity check successful +Parsing of Initial Config Successful +Auto-commit Successful + +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://` and login with admin and your previously configured password. + +## Configuration adjustment + +Adjust VM-Series configuration according to the instructions below. + +### Change the Loopback IP Addresses + +For the VM-Series that are backend instance group members of the public-facing loadbalancer - go to Network -> Interfaces -> Loopback: +- IPv4 tab: change the value of `1.1.1.1` with the value from the `` from the Terraform outputs. +- IPv6 tab: + - change the value of `1::1/128` with the value from the `` from the Terraform outputs. Use `/128` as netmask. + - change the value of `fd20::1/128` with the value from the `` from the Terraform outputs. Use `/128` as netmask. + +### Change Source NAT IP pool + +Navigate to Policies -> NAT -> [Internet-Access-NAT-IPv6] and cahnge Translated Packet -> Source Address Translation -> Translated Address from `1::/96` to `` + +## Check traffic from spoke VMs + +The firewalls are bootstrapped with a generic `allow any` policy just for demo purposes along with an outboud SNAT policy to allow Inernet access from spoke VMs. + +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 ipv4.google.com +@spoke1-vm:~$ping6 ipv6.google.com +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.3, < 2.0 | + +### Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | n/a | +| [local](#provider\_local) | n/a | +| [null](#provider\_null) | n/a | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [bootstrap](#module\_bootstrap) | ../../modules/bootstrap | 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 | +| [vmseries](#module\_vmseries) | ../../modules/vmseries | 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 | +| [local_file.bootstrap_xml](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [local_sensitive_file.init_cfg](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/sensitive_file) | resource | +| [null_resource.pbr_override_vmseries](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | +| [null_resource.policy_routes](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | 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 | +|------|-------------|------|---------|:--------:| +| [bootstrap\_buckets](#input\_bootstrap\_buckets) | A map containing each bootstrap bucket setting.

Example of variable deployment:
bootstrap_buckets = {
vmseries-bootstrap-bucket-01 = {
bucket_name_prefix = "bucket-01-"
location = "us"
service_account_key = "sa-vmseries-01"
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-swfw-modules/tree/main/modules/bootstrap#Inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | 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-swfw-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.

Example of variable deployment :
lbs_internal = {
"internal-lb" = {
name = "internal-lb"
health_check_port = "80"
backends = ["fw-vmseries-01", "fw-vmseries-02"]
ip_address = "10.10.12.5"
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-swfw-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-swfw-modules/tree/main/modules/vpc#input_networks)

Multiple keys can be added and will be deployed by the code. | `any` | n/a | yes | +| [policy\_routes](#input\_policy\_routes) | A map containing Policy-Based Routes that are used to route outgoing IPv6 traffic to ILB.
Note that policy routes support ILB only as a next-hop.

Example :
routes = {
spoke1-vpc-default-ipv6 = {
name = "spoke1-vpc-default-ipv6"
destination_range = "::/0"
vpc_network_key = "fw-spoke1-vpc"
lb_internal_key = "internal-lb-ipv6"
}
spoke2-vpc-default-ipv6 = {
name = "spoke2-vpc-default-ipv6"
destination_range = "::/0"
vpc_network_key = "fw-spoke2-vpc"
lb_internal_key = "internal-lb-ipv6"
}
}
Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [policy\_routes\_trust\_vpc\_network\_key](#input\_policy\_routes\_trust\_vpc\_network\_key) | Trust VPC network\_key that is used to configure a DEFAULT\_ROUTING PBR that prevents network loops. | `string` | n/a | yes | +| [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-swfw-modules/tree/main/modules/iam_service_account#Inputs)

Multiple keys can be added and will be deployed by the code. | `map(any)` | `{}` | no | +| [vmseries](#input\_vmseries) | A map containing each individual vmseries setting.

Example of variable deployment :
vmseries = {
"fw-vmseries-01" = {
name = "fw-vmseries-01"
zone = "us-east1-b"
machine_type = "n2-standard-4"
min_cpu_platform = "Intel Cascade Lake"
tags = ["vmseries"]
service_account_key = "sa-vmseries-01"
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",
]
bootstrap_bucket_key = "vmseries-bootstrap-bucket-01"
bootstrap_options = {
panorama-server = "1.1.1.1"
dns-primary = "8.8.8.8"
dns-secondary = "8.8.4.4"
}
bootstrap_template_map = {
trust_gcp_router_ip = "10.10.12.1"
untrust_gcp_router_ip = "10.10.11.1"
private_network_cidr = "192.168.0.0/16"
untrust_loopback_ip = "1.1.1.1/32" #This is placeholder IP - you must replace it on the vmseries config with the LB public IP address after the infrastructure is deployed
trust_loopback_ip = "10.10.12.5/32"
}
named_ports = [
{
name = "http"
port = 80
},
{
name = "https"
port = 443
}
]
network_interfaces = [
{
vpc_network_key = "fw-untrust-vpc"
subnetwork_key = "fw-untrust-sub"
private_ip = "10.10.11.2"
create_public_ip = true
},
{
vpc_network_key = "fw-mgmt-vpc"
subnetwork_key = "fw-mgmt-sub"
private_ip = "10.10.10.2"
create_public_ip = true
},
{
vpc_network_key = "fw-trust-vpc"
subnetwork_key = "fw-trust-sub"
private_ip = "10.10.12.2"
},
]
}
}
For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-swfw-modules/tree/main/modules/vmseries#inputs)

The bootstrap\_template\_map contains variables that will be applied to the bootstrap template. Each firewall Day 0 bootstrap will be parametrised based on these inputs.
Multiple keys can be added and will be deployed by the code. | `any` | n/a | yes | +| [vmseries\_common](#input\_vmseries\_common) | A map containing common vmseries setting.

Example of variable deployment :
vmseries_common = {
ssh_keys = "admin:AAAABBBB..."
vmseries_image = "vmseries-flex-byol-1029h1"
machine_type = "n2-standard-4"
min_cpu_platform = "Intel Cascade Lake"
service_account_key = "sa-vmseries-01"
bootstrap_options = {
type = "dhcp-client"
mgmt-interface-swap = "enable"
}
}
Bootstrap options can be moved between vmseries individual instance variable (`vmseries`) and this common vmserie variable (`vmseries_common`). | `any` | n/a | yes | +| [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-swfw-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. | +| [vmseries\_ipv6\_private\_ips](#output\_vmseries\_ipv6\_private\_ips) | Private IPv6 addresses of the VM-Series instances. | +| [vmseries\_ipv6\_public\_ips](#output\_vmseries\_ipv6\_public\_ips) | Public IPv6 addresses of the VM-Series instances. | +| [vmseries\_private\_ips](#output\_vmseries\_private\_ips) | Private IPv4 addresses of the VM-Series instances. | +| [vmseries\_public\_ips](#output\_vmseries\_public\_ips) | Public IPv4 addresses of the VM-Series instances. | + diff --git a/examples/vpc_peering_common_dual_stack/example.tfvars b/examples/vpc_peering_common_dual_stack/example.tfvars new file mode 100644 index 0000000..6825e4a --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/example.tfvars @@ -0,0 +1,486 @@ +# General +project = "" # Modify this value as per deployment requirements +region = "us-east1" # Modify this value as per deployment requirements +name_prefix = "" # Modify this value as per deployment requirements + +# 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" + ] + } +} + +bootstrap_buckets = { + vmseries-bootstrap-bucket-01 = { + bucket_name_prefix = "bucket-01-" + location = "us" + service_account_key = "sa-vmseries-01" + } +} + +# 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-east1" + } + } + firewall_rules = { + allow-mgmt-ingress = { + name = "allow-mgmt-vpc" + source_ranges = ["1.1.1.1/32"] # Modify this value as per deployment requirements. Replace 1.1.1.1/32 with your own source 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-east1" + stack_type = "IPV4_IPV6" + ipv6_access_type = "EXTERNAL" + } + } + firewall_rules = { + allow-untrust-ingress-ipv4-1 = { + name = "allow-untrust-vpc-ipv4-1" + source_ranges = ["0.0.0.0/0"] # Allow connections via Network Load Balancer from any source IP. Change to a more specific IPv6 range if required. + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + allow-untrust-ingress-ipv6-1 = { + name = "allow-untrust-vpc-ipv6-1" + source_ranges = ["::/0"] # Allow connections via Network Load Balancer from any source IP. Change to a more specific IPv6 range if required. + 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" + enable_ula_internal_ipv6 = true + subnetworks = { + fw-trust-sub = { + name = "fw-trust-sub" + create_subnetwork = true + stack_type = "IPV4_IPV6" + ip_cidr_range = "10.10.12.0/28" + ipv6_access_type = "INTERNAL" + region = "us-east1" + } + } + firewall_rules = { + allow-trust-ingress-ipv4-1 = { + name = "allow-trust-vpc-ipv4-1" + source_ranges = ["192.168.0.0/16", "130.211.0.0/22", "35.191.0.0/16"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + allow-trust-ingress-ipv6-1 = { + name = "allow-trust-vpc-ipv6-1" + source_ranges = ["fd20::/20", "2600:2d00:1:b029::/64"] + 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" + enable_ula_internal_ipv6 = true + + subnetworks = { + fw-spoke1-sub = { + name = "fw-spoke1-sub" + create_subnetwork = true + stack_type = "IPV4_IPV6" + ip_cidr_range = "192.168.1.0/28" + ipv6_access_type = "INTERNAL" + region = "us-east1" + } + } + firewall_rules = { + allow-spoke1-ingress-ipv4-1 = { + name = "allow-spoke1-vpc-ipv4-1" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + allow-spoke1-ingress-ipv6-1 = { + name = "allow-spoke1-vpc-ipv6-1" + source_ranges = ["fd20::/20"] # Common GCP IPv6 ULA range + 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" + enable_ula_internal_ipv6 = true + + subnetworks = { + fw-spoke2-sub = { + name = "fw-spoke2-sub" + create_subnetwork = true + stack_type = "IPV4_IPV6" + ip_cidr_range = "192.168.2.0/28" + ipv6_access_type = "INTERNAL" + region = "us-east1" + } + } + firewall_rules = { + allow-spoke2-ingress-ipv4-1 = { + name = "allow-spoke2-vpc-ipv4-1" + source_ranges = ["192.168.0.0/16", "35.235.240.0/20", "10.10.12.0/28"] + priority = "1000" + allowed_protocol = "all" + allowed_ports = [] + } + allow-spoke2-ingress-ipv6-1 = { + name = "allow-spoke2-vpc-ipv6-1" + source_ranges = ["fd20::/20"] # Common GCP IPv6 ULA range + 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 + stack_type = "IPV4_IPV6" + }, + 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 + stack_type = "IPV4_IPV6" + } +} + +# IPv4 static routes +routes = { + fw-default-trust-ipv4 = { + name = "fw-default-trust-ipv4" + destination_range = "0.0.0.0/0" + vpc_network_key = "fw-trust-vpc" + lb_internal_key = "internal-lb-ipv4" + } +} + +# IPv6 policy-based routing +policy_routes = { + spoke1-vpc-default-ipv6 = { + name = "spoke1-vpc-default-ipv6" + destination_range = "::/0" + vpc_network_key = "fw-spoke1-vpc" + lb_internal_key = "internal-lb-ipv6" + } + spoke2-vpc-default-ipv6 = { + name = "spoke2-vpc-default-ipv6" + destination_range = "::/0" + vpc_network_key = "fw-spoke2-vpc" + lb_internal_key = "internal-lb-ipv6" + } +} + +policy_routes_trust_vpc_network_key = "fw-trust-vpc" + +# VM-Series + +vmseries_common = { + ssh_keys = "admin:" # Modify this value as per deployment requirements + vmseries_image = "vmseries-flex-byol-1114" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + service_account_key = "sa-vmseries-01" + bootstrap_options = { + type = "dhcp-client" + mgmt-interface-swap = "enable" + } +} + +vmseries = { + fw-vmseries-01 = { + name = "fw-vmseries-01" + zone = "us-east1-b" + tags = ["vmseries"] + 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", + ] + bootstrap_bucket_key = "vmseries-bootstrap-bucket-01" + bootstrap_options = { + panorama-server = "1.1.1.1" # Modify this value as per deployment requirements + dns-primary = "8.8.8.8" # Modify this value as per deployment requirements + dns-secondary = "8.8.4.4" # Modify this value as per deployment requirements + } + bootstrap_template_map = { + trust_gcp_router_ip = "10.10.12.1" + untrust_gcp_router_ip = "10.10.11.1" + private_network_cidr = "192.168.0.0/16" + untrust_loopback_ip = "1.1.1.1/32" # This is placeholder IP - you must replace it in the VM-Series config with the External LB IPv4 address after the infrastructure is deployed + trust_loopback_ip = "10.10.12.5/32" + untrust_loopback_ipv6 = "1::1/128" # This is placeholder IP - you must replace it in the VM-Series config with the External LB IPv6 address after the infrastructure is deployed + trust_loopback_ipv6 = "fd20::1/128" # This is placeholder IP - you must replace it in the VM-Series config with the Internal LB IPv6 address after the infrastructure is deployed + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + stack_type = "IPV4_IPV6" + private_ip = "10.10.11.2" + create_public_ip = true + create_public_ipv6 = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + private_ip = "10.10.10.2" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + stack_type = "IPV4_IPV6" + private_ip = "10.10.12.2" + } + ] + }, + fw-vmseries-02 = { + name = "fw-vmseries-02" + zone = "us-east1-c" + tags = ["vmseries"] + 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", + ] + bootstrap_bucket_key = "vmseries-bootstrap-bucket-01" + bootstrap_options = { + panorama-server = "1.1.1.1" # Modify this value as per deployment requirements + dns-primary = "8.8.8.8" # Modify this value as per deployment requirements + dns-secondary = "8.8.4.4" # Modify this value as per deployment requirements + } + bootstrap_template_map = { + trust_gcp_router_ip = "10.10.12.1" + untrust_gcp_router_ip = "10.10.11.1" + private_network_cidr = "192.168.0.0/16" + untrust_loopback_ip = "1.1.1.1/32" # This is placeholder IP - you must replace it in the VM-Series config with the External LB IPv4 address after the infrastructure is deployed + trust_loopback_ip = "10.10.12.5/32" + untrust_loopback_ipv6 = "1::1/128" # This is placeholder IP - you must replace it in the VM-Series config with the External LB IPv6 address after the infrastructure is deployed + trust_loopback_ipv6 = "fd20::1/128" # This is placeholder IP - you must replace it in the VM-Series config with the Internal LB IPv6 address after the infrastructure is deployed + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + stack_type = "IPV4_IPV6" + private_ip = "10.10.11.3" + create_public_ip = true + create_public_ipv6 = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + private_ip = "10.10.10.3" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + stack_type = "IPV4_IPV6" + private_ip = "10.10.12.3" + } + ] + } +} + +# Spoke Linux VMs +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" + stack_type = "IPV4_IPV6" + 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-east1-b" + linux_disk_size = "50" # Modify this value as per deployment requirements + vpc_network_key = "fw-spoke2-vpc" + subnetwork_key = "fw-spoke2-sub" + stack_type = "IPV4_IPV6" + 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-ipv4 = { + name = "internal-lb-ipv4" + health_check_port = "80" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + ip_address = "10.10.12.5" + subnetwork = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + ip_version = "IPV4" + } + internal-lb-ipv6 = { + name = "internal-lb-ipv6" + health_check_port = "80" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + ip_address = null + subnetwork = "fw-trust-sub" + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + ip_version = "IPV6" + } +} + +# External Network Loadbalancer +lbs_external = { + external-lb = { + name = "external-lb-ipv4-ipv6" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + rules = { + all-ports-ipv4 = { + ip_protocol = "L3_DEFAULT" + } + all-ports-ipv6 = { + ip_version = "IPV6" + ip_protocol = "L3_DEFAULT" + } + } + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + http_health_check_port = "80" + http_health_check_request_path = "/unauth/php/health.php" + } +} \ No newline at end of file diff --git a/examples/vpc_peering_common_dual_stack/main.tf b/examples/vpc_peering_common_dual_stack/main.tf new file mode 100644 index 0000000..a38c24e --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/main.tf @@ -0,0 +1,273 @@ +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 +} + +resource "local_file" "bootstrap_xml" { + + for_each = { for k, v in var.vmseries : k => v + if can(v.bootstrap_template_map) + } + + filename = "files/${each.key}/config/bootstrap.xml" + content = templatefile("templates/bootstrap_common.tmpl", + { + trust_gcp_router_ip = each.value.bootstrap_template_map.trust_gcp_router_ip + private_network_cidr = each.value.bootstrap_template_map.private_network_cidr + untrust_gcp_router_ip = each.value.bootstrap_template_map.untrust_gcp_router_ip + trust_loopback_ip = each.value.bootstrap_template_map.trust_loopback_ip + untrust_loopback_ip = each.value.bootstrap_template_map.untrust_loopback_ip + trust_loopback_ipv6 = each.value.bootstrap_template_map.trust_loopback_ipv6 + untrust_loopback_ipv6 = each.value.bootstrap_template_map.untrust_loopback_ipv6 + } + ) +} + +resource "local_sensitive_file" "init_cfg" { + + for_each = { for k, v in var.vmseries : k => v + if can(v.bootstrap_template_map) + } + + filename = "files/${each.key}/config/init-cfg.txt" + content = templatefile( + "templates/init-cfg.tmpl", + { bootstrap_options = merge(var.vmseries_common.bootstrap_options, each.value.bootstrap_options) } + ) +} + +module "bootstrap" { + source = "../../modules/bootstrap" + + for_each = var.bootstrap_buckets + + folders = keys(var.vmseries) + + name_prefix = "${var.name_prefix}${each.value.bucket_name_prefix}" + service_account = module.iam_service_account[each.value.service_account_key].email + location = each.value.location + files = merge( + { for k, v in var.vmseries : "files/${k}/config/bootstrap.xml" => "${k}/config/bootstrap.xml" if can(v.bootstrap_template_map) }, + { for k, v in var.vmseries : "files/${k}/config/init-cfg.txt" => "${k}/config/init-cfg.txt" if can(v.bootstrap_template_map) }, + ) +} + +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 + enable_ula_internal_ipv6 = try(each.value.enable_ula_internal_ipv6, false) + internal_ipv6_range = try(each.value.internal_ipv6_range, null) + 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 +} + +resource "null_resource" "policy_routes" { + for_each = var.policy_routes + + triggers = { + project = var.project + name = "${var.name_prefix}${each.key}-pbr" + } + provisioner "local-exec" { + command = join(" ", [ + "gcloud beta network-connectivity policy-based-routes create ${self.triggers.name}", + "--priority=90", + "--source-range=::/0", + "--destination-range=::/0", + "--ip-protocol=ALL", + "--protocol-version=IPv6", + "--network=${module.vpc[each.value.vpc_network_key].network.id}", + "--next-hop-ilb-ip=${split("/", module.lb_internal[each.value.lb_internal_key].address)[0]}", + "--description=Policy-based-route-for-IPv6-outbound-connectivity", + "--project ${var.project}" + ]) + interpreter = ["bash", "-c"] + } + provisioner "local-exec" { + when = destroy + command = "gcloud beta network-connectivity policy-based-routes delete ${self.triggers.name} --project ${self.triggers.project} --quiet || true" + interpreter = ["bash", "-c"] + } +} + +resource "null_resource" "pbr_override_vmseries" { + triggers = { + project = var.project + name = "${var.name_prefix}pbr-override-vmseries" + } + provisioner "local-exec" { + command = join(" ", [ + "gcloud beta network-connectivity policy-based-routes create ${self.triggers.name}", + "--priority=10", + "--tags=vmseries", + "--ip-protocol=ALL", + "--protocol-version=IPv6", + "--network=${module.vpc[var.policy_routes_trust_vpc_network_key].network.id}", + "--next-hop-other-routes=DEFAULT_ROUTING", + "--description=Use-DEFAULT_ROUTING-for-packets-coming-from-VM-Series", + "--project ${var.project}" + ]) + } + provisioner "local-exec" { + when = destroy + command = "gcloud beta network-connectivity policy-based-routes delete ${self.triggers.name} --project ${self.triggers.project} --quiet || true" + } +} + +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 + stack_type = each.value.stack_type +} + +module "vmseries" { + source = "../../modules/vmseries" + + for_each = var.vmseries + + name = "${var.name_prefix}${each.value.name}" + zone = each.value.zone + ssh_keys = try(each.value.ssh_keys, var.vmseries_common.ssh_keys) + vmseries_image = try(each.value.vmseries_image, var.vmseries_common.vmseries_image) + machine_type = try(each.value.machine_type, var.vmseries_common.machine_type) + min_cpu_platform = try(each.value.min_cpu_platform, var.vmseries_common.min_cpu_platform, "Intel Cascade Lake") + tags = try(each.value.tags, var.vmseries_common.tags, []) + service_account = try(module.iam_service_account[each.value.service_account_key].email, module.iam_service_account[var.vmseries_common.service_account_key].email) + scopes = try(each.value.scopes, var.vmseries_common.scopes, []) + create_instance_group = true + + bootstrap_options = try( + merge( + { vmseries-bootstrap-gce-storagebucket = "${module.bootstrap[each.value.bootstrap_bucket_key].bucket_name}/${each.key}/" }, + var.vmseries_common.bootstrap_options), + merge( + try(each.value.bootstrap_options, {}), + try(var.vmseries_common.bootstrap_options, {}) + )) + + named_ports = try(each.value.named_ports, []) + + network_interfaces = [for v in each.value.network_interfaces : + { + subnetwork = module.vpc[v.vpc_network_key].subnetworks[v.subnetwork_key].self_link + stack_type = try(v.stack_type, null) + private_ip = v.private_ip + create_public_ip = try(v.create_public_ip, false) + public_ip = try(v.public_ip, null) + create_public_ipv6 = try(v.create_public_ipv6, false) + public_ipv6 = try(v.public_ipv6, null) + }] +} + +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 + stack_type = each.value.stack_type + 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 = { for v in each.value.backends : v => module.vmseries[v].instance_group_self_link } + ip_version = lookup(each.value, "ip_version", null) + ip_address = each.value.ip_address + 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 = { for v in each.value.backends : v => module.vmseries[v].instance_group_self_link } + rules = { for k, v in each.value.rules : "${var.name_prefix}${k}" => v } + subnetwork = try(module.vpc[each.value.vpc_network_key].subnetworks[each.value.subnetwork_key].self_link, null) + + 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_common_dual_stack/main_test.go b/examples/vpc_peering_common_dual_stack/main_test.go new file mode 100644 index 0000000..898372f --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/main_test.go @@ -0,0 +1,65 @@ +package vpc_peering_common_dual_stack + +import ( + "log" + "testing" + + "github.com/PaloAltoNetworks/terraform-modules-swfw-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_common_dual_stack/outputs.tf b/examples/vpc_peering_common_dual_stack/outputs.tf new file mode 100644 index 0000000..7ec97d3 --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/outputs.tf @@ -0,0 +1,38 @@ +output "vmseries_private_ips" { + description = "Private IPv4 addresses of the VM-Series instances." + value = { for k, v in module.vmseries : k => v.private_ips } +} + +output "vmseries_ipv6_private_ips" { + description = "Private IPv6 addresses of the VM-Series instances." + value = { for k, v in module.vmseries : k => v.ipv6_private_ips } +} + +output "vmseries_public_ips" { + description = "Public IPv4 addresses of the VM-Series instances." + value = { for k, v in module.vmseries : k => v.public_ips } +} + +output "vmseries_ipv6_public_ips" { + description = "Public IPv6 addresses of the VM-Series instances." + value = { for k, v in module.vmseries : k => v.ipv6_public_ips } +} + +output "lbs_internal_ips" { + description = "Private IP addresses of internal network loadbalancers." + value = { for k, v in module.lb_internal : k => try(split("/", v.address)[0], v.address, null) } +} + +output "lbs_external_ips" { + description = "Public IP addresses of external network loadbalancers." + value = flatten([for k1, v1 in module.lb_external : [ + for k2, v2 in v1.ip_addresses : { + (k2) = try(split("/", v2)[0], v2, null) + }] + ]) +} + +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 } +} diff --git a/examples/vpc_peering_common_dual_stack/templates/bootstrap_common.tmpl b/examples/vpc_peering_common_dual_stack/templates/bootstrap_common.tmpl new file mode 100644 index 0000000..e60feb3 --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/templates/bootstrap_common.tmpl @@ -0,0 +1,858 @@ + + + + + + * + + + yes + + + + + + yes + 8 + + + + + + + + + + + + yes + 5 + + + yes + 5 + + + yes + 5 + + + yes + 10 + + + yes + 5 + + + + yes + + + + 10 + 10 + + 100 + 50 + + + + 10 + 10 + + 100 + 50 + + + + + + 100 + yes + + + + + + + + + + + + yes + + + + + + + no + + + + + + no + + no + + + + + yes + + + + yes + + + + + + yes + 100 + + + + no + + + + no + + + no + + + no + + lb_health_check + + no + + + + + + + yes + + + + + + + no + + + + + + no + + no + + + + + yes + + + + no + + + + + + yes + 100 + + + + no + + + + no + + + no + + + no + + + no + + lb_health_check + + + + + + + + no + + + + + + + yes +
+ + yes + + + yes + +
+
+ lb_health_check +
+
+
+
+ + + + 3 + 5 + wait-recover + + + + + + + + + + + + + yes + + + + + + + + + aes-128-cbc + 3des + + + sha1 + + + group2 + + + 8 + + + + + aes-128-cbc + + + sha256 + + + group19 + + + 8 + + + + + aes-256-cbc + + + sha384 + + + group20 + + + 8 + + + + + + + + aes-128-cbc + 3des + + + sha1 + + + group2 + + 1 + + + + + + aes-128-gcm + + + none + + + group19 + + 1 + + + + + + aes-256-gcm + + + none + + + group20 + + 1 + + + + + + + aes-128-cbc + + + sha1 + + + + + + + + + + + + + real-time + + + high + + + high + + + medium + + + medium + + + low + + + low + + + low + + + + + + + + + + + + no + + + 1.25 + 0.5 + 900 + 300 + 900 + yes + + + + + yes + + + + + no + + + no + + + no + + + + ethernet1/1 + ethernet1/2 + loopback.10 + + + + + + yes + yes + 4 + + + + + + + ${untrust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/1 + 10 + 35.191.0.0/16 + + + + + + + ${trust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/2 + 10 + 35.191.0.0/16 + + + + + + + ${untrust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/1 + 10 + 209.85.152.0/22 + + + + + + + ${trust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/2 + 10 + 209.85.152.0/22 + + + + + + + ${untrust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/1 + 10 + 209.85.204.0/22 + + + + + + + ${trust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/2 + 10 + 209.85.204.0/22 + + + + + + + ${untrust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/1 + 10 + 130.211.0.0/22 + + + + + + + ${trust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/2 + 10 + 130.211.0.0/22 + + + + + + + ${untrust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/1 + 10 + 0.0.0.0/0 + + + + + + + ${trust_gcp_router_ip} + + + None + + + no + any + 2 + + ethernet1/2 + 10 + ${private_network_cidr} + + + + + + + + + + + fe80::1 + + + None + + ethernet1/1 + 10 + 2600:1901:8001::/48 + + + + + + + fe80::1 + + + None + + ethernet1/2 + 10 + 2600:2d00:1:b029::/64 + + + + + + + fe80::10 + + + None + + ethernet1/2 + 10 + fd20::/20 + + + + + + + + + +
+ + + + + yes + no + no + no + + + updates.paloaltonetworks.com + + + + + wednesday + 01:02 + download-only + + + + + US/Pacific + + yes + yes + + + + 0.us.pool.ntp.org + + + + + + 1.us.pool.ntp.org + + + + + + + + + yes + + + FQDN + + panadmin + + + yes + no + no + no + + + + + + + + + + + + + + + ethernet1/1 + loopback.10 + + + + + + + ethernet1/2 + + + + + + + + + + + + + any + + + any + + + any + + + any + + + any + + + any + + + any + + + any + + + any + + + any + + allow + + + + + + + + + + ethernet1/1 + + + + + public + + + private + + + ${private_network_cidr} + + + any + + any + + + nptv6 + + private + + + public + + any + any + + fd20::/20 + + + any + + + + 1::/96 + + + no + + + + + + + + ethernet1/1 + ethernet1/2 + loopback.10 + + + + + +
+
+
\ No newline at end of file diff --git a/examples/vpc_peering_common_dual_stack/templates/init-cfg.tmpl b/examples/vpc_peering_common_dual_stack/templates/init-cfg.tmpl new file mode 100644 index 0000000..54fe29c --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/templates/init-cfg.tmpl @@ -0,0 +1,3 @@ +%{ for k, v in bootstrap_options ~} +${k}=${v} +%{ endfor ~} \ No newline at end of file diff --git a/examples/vpc_peering_common_dual_stack/variables.tf b/examples/vpc_peering_common_dual_stack/variables.tf new file mode 100644 index 0000000..fdf7869 --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/variables.tf @@ -0,0 +1,396 @@ +# 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-swfw-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 = {} +} + +#Bootstrap bucket + +variable "bootstrap_buckets" { + description = <<-EOF + A map containing each bootstrap bucket setting. + + Example of variable deployment: + + ``` + bootstrap_buckets = { + vmseries-bootstrap-bucket-01 = { + bucket_name_prefix = "bucket-01-" + location = "us" + service_account_key = "sa-vmseries-01" + } + } + ``` + + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-swfw-modules/tree/main/modules/bootstrap#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-swfw-modules/tree/main/modules/vpc#input_networks) + + Multiple keys can be added and will be deployed by the code. + EOF +} + +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-swfw-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 = {} +} + +variable "policy_routes" { + description = <<-EOF + A map containing Policy-Based Routes that are used to route outgoing IPv6 traffic to ILB. + Note that policy routes support ILB only as a next-hop. + + Example : + + ``` + routes = { + spoke1-vpc-default-ipv6 = { + name = "spoke1-vpc-default-ipv6" + destination_range = "::/0" + vpc_network_key = "fw-spoke1-vpc" + lb_internal_key = "internal-lb-ipv6" + } + spoke2-vpc-default-ipv6 = { + name = "spoke2-vpc-default-ipv6" + destination_range = "::/0" + vpc_network_key = "fw-spoke2-vpc" + lb_internal_key = "internal-lb-ipv6" + } + } + ``` + + Multiple keys can be added and will be deployed by the code. + EOF + type = map(any) + default = {} +} + +variable "policy_routes_trust_vpc_network_key" { + description = "Trust VPC network_key that is used to configure a DEFAULT_ROUTING PBR that prevents network loops." + type = string +} + +#vmseries + +variable "vmseries_common" { + description = <<-EOF + A map containing common vmseries setting. + + Example of variable deployment : + + ``` + vmseries_common = { + ssh_keys = "admin:AAAABBBB..." + vmseries_image = "vmseries-flex-byol-1029h1" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + service_account_key = "sa-vmseries-01" + bootstrap_options = { + type = "dhcp-client" + mgmt-interface-swap = "enable" + } + } + ``` + + Bootstrap options can be moved between vmseries individual instance variable (`vmseries`) and this common vmserie variable (`vmseries_common`). + EOF +} +variable "vmseries" { + description = <<-EOF + A map containing each individual vmseries setting. + + Example of variable deployment : + + ``` + vmseries = { + "fw-vmseries-01" = { + name = "fw-vmseries-01" + zone = "us-east1-b" + machine_type = "n2-standard-4" + min_cpu_platform = "Intel Cascade Lake" + tags = ["vmseries"] + service_account_key = "sa-vmseries-01" + 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", + ] + bootstrap_bucket_key = "vmseries-bootstrap-bucket-01" + bootstrap_options = { + panorama-server = "1.1.1.1" + dns-primary = "8.8.8.8" + dns-secondary = "8.8.4.4" + } + bootstrap_template_map = { + trust_gcp_router_ip = "10.10.12.1" + untrust_gcp_router_ip = "10.10.11.1" + private_network_cidr = "192.168.0.0/16" + untrust_loopback_ip = "1.1.1.1/32" #This is placeholder IP - you must replace it on the vmseries config with the LB public IP address after the infrastructure is deployed + trust_loopback_ip = "10.10.12.5/32" + } + named_ports = [ + { + name = "http" + port = 80 + }, + { + name = "https" + port = 443 + } + ] + network_interfaces = [ + { + vpc_network_key = "fw-untrust-vpc" + subnetwork_key = "fw-untrust-sub" + private_ip = "10.10.11.2" + create_public_ip = true + }, + { + vpc_network_key = "fw-mgmt-vpc" + subnetwork_key = "fw-mgmt-sub" + private_ip = "10.10.10.2" + create_public_ip = true + }, + { + vpc_network_key = "fw-trust-vpc" + subnetwork_key = "fw-trust-sub" + private_ip = "10.10.12.2" + }, + ] + } + } + ``` + For a full list of available configuration items - please refer to [module documentation](https://github.com/PaloAltoNetworks/terraform-google-swfw-modules/tree/main/modules/vmseries#inputs) + + The bootstrap_template_map contains variables that will be applied to the bootstrap template. Each firewall Day 0 bootstrap will be parametrised based on these inputs. + Multiple keys can be added and will be deployed by the code. + + EOF +} + +#Load Balancers + +variable "lbs_internal" { + description = <<-EOF + A map containing each internal loadbalancer setting. + + Example of variable deployment : + + ``` + lbs_internal = { + "internal-lb" = { + name = "internal-lb" + health_check_port = "80" + backends = ["fw-vmseries-01", "fw-vmseries-02"] + ip_address = "10.10.12.5" + 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-swfw-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-swfw-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_common_dual_stack/versions.tf b/examples/vpc_peering_common_dual_stack/versions.tf new file mode 100644 index 0000000..785e926 --- /dev/null +++ b/examples/vpc_peering_common_dual_stack/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 +}