From ffa9a62ca71b6acd1f0a20f76a7aa90013da5506 Mon Sep 17 00:00:00 2001 From: "create-pr-on-fork-for-pan-dev[bot]" <135888023+create-pr-on-fork-for-pan-dev[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:27:35 +0100 Subject: [PATCH 1/3] Sync aws Terraform module documentation (#472) Co-authored-by: pan-dev-content-sync-trigger[bot] --- .../vmseries/examples/panorama_standalone.md | 8 +- .../docs/swfw/aws/vmseries/modules/alb.md | 7 +- .../docs/swfw/aws/vmseries/modules/asg.md | 7 +- .../swfw/aws/vmseries/modules/bootstrap.md | 7 +- .../vmseries/modules/crosszone_failover.md | 88 ++++++++ .../docs/swfw/aws/vmseries/modules/gwlb.md | 11 +- .../aws/vmseries/modules/gwlb_endpoint_set.md | 6 +- .../aws/vmseries/modules/names_generator.md | 213 ++++++++++++++++++ .../aws/vmseries/modules/nat_gateway_set.md | 7 +- .../docs/swfw/aws/vmseries/modules/nlb.md | 11 +- .../swfw/aws/vmseries/modules/panorama.md | 7 +- .../swfw/aws/vmseries/modules/subnet_set.md | 8 +- .../aws/vmseries/modules/transit_gateway.md | 6 +- .../modules/transit_gateway_attachment.md | 6 +- .../modules/transit_gateway_peering.md | 8 +- .../swfw/aws/vmseries/modules/vmseries.md | 7 +- .../docs/swfw/aws/vmseries/modules/vpc.md | 12 +- .../swfw/aws/vmseries/modules/vpc_endpoint.md | 77 +++++++ .../swfw/aws/vmseries/modules/vpc_route.md | 6 +- .../docs/swfw/aws/vmseries/modules/vpn.md | 85 +++++++ .../centralized_design.md | 8 +- .../centralized_design_autoscale.md | 8 +- .../combined_design.md | 8 +- .../combined_design_autoscale.md | 14 +- .../isolated_design.md | 8 +- .../isolated_design_autoscale.md | 14 +- 26 files changed, 569 insertions(+), 78 deletions(-) create mode 100644 products/terraform/docs/swfw/aws/vmseries/modules/crosszone_failover.md create mode 100644 products/terraform/docs/swfw/aws/vmseries/modules/names_generator.md create mode 100644 products/terraform/docs/swfw/aws/vmseries/modules/vpc_endpoint.md create mode 100644 products/terraform/docs/swfw/aws/vmseries/modules/vpn.md diff --git a/products/terraform/docs/swfw/aws/vmseries/examples/panorama_standalone.md b/products/terraform/docs/swfw/aws/vmseries/examples/panorama_standalone.md index 6ff278cd7..4cf207dba 100644 --- a/products/terraform/docs/swfw/aws/vmseries/examples/panorama_standalone.md +++ b/products/terraform/docs/swfw/aws/vmseries/examples/panorama_standalone.md @@ -76,13 +76,13 @@ Use a web browser to access https://x.x.x.x and login with admin and your previo | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -100,8 +100,10 @@ Use a web browser to access https://x.x.x.x and login with admin and your previo | [aws_iam_instance_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | | [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -112,7 +114,7 @@ Use a web browser to access https://x.x.x.x and login with admin and your previo | [panoramas](#input\_panoramas) | A map defining Panorama instances

Following properties are available:
- `instances`: map of Panorama instances with attributes:
- `az`: name of the Availability Zone
- `private_ip_address`: private IP address for management interface
- `panos_version`: PAN-OS version used for Panorama
- `network`: definition of network settings in object with attributes:
- `vpc`: name of the VPC (needs to be one of the keys in map `vpcs`)
- `vpc_subnet`: key of the VPC and subnet connected by '-' character
- `security_group`: security group assigned to ENI used by Panorama
- `create_public_ip`: true, if public IP address for management should be created
- `ebs`: EBS settings defined in object with attributes:
- `volumes`: list of EBS volumes attached to each instance
- `kms_key_alias`: KMS key alias used for encrypting Panorama EBS
- `iam`: IAM settings in object with attrbiutes:
- `create_role`: enable creation of IAM role
- `role_name`: name of the role to create or use existing one
- `enable_imdsv2`: whether to enable IMDSv2 on the EC2 instance

Example:
{
panorama\_ha\_pair = {
instances = {
"primary" = {
az = "eu-central-1a"
private\_ip\_address = "10.255.0.4"
}
"secondary" = {
az = "eu-central-1b"
private\_ip\_address = "10.255.1.4"
}
}

panos\_version = "10.2.3"

network = {
vpc = "management\_vpc"
vpc\_subnet = "management\_vpc-mgmt"
security\_group = "panorama\_mgmt"
create\_public\_ip = true
}

ebs = {
volumes = [
{
name = "ebs-1"
ebs\_device\_name = "/dev/sdb"
ebs\_size = "2000"
ebs\_encrypted = true
},
{
name = "ebs-2"
ebs\_device\_name = "/dev/sdc"
ebs\_size = "2000"
ebs\_encrypted = true
}
]
kms\_key\_alias = "aws/ebs"
}

iam = {
create\_role = true
role\_name = "panorama"
}

enable\_imdsv2 = false
}
}
|
map(object({
instances = map(object({
az = string
private\_ip\_address = string
}))

panos\_version = string

network = object({
vpc = string
vpc\_subnet = string
security\_group = string
create\_public\_ip = bool
})

ebs = object({
volumes = list(object({
name = string
ebs\_device\_name = string
ebs\_size = string
ebs\_encrypted = bool
}))
kms\_key\_alias = string
})

iam = object({
create\_role = bool
role\_name = string
})

enable\_imdsv2 = bool
}))
| `{}` | no | | [region](#input\_region) | AWS region used to deploy whole infrastructure | `string` | n/a | yes | | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet`: built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `to_cidr`: destination IP range
- `next_hop_key`: must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type`: internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
{
security\_vpc = {
name = "security-vpc"
cidr = "10.100.0.0/16"
security\_groups = {
panorama\_mgmt = {
name = "panorama\_mgmt"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
https = {
description = "Permit HTTPS"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["130.41.247.0/24"]
}
ssh = {
description = "Permit SSH"
type = "ingress", from\_port = "22", to\_port = "22", protocol = "tcp"
cidr\_blocks = ["130.41.247.0/24"]
}
}
}
}
subnets = {
"10.100.0.0/24" = { az = "eu-central-1a", set = "mgmt" }
"10.100.64.0/24" = { az = "eu-central-1b", set = "mgmt" }
}
routes = {
mgmt\_default = {
vpc\_subnet = "security\_vpc-mgmt"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "security\_vpc"
next\_hop\_type = "internet\_gateway"
}
}
}
}
|
map(object({
name = string
cidr = string
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet`: built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `to_cidr`: destination IP range
- `next_hop_key`: must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type`: internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
{
security\_vpc = {
name = "security-vpc"
cidr = "10.100.0.0/16"
security\_groups = {
panorama\_mgmt = {
name = "panorama\_mgmt"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
https = {
description = "Permit HTTPS"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["130.41.247.0/24"]
}
ssh = {
description = "Permit SSH"
type = "ingress", from\_port = "22", to\_port = "22", protocol = "tcp"
cidr\_blocks = ["130.41.247.0/24"]
}
}
}
}
subnets = {
"10.100.0.0/24" = { az = "eu-central-1a", set = "mgmt" }
"10.100.64.0/24" = { az = "eu-central-1b", set = "mgmt" }
}
routes = {
mgmt\_default = {
vpc\_subnet = "security\_vpc-mgmt"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "security\_vpc"
next\_hop\_type = "internet\_gateway"
}
}
}
}
|
map(object({
name = string
cidr = string
security\_groups = any
subnets = map(object({
az = string
set = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/alb.md b/products/terraform/docs/swfw/aws/vmseries/modules/alb.md index 855221ce6..10f0c826a 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/alb.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/alb.md @@ -20,7 +20,7 @@ title: Palo Alto Networks Application Load Balancer Module for AWS A Terraform module for deploying an Application Load Balancer in AWS cloud. This is always a public Load Balancer with Target Groups of `IP` type. It is intended to be placed just in front of Next Generation Firewalls. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/alb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/alb) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/alb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/alb) ## Usage @@ -98,13 +98,13 @@ module "public_alb" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -127,6 +127,7 @@ No modules. | [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | | [aws_elb_service_account.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/elb_service_account) | data source | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | | [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source | ### Inputs diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/asg.md b/products/terraform/docs/swfw/aws/vmseries/modules/asg.md index 82dcbe63a..be0681ca9 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/asg.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/asg.md @@ -20,7 +20,7 @@ title: Palo Alto Networks Autoscaling Group Module for AWS A Terraform module for deploying VM-Series in Autoscaling group in AWS cloud. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/asg) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/asg) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/asg) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/asg) ## Usage @@ -34,7 +34,7 @@ For example usage, please refer to the [Examples](https://github.com/PaloAltoNet |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | | [archive](#requirement\_archive) | ~> 2.2 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | | [null](#requirement\_null) | 3.2.1 | ### Providers @@ -42,7 +42,7 @@ For example usage, please refer to the [Examples](https://github.com/PaloAltoNet | Name | Version | |------|---------| | [archive](#provider\_archive) | ~> 2.2 | -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | | [null](#provider\_null) | 3.2.1 | ### Modules @@ -70,6 +70,7 @@ No modules. | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_kms_alias.ebs_kms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/bootstrap.md b/products/terraform/docs/swfw/aws/vmseries/modules/bootstrap.md index 1f8b932af..9a2c3b47f 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/bootstrap.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/bootstrap.md @@ -29,7 +29,7 @@ The bootstrap package may optionally include a PAN-OS software image, application and threat signature updates, VM-Series plug-ins, and/or license files. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/bootstrap) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/bootstrap) ## Directory and file structure The root directory of the Terraform plan calling this module should include a @@ -93,14 +93,14 @@ variables and associated values. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | | [random](#requirement\_random) | ~> 3.3.2 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | | [random](#provider\_random) | ~> 3.3.2 | ### Modules @@ -125,6 +125,7 @@ No modules. | [aws_s3_object.init_cfg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource | | [random_id.sufix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_role) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | | [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source | ### Inputs diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/crosszone_failover.md b/products/terraform/docs/swfw/aws/vmseries/modules/crosszone_failover.md new file mode 100644 index 000000000..15c13a578 --- /dev/null +++ b/products/terraform/docs/swfw/aws/vmseries/modules/crosszone_failover.md @@ -0,0 +1,88 @@ +--- +hide_title: true +id: crosszone_failover +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- aws +pagination_next: null +pagination_prev: null +sidebar_label: Crosszone Failover +title: Crosszone Failover Module for AWS +--- + +# Crosszone Failover Module for AWS + +A Terraform module for deploying a Crosszone Failover for VM-Series firewalls. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/crosszone_failover) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/crosszone_failover) + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | +| [aws](#requirement\_aws) | ~> 5.17 | + +### Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 5.17 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [aws_api_gateway_deployment.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_integration.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_integration_response.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration_response) | resource | +| [aws_api_gateway_method.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_method_response.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_response) | resource | +| [aws_api_gateway_resource.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.pan_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_iam_role.lambda_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.lambda_exec](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.test_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.rt_failover](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_permission.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | +| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | +| [aws_s3_bucket_server_side_encryption_configuration.example](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | +| [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | +| [aws_s3_object.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource | +| [aws_vpc_endpoint.api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint) | resource | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [lambda\_file\_location](#input\_lambda\_file\_location) | Name of folder where lambda package is stored in this workspace. | `string` | `"lambda-package"` | no | +| [lambda\_file\_name](#input\_lambda\_file\_name) | File name of lambda package. | `string` | `"crosszone_ha_instance_id.zip"` | no | +| [lambda\_s3\_bucket](#input\_lambda\_s3\_bucket) | Name of bucket with lambda zip package to deploy. | `string` | `""` | no | +| [prefix\_name\_tag](#input\_prefix\_name\_tag) | Prefix used to build name tags for resources. | `string` | `""` | no | +| [region](#input\_region) | AWS Region. | `any` | n/a | yes | +| [reserved\_concurrent\_executions](#input\_reserved\_concurrent\_executions) | Amount of reserved concurrent execussions for lambda function. | `number` | `100` | no | +| [sg\_state](#input\_sg\_state) | Exported state from base infra workspace to make SG names to IDs. | `any` | n/a | yes | +| [subnet\_state](#input\_subnet\_state) | Exported state from base VPC workspace to map resource names to IDs. | `any` | n/a | yes | +| [tags](#input\_tags) | Map of additional tags to apply to all resources. | `map(any)` | `{}` | no | +| [vpc\_id](#input\_vpc\_id) | VPC ID. | `any` | n/a | yes | + +### Outputs + +No outputs. + \ No newline at end of file diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/gwlb.md b/products/terraform/docs/swfw/aws/vmseries/modules/gwlb.md index 65da1bef6..92a19bc34 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/gwlb.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/gwlb.md @@ -21,7 +21,7 @@ title: AWS Gateway Load Balancer Module This module creates a single Gateway Load Balancer (GWLB). Routes from other VPCs can direct traffic towards the GWLB through the use of a separate module `gwlb_endpoint_set`. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/gwlb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/gwlb) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/gwlb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/gwlb) ## Attaching new targets to the pre-existing GWLB @@ -42,13 +42,13 @@ resource aws_lb_target_group_attachment this { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -65,11 +65,13 @@ No modules. | [aws_vpc_endpoint_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint_service) | resource | | [aws_vpc_endpoint_service_allowed_principal.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint_service_allowed_principal) | resource | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| +| [acceptance\_required](#input\_acceptance\_required) | Whether or not VPC endpoint connection requests to the service must be accepted by the service owner - true or false | `bool` | `false` | no | | [allowed\_principals](#input\_allowed\_principals) | List of AWS Principal ARNs who are allowed access to the GWLB Endpoint Service. For example `["arn:aws:iam::123456789000:root"]`. | `list(string)` | `[]` | no | | [deregistration\_delay](#input\_deregistration\_delay) | See the `aws` provider [documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group#deregistration_delay). | `number` | `null` | no | | [enable\_lb\_deletion\_protection](#input\_enable\_lb\_deletion\_protection) | Whether to enable deletion protection on the gateway loadbalancer. | `bool` | `false` | no | @@ -85,10 +87,11 @@ No modules. | [healthy\_threshold](#input\_healthy\_threshold) | The number of successful health checks required before an unhealthy target becomes healthy. Minimum 2 and maximum 10. | `number` | `3` | no | | [lb\_tags](#input\_lb\_tags) | Map of AWS tags to apply to the created Load Balancer object. These tags are applied after the `global_tags`. | `map(string)` | `{}` | no | | [lb\_target\_group\_tags](#input\_lb\_target\_group\_tags) | Map of AWS tags to apply to the created GWLB Target Group. These tags are applied after the `global_tags`. | `map(string)` | `{}` | no | -| [name](#input\_name) | Name of the created GWLB and its Target Group. Must be unique per AWS region per AWS account. | `string` | n/a | yes | +| [name](#input\_name) | Name of the created GWLB. Must be unique per AWS region per AWS account. | `string` | n/a | yes | | [stickiness\_type](#input\_stickiness\_type) | If `stickiness_type` is `null`, then attribute `enabled` is set to `false` in stickiness configuration block,
value provided in `type` is ignored and by default the Gateway Load Balancer uses 5-tuple to maintain flow stickiness to a specific target appliance.
If `stickiness_type` is not `null`, then attribute `enabled` is set to `true` in stickiness configuration block
and the stickiness `type` can be then customized by using value:
- `source_ip_dest_ip_proto` for 3-tuple (Source IP, Destination IP and Transport Protocol)
- `source_ip_dest_ip` for 2-tuple (Source IP and Destination IP)
 | `string` | `null` | no |
 |  [subnets](#input\_subnets) | Map of subnets where to create the GWLB. Each map's key is the availability zone name and each map's object has an attribute
`id` identifying AWS subnet.
Example for users of module `subnet_set`:
subnets = module.subnet\_set.subnets
Example:
subnets = {
"us-east-1a" = { id = "snet-123007" }
"us-east-1b" = { id = "snet-123008" }
}
|
map(object({
id = string
}))
| n/a | yes | | [target\_instances](#input\_target\_instances) | Map of instances to attach to the GWLB Target Group. |
map(object({
id = string
}))
| `{}` | no | +| [tg\_name](#input\_tg\_name) | Name of the created Target Group for GWLB. If not set, then value of variable name is used. | `string` | `null` | no | | [unhealthy\_threshold](#input\_unhealthy\_threshold) | The number of failed health checks required before a healthy target becomes unhealthy. Minimum 2 and maximum 10. | `number` | `3` | no | | [vpc\_id](#input\_vpc\_id) | AWS identifier of a VPC containing the Endpoint. | `string` | n/a | yes | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/gwlb_endpoint_set.md b/products/terraform/docs/swfw/aws/vmseries/modules/gwlb_endpoint_set.md index 41d67dd79..6cdde4f3c 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/gwlb_endpoint_set.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/gwlb_endpoint_set.md @@ -21,7 +21,7 @@ title: AWS GWLB Endpoint Set This module creates a set of [VPC GWLB Endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/vpce-gateway-load-balancer.html) over a range of one or more Availability Zones. All the Endpoints transfer the traffic to the same Gateway Load Balancer (GWLB). -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/gwlb_endpoint_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/gwlb_endpoint_set) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/gwlb_endpoint_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/gwlb_endpoint_set) ## Reference @@ -30,13 +30,13 @@ over a range of one or more Availability Zones. All the Endpoints transfer the t | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/names_generator.md b/products/terraform/docs/swfw/aws/vmseries/modules/names_generator.md new file mode 100644 index 000000000..20381e204 --- /dev/null +++ b/products/terraform/docs/swfw/aws/vmseries/modules/names_generator.md @@ -0,0 +1,213 @@ +--- +hide_title: true +id: names_generator +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- aws +pagination_next: null +pagination_prev: null +sidebar_label: Names Generator +title: Palo Alto Networks Flexible Names Generator +--- + +# Palo Alto Networks Flexible Names Generator + +A Terraform module for flexible names generation for resources created in AWS by VM-Series modules. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/names_generator) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/names_generator) + +## Usage + +In order to invoke the module to generated flexible names for all resources created by Terraform for VM-Series, you need to defined map e.g. as below for combined design example: + +```hcl +module "generator" { + source = "../../modules/names_generator" + + region = var.region + name_prefix = var.name_prefix + name_template = var.name_templates.name_template + template_assignments = var.template_assignments.assigned_template + names = { + vpc = { for k, v in var.vpcs : k => v.name } + internet_gateway = { for k, v in var.vpcs : k => v.name } + vpn_gateway = { for k, v in var.vpcs : k => v.name } + subnet = { for _, v in local.subnets : "${v.name}${v.az}" => "${v.name}${v.az}" } + security_group = { for _, v in local.security_groups : v.key => v.name } + route_table = merge( + { for k, v in var.vpcs : k => "igw_${v.name}" }, + { for _, v in local.subnets : "${v.name}${v.az}" => "${v.name}${v.az}" } + ) + nat_gateway = { for _, v in local.nat_gateways : v.key => v.name } + transit_gateway = { "tgw" : var.tgw.name } + transit_gateway_route_table = { for k, v in var.tgw.route_tables : k => v.name } + transit_gateway_attachment = { for k, v in var.tgw.attachments : k => v.name } + gateway_loadbalancer = { for k, v in var.gwlbs : k => v.name } + gateway_loadbalancer_target_group = { for k, v in var.gwlbs : k => v.name } + gateway_loadbalancer_endpoint = { for k, v in var.gwlb_endpoints : k => v.name } + application_loadbalancer = { for k, v in var.spoke_albs : k => k } + application_loadbalancer_target_group = { for _, v in local.alb_tg : v.key => v.value } + network_loadbalancer = { for k, v in var.spoke_nlbs : k => k } + network_loadbalancer_target_group = { for _, v in local.nlb_tg : v.key => v.value } + vm = { for k, v in var.spoke_vms : k => k } + vmseries = { for vmseries in local.vmseries_instances : "${vmseries.group}-${vmseries.instance}" => "${vmseries.group}-${vmseries.instance}" } + vmseries_network_interface = { for n in local.vmseries_network_interfaces : "${n.group}-${n.instance}-${n.nic}" => "${n.nic}-${n.instance}" } + iam_role = { + security : "vmseries" + spoke : "spokevm" + } + iam_instance_profile = { + security : "vmseries" + spoke : "spokevm" + } + } +} +``` + +For each kind of resource output from module can be used e.g. as below for VPC: + +```hcl +module "vpc" { + source = "../../modules/vpc" + + for_each = var.vpcs + + name = module.generator.names.vpc[each.key] + ... +} +``` + +or GWLB and its endpoints: + +```hcl +module "gwlb" { + source = "../../../modules/gwlb" + + for_each = var.gwlbs + + name = module.generator.names.gateway_loadbalancer[each.key] + ... +} + +module "gwlbe_endpoint" { + source = "../../../modules/gwlb_endpoint_set" + + for_each = var.gwlb_endpoints + + name = module.generator.names.gateway_loadbalancer_endpoint[each.key] + ... +} +``` + +Map of templates needs to be defined in ``terraform.tfvars``: + +```hcl +name_templates = { + name_at_the_end = { + delimiter = "-" + parts = [ + { prefix = null }, + { abbreviation = "__default__" }, + { bu = "cloud" }, + { env = "tst" }, + { suffix = "ec1" }, + { name = "%s" }, + ] } + name_after_abbr = { + delimiter = "-" + parts = [ + { prefix = null }, + { abbreviation = "__default__" }, + { name = "%s" }, + { bu = "cloud" }, + { env = "tst" }, + { suffix = "ec1" }, + ] } + name_with_az = { + delimiter = "-" + parts = [ + { prefix = null }, + { abbreviation = "__default__" }, + { name = "%s" }, + { bu = "cloud" }, + { env = "tst" }, + { suffix = "ec1" }, + { az = "__az_numeric__" }, # __az_literal__, __az_numeric__ + ] } + name_max_32_characters = { + delimiter = "-" + parts = [ + { prefix = null }, + { abbreviation = "__default__" }, + { name = "%s" }, + { bu = "cloud" }, + { env = "tst" }, + ] } +} +``` + +Besides that for each kind template needs to be assigned (or default template needs to be used): + +```hcl +template_assignments = { + default = "name_after_abbr" + subnet = "name_with_az" + route_table = "name_with_az" + nat_gateway = "name_at_the_end" + vm = "name_at_the_end" + vmseries = "name_at_the_end" + vmseries_network_interface = "name_at_the_end" + application_loadbalancer = "name_max_32_characters" + application_loadbalancer_target_group = "name_max_32_characters" + network_loadbalancer = "name_max_32_characters" + network_loadbalancer_target_group = "name_max_32_characters" + gateway_loadbalancer = "name_max_32_characters" + gateway_loadbalancer_target_group = "name_max_32_characters" +} +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | +| [aws](#requirement\_aws) | ~> 5.17 | + +### Providers + +No providers. + +### Modules + +No modules. + +### Resources + +No resources. + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [abbreviations](#input\_abbreviations) | Map of abbreviations used for resources (placed in place of "\_\_default\_\_"). | `map(string)` |
{
"application\_loadbalancer": "alb",
"application\_loadbalancer\_target\_group": "atg",
"gateway\_loadbalancer": "gwlb",
"gateway\_loadbalancer\_endpoint": "gwep",
"gateway\_loadbalancer\_target\_group": "gwtg",
"iam\_instance\_profile": "profile",
"iam\_role": "role",
"internet\_gateway": "igw",
"nat\_gateway": "ngw",
"network\_loadbalancer": "nlb",
"network\_loadbalancer\_target\_group": "ntg",
"route\_table": "rt",
"route\_table\_internet\_gateway": "rt",
"security\_group": "sg",
"subnet": "snet",
"transit\_gateway": "tgw",
"transit\_gateway\_attachment": "att",
"transit\_gateway\_route\_table": "trt",
"vm": "vm",
"vmseries": "vm",
"vmseries\_network\_interface": "nic",
"vpc": "vpc",
"vpn\_gateway": "vgw"
}
| no | +| [az\_map\_literal\_to\_numeric](#input\_az\_map\_literal\_to\_numeric) | Map of number used instead of letters for AZs (placed in place of "\_\_az\_numeric\_\_"). | `map(string)` |
{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
"f": 6,
"g": 7,
"h": 8,
"i": 9
}
| no | +| [name\_prefix](#input\_name\_prefix) | Prefix used in names for the resources | `string` | n/a | yes | +| [name\_templates](#input\_name\_templates) | Map of templates used to generate names. Each template is defined by list of objects. Each object contains 1 element defined by key and string value.

Important:
0. Delimiter specifies the delimiter used between all components of the new name.
1. Elements with key `prefix` (value is not important) will be replaced with value of the `name_prefix` variable (e.g. `{ prefix = null }`)
2. `%s` will be eventually replaced by resource name
3. `__default__` is a marker that we will be replaced with a default resource abbreviation, anything else will be used literally.
4. `__az_numeric__` is a marker that will be used to replace the availability zone letter indicator with a number (e.g. a->1, b->2, ...)
5. `__az_literal__` is a marker that will be used to replace the full availability zone name with a letter (e.g. `eu-central-1a` will become `a`)
6. Order matters

Example:

name\_template = {
name\_at\_the\_end = {
delimiter = "-"
parts = [
{ prefix = null },
{ abbreviation = "\_\_default\_\_" },
{ bu = "cloud" },
{ env = "tst" },
{ suffix = "ec1" },
{ name = "%s" },
] }
name\_after\_abbr = {
delimiter = "-"
parts = [
{ prefix = null },
{ abbreviation = "\_\_default\_\_" },
{ name = "%s" },
{ bu = "cloud" },
{ env = "tst" },
{ suffix = "ec1" },
] }
name\_with\_az = {
delimiter = "-"
parts = [
{ prefix = null },
{ abbreviation = "\_\_default\_\_" },
{ name = "%s" },
{ bu = "cloud" },
{ env = "tst" },
{ suffix = "ec1" },
{ az = "\_\_az\_numeric\_\_" }, # \_\_az\_literal\_\_, \_\_az\_numeric\_\_
] }
name\_max\_32\_characters = {
delimiter = "-"
parts = [
{ prefix = null },
{ abbreviation = "\_\_default\_\_" },
{ name = "%s" },
{ bu = "cloud" },
{ env = "tst" },
] }
} |
map(object({
delimiter = string
parts = list(map(string))
}))
| `{}` | no | +| [names](#input\_names) | Map of objects defining names used for resources.

Example:

names = {
vpc = { for k, v in var.vpcs : k => v.name }
gateway\_loadbalancer = { for k, v in var.gwlbs : k => v.name }
gateway\_loadbalancer\_endpoint = { for k, v in var.gwlb\_endpoints : k => v.name }
}

Please take a look combined\_design example, which contains full map for names. | `map(map(string))` | `{}` | no | +| [region](#input\_region) | AWS region used to deploy whole infrastructure | `string` | n/a | yes | +| [template\_assignments](#input\_template\_assignments) | Map of templates (used to generate names) assigned to each kind of resource.

Example:

template\_assignments = {
default = "name\_after\_abbr"
subnet = "name\_with\_az"
route\_table = "name\_with\_az"
nat\_gateway = "name\_at\_the\_end"
vm = "name\_at\_the\_end"
vmseries = "name\_at\_the\_end"
vmseries\_network\_interface = "name\_at\_the\_end"
application\_loadbalancer = "name\_max\_32\_characters"
application\_loadbalancer\_target\_group = "name\_max\_32\_characters"
network\_loadbalancer = "name\_max\_32\_characters"
network\_loadbalancer\_target\_group = "name\_max\_32\_characters"
gateway\_loadbalancer = "name\_max\_32\_characters"
gateway\_loadbalancer\_target\_group = "name\_max\_32\_characters"
} | `map(string)` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [names](#output\_names) | Map of generated names for each kind of resources.

Example:

names = {
vpc = {
app1\_vpc = "example-vpc-app1-cloud-tst-ec1"
app2\_vpc = "example-vpc-app2-cloud-tst-ec1"
security\_vpc = "example-vpc-security-cloud-tst-ec1"
}
gateway\_loadbalancer = {
security\_gwlb = "example-gwlb-security-cloud-tst"
}
gateway\_loadbalancer\_endpoint = {
app1\_inbound = "example-gwep-app1-cloud-tst-ec1"
app2\_inbound = "example-gwep-app2-cloud-tst-ec1"
security\_gwlb\_eastwest = "example-gwep-eastwest-cloud-tst-ec1"
security\_gwlb\_outbound = "example-gwep-outbound-cloud-tst-ec1"
}
} | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/nat_gateway_set.md b/products/terraform/docs/swfw/aws/vmseries/modules/nat_gateway_set.md index e2300dc5e..40aa2abbb 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/nat_gateway_set.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/nat_gateway_set.md @@ -20,7 +20,7 @@ title: Palo Alto Networks NAT Gateway Set Module for AWS A Terraform module for deploying a NAT Gateway set in AWS cloud. The "set" means that the module will create an identical/similar NAT Gateway in each specified Availability Zone. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/nat_gateway_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/nat_gateway_set) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/nat_gateway_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/nat_gateway_set) ## Usage @@ -61,13 +61,13 @@ module "nat_gateway_set" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -88,6 +88,7 @@ No modules. |------|-------------|------|---------|:--------:| | [create\_eip](#input\_create\_eip) | If false, does not create a new Elastic IP, but instead reads a pre-existing one. This input is ignored if `create_nat_gateway` is false. | `bool` | `true` | no | | [create\_nat\_gateway](#input\_create\_nat\_gateway) | If false, does not create a new NAT Gateway, but instead reads a pre-existing one. | `bool` | `true` | no | +| [eip\_domain](#input\_eip\_domain) | Indicates if this EIP is for use in VPC | `string` | `"vpc"` | no | | [eip\_tags](#input\_eip\_tags) | n/a | `map(string)` | `{}` | no | | [eips](#input\_eips) | Optional map of Elastic IP attributes. Each key is an Availability Zone name, for example "us-east-1b". Each entry has optional attributes `name`, `public_ip`, `id`.
These are mainly useful to select a pre-existing Elastic IP when create\_eip is false. Example:
eips = {
"us-east-1a" = { id = aws\_eip.a.id }
"us-east-1b" = { id = aws\_eip.b.id }
}
The `name` attribute can be used both for selecting the pre-existing Elastic IP, or for customizing a newly created Elastic IP:
eips = {
"us-east-1a" = { name = "Alice" }
"us-east-1b" = { name = "Bob" }
}
| `map` | `{}` | no | | [global\_tags](#input\_global\_tags) | n/a | `map(string)` | `{}` | no | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/nlb.md b/products/terraform/docs/swfw/aws/vmseries/modules/nlb.md index 75ba2ddc5..63b29e623 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/nlb.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/nlb.md @@ -20,11 +20,11 @@ title: Palo Alto Networks Network Load Balancer Module for AWS A Terraform module for deploying a Network Load Balancer in AWS cloud. This can be used both as a public facing Load Balancer (to balance incoming traffic to Firewalls) or as an internal Load Balancer (to balance traffic from Firewalls to the actual application.) -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/nlb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/nlb) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/nlb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/nlb) ## Usage -For example usage please refer to the [tgw_inbound_with_alb_nlb](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/tgw_inbound_with_alb_nlb) example. +For example usage please refer to the [*Centralized Design*](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/centralized_design), [*Combined Design*](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/combined_design/) or [*Isolated Design*](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/isolated_design/) examples. ## Reference @@ -33,13 +33,13 @@ For example usage please refer to the [tgw_inbound_with_alb_nlb](https://registr | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -62,6 +62,7 @@ No modules. | [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | | [aws_elb_service_account.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/elb_service_account) | data source | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | | [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket) | data source | ### Inputs @@ -71,7 +72,7 @@ No modules. | [access\_logs\_byob](#input\_access\_logs\_byob) | Bring Your Own Bucket - in case you would like to re-use an existing S3 Bucket for Load Balancer's access logs.

NOTICE.
This code does not set up proper `Bucket Policies` for existing buckets. They have to be already in place. | `bool` | `false` | no | | [access\_logs\_s3\_bucket\_name](#input\_access\_logs\_s3\_bucket\_name) | Name of an S3 Bucket that will be used as storage for Load Balancer's access logs.

When used with `configure_access_logs` it becomes the name of a newly created S3 Bucket.
When used with `access_logs_byob` it is a name of an existing bucket. | `string` | `"pantf-alb-access-logs-bucket"` | no | | [access\_logs\_s3\_bucket\_prefix](#input\_access\_logs\_s3\_bucket\_prefix) | A path to a location inside a bucket under which access logs will be stored. When omitted defaults to the root folder of a bucket. | `string` | `null` | no | -| [balance\_rules](#input\_balance\_rules) | An object that contains the listener, target group, and health check configuration.
It consist of maps of applications like follows:
balance\_rules = {
"application\_name" = {
protocol = "communication protocol, since this is a NLB module accepted values are TCP or TLS"
port = "communication port"
target\_type = "type of the target that will be attached to a target group, no defaults here, has to be provided explicitly (regardless the defaults terraform could accept)"
target\_port = "for target types supporting port values, the port number on which the target accepts communication, defaults to the communication port value"
targets = "a map of targets, where key is the target name (used to create a name for the target attachment), value is the target ID (IP, resource ID, etc - the actual value depends on the target type)"

health\_check\_port = "port used by the target group healthcheck, if ommited, `traffic-port` will be used"
threshold = "number of consecutive health checks before considering target healthy or unhealthy, defaults to 3"
interval = "time between each health check, between 5 and 300 seconds, defaults to 30s"

certificate\_arn = "(TLS ONLY) this is the arn of a certificate"
alpn\_policy = "(TLS ONLY) ALPN policy name, for possible values check (terraform documentation)[https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb\_listener#alpn\_policy], defaults to `None`"
}
}
The `application_name` key is valid only for letters, numbers and a dash (`-`) - that's an AWS limitation.



`protocol` and `port` are used for `listener`, `target group` and `target group attachment`. Partially also for health checks (see below).



All listeners are always of forward action.



If you add FWs as targets, make sure you use `target_type = "ip"` and you provide the correct FW IPs in `target` map. IPs should be from the subnet set that the Load Balancer was created in. An example on how to feed this variable with data:
fw\_instance\_ips = { for k, v in var.vmseries : k => module.vmseries[k].interfaces["untrust"].private\_ip }
For format of `var.vmseries` check the (`vmseries` module)[../vmseries/README.md]. The key is the VM name. By using those keys, we can loop through all vmseries modules and take the private IP from the interface that is assigned to the subnet we require. The subnet can be identified by the subnet set name (like above). In other words, the `for` loop returns the following map:
{
vm01 = "1.1.1.1"
vm02 = "2.2.2.2"
...
}


Healthchecks are by default of type TCP. Reason for that is the fact, that HTTP requests might flow through the FW to the actual application. So instead of checking the status of the FW we might check the status of the application.

You have an option to specify a health check port. This way you can set up a Management Profile with an Administrative Management Service limited only to NLBs private IPs and use a port for that service as the health check port. This way you make sure you separate the actual health check from the application rule's port.



EXAMPLE
balance\_rules = {
"HTTPS-APP" = {
protocol = "TCP"
port = "443"
health\_check\_port = "80"
threshold = 2
interval = 10
target\_port = 8443
target\_type = "ip"
targets = { for k, v in var.vmseries : k => module.vmseries[k].interfaces["untrust"].private\_ip }
stickiness = true
}
}
| `any` | n/a | yes | +| [balance\_rules](#input\_balance\_rules) | An object that contains the listener, target group, and health check configuration.
It consist of maps of applications like follows:
balance\_rules = {
"application\_name" = {
protocol = "communication protocol, since this is a NLB module accepted values are TCP or TLS"
port = "communication port"
target\_type = "type of the target that will be attached to a target group, no defaults here, has to be provided explicitly (regardless the defaults terraform could accept)"
target\_port = "for target types supporting port values, the port number on which the target accepts communication, defaults to the communication port value"
targets = "a map of targets, where key is the target name (used to create a name for the target attachment), value is the target ID (IP, resource ID, etc - the actual value depends on the target type)"
target\_az = "This parameter is not supported if the target type of the target group is instance or alb. If the target type is ip and the IP address is outside the VPC, this parameter is required."
health\_check\_port = "port used by the target group healthcheck, if ommited, `traffic-port` will be used"
threshold = "number of consecutive health checks before considering target healthy or unhealthy, defaults to 3"
interval = "time between each health check, between 5 and 300 seconds, defaults to 30s"

certificate\_arn = "(TLS ONLY) this is the arn of a certificate"
alpn\_policy = "(TLS ONLY) ALPN policy name, for possible values check (terraform documentation)[https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb\_listener#alpn\_policy], defaults to `None`"
}
}
The `application_name` key is valid only for letters, numbers and a dash (`-`) - that's an AWS limitation.



`protocol` and `port` are used for `listener`, `target group` and `target group attachment`. Partially also for health checks (see below).



All listeners are always of forward action.



If you add FWs as targets, make sure you use `target_type = "ip"` and you provide the correct FW IPs in `target` map. IPs should be from the subnet set that the Load Balancer was created in. An example on how to feed this variable with data:
fw\_instance\_ips = { for k, v in var.vmseries : k => module.vmseries[k].interfaces["untrust"].private\_ip }
For format of `var.vmseries` check the (`vmseries` module)[../vmseries/README.md]. The key is the VM name. By using those keys, we can loop through all vmseries modules and take the private IP from the interface that is assigned to the subnet we require. The subnet can be identified by the subnet set name (like above). In other words, the `for` loop returns the following map:
{
vm01 = "1.1.1.1"
vm02 = "2.2.2.2"
...
}


Healthchecks are by default of type TCP. Reason for that is the fact, that HTTP requests might flow through the FW to the actual application. So instead of checking the status of the FW we might check the status of the application.

You have an option to specify a health check port. This way you can set up a Management Profile with an Administrative Management Service limited only to NLBs private IPs and use a port for that service as the health check port. This way you make sure you separate the actual health check from the application rule's port.



EXAMPLE
balance\_rules = {
"HTTPS-APP" = {
protocol = "TCP"
port = "443"
health\_check\_port = "80"
threshold = 2
interval = 10
target\_port = 8443
target\_type = "ip"
targets = { for k, v in var.vmseries : k => module.vmseries[k].interfaces["untrust"].private\_ip }
target\_az = "all"
stickiness = true
}
}
| `any` | n/a | yes | | [configure\_access\_logs](#input\_configure\_access\_logs) | Configure Load Balancer to store access logs in an S3 Bucket.

When used with `access_logs_byob` set to `false` forces creation of a new bucket.
If, however, `access_logs_byob` is set to `true` an existing bucket can be used.

The name of the newly created or existing bucket is controlled via `access_logs_s3_bucket_name`. | `bool` | `false` | no | | [create\_dedicated\_eips](#input\_create\_dedicated\_eips) | If set to `true`, a set of EIPs will be created for each zone/subnet. Otherwise AWS will handle IP management. | `bool` | `false` | no | | [enable\_cross\_zone\_load\_balancing](#input\_enable\_cross\_zone\_load\_balancing) | Enable load balancing between instances in different AZs. Defaults to `true`.
Change to `false` only if absolutely necessary. By default, there is only one FW in each AZ.
Turning this off means 1:1 correlation between a public IP assigned to an AZ and a FW deployed in that AZ. | `bool` | `true` | no | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/panorama.md b/products/terraform/docs/swfw/aws/vmseries/modules/panorama.md index da9c7266d..f6d49d4e3 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/panorama.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/panorama.md @@ -22,7 +22,7 @@ A Terraform module for deploying Panorama in AWS cloud. Panorama deployed on AWS is Bring Your Own License (BYOL), supports all deployment modes (Panorama, Log Collector, and Management Only), and shares the same processes and functionality as the M-Series hardware appliances. For more information on Panorama modes, see [Panorama Models](https://docs.paloaltonetworks.com/panorama/10-2/panorama-admin/panorama-overview/panorama-models). -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/panorama) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/panorama) ## Usage @@ -35,13 +35,13 @@ For usage, check the "examples" folder in the root of the repository. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -68,6 +68,7 @@ No modules. | [ebs\_encrypted](#input\_ebs\_encrypted) | Whether to enable EBS encryption on root volume. | `bool` | `true` | no | | [ebs\_kms\_key\_alias](#input\_ebs\_kms\_key\_alias) | The alias for the customer managed KMS key to use for volume encryption.
If this is set to `null` the default master key that protects EBS volumes will be used | `string` | `null` | no | | [ebs\_volumes](#input\_ebs\_volumes) | List of EBS volumes to create and attach to Panorama.
Available options:
- `name` (Optional) Name tag for the EBS volume. If not provided defaults to the value of `var.name`.
- `ebs_device_name` (Required) The EBS device name to expose to the instance (for example, /dev/sdh or xvdh).
See [Device Naming on Linux Instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/device_naming.html#available-ec2-device-names) for more information.
- `ebs_size` (Optional) The size of the EBS volume in GiBs. Defaults to 2000 GiB.
- `force_detach` (Optional) Set to true if you want to force the volume to detach. Useful if previous attempts failed, but use this option only as a last resort, as this can result in data loss.
- `skip_destroy` (Optional) Set this to true if you do not wish to detach the volume from the instance to which it is attached at destroy time, and instead just remove the attachment from Terraform state.
This is useful when destroying an instance attached to third-party volumes.

Note: Terraform must be running with credentials which have the `GenerateDataKeyWithoutPlaintext` permission on the specified KMS key
as required by the [EBS KMS CMK volume provisioning process](https://docs.aws.amazon.com/kms/latest/developerguide/services-ebs.html#ebs-cmk) to prevent a volume from being created and almost immediately deleted.
If null, the default EBS encryption KMS key in the current region is used.

Example:
ebs\_volumes = [
{
name = "ebs-1"
ebs\_device\_name = "/dev/sdb"
ebs\_size = "2000"
},
{
name = "ebs-2"
ebs\_device\_name = "/dev/sdb"
ebs\_size = "2000"
},
{
name = "ebs-3"
ebs\_device\_name = "/dev/sdb"
ebs\_size = "2000"
},
]
| `list(any)` | `[]` | no | +| [eip\_domain](#input\_eip\_domain) | Indicates if this EIP is for use in VPC | `string` | `"vpc"` | no | | [enable\_imdsv2](#input\_enable\_imdsv2) | Whether to enable IMDSv2 on the EC2 instance.
Support for this feature has been added in VM-Series Plugin [3.0.0](https://docs.paloaltonetworks.com/plugins/vm-series-and-panorama-plugins-release-notes/vm-series-plugin/vm-series-plugin-30/vm-series-plugin-300#id126d0957-95d7-4b29-9147-fff20027986e), which in turn requires PAN-OS version 10.2.0 at minimum. | `string` | `false` | no | | [global\_tags](#input\_global\_tags) | A map of tags to assign to the resources.
If configured with a provider `default_tags` configuration block present, tags with matching keys will overwrite those defined at the provider-level." | `map(any)` | `{}` | no | | [instance\_type](#input\_instance\_type) | EC2 instance type for Panorama. Default set to Palo Alto Networks recommended instance type. | `string` | `"c5.4xlarge"` | no | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/subnet_set.md b/products/terraform/docs/swfw/aws/vmseries/modules/subnet_set.md index 1943e0530..3704bc079 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/subnet_set.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/subnet_set.md @@ -20,7 +20,7 @@ title: Palo Alto Networks Subnet-Set Module for AWS A Terraform module for deploying a subnet-set in AWS cloud. The "set" means that the module will create an identical/similar subnet in each specified Availability Zone. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/subnet_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/subnet_set) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/subnet_set) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/subnet_set) ## Usage @@ -55,13 +55,13 @@ module "subnet_sets" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -88,7 +88,7 @@ No modules. | [global\_tags](#input\_global\_tags) | Optional map of arbitrary tags to apply to all the created resources. | `map(string)` | `{}` | no | | [has\_secondary\_cidrs](#input\_has\_secondary\_cidrs) | The input that depends on the secondary CIDR ranges of the VPC `vpc_id`. The actual value (true or false) is ignored, the input is used only to delay subnet creation until the secondary CIDR ranges are processed by Terraform. | `bool` | `true` | no | | [map\_public\_ip\_on\_launch](#input\_map\_public\_ip\_on\_launch) | See the [provider's documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet#map_public_ip_on_launch). | `bool` | `null` | no | -| [nacl\_associations](#input\_nacl\_associations) | NACLs associations with subnets | `map(string)` | `null` | no | +| [nacl\_associations](#input\_nacl\_associations) | NACLs associations with subnets | `map(string)` | `{}` | no | | [name](#input\_name) | Subnet set name, used to construct default subnet names. | `string` | `null` | no | | [propagating\_vgws](#input\_propagating\_vgws) | See the [provider's documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table). | `list(string)` | `[]` | no | | [vpc\_id](#input\_vpc\_id) | Id of the VPC to create resource in. | `string` | n/a | yes | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway.md b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway.md index ef67d8a3a..7305af387 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway.md @@ -23,7 +23,7 @@ tables explicitly through respective input variables. >A transit gateway is a network transit hub that you can use to interconnect your virtual private clouds (VPCs) and on-premises networks. As your cloud infrastructure expands globally, inter-Region peering connects transit gateways together using the AWS Global Infrastructure. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/transit_gateway) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/transit_gateway) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/transit_gateway) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/transit_gateway) ## Usage @@ -36,13 +36,13 @@ For example usage, please refer to the [Examples](https://github.com/PaloAltoNet | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_attachment.md b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_attachment.md index 8a502fa6d..43a26297c 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_attachment.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_attachment.md @@ -22,7 +22,7 @@ A Terraform module for deploying AWS Transit Gateways Attachments. >AWS provides a network transit hub called a Transit Gateway. One or more VPCs can connect to a Transit Gateway through a Transit Gateway (TGW) Attachment. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/transit_gateway_attachment) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/transit_gateway_attachment) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/transit_gateway_attachment) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/transit_gateway_attachment) ## Usage @@ -35,13 +35,13 @@ For example usage, please refer to the [Examples](https://github.com/PaloAltoNet | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_peering.md b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_peering.md index eb8804cc3..cf312b3ce 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_peering.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/transit_gateway_peering.md @@ -18,7 +18,7 @@ title: AWS Transit Gateway Peering # AWS Transit Gateway Peering -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/transit_gateway_peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/transit_gateway_peering) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/transit_gateway_peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/transit_gateway_peering) ## Usage @@ -60,14 +60,14 @@ The static routes are currently not handled by this module. | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | -| [aws.remote](#provider\_aws.remote) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | +| [aws.remote](#provider\_aws.remote) | ~> 5.17 | ### Modules diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/vmseries.md b/products/terraform/docs/swfw/aws/vmseries/modules/vmseries.md index 41e78bca0..c4f6cd3f6 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/vmseries.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/vmseries.md @@ -20,7 +20,7 @@ title: Palo Alto Networks VM-Series Module for AWS A Terraform module for deploying a VM-Series firewall in AWS cloud. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/vmseries) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/vmseries) ## Usage @@ -37,13 +37,13 @@ The changes in user data bootstrap entries will not affect the existing VM-Serie | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -69,6 +69,7 @@ No modules. | [bootstrap\_options](#input\_bootstrap\_options) | VM-Series bootstrap options to provide using instance user data. Contents determine type of bootstap method to use.
If empty (the default), bootstrap process is not triggered at all.
For more information on available methods, please refer to VM-Series documentation for specific version.
For 10.0 docs are available [here](https://docs.paloaltonetworks.com/vm-series/10-0/vm-series-deployment/bootstrap-the-vm-series-firewall.html). | `string` | `""` | no | | [ebs\_encrypted](#input\_ebs\_encrypted) | Whether to enable EBS encryption on volumes. | `bool` | `true` | no | | [ebs\_kms\_key\_alias](#input\_ebs\_kms\_key\_alias) | The alias for the customer managed KMS key to use for volume encryption. Should be prepended with the word "alias" followed by a forward slash (alias/example-key-alias).
If `null` (the default), the default master key that protects EBS volumes will be used. | `string` | `null` | no | +| [eip\_domain](#input\_eip\_domain) | Indicates if this EIP is for use in VPC | `string` | `"vpc"` | no | | [enable\_imdsv2](#input\_enable\_imdsv2) | Whether to enable IMDSv2 on the EC2 instance.
Support for this feature has been added in VM-Series Plugin [3.0.0](https://docs.paloaltonetworks.com/plugins/vm-series-and-panorama-plugins-release-notes/vm-series-plugin/vm-series-plugin-30/vm-series-plugin-300#id126d0957-95d7-4b29-9147-fff20027986e), which in turn requires VM-Series version 10.2.0 at minimum. | `string` | `false` | no | | [enable\_instance\_termination\_protection](#input\_enable\_instance\_termination\_protection) | Whether to enable termination protection on the EC2 instance. | `bool` | `false` | no | | [iam\_instance\_profile](#input\_iam\_instance\_profile) | IAM instance profile. | `string` | `null` | no | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/vpc.md b/products/terraform/docs/swfw/aws/vmseries/modules/vpc.md index 414363251..e3d861d03 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/vpc.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/vpc.md @@ -25,7 +25,7 @@ module is that it does not create multiple resources based on Terraform `count` [easier removal](https://github.com/PaloAltoNetworks/terraform-best-practices#22-looping) of any single subnet, without the need to briefly destroy and re-create any other subnet. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/vpc) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/vpc) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/vpc) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/vpc) ## Usage @@ -50,13 +50,13 @@ module "vpc" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -100,9 +100,13 @@ No modules. | [instance\_tenancy](#input\_instance\_tenancy) | VPC level [instance tenancy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#instance_tenancy). | `string` | `null` | no | | [nacls](#input\_nacls) | The `nacls` variable is a map of maps, where each map represents an AWS NACL.

Example:
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
block\_outbound\_icmp = {
rule\_number = 110
egress = true
protocol = "icmp"
rule\_action = "deny"
cidr\_block = "10.100.1.0/24"
from\_port = null
to\_port = null
}
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
| `any` | `{}` | no | | [name](#input\_name) | Name of the VPC to create or use. | `string` | n/a | yes | +| [name\_internet\_gateway](#input\_name\_internet\_gateway) | Name of the IGW to create or use. | `string` | `null` | no | +| [name\_vpn\_gateway](#input\_name\_vpn\_gateway) | Name of the VPN gateway to create. | `string` | `null` | no | | [ntp\_servers](#input\_ntp\_servers) | Specify a list of NTP server addresses for DHCP options set, default to AWS provided | `list(string)` | `[]` | no | +| [route\_table\_internet\_gateway](#input\_route\_table\_internet\_gateway) | Name of route table for the IGW. | `string` | `null` | no | +| [route\_table\_vpn\_gateway](#input\_route\_table\_vpn\_gateway) | Name of the route table for VPN gateway. | `string` | `null` | no | | [secondary\_cidr\_blocks](#input\_secondary\_cidr\_blocks) | Secondary CIDR block to assign to a new VPC. | `list(string)` | `[]` | no | -| [security\_groups](#input\_security\_groups) | The `security_groups` variable is a map of maps, where each map represents an AWS Security Group.
The key of each entry acts as the Security Group name.
List of available attributes of each Security Group entry:
- `rules`: A list of objects representing a Security Group rule. The key of each entry acts as the name of the rule and
needs to be unique across all rules in the Security Group.
List of attributes available to define a Security Group rule:
- `description`: Security Group description.
- `type`: Specifies if rule will be evaluated on ingress (inbound) or egress (outbound) traffic.
- `cidr_blocks`: List of CIDR blocks - for ingress, determines the traffic that can reach your instance. For egress
Determines the traffic that can leave your instance, and where it can go.
- `prefix_list_ids`: List of Prefix List IDs


Example:
security\_groups = {
vmseries-mgmt = {
name = "vmseries-mgmt"
rules = {
all-outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
https-inbound-private = {
description = "Permit HTTPS for VM-Series Management"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["10.0.0.0/8"]
}
https-inbound-eip = {
description = "Permit HTTPS for VM-Series Management from known public IPs"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["100.100.100.100/32"]
}
ssh-inbound-eip = {
description = "Permit SSH for VM-Series Management from known public IPs"
type = "ingress", from\_port = "22", to\_port = "22", protocol = "tcp"
cidr\_blocks = ["100.100.100.100/32"]
}
https-inbound-prefix-list = {
description = "Permit HTTPS for VM-Series Management for IPs in managed prefix list"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
prefix\_list\_ids = ["pl-1a2b3c4d5e6f7g8h9i"]
}
}
}
}
| `any` | `{}` | no | +| [security\_groups](#input\_security\_groups) | The `security_groups` variable is a map of maps, where each map represents an AWS Security Group.
The key of each entry acts as the Security Group name.
List of available attributes of each Security Group entry:
- `rules`: A list of objects representing a Security Group rule. The key of each entry acts as the name of the rule and
needs to be unique across all rules in the Security Group.
List of attributes available to define a Security Group rule:
- `description`: Security Group description.
- `type`: Specifies if rule will be evaluated on ingress (inbound) or egress (outbound) traffic.
- `cidr_blocks`: List of CIDR blocks - for ingress, determines the traffic that can reach your instance. For egress
Determines the traffic that can leave your instance, and where it can go.
- `prefix_list_ids`: List of Prefix List IDs
- `self`: security group itself will be added as a source to the rule. Cannot be specified with cidr\_blocks, or security\_groups.
- `source_security_groups`: list of security group IDs to be used as a source to the rule. Cannot be specified with cidr\_blocks, or self.


Example:
security\_groups = {
vmseries-mgmt = {
name = "vmseries-mgmt"
rules = {
all-outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
https-inbound-private = {
description = "Permit HTTPS for VM-Series Management"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["10.0.0.0/8"]
}
https-inbound-eip = {
description = "Permit HTTPS for VM-Series Management from known public IPs"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
cidr\_blocks = ["100.100.100.100/32"]
}
ssh-inbound-eip = {
description = "Permit SSH for VM-Series Management from known public IPs"
type = "ingress", from\_port = "22", to\_port = "22", protocol = "tcp"
cidr\_blocks = ["100.100.100.100/32"]
}
https-inbound-self = {
description = "Permit HTTPS from instances with the same security group"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
self = true
}
https-inbound-security-groups = {
description = "Permit HTTPS traffic for the resources associated with the specified security group"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
source\_security\_groups = ["sg-1a2b3c4d5e6f7g8h9i"]
}
https-inbound-prefix-list = {
description = "Permit HTTPS for VM-Series Management for IPs in managed prefix list"
type = "ingress", from\_port = "443", to\_port = "443", protocol = "tcp"
prefix\_list\_ids = ["pl-1a2b3c4d5e6f7g8h9i"]
}
}
}
}
| `any` | `{}` | no | | [use\_internet\_gateway](#input\_use\_internet\_gateway) | If an existing VPC is provided and has IG attached, set to `true` to reuse it. | `bool` | `false` | no | | [vpc\_tags](#input\_vpc\_tags) | Optional map of arbitrary tags to apply to VPC resource. | `map` | `{}` | no | | [vpn\_gateway\_amazon\_side\_asn](#input\_vpn\_gateway\_amazon\_side\_asn) | ASN for the Amazon side of the gateway. | `string` | `null` | no | diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/vpc_endpoint.md b/products/terraform/docs/swfw/aws/vmseries/modules/vpc_endpoint.md new file mode 100644 index 000000000..c3ae00ecd --- /dev/null +++ b/products/terraform/docs/swfw/aws/vmseries/modules/vpc_endpoint.md @@ -0,0 +1,77 @@ +--- +hide_title: true +id: vpc_endpoint +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- aws +pagination_next: null +pagination_prev: null +sidebar_label: VPC Endpoint +title: VPC Endpoint Module for AWS +--- + +# VPC Endpoint Module for AWS + +A Terraform module for deploying a VPC Endpoint for VM-Series firewalls. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/vpc_endpoint) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/vpc_endpoint) + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | +| [aws](#requirement\_aws) | ~> 5.17 | + +### Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 5.17 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [aws_vpc_endpoint.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint) | resource | +| [aws_vpc_endpoint_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint_route_table_association) | resource | +| [aws_vpc_endpoint_subnet_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint_subnet_association) | resource | +| [aws_vpc_endpoint.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc_endpoint) | data source | +| [aws_vpc_endpoint_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc_endpoint_service) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [auto\_accept](#input\_auto\_accept) | If a service connection requires service owner's acceptance, the request will be approved automatically, provided that both parties are members of the same AWS account. | `bool` | `null` | no | +| [create](#input\_create) | If false, does not create a new AWS VPC Endpoint, but instead uses a pre-existing one. The inputs `name`, `service_name`, `simple_service_name`, `tags`, `type`, and `vpc_id` can be used to match the pre-existing endpoint. | `bool` | `true` | no | +| [name](#input\_name) | n/a | `string` | `null` | no | +| [policy](#input\_policy) | n/a | `string` | `null` | no | +| [private\_dns\_enabled](#input\_private\_dns\_enabled) | n/a | `bool` | `null` | no | +| [route\_table\_ids](#input\_route\_table\_ids) | n/a | `map(string)` | `{}` | no | +| [security\_group\_ids](#input\_security\_group\_ids) | n/a | `list(string)` | `[]` | no | +| [service\_name](#input\_service\_name) | The exact service name. This input is ignored if `simple_service_name` is defined. Typically "com.amazonaws.REGION.SERVICE", for example: "com.amazonaws.us-west-2.s3" | `string` | `null` | no | +| [simple\_service\_name](#input\_simple\_service\_name) | The simplified service name for AWS service, for example: "s3". Uses the service from the current region. If null, the `service_name` input is used instead. | `string` | `null` | no | +| [subnets](#input\_subnets) | Map of Subnets where to create the Endpoints. Each map's key is the availability zone name and each map's object has an attribute
`id` identifying AWS Subnet. Importantly, the traffic returning from the Endpoint uses the Subnet's route table.
The keys of this input map are used for the output map `endpoints`.
Example for users of module `subnet_set`:
subnets = module.subnet\_set.subnets
Example:
subnets = {
"us-east-1a" = { id = "snet-123007" }
"us-east-1b" = { id = "snet-123008" }
}
|
map(object({
id = string
}))
| `{}` | no | +| [tags](#input\_tags) | n/a | `map(string)` | `{}` | no | +| [type](#input\_type) | The type of the service.
The type "Gateway" does not tolerate inputs `subnets`, `security_group_ids`, and `private_dns_enabled`.
The type "Interface" does not tolerate input `route_table_ids`.
The type "GatewayLoadBalancer" is similar to "Gateway", but can be deployed with the dedicated module `gwlb_endpoint_set`.
If null, "Gateway" is used by default. | `string` | n/a | yes | +| [vpc\_id](#input\_vpc\_id) | n/a | `string` | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| [endpoint](#output\_endpoint) | The created `aws_vpc_endpoint` object. Alternatively, the data resource if the input `create` is false. | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/vpc_route.md b/products/terraform/docs/swfw/aws/vmseries/modules/vpc_route.md index 31dd549e4..0ce5e19de 100644 --- a/products/terraform/docs/swfw/aws/vmseries/modules/vpc_route.md +++ b/products/terraform/docs/swfw/aws/vmseries/modules/vpc_route.md @@ -20,7 +20,7 @@ title: Palo Alto Networks VPC Route Module for AWS A Terraform module for deploying a VPC route in AWS cloud. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/examples/vpc_route) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/examples/vpc_route) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/vpc_route) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/vpc_route) ## Usage @@ -86,13 +86,13 @@ module "vpc_route" { | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules diff --git a/products/terraform/docs/swfw/aws/vmseries/modules/vpn.md b/products/terraform/docs/swfw/aws/vmseries/modules/vpn.md new file mode 100644 index 000000000..49ab6c552 --- /dev/null +++ b/products/terraform/docs/swfw/aws/vmseries/modules/vpn.md @@ -0,0 +1,85 @@ +--- +hide_title: true +id: vpn +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- aws +pagination_next: null +pagination_prev: null +sidebar_label: VPN +title: VPN Module for AWS +--- + +# VPN Module for AWS + +A Terraform module for deploying a VPN for VM-Series firewalls. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-aws-vmseries-modules/tree/main/modules/vpn) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/aws/latest/submodules/vpn) + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | +| [aws](#requirement\_aws) | ~> 5.17 | + +### Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | ~> 5.17 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.tunnel1_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.tunnel2_log](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_customer_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/customer_gateway) | resource | +| [aws_ec2_transit_gateway_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_association) | resource | +| [aws_ec2_transit_gateway_route_table_propagation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route_table_propagation) | resource | +| [aws_kms_alias.tunnel1_kms_alias](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource | +| [aws_kms_alias.tunnel2_kms_alias](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource | +| [aws_kms_key.tunnel1_kms_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | +| [aws_kms_key.tunnel2_kms_key](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | +| [aws_vpn_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpn_connection) | resource | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | +| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [customer\_gateway](#input\_customer\_gateway) | Customer gateway defined by attributes:
- bgp\_asn - (Required) The gateway's Border Gateway Protocol (BGP) Autonomous System Number (ASN).
- certificate\_arn - (Optional) The Amazon Resource Name (ARN) for the customer gateway certificate.
- device\_name - (Optional) A name for the customer gateway device.
- ip\_address - (Optional) The IPv4 address for the customer gateway device's outside interface.
- type - (Required) The type of customer gateway. The only type AWS supports at this time is "ipsec.1".
- tags - (Optional) Tags to apply to the gateway. If configured with a provider default\_tags configuration block present, tags with matching keys will overwrite those defined at the provider-level. | `any` | n/a | yes | +| [name\_prefix](#input\_name\_prefix) | A prefix added to all resource names created by this module | `string` | `""` | no | +| [name\_suffix](#input\_name\_suffix) | A sufix added to all resource names created by this module | `string` | `""` | no | +| [region](#input\_region) | AWS region used to deploy whole infrastructure | `string` | n/a | yes | +| [tags](#input\_tags) | Optional map of arbitrary tags to apply to all the created resources. | `map(string)` | `{}` | no | +| [transit\_gateway\_associate\_route\_table\_id](#input\_transit\_gateway\_associate\_route\_table\_id) | TGW route table ID used to associate VPN attachments created by VPN connections | `string` | n/a | yes | +| [transit\_gateway\_id](#input\_transit\_gateway\_id) | TGW's ID used by VPN connection | `string` | n/a | yes | +| [transit\_gateway\_propagate\_route\_table\_id](#input\_transit\_gateway\_propagate\_route\_table\_id) | TGW route table ID into which VPN attachment will propagate routes received by BGP | `string` | n/a | yes | +| [vpn\_connection](#input\_vpn\_connection) | VPN connection defined by attributes:
- customer\_gateway\_id - (Required) The ID of the customer gateway.
- type - (Required) The type of VPN connection. The only type AWS supports at this time is "ipsec.1".
- transit\_gateway\_id - (Optional) The ID of the EC2 Transit Gateway.
- static\_routes\_only - (Optional, Default false) Whether the VPN connection uses static routes exclusively. Static routes must be used for devices that don't support BGP.
- enable\_acceleration - (Optional, Default false) Indicate whether to enable acceleration for the VPN connection. Supports only EC2 Transit Gateway.
- tags - (Optional) Tags to apply to the connection. If configured with a provider default\_tags configuration block present, tags with matching keys will overwrite those defined at the provider-level.
- local\_ipv4\_network\_cidr - (Optional, Default 0.0.0.0/0) The IPv4 CIDR on the customer gateway (on-premises) side of the VPN connection.
- local\_ipv6\_network\_cidr - (Optional, Default ::/0) The IPv6 CIDR on the customer gateway (on-premises) side of the VPN connection.
- outside\_ip\_address\_type - (Optional, Default PublicIpv4) Indicates if a Public S2S VPN or Private S2S VPN over AWS Direct Connect. Valid values are PublicIpv4 \| PrivateIpv4
- remote\_ipv4\_network\_cidr - (Optional, Default 0.0.0.0/0) The IPv4 CIDR on the AWS side of the VPN connection.
- remote\_ipv6\_network\_cidr - (Optional, Default ::/0) The IPv6 CIDR on the customer gateway (on-premises) side of the VPN connection.
- transport\_transit\_gateway\_attachment\_id - (Required when outside\_ip\_address\_type is set to PrivateIpv4). The attachment ID of the Transit Gateway attachment to Direct Connect Gateway. The ID is obtained through a data source only.
- tunnel\_inside\_ip\_version - (Optional, Default ipv4) Indicate whether the VPN tunnels process IPv4 or IPv6 traffic. Valid values are ipv4 \| ipv6. ipv6 Supports only EC2 Transit Gateway.
- tunnel1\_inside\_cidr - (Optional) The CIDR block of the inside IP addresses for the first VPN tunnel. Valid value is a size /30 CIDR block from the 169.254.0.0/16 range.
- tunnel2\_inside\_cidr - (Optional) The CIDR block of the inside IP addresses for the second VPN tunnel. Valid value is a size /30 CIDR block from the 169.254.0.0/16 range.
- tunnel1\_inside\_ipv6\_cidr - (Optional) The range of inside IPv6 addresses for the first VPN tunnel. Supports only EC2 Transit Gateway. Valid value is a size /126 CIDR block from the local fd00::/8 range.
- tunnel2\_inside\_ipv6\_cidr - (Optional) The range of inside IPv6 addresses for the second VPN tunnel. Supports only EC2 Transit Gateway. Valid value is a size /126 CIDR block from the local fd00::/8 range.
- tunnel1\_preshared\_key - (Optional) The preshared key of the first VPN tunnel. The preshared key must be between 8 and 64 characters in length and cannot start with zero(0). Allowed characters are alphanumeric characters, periods(.) and underscores(\_).
- tunnel2\_preshared\_key - (Optional) The preshared key of the second VPN tunnel. The preshared key must be between 8 and 64 characters in length and cannot start with zero(0). Allowed characters are alphanumeric characters, periods(.) and underscores(\_).
- tunnel1\_dpd\_timeout\_action - (Optional, Default clear) The action to take after DPD timeout occurs for the first VPN tunnel. Specify restart to restart the IKE initiation. Specify clear to end the IKE session. Valid values are clear \| none \| restart.
- tunnel2\_dpd\_timeout\_action - (Optional, Default clear) The action to take after DPD timeout occurs for the second VPN tunnel. Specify restart to restart the IKE initiation. Specify clear to end the IKE session. Valid values are clear \| none \| restart.
- tunnel1\_dpd\_timeout\_seconds - (Optional, Default 30) The number of seconds after which a DPD timeout occurs for the first VPN tunnel. Valid value is equal or higher than 30.
- tunnel2\_dpd\_timeout\_seconds - (Optional, Default 30) The number of seconds after which a DPD timeout occurs for the second VPN tunnel. Valid value is equal or higher than 30.
- tunnel1\_enable\_tunnel\_lifecycle\_control - (Optional, Default false) Turn on or off tunnel endpoint lifecycle control feature for the first VPN tunnel. Valid values are true \| false.
- tunnel2\_enable\_tunnel\_lifecycle\_control - (Optional, Default false) Turn on or off tunnel endpoint lifecycle control feature for the second VPN tunnel. Valid values are true \| false.
- tunnel1\_ike\_versions - (Optional) The IKE versions that are permitted for the first VPN tunnel. Valid values are ikev1 \| ikev2.
- tunnel2\_ike\_versions - (Optional) The IKE versions that are permitted for the second VPN tunnel. Valid values are ikev1 \| ikev2.
- tunnel1\_log\_options - (Required) Options for logging VPN tunnel activity:
- enabled - (Required) true if logs need to stored in CloudWatch logs
- log\_group - (Required) The name of the log group.
- retention\_in\_days - (Required) Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653.
- encrypted - (Required) true if logs need to be encrypted
- tunnel2\_log\_options - (Required) Options for logging VPN tunnel activity:
- enabled - (Required) Required if logs need to stored in CloudWatch logs
- log\_group - (Required) The name of the log group.
- retention\_in\_days - (Required) Specifies the number of days you want to retain log events in the specified log group. Possible values are: 1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, and 3653.
- encrypted - (Required) true if logs need to be encrypted
- tunnel1\_phase1\_dh\_group\_numbers - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the first VPN tunnel for phase 1 IKE negotiations. Valid values are 2 \| 14 \| 15 \| 16 \| 17 \| 18 \| 19 \| 20 \| 21 \| 22 \| 23 \| 24.
- tunnel2\_phase1\_dh\_group\_numbers - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the second VPN tunnel for phase 1 IKE negotiations. Valid values are 2 \| 14 \| 15 \| 16 \| 17 \| 18 \| 19 \| 20 \| 21 \| 22 \| 23 \| 24.
- tunnel1\_phase1\_encryption\_algorithms - (Optional) List of one or more encryption algorithms that are permitted for the first VPN tunnel for phase 1 IKE negotiations. Valid values are AES128 \| AES256 \| AES128-GCM-16 \| AES256-GCM-16.
- tunnel2\_phase1\_encryption\_algorithms - (Optional) List of one or more encryption algorithms that are permitted for the second VPN tunnel for phase 1 IKE negotiations. Valid values are AES128 \| AES256 \| AES128-GCM-16 \| AES256-GCM-16.
- tunnel1\_phase1\_integrity\_algorithms - (Optional) One or more integrity algorithms that are permitted for the first VPN tunnel for phase 1 IKE negotiations. Valid values are SHA1 \| SHA2-256 \| SHA2-384 \| SHA2-512.
- tunnel2\_phase1\_integrity\_algorithms - (Optional) One or more integrity algorithms that are permitted for the second VPN tunnel for phase 1 IKE negotiations. Valid values are SHA1 \| SHA2-256 \| SHA2-384 \| SHA2-512.
- tunnel1\_phase1\_lifetime\_seconds - (Optional, Default 28800) The lifetime for phase 1 of the IKE negotiation for the first VPN tunnel, in seconds. Valid value is between 900 and 28800.
- tunnel2\_phase1\_lifetime\_seconds - (Optional, Default 28800) The lifetime for phase 1 of the IKE negotiation for the second VPN tunnel, in seconds. Valid value is between 900 and 28800.
- tunnel1\_phase2\_dh\_group\_numbers - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the first VPN tunnel for phase 2 IKE negotiations. Valid values are 2 \| 5 \| 14 \| 15 \| 16 \| 17 \| 18 \| 19 \| 20 \| 21 \| 22 \| 23 \| 24.
- tunnel2\_phase2\_dh\_group\_numbers - (Optional) List of one or more Diffie-Hellman group numbers that are permitted for the second VPN tunnel for phase 2 IKE negotiations. Valid values are 2 \| 5 \| 14 \| 15 \| 16 \| 17 \| 18 \| 19 \| 20 \| 21 \| 22 \| 23 \| 24.
- tunnel1\_phase2\_encryption\_algorithms - (Optional) List of one or more encryption algorithms that are permitted for the first VPN tunnel for phase 2 IKE negotiations. Valid values are AES128 \| AES256 \| AES128-GCM-16 \| AES256-GCM-16.
- tunnel2\_phase2\_encryption\_algorithms - (Optional) List of one or more encryption algorithms that are permitted for the second VPN tunnel for phase 2 IKE negotiations. Valid values are AES128 \| AES256 \| AES128-GCM-16 \| AES256-GCM-16.
- tunnel1\_phase2\_integrity\_algorithms - (Optional) List of one or more integrity algorithms that are permitted for the first VPN tunnel for phase 2 IKE negotiations. Valid values are SHA1 \| SHA2-256 \| SHA2-384 \| SHA2-512.
- tunnel2\_phase2\_integrity\_algorithms - (Optional) List of one or more integrity algorithms that are permitted for the second VPN tunnel for phase 2 IKE negotiations. Valid values are SHA1 \| SHA2-256 \| SHA2-384 \| SHA2-512.
- tunnel1\_phase2\_lifetime\_seconds - (Optional, Default 3600) The lifetime for phase 2 of the IKE negotiation for the first VPN tunnel, in seconds. Valid value is between 900 and 3600.
- tunnel2\_phase2\_lifetime\_seconds - (Optional, Default 3600) The lifetime for phase 2 of the IKE negotiation for the second VPN tunnel, in seconds. Valid value is between 900 and 3600.
- tunnel1\_rekey\_fuzz\_percentage - (Optional, Default 100) The percentage of the rekey window for the first VPN tunnel (determined by tunnel1\_rekey\_margin\_time\_seconds) during which the rekey time is randomly selected. Valid value is between 0 and 100.
- tunnel2\_rekey\_fuzz\_percentage - (Optional, Default 100) The percentage of the rekey window for the second VPN tunnel (determined by tunnel2\_rekey\_margin\_time\_seconds) during which the rekey time is randomly selected. Valid value is between 0 and 100.
- tunnel1\_rekey\_margin\_time\_seconds - (Optional, Default 540) The margin time, in seconds, before the phase 2 lifetime expires, during which the AWS side of the first VPN connection performs an IKE rekey. The exact time of the rekey is randomly selected based on the value for tunnel1\_rekey\_fuzz\_percentage. Valid value is between 60 and half of tunnel1\_phase2\_lifetime\_seconds.
- tunnel2\_rekey\_margin\_time\_seconds - (Optional, Default 540) The margin time, in seconds, before the phase 2 lifetime expires, during which the AWS side of the second VPN connection performs an IKE rekey. The exact time of the rekey is randomly selected based on the value for tunnel2\_rekey\_fuzz\_percentage. Valid value is between 60 and half of tunnel2\_phase2\_lifetime\_seconds.
- tunnel1\_replay\_window\_size - (Optional, Default 1024) The number of packets in an IKE replay window for the first VPN tunnel. Valid value is between 64 and 2048.
- tunnel2\_replay\_window\_size - (Optional, Default 1024) The number of packets in an IKE replay window for the second VPN tunnel. Valid value is between 64 and 2048.
- tunnel1\_startup\_action - (Optional, Default add) The action to take when the establishing the tunnel for the first VPN connection. By default, your customer gateway device must initiate the IKE negotiation and bring up the tunnel. Specify start for AWS to initiate the IKE negotiation. Valid values are add \| start.
- tunnel2\_startup\_action - (Optional, Default add) The action to take when the establishing the tunnel for the second VPN connection. By default, your customer gateway device must initiate the IKE negotiation and bring up the tunnel. Specify start for AWS to initiate the IKE negotiation. Valid values are add \| start. | `any` | n/a | yes | +| [vpn\_gateway\_id](#input\_vpn\_gateway\_id) | Virtual Private Gateway's ID used by VPN connection | `string` | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| [customer\_gateway](#output\_customer\_gateway) | Object describing created customer gateway | +| [tunnel1](#output\_tunnel1) | Tunnel 1 details (public IP address, inside IP addresses, BGP ASN) | +| [tunnel2](#output\_tunnel2) | Tunnel 2 details (public IP address, inside IP addresses, BGP ASN) | +| [vpn\_connection](#output\_vpn\_connection) | Object describing created Site-to-Site VPN connection | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design.md index 213c59932..ddb27294c 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design.md @@ -70,14 +70,14 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | | [local](#requirement\_local) | ~> 2.4.0 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -110,8 +110,10 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | [aws_instance.spoke_vms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | | [aws_lb_target_group_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -129,7 +131,7 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [tgw](#input\_tgw) | A object defining Transit Gateway.

Following properties are available:
- `create`: set to false, if existing TGW needs to be reused
- `id`: id of existing TGW or null
- `name`: name of TGW to create or use
- `asn`: ASN number
- `route_tables`: map of route tables
- `attachments`: map of TGW attachments

Example:
tgw = {
create = true
id = null
name = "tgw"
asn = "64512"
route\_tables = {
"from\_security\_vpc" = {
create = true
name = "from\_security"
}
}
attachments = {
security = {
name = "vmseries"
vpc\_subnet = "security\_vpc-tgw\_attach"
route\_table = "from\_security\_vpc"
propagate\_routes\_to = "from\_spoke\_vpc"
}
}
}
|
object({
create = bool
id = string
name = string
asn = string
route\_tables = map(object({
create = bool
name = string
}))
attachments = map(object({
name = string
vpc\_subnet = string
route\_table = string
propagate\_routes\_to = string
}))
})
| `null` | no | | [vmseries](#input\_vmseries) | A map defining VM-Series instances

Following properties are available:
- `instances`: map of VM-Series instances
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `system_services`: map of system services
- `application_lb`: ALB placed in front of the Firewalls' public interfaces
- `network_lb`: NLB placed in front of the Firewalls' public interfaces

Example:
vmseries = {
vmseries = {
instances = {
"01" = { az = "eu-central-1a" }
"02" = { az = "eu-central-1b" }
}

# Value of `panorama-server`, `auth-key`, `dgname`, `tplname` can be taken from plugin `sw\_fw\_license`
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable"
dhcp-send-hostname = "yes"
dhcp-send-client-id = "yes"
dhcp-accept-server-hostname = "yes"
dhcp-accept-server-domain = "yes"
}

panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here

# Value of `vpc` must match key of objects stored in `vpcs`
vpc = "security\_vpc"

# Value of `gwlb` must match key of objects stored in `gwlbs`
gwlb = "security\_gwlb"

interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
vpc\_subnet = "security\_vpc-private"
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
vpc\_subnet = "security\_vpc-mgmt"
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
vpc\_subnet = "security\_vpc-public"
create\_public\_ip = true
source\_dest\_check = false
}
}

# Value of `gwlb\_endpoint` must match key of objects stored in `gwlb\_endpoints`
subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}

system\_services = {
dns\_primary = "4.2.2.2" # TODO: update here
dns\_secondy = null # TODO: update here
ntp\_primary = "pool.ntp.org" # TODO: update here
ntp\_secondy = null # TODO: update here
}

application\_lb = null
network\_lb = null
}
}
|
map(object({
instances = map(object({
az = string
}))

bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
vpc\_subnet = string
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

system\_services = object({
dns\_primary = string
dns\_secondy = string
ntp\_primary = string
ntp\_secondy = string
})

application\_lb = object({
name = string
rules = any
})

network\_lb = object({
name = string
rules = any
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design_autoscale.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design_autoscale.md index b893042fc..1a9896bec 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design_autoscale.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/centralized_design_autoscale.md @@ -151,14 +151,14 @@ statistic = "Maximum" | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | | [local](#requirement\_local) | ~> 2.4.0 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -190,8 +190,10 @@ statistic = "Maximum" | [aws_iam_role_policy.vm_series_ec2_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_instance.spoke_vms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -209,7 +211,7 @@ statistic = "Maximum" | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [tgw](#input\_tgw) | A object defining Transit Gateway.

Following properties are available:
- `create`: set to false, if existing TGW needs to be reused
- `id`: id of existing TGW or null
- `name`: name of TGW to create or use
- `asn`: ASN number
- `route_tables`: map of route tables
- `attachments`: map of TGW attachments

Example:
tgw = {
create = true
id = null
name = "tgw"
asn = "64512"
route\_tables = {
"from\_security\_vpc" = {
create = true
name = "from\_security"
}
}
attachments = {
security = {
name = "vmseries"
vpc\_subnet = "security\_vpc-tgw\_attach"
route\_table = "from\_security\_vpc"
propagate\_routes\_to = "from\_spoke\_vpc"
}
}
}
|
object({
create = bool
id = string
name = string
asn = string
route\_tables = map(object({
create = bool
name = string
}))
attachments = map(object({
name = string
vpc\_subnet = string
route\_table = string
propagate\_routes\_to = string
}))
})
| `null` | no | | [vmseries\_asgs](#input\_vmseries\_asgs) | A map defining Autoscaling Groups with VM-Series instances.

Following properties are available:
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `interfaces`: configuration of network interfaces for VM-Series used by Lamdba while provisioning new VM-Series in autoscaling group
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `asg`: the number of Amazon EC2 instances that should be running in the group (desired, minimum, maximum)
- `scaling_plan`: scaling plan with attributes
- `enabled`: `true` if automatic dynamic scaling policy should be created
- `metric_name`: name of the metric used in dynamic scaling policy
- `target_value`: target value for the metric used in dynamic scaling policy
- `statistic`: statistic of the metric. Valid values: Average, Maximum, Minimum, SampleCount, Sum
- `cloudwatch_namespace`: name of CloudWatch namespace, where metrics are available (it should be the same as namespace configured in VM-Series plugin in PAN-OS)
- `tags`: tags configured for dynamic scaling policy

Example:
vmseries\_asgs = {
main\_asg = {
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable" # TODO: update here
panorama-server = "" # TODO: update here
auth-key = "" # TODO: update here
dgname = "" # TODO: update here
tplname = "" # TODO: update here
dhcp-send-hostname = "yes" # TODO: update here
dhcp-send-client-id = "yes" # TODO: update here
dhcp-accept-server-hostname = "yes" # TODO: update here
dhcp-accept-server-domain = "yes" # TODO: update here
}

panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here

vpc = "security\_vpc"
gwlb = "security\_gwlb"

interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
subnet = {
"privatea" = "eu-central-1a",
"privateb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
subnet = {
"mgmta" = "eu-central-1a",
"mgmtb" = "eu-central-1b"
}
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
subnet = {
"publica" = "eu-central-1a",
"publicb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
}

subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}

asg = {
desired\_cap = 2
min\_size = 2
max\_size = 4
}

scaling\_plan = {
enabled = true # TODO: update here
metric\_name = "panSessionActive" # TODO: update here
target\_value = 75 # TODO: update here
statistic = "Average" # TODO: update here
cloudwatch\_namespace = "example-vmseries" # TODO: update here
tags = {
ManagedBy = "terraform"
}
}

application\_lb = null
network\_lb = null
}
}
|
map(object({
bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
subnet = map(string)
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

asg = object({
desired\_cap = number
min\_size = number
max\_size = number
})

scaling\_plan = object({
enabled = bool
metric\_name = string
target\_value = number
statistic = string
cloudwatch\_namespace = string
tags = map(string)
})

application\_lb = object({
name = string
rules = any
})

network\_lb = object({
name = string
rules = any
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design.md index ba413ac8f..785798fa0 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design.md @@ -105,13 +105,13 @@ If no errors occurred during deployment, configure the VM-Series machines as exp | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -143,8 +143,10 @@ If no errors occurred during deployment, configure the VM-Series machines as exp | [aws_instance.spoke_vms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | | [aws_lb_target_group_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -163,7 +165,7 @@ If no errors occurred during deployment, configure the VM-Series machines as exp | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [tgw](#input\_tgw) | A object defining Transit Gateway.

Following properties are available:
- `create`: set to false, if existing TGW needs to be reused
- `id`: id of existing TGW or null
- `name`: name of TGW to create or use
- `asn`: ASN number
- `route_tables`: map of route tables
- `attachments`: map of TGW attachments

Example:
tgw = {
create = true
id = null
name = "tgw"
asn = "64512"
route\_tables = {
"from\_security\_vpc" = {
create = true
name = "from\_security"
}
}
attachments = {
security = {
name = "vmseries"
vpc\_subnet = "security\_vpc-tgw\_attach"
route\_table = "from\_security\_vpc"
propagate\_routes\_to = "from\_spoke\_vpc"
}
}
}
|
object({
create = bool
id = string
name = string
asn = string
route\_tables = map(object({
create = bool
name = string
}))
attachments = map(object({
name = string
vpc\_subnet = string
route\_table = string
propagate\_routes\_to = string
}))
})
| `null` | no | | [vmseries](#input\_vmseries) | A map defining VM-Series instances
Following properties are available:
- `instances`: map of VM-Series instances
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `system_services`: map of system services
- `application_lb`: ALB placed in front of the Firewalls' public interfaces
- `network_lb`: NLB placed in front of the Firewalls' public interfaces
Example:
vmseries = {
vmseries = {
instances = {
"01" = { az = "eu-central-1a" }
"02" = { az = "eu-central-1b" }
}
# Value of `panorama-server`, `auth-key`, `dgname`, `tplname` can be taken from plugin `sw\_fw\_license`
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable"
dhcp-send-hostname = "yes"
dhcp-send-client-id = "yes"
dhcp-accept-server-hostname = "yes"
dhcp-accept-server-domain = "yes"
}
panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here
# Value of `vpc` must match key of objects stored in `vpcs`
vpc = "security\_vpc"
# Value of `gwlb` must match key of objects stored in `gwlbs`
gwlb = "security\_gwlb"
interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
vpc\_subnet = "security\_vpc-private"
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
vpc\_subnet = "security\_vpc-mgmt"
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
vpc\_subnet = "security\_vpc-public"
create\_public\_ip = true
source\_dest\_check = false
}
}
# Value of `gwlb\_endpoint` must match key of objects stored in `gwlb\_endpoints`
subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}
system\_services = {
dns\_primary = "4.2.2.2" # TODO: update here
dns\_secondy = null # TODO: update here
ntp\_primary = "pool.ntp.org" # TODO: update here
ntp\_secondy = null # TODO: update here
}
application\_lb = null
network\_lb = null
}
}
|
map(object({
instances = map(object({
az = string
}))

bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
vpc\_subnet = string
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

system\_services = object({
dns\_primary = string
dns\_secondy = string
ntp\_primary = string
ntp\_secondy = string
})

application\_lb = object({
name = string
rules = any
})

network\_lb = object({
name = string
rules = any
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design_autoscale.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design_autoscale.md index 9a1aa17c3..fb2ab7b93 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design_autoscale.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/combined_design_autoscale.md @@ -61,7 +61,9 @@ The following steps should be followed before deploying the Terraform code prese 7. Configure interface management profile to enable health checks from GWLB 8. Configure network interfaces and subinterfaces, zones and virtual router in template 9. Configure [static routes with path monitoring](https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-networking-admin/static-routes/configure-path-monitoring-for-a-static-route) -Details +10. Configure VPC peering between VPC with Panorama and VPC with VM-Series in autoscaling group (after deploying that example) + +### Details - static routes with path monitoring Using multiple template stacks, one for each AZ complicates autoscaling and the Panorama Licensing plugin configuration. The virtual router (VR) configuration combined with path monitoring outlined below avoids using AZ-specific template stacks and variables. @@ -93,8 +95,6 @@ An example XML configuration snippet (for PANOS 10.2.3) of the described configu load config partial mode merge from-xpath /config/devices/entry/template/entry[@name='asg'] to-xpath /config/devices/entry/template/entry[@name='asg'] from template-asg-path-monitoring.xml ``` -10. Configure VPC peering between VPC with Panorama and VPC with VM-Series in autoscaling group (after deploying that example) - ## Usage ### NAT Gateway Option @@ -226,13 +226,13 @@ statistic = "Maximum" | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -262,8 +262,10 @@ statistic = "Maximum" | [aws_iam_role_policy.vm_series_ec2_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | | [aws_instance.spoke_vms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -281,7 +283,7 @@ statistic = "Maximum" | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [tgw](#input\_tgw) | A object defining Transit Gateway.

Following properties are available:
- `create`: set to false, if existing TGW needs to be reused
- `id`: id of existing TGW or null
- `name`: name of TGW to create or use
- `asn`: ASN number
- `route_tables`: map of route tables
- `attachments`: map of TGW attachments

Example:
tgw = {
create = true
id = null
name = "tgw"
asn = "64512"
route\_tables = {
"from\_security\_vpc" = {
create = true
name = "from\_security"
}
}
attachments = {
security = {
name = "vmseries"
vpc\_subnet = "security\_vpc-tgw\_attach"
route\_table = "from\_security\_vpc"
propagate\_routes\_to = "from\_spoke\_vpc"
}
}
}
|
object({
create = bool
id = string
name = string
asn = string
route\_tables = map(object({
create = bool
name = string
}))
attachments = map(object({
name = string
vpc\_subnet = string
route\_table = string
propagate\_routes\_to = string
}))
})
| `null` | no | | [vmseries\_asgs](#input\_vmseries\_asgs) | A map defining Autoscaling Groups with VM-Series instances.

Following properties are available:
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `interfaces`: configuration of network interfaces for VM-Series used by Lamdba while provisioning new VM-Series in autoscaling group
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `asg`: the number of Amazon EC2 instances that should be running in the group (desired, minimum, maximum)
- `scaling_plan`: scaling plan with attributes
- `enabled`: `true` if automatic dynamic scaling policy should be created
- `metric_name`: name of the metric used in dynamic scaling policy
- `target_value`: target value for the metric used in dynamic scaling policy
- `statistic`: statistic of the metric. Valid values: Average, Maximum, Minimum, SampleCount, Sum
- `cloudwatch_namespace`: name of CloudWatch namespace, where metrics are available (it should be the same as namespace configured in VM-Series plugin in PAN-OS)
- `tags`: tags configured for dynamic scaling policy

Example:
vmseries\_asgs = {
main\_asg = {
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable" # TODO: update here
panorama-server = "" # TODO: update here
auth-key = "" # TODO: update here
dgname = "" # TODO: update here
tplname = "" # TODO: update here
dhcp-send-hostname = "yes" # TODO: update here
dhcp-send-client-id = "yes" # TODO: update here
dhcp-accept-server-hostname = "yes" # TODO: update here
dhcp-accept-server-domain = "yes" # TODO: update here
}

panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here

vpc = "security\_vpc"
gwlb = "security\_gwlb"

interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
subnet = {
"privatea" = "eu-central-1a",
"privateb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
subnet = {
"mgmta" = "eu-central-1a",
"mgmtb" = "eu-central-1b"
}
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
subnet = {
"publica" = "eu-central-1a",
"publicb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
}

subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}

asg = {
desired\_cap = 2
min\_size = 2
max\_size = 4
}

scaling\_plan = {
enabled = true # TODO: update here
metric\_name = "panSessionActive" # TODO: update here
target\_value = 75 # TODO: update here
statistic = "Average" # TODO: update here
cloudwatch\_namespace = "example-vmseries" # TODO: update here
tags = {
ManagedBy = "terraform"
}
}

delicense = {
enabled = true
ssm\_param\_name = "example\_param\_store\_delicense" # TODO: update here
}
}
}
|
map(object({
bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
subnet = map(string)
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

asg = object({
desired\_cap = number
min\_size = number
max\_size = number
})

scaling\_plan = object({
enabled = bool
metric\_name = string
target\_value = number
statistic = string
cloudwatch\_namespace = string
tags = map(string)
})

delicense = object({
enabled = bool
ssm\_param\_name = string
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design.md index 8f2b24c0f..0bdf95828 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design.md @@ -76,13 +76,13 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -110,8 +110,10 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | [aws_lb_target_group_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group_attachment) | resource | | [aws_vpc_peering_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -128,7 +130,7 @@ In example VM-Series are licensed using [Panorama-Based Software Firewall Licens | [spoke\_vms](#input\_spoke\_vms) | A map defining VMs in spoke VPCs.

Following properties are available:
- `az`: name of the Availability Zone
- `vpc`: name of the VPC (needs to be one of the keys in map `vpcs`)
- `vpc_subnet`: key of the VPC and subnet connected by '-' character
- `security_group`: security group assigned to ENI used by VM
- `type`: EC2 type VM

Example:
spoke\_vms = {
"app1\_vm01" = {
az = "eu-central-1a"
vpc = "app1\_vpc"
vpc\_subnet = "app1\_vpc-app1\_vm"
security\_group = "app1\_vm"
type = "t2.micro"
}
}
|
map(object({
az = string
vpc = string
vpc\_subnet = string
security\_group = string
type = string
}))
| `{}` | no | | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [vmseries](#input\_vmseries) | A map defining VM-Series instances
Following properties are available:
- `instances`: map of VM-Series instances
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `system_services`: map of system services
- `application_lb`: ALB placed in front of the Firewalls' public interfaces
- `network_lb`: NLB placed in front of the Firewalls' public interfaces
Example:
vmseries = {
vmseries = {
instances = {
"01" = { az = "eu-central-1a" }
"02" = { az = "eu-central-1b" }
}
# Value of `panorama-server`, `auth-key`, `dgname`, `tplname` can be taken from plugin `sw\_fw\_license`
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable"
dhcp-send-hostname = "yes"
dhcp-send-client-id = "yes"
dhcp-accept-server-hostname = "yes"
dhcp-accept-server-domain = "yes"
}
panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here
# Value of `vpc` must match key of objects stored in `vpcs`
vpc = "security\_vpc"
# Value of `gwlb` must match key of objects stored in `gwlbs`
gwlb = "security\_gwlb"
interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
vpc\_subnet = "security\_vpc-private"
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
vpc\_subnet = "security\_vpc-mgmt"
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
vpc\_subnet = "security\_vpc-public"
create\_public\_ip = true
source\_dest\_check = false
}
}
# Value of `gwlb\_endpoint` must match key of objects stored in `gwlb\_endpoints`
subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}
system\_services = {
dns\_primary = "4.2.2.2" # TODO: update here
dns\_secondy = null # TODO: update here
ntp\_primary = "pool.ntp.org" # TODO: update here
ntp\_secondy = null # TODO: update here
}
application\_lb = null
network\_lb = null
}
}
|
map(object({
instances = map(object({
az = string
}))

bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
vpc\_subnet = string
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

system\_services = object({
dns\_primary = string
dns\_secondy = string
ntp\_primary = string
ntp\_secondy = string
})

application\_lb = object({
name = string
rules = any
})

network\_lb = object({
name = string
rules = any
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design_autoscale.md b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design_autoscale.md index 22d315838..d7b16478e 100644 --- a/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design_autoscale.md +++ b/products/terraform/docs/swfw/aws/vmseries/reference-architectures/isolated_design_autoscale.md @@ -57,7 +57,9 @@ The following steps should be followed before deploying the Terraform code prese 7. Configure interface management profile to enable health checks from GWLB 8. Configure network interfaces and subinterfaces, zones and virtual router in template 9. Configure [static routes with path monitoring](https://docs.paloaltonetworks.com/pan-os/10-1/pan-os-networking-admin/static-routes/configure-path-monitoring-for-a-static-route) -Details +10. Configure VPC peering between VPC with Panorama and VPC with VM-Series in autoscaling group (after deploying that example) + +### Details - static routes with path monitoring Using multiple template stacks, one for each AZ complicates autoscaling and the Panorama Licensing plugin configuration. The virtual router (VR) configuration combined with path monitoring outlined below avoids using AZ-specific template stacks and variables. @@ -89,8 +91,6 @@ An example XML configuration snippet (for PANOS 10.2.3) of the described configu load config partial mode merge from-xpath /config/devices/entry/template/entry[@name='asg'] to-xpath /config/devices/entry/template/entry[@name='asg'] from template-asg-path-monitoring.xml ``` -10. Configure VPC peering between VPC with Panorama and VPC with VM-Series in autoscaling group (after deploying that example) - ## Usage 1. Copy `example.tfvars` into `terraform.tfvars` @@ -185,13 +185,13 @@ statistic = "Maximum" | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0.0 | -| [aws](#requirement\_aws) | ~> 4.25 | +| [aws](#requirement\_aws) | ~> 5.17 | ### Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | ~> 4.25 | +| [aws](#provider\_aws) | ~> 5.17 | ### Modules @@ -218,8 +218,10 @@ statistic = "Maximum" | [aws_instance.spoke_vms](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource | | [aws_vpc_peering_connection.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_peering_connection) | resource | | [aws_ami.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source | +| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | | [aws_ebs_default_kms_key.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ebs_default_kms_key) | data source | | [aws_kms_alias.current_arn](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/kms_alias) | data source | +| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | ### Inputs @@ -236,7 +238,7 @@ statistic = "Maximum" | [spoke\_vms](#input\_spoke\_vms) | A map defining VMs in spoke VPCs.

Following properties are available:
- `az`: name of the Availability Zone
- `vpc`: name of the VPC (needs to be one of the keys in map `vpcs`)
- `vpc_subnet`: key of the VPC and subnet connected by '-' character
- `security_group`: security group assigned to ENI used by VM
- `type`: EC2 type VM

Example:
spoke\_vms = {
"app1\_vm01" = {
az = "eu-central-1a"
vpc = "app1\_vpc"
vpc\_subnet = "app1\_vpc-app1\_vm"
security\_group = "app1\_vm"
type = "t2.micro"
}
}
|
map(object({
az = string
vpc = string
vpc\_subnet = string
security\_group = string
type = string
}))
| `{}` | no | | [ssh\_key\_name](#input\_ssh\_key\_name) | Name of the SSH key pair existing in AWS key pairs and used to authenticate to VM-Series or test boxes | `string` | n/a | yes | | [vmseries\_asgs](#input\_vmseries\_asgs) | A map defining Autoscaling Groups with VM-Series instances.

Following properties are available:
- `bootstrap_options`: VM-Seriess bootstrap options used to connect to Panorama
- `panos_version`: PAN-OS version used for VM-Series
- `ebs_kms_id`: alias for AWS KMS used for EBS encryption in VM-Series
- `vpc`: key of VPC
- `gwlb`: key of GWLB
- `interfaces`: configuration of network interfaces for VM-Series used by Lamdba while provisioning new VM-Series in autoscaling group
- `subinterfaces`: configuration of network subinterfaces used to map with GWLB endpoints
- `asg`: the number of Amazon EC2 instances that should be running in the group (desired, minimum, maximum)
- `scaling_plan`: scaling plan with attributes
- `enabled`: `true` if automatic dynamic scaling policy should be created
- `metric_name`: name of the metric used in dynamic scaling policy
- `target_value`: target value for the metric used in dynamic scaling policy
- `statistic`: statistic of the metric. Valid values: Average, Maximum, Minimum, SampleCount, Sum
- `cloudwatch_namespace`: name of CloudWatch namespace, where metrics are available (it should be the same as namespace configured in VM-Series plugin in PAN-OS)
- `tags`: tags configured for dynamic scaling policy

Example:
vmseries\_asgs = {
main\_asg = {
bootstrap\_options = {
mgmt-interface-swap = "enable"
plugin-op-commands = "panorama-licensing-mode-on,aws-gwlb-inspect:enable,aws-gwlb-overlay-routing:enable" # TODO: update here
panorama-server = "" # TODO: update here
auth-key = "" # TODO: update here
dgname = "" # TODO: update here
tplname = "" # TODO: update here
dhcp-send-hostname = "yes" # TODO: update here
dhcp-send-client-id = "yes" # TODO: update here
dhcp-accept-server-hostname = "yes" # TODO: update here
dhcp-accept-server-domain = "yes" # TODO: update here
}

panos\_version = "10.2.3" # TODO: update here
ebs\_kms\_id = "alias/aws/ebs" # TODO: update here

vpc = "security\_vpc"
gwlb = "security\_gwlb"

interfaces = {
private = {
device\_index = 0
security\_group = "vmseries\_private"
subnet = {
"privatea" = "eu-central-1a",
"privateb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
mgmt = {
device\_index = 1
security\_group = "vmseries\_mgmt"
subnet = {
"mgmta" = "eu-central-1a",
"mgmtb" = "eu-central-1b"
}
create\_public\_ip = true
source\_dest\_check = true
}
public = {
device\_index = 2
security\_group = "vmseries\_public"
subnet = {
"publica" = "eu-central-1a",
"publicb" = "eu-central-1b"
}
create\_public\_ip = false
source\_dest\_check = false
}
}

subinterfaces = {
inbound = {
app1 = {
gwlb\_endpoint = "app1\_inbound"
subinterface = "ethernet1/1.11"
}
app2 = {
gwlb\_endpoint = "app2\_inbound"
subinterface = "ethernet1/1.12"
}
}
outbound = {
only\_1\_outbound = {
gwlb\_endpoint = "security\_gwlb\_outbound"
subinterface = "ethernet1/1.20"
}
}
eastwest = {
only\_1\_eastwest = {
gwlb\_endpoint = "security\_gwlb\_eastwest"
subinterface = "ethernet1/1.30"
}
}
}

asg = {
desired\_cap = 2
min\_size = 2
max\_size = 4
}

scaling\_plan = {
enabled = true # TODO: update here
metric\_name = "panSessionActive" # TODO: update here
target\_value = 75 # TODO: update here
statistic = "Average" # TODO: update here
cloudwatch\_namespace = "example-vmseries" # TODO: update here
tags = {
ManagedBy = "terraform"
}
}
}
}
|
map(object({
bootstrap\_options = object({
mgmt-interface-swap = string
plugin-op-commands = string
panorama-server = string
auth-key = string
dgname = string
tplname = string
dhcp-send-hostname = string
dhcp-send-client-id = string
dhcp-accept-server-hostname = string
dhcp-accept-server-domain = string
})

panos\_version = string
ebs\_kms\_id = string

vpc = string
gwlb = string

interfaces = map(object({
device\_index = number
security\_group = string
subnet = map(string)
create\_public\_ip = bool
source\_dest\_check = bool
}))

subinterfaces = map(map(object({
gwlb\_endpoint = string
subinterface = string
})))

asg = object({
desired\_cap = number
min\_size = number
max\_size = number
})

scaling\_plan = object({
enabled = bool
metric\_name = string
target\_value = number
statistic = string
cloudwatch\_namespace = string
tags = map(string)
})
}))
| `{}` | no | -| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = map(object({
name = string
rules = map(object({
description = string
type = string,
from\_port = string
to\_port = string,
protocol = string
cidr\_blocks = list(string)
}))
}))
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | +| [vpcs](#input\_vpcs) | A map defining VPCs with security groups and subnets.

Following properties are available:
- `name`: VPC name
- `cidr`: CIDR for VPC
- `nacls`: map of network ACLs
- `security_groups`: map of security groups
- `subnets`: map of subnets with properties:
- `az`: availability zone
- `set`: internal identifier referenced by main.tf
- `nacl`: key of NACL (can be null)
- `routes`: map of routes with properties:
- `vpc_subnet` - built from key of VPCs concatenate with `-` and key of subnet in format: `VPCKEY-SUBNETKEY`
- `next_hop_key` - must match keys use to create TGW attachment, IGW, GWLB endpoint or other resources
- `next_hop_type` - internet\_gateway, nat\_gateway, transit\_gateway\_attachment or gwlbe\_endpoint

Example:
vpcs = {
example\_vpc = {
name = "example-spoke-vpc"
cidr = "10.104.0.0/16"
nacls = {
trusted\_path\_monitoring = {
name = "trusted-path-monitoring"
rules = {
allow\_inbound = {
rule\_number = 300
egress = false
protocol = "-1"
rule\_action = "allow"
cidr\_block = "0.0.0.0/0"
from\_port = null
to\_port = null
}
}
}
}
security\_groups = {
example\_vm = {
name = "example\_vm"
rules = {
all\_outbound = {
description = "Permit All traffic outbound"
type = "egress", from\_port = "0", to\_port = "0", protocol = "-1"
cidr\_blocks = ["0.0.0.0/0"]
}
}
}
}
subnets = {
"10.104.0.0/24" = { az = "eu-central-1a", set = "vm", nacl = null }
"10.104.128.0/24" = { az = "eu-central-1b", set = "vm", nacl = null }
}
routes = {
vm\_default = {
vpc\_subnet = "app1\_vpc-app1\_vm"
to\_cidr = "0.0.0.0/0"
next\_hop\_key = "app1"
next\_hop\_type = "transit\_gateway\_attachment"
}
}
}
}
|
map(object({
name = string
cidr = string
nacls = map(object({
name = string
rules = map(object({
rule\_number = number
egress = bool
protocol = string
rule\_action = string
cidr\_block = string
from\_port = string
to\_port = string
}))
}))
security\_groups = any
subnets = map(object({
az = string
set = string
nacl = string
}))
routes = map(object({
vpc\_subnet = string
to\_cidr = string
next\_hop\_key = string
next\_hop\_type = string
}))
}))
| `{}` | no | ### Outputs From 0e593ae74f73770ab4cf25e13f40e4bab9b8436b Mon Sep 17 00:00:00 2001 From: "create-pr-on-fork-for-pan-dev[bot]" <135888023+create-pr-on-fork-for-pan-dev[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:27:59 +0100 Subject: [PATCH 2/3] Sync azure Terraform module documentation (#473) Co-authored-by: pan-dev-content-sync-trigger[bot] --- .../vmseries/examples/gwlb_with_vmseries.md | 157 ++++++++++++ .../docs/swfw/azure/vmseries/modules/appgw.md | 2 +- .../vmseries/modules/application_insights.md | 2 +- .../swfw/azure/vmseries/modules/bootstrap.md | 3 +- .../docs/swfw/azure/vmseries/modules/gwlb.md | 75 ++++++ .../azure/vmseries/modules/loadbalancer.md | 6 +- .../docs/swfw/azure/vmseries/modules/natgw.md | 2 +- .../swfw/azure/vmseries/modules/panorama.md | 2 +- .../modules/virtual_network_gateway.md | 92 +++++++ .../swfw/azure/vmseries/modules/vmseries.md | 2 +- .../docs/swfw/azure/vmseries/modules/vmss.md | 2 +- .../docs/swfw/azure/vmseries/modules/vnet.md | 2 +- .../azure/vmseries/modules/vnet_peering.md | 2 +- .../b10403f9-795a-4501-a189-3c21d44fc9e7.png | Bin 0 -> 143283 bytes .../common_vmseries.md | 8 +- .../common_vmseries_and_autoscale.md | 227 ++++++++++++++++++ .../dedicated_vmseries.md | 8 +- .../dedicated_vmseries_and_autoscale.md | 4 +- 18 files changed, 575 insertions(+), 21 deletions(-) create mode 100644 products/terraform/docs/swfw/azure/vmseries/examples/gwlb_with_vmseries.md create mode 100644 products/terraform/docs/swfw/azure/vmseries/modules/gwlb.md create mode 100644 products/terraform/docs/swfw/azure/vmseries/modules/virtual_network_gateway.md create mode 100644 products/terraform/docs/swfw/azure/vmseries/reference-architectures/b10403f9-795a-4501-a189-3c21d44fc9e7.png create mode 100644 products/terraform/docs/swfw/azure/vmseries/reference-architectures/common_vmseries_and_autoscale.md diff --git a/products/terraform/docs/swfw/azure/vmseries/examples/gwlb_with_vmseries.md b/products/terraform/docs/swfw/azure/vmseries/examples/gwlb_with_vmseries.md new file mode 100644 index 000000000..fcf48503c --- /dev/null +++ b/products/terraform/docs/swfw/azure/vmseries/examples/gwlb_with_vmseries.md @@ -0,0 +1,157 @@ +--- +hide_title: true +id: gwlb_with_vmseries +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- azure +pagination_next: null +pagination_prev: null +sidebar_label: GWLB With VM-Series +title: VM-Series Azure Gateway Load Balancer example +--- + +# VM-Series Azure Gateway Load Balancer example + +The exmaple allows to deploy VM-Series firewalls for inbound and outbound traffic inspection utilizing Azure Gateway Load Balancer in service chain model as described in the following [document](https://docs.paloaltonetworks.com/vm-series/10-2/vm-series-deployment/set-up-the-vm-series-firewall-on-azure/deploy-the-vm-series-firewall-with-the-azure-gwlb). + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/gwlb_with_vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/gwlb_with_vmseries) + +## Usage + +### Deployment Steps + +* Checkout the code locally. +* Copy `example.tfvars` to `terraform.tfvars` and adjust it to your needs. +* Copy `files/init-cfg.txt.sample` to `files/init-cfg.txt` and fill it in with required bootstrap parameters (see this [documentation](https://docs.paloaltonetworks.com/vm-series/10-2/vm-series-deployment/bootstrap-the-vm-series-firewall/create-the-init-cfgtxt-file/init-cfgtxt-file-components) for details). +* (optional) Authenticate to AzureRM, switch to the Subscription of your choice if necessary. +* Initialize the Terraform module: + + terraform init + +* (optional) Plan you infrastructure to see what will be actually deployed: + + terraform plan + +* Deploy the infrastructure: + + terraform apply + +* At this stage you have to wait a few minutes for the firewalls to bootstrap. + +### Post deploy + +Firewalls in this example are configured with password authentication. To retrieve the initial credentials run: + +* for username: + + terraform output username + +* for password: + + terraform output password + +The management public IP addresses are available in the `vmseries_mgmt_ips` output: + +```sh +terraform output vmseries_mgmt_ips +``` + +You can now login to the devices using either: + +* CLI - ssh client is required +* Web UI (https) - any modern web browser, note that initially the traffic is encrypted with a self-signed certificate. + +With default example configuration, the devices already contain `DAY0` configuration, so all network interfaces should be configured and Azure Gateway Load Balancer should already report that the devices are healthy. + +You can now proceed with licensing the devices and configuring your first rules. + +Please also refer to [this repository](https://github.com/PaloAltoNetworks/iron-skillet) for `DAY1` configuration (security hardening). + +### Cleanup + +To remove the deployed infrastructure run: + +```sh +terraform destroy +``` + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0.0, < 2.0 | + +### Providers + +| Name | Version | +|------|---------| +| [http](#provider\_http) | n/a | +| [azurerm](#provider\_azurerm) | n/a | +| [local](#provider\_local) | n/a | +| [random](#provider\_random) | n/a | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [vnet](#module\_vnet) | ../../modules/vnet | n/a | +| [gwlb](#module\_gwlb) | ../../modules/gwlb | n/a | +| [ai](#module\_ai) | ../../modules/application_insights | n/a | +| [bootstrap](#module\_bootstrap) | ../../modules/bootstrap | n/a | +| [bootstrap\_share](#module\_bootstrap\_share) | ../../modules/bootstrap | n/a | +| [vmseries](#module\_vmseries) | ../../modules/vmseries | n/a | +| [load\_balancer](#module\_load\_balancer) | ../../modules/loadbalancer | n/a | +| [appvm](#module\_appvm) | ../../modules/virtual_machine | n/a | + +### Resources + +| Name | Type | +|------|------| +| [azurerm_availability_set.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/availability_set) | resource | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [local_file.bootstrap_xml](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | +| [random_password.appvms](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [random_password.vmseries](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source | +| [http_http.this](https://registry.terraform.io/providers/hashicorp/http/latest/docs/data-sources/http) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name\_prefix](#input\_name\_prefix) | Prefix for resource names. | `string` | `""` | no | +| [location](#input\_location) | Location where the resources will be deployed. | `string` | n/a | yes | +| [create\_resource\_group](#input\_create\_resource\_group) | When set to `true` it will cause a Resource Group creation. Name of the newly specified RG is controlled by `resource_group_name`.
When set to `false` the `resource_group_name` parameter is used to specify a name of an existing Resource Group. | `bool` | `true` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | Name of the Resource Group to create or use. | `string` | n/a | yes | +| [enable\_zones](#input\_enable\_zones) | If `true`, enable zone support for resources. | `bool` | `true` | no | +| [tags](#input\_tags) | Map of tags to assign to all of the created resources. | `map(string)` | `{}` | no | +| [vnets](#input\_vnets) | Map with VNet definitions. Each item supports following inputs for `vnet` module:
- `name` - (required\|string) VNet name.
- `create_virtual_network` - (optional\|bool) Whether to create a new or source an existing VNet, defaults to `true`.
- `address_space` - (optional\|list) List of CIDRs for the new VNet.
- `resource_group_name` - (optional\|string) VNet's Resource Group, by default the one specified by `var.resource_group_name`.
- `create_subnets` - (optional\|bool) Whether to create or source items from `subnets`, defaults to `true`.
- `subnets` - (required\|map) Subnet definitions.
- `network_security_groups` - (optional\|map) NSGs to create.
- `route_tables` - (optional\|map) Route Tables to create.

Please consult [module documentation](../../modules/vnet) for details. | `any` | n/a | yes | +| [gateway\_load\_balancers](#input\_gateway\_load\_balancers) | Map with Gateway Load Balancer definitions. Following settings are supported:
- `name` - (required\|string) Gateway Load Balancer name.
- `vnet_key` - (required\|string) Key of a VNet from `var.vnets` that contains target Subnet for LB's frontned. Used to get Subnet ID in combination with `subnet_key` below.
- `subnet_key` - (required\|string) Key of a Subnet from `var.vnets[vnet_key]`.
- `frontend_ip_config` - (optional\|map) Remaining Frontned IP configuration.
- `resource_group_name` - (optional\|string) LB's Resource Group, by default the one specified by `var.resource_group_name`.
- `backends` - (optional\|map) LB's backend configurations.
- `heatlh_probe` - (optional\|map) Health probe configuration.

Please consult [module documentation](../../modules/gwlb) for details. | `any` | `{}` | no | +| [application\_insights](#input\_application\_insights) | A map defining Azure Application Insights. There are three ways to use this variable:

* when the value is set to `null` (default) no AI is created
* when the value is a map containing `name` key (other keys are optional) a single AI instance will be created under the name that is the value of the `name` key
* when the value is an empty map or a map w/o the `name` key, an AI instance per each VMSeries VM will be created. All instances will share the same configuration. All instances will have names corresponding to their VM name.

Names for all AI instances are prefixed with `var.name_prefix`.

Properties supported (for details on each property see [module documentation](../modules/application\_insights)):

- `name` - (optional\|string) Name of a single AI instance
- `workspace_mode` - (optional\|bool) Use AI Workspace mode instead of the Classical (deprecated), defaults to `true`.
- `workspace_name` - (optional\|string) Name of the Log Analytics Workspace created when AI is deployed in Workspace mode, defaults to AI name suffixed with `-wrkspc`.
- `workspace_sku` - (optional\|string) SKU used by WAL, see module documentation for details, defaults to PerGB2018.
- `metrics_retention_in_days` - (optional\|number) Defaults to current Azure default value, see module documentation for details.

Example of an AIs created per VM, in Workspace mode, with metrics retention set to 1 year:
vmseries = {
'vm-1' = {
....
}
'vm-2' = {
....
}
}

application\_insights = {
metrics\_retention\_in\_days = 365
}
| `map(string)` | `null` | no | +| [bootstrap\_storages](#input\_bootstrap\_storages) | A map defining Azure Storage Accounts used to host file shares for bootstrapping NGFWs. This variable defines only Storage Accounts, file shares are defined per each VM. See `vmseries` variable, `bootstrap_storage` property.
Following properties are supported:
- `name` - (required\|string) Name of the Storage Account. Please keep in mind that storage account name has to be globally unique. This name will not be prefixed with the value of `var.name_prefix`.
- `create_storage_account` - (optional\|bool) Whether to create or source an existing Storage Account, defaults to `true`.
- `resource_group_name` - (optional\|string) Name of the Resource Group hosting the Storage Account, defaults to `var.resource_group_name`.
- `storage_acl` - (optional\|bool) Allows to enable network ACLs on the Storage Account. If set to `true`, `storage_allow_vnet_subnets` and `storage_allow_inbound_public_ips` options become available. Defaults to `false`.
- `storage_allow_vnet_subnets` - (optional\|map) Map with objects that contains `vnet_key`/`subnet_key` used to identify subnets allowed to access the Storage Account. Note that `enable_storage_service_endpoint` has to be set to `true` in the corresponding subnet configuration.
- `storage_allow_inbound_public_ips` - (optional\|list) Whitelist that contains public IPs/ranges allowed to access the Storage Account. Note that the code automatically to queries https://ifcondif.me to obtain the public IP address of the machine executing the code to enable bootstrap files upload. | `any` | `{}` | no | +| [vmseries\_common](#input\_vmseries\_common) | Configuration common for all firewall instances. Following settings can be specified:
- `username` - (required\|string)
- `password` - (optional\|string)
- `ssh_keys` - (optional\|string)
- `img_version` - (optional\|string)
- `img_sku` - (optional\|string)
- `vm_size` - (optional\|string)
- `bootstrap_options` - (optional\|string)
- `vnet_key` - (optional\|string)
- `interfaces` - (optional\|list(object))
- `ai_update_interval` - (optional\|number)

All are used directly as inputs for `vmseries` module (please see [documentation](../../modules/vmseries) for details), except for the last three:
- `vnet_key` - (required\|string) Used to identify VNet in which subnets for interfaces exist.
- `ai_update_interval` - (optional\|number) If Application Insights are used this property can override the default metrics update interval (in minutes). | `any` | n/a | yes | +| [vmseries](#input\_vmseries) | Map with VM-Series instance specific configuration. Following properties are supported:
- `name` - (required\|string) Instance name.
- `avzone` - (optional\|string) AZ to deploy instance in, defaults to "1".
- `availability_set_key` - (optional\|string) Key from `var.availability_sets`, used to determine Availabbility Set ID.
- `bootstrap_storage` - (optional\|map) Map that contains bootstrap package contents definition, when present triggers creation of a File Share in an existing Storage Account. Following properties supported:
- `key` - (required\|string) Identifies Storage Account to use from `var.bootstrap_storages`.
- `static_files` - (optional\|map) Map where keys are local file paths, values determine destination in the bootstrap package (file share) where the file will be copied.
- `template_bootstrap_xml` - (optional\|string) Path to the `bootstrap.xml` template. When defined it will trigger creation of the `bootstrap.xml` file and it's upload to the boostrap package. This is a simple `day 0` configuration file that should set up only basic networking. Specifying this property forces additional properties that are required to properly template the file. They can be defined per each VM or globally for all VMs (in `var.vmseries_common`). The properties are listed below.
- `interfaces` - List of objects with interface definitions. Utilizes all properties of `interfaces` input (see [documantation](../../modules/vmseries#inputs)), expect for `subnet_id` and `lb_backend_pool_id`, which are determined based on the following new items:
- `subnet_key` - (optional\|string) Key of a subnet from `var.vnets[vnet_key]` to associate interface with.
- `gwlb_key` - (optional\|string) Key from `var.gwlbs` that identifies GWLB that will be associated with the interface, required when `enable_backend_pool` is `true`.
- `gwlb_backend_key` - (optional\|string) Key that identifies a backend from the GWLB selected by `gwlb_key` to associate th interface with, required when `enable_backend_pool` is `true`.

Additionally, it's possible to override following settings from `var.vmseries_common`:
- `bootstrap_options` - When defined, it not only takes precedence over `var.vmseries_common.bootstrap_options`, but also over `bootstrap_storage` described below.
- `img_version`
- `img_sku`
- `vm_size`
- `ai_update_interval` | `map(any)` | n/a | yes | +| [availability\_sets](#input\_availability\_sets) | A map defining availability sets. Can be used to provide infrastructure high availability when zones cannot be used.

Following properties are supported:
- `name` - (required\|string) Name of the Application Insights.
- `update_domain_count` - (optional\|int) Specifies the number of update domains that are used, defaults to 5 (Azure defaults).
- `fault_domain_count` - (optional\|int) Specifies the number of fault domains that are used, defaults to 3 (Azure defaults).

Please keep in mind that Azure defaults are not working for each region (especially the small ones, w/o any Availability Zones). Please verify how many update and fault domain are supported in a region before deploying this resource. | `any` | `{}` | no | +| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.
Following properties are available (for details refer to module's documentation):
- `name` - (required\|string) Name of the Load Balancer resource.
- `network_security_group_name` - (optional\|string) Public LB only - name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name` - (optional\|string) Public LB only - name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips` - (optional\|string) Public LB only - list of IP addresses that will be allowed in the ingress rules.
- `avzones` - (optional\|list) For regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips` - (optional\|map) Map configuring both a listener and load balancing/outbound rules, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), values are objects with the following properties:
- `create_public_ip` - (optional\|bool) Public LB only - defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name` - (optional\|string) Public LB only - defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group` - (optional\|string) Public LB only - defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address` - (optional\|string) Private LB only - defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key` - (optional\|string) Private LB only - defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key` - (optional\|string) Private LB only - defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `in_rules`/`out_rules` - (optional\|map) Configuration of load balancing/outbound rules, please refer to [load\_balancer module documentation](../../modules/loadbalancer#inputs) for details.

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "internal\_app\_lb"
frontend\_ips = {
"ha-ports" = {
vnet\_key = "internal\_app\_vnet"
subnet\_key = "internal\_app\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | +| [appvms\_common](#input\_appvms\_common) | Common settings for sample applications:
- `username` - (required\|string)
- `password` - (optional\|string)
- `ssh_keys` - (optional\|list(string)
- `vm_size` - (optional\|string)
- `disk_type` - (optional\|string)
- `accelerated_networking` - (optional\|bool)

At least one of `password` or `ssh_keys` has to be provided. | `any` | n/a | yes | +| [appvms](#input\_appvms) | Configuration for sample application VMs. Available settings:
- `name` - (required\|string) Instance name.
- `avzone` - (optional\|string) AZ to deploy instance in, defaults to "1".
- `vnet_key` - (required\|string) Used to identify VNet in which subnets for interfaces exist.
- `subnet_key` - (required\|string) Key of a subnet from `var.vnets[vnet_key]` to associate interface with.
- `load_balancer_key` - (optional\|string) Key from `var.gwlbs` that identifies GWLB that will be associated with the interface, required when `enable_backend_pool` is `true`. | `any` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [username](#output\_username) | Initial administrative username to use for VM-Series. | +| [password](#output\_password) | Initial administrative password to use for VM-Series. | +| [vmseries\_mgmt\_ips](#output\_vmseries\_mgmt\_ips) | IP addresses for VM-Series management. | +| [gwlb\_frontend\_ip\_configuration\_ids](#output\_gwlb\_frontend\_ip\_configuration\_ids) | Configuration IDs of Gateway Load Balancers' frontends. | +| [appvms\_username](#output\_appvms\_username) | Initial administrative username to use for application VMs. | +| [appvms\_password](#output\_appvms\_password) | Initial administrative password to use for application VMs. | +| [lb\_frontend\_ips](#output\_lb\_frontend\_ips) | IP addresses of the Load Balancers serving applications. | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/appgw.md b/products/terraform/docs/swfw/azure/vmseries/modules/appgw.md index 0119d2bea..1938ff7d5 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/appgw.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/appgw.md @@ -22,7 +22,7 @@ A terraform module for deploying an Application Gateway v2. The module is dedica In the center of module's configuration is the `rules` property. See the the [rules property explained](#rules-property-explained) and [`rules` property examples](#rules-property-examples) topics for more details. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/appgw) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/appgw) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/appgw) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/appgw) ## Rules property explained diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/application_insights.md b/products/terraform/docs/swfw/azure/vmseries/modules/application_insights.md index 7016cdc7e..1b8971e17 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/application_insights.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/application_insights.md @@ -40,7 +40,7 @@ In both situations the instrumentation key for the Application Insights has to b } } -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/application_insights) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/application_insights) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/application_insights) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/application_insights) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/bootstrap.md b/products/terraform/docs/swfw/azure/vmseries/modules/bootstrap.md index 6f8e035dc..0600cb995 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/bootstrap.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/bootstrap.md @@ -23,7 +23,7 @@ to [bootstrap a VM-Series firewalls in Azure](https://docs.paloaltonetworks.com/ The module does *not* configure the bootstrap images, licenses, or configurations. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/bootstrap) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/bootstrap) ## Usage @@ -104,6 +104,7 @@ No modules. | [location](#input\_location) | Region to deploy bootstrap resources. Ignored when `create_storage_account` is set to `false`. | `string` | `null` | no | | [min\_tls\_version](#input\_min\_tls\_version) | The minimum supported TLS version for the storage account. | `string` | `"TLS1_2"` | no | | [files](#input\_files) | Map of all files to copy to bucket. The keys are local paths, the values are remote paths.
Always use slash `/` as directory separator (unix-like), not the backslash `\`.
Example:
files = {
"dir/my.txt" = "config/init-cfg.txt"
}
| `map(string)` | `{}` | no | +| [bootstrap\_files\_dir](#input\_bootstrap\_files\_dir) | Bootstrap file directory. If the variable has a value of `null` (default) - then it will not upload any other files other than the ones specified in the `files` variable. More information can be found at https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/bootstrap-the-vm-series-firewall/bootstrap-package. | `string` | `null` | no | | [files\_md5](#input\_files\_md5) | Optional map of MD5 hashes of file contents.
Normally the map could be empty, because all the files that exist before the `terraform apply` will have their hashes auto-calculated.
This input is necessary only for the selected files which are created/modified within the same Terraform run as this module.
The keys of the map should be identical with selected keys of the `files` input, while the values should be MD5 hashes of the contents of that file.

Example:
files\_md5 = {
"dir/my.txt" = "6f7ce3191b50a58cc13e751a8f7ae3fd"
}
| `map(string)` | `{}` | no | | [storage\_share\_name](#input\_storage\_share\_name) | Name of a storage File Share to be created that will hold `files` used for bootstrapping.
For rules defining a valid name see [Microsoft documentation](https://docs.microsoft.com/en-us/rest/api/storageservices/Naming-and-Referencing-Shares--Directories--Files--and-Metadata#share-names). | `string` | `null` | no | | [storage\_share\_quota](#input\_storage\_share\_quota) | Maximum size of a File Share. | `number` | `50` | no | diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/gwlb.md b/products/terraform/docs/swfw/azure/vmseries/modules/gwlb.md new file mode 100644 index 000000000..f49c44a4e --- /dev/null +++ b/products/terraform/docs/swfw/azure/vmseries/modules/gwlb.md @@ -0,0 +1,75 @@ +--- +hide_title: true +id: gwlb +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- azure +pagination_next: null +pagination_prev: null +sidebar_label: GWLB +title: Gateway Load Balancer Module for Azure +--- + +# Gateway Load Balancer Module for Azure + +A Terraform module for deploying a Gateway Load Balancer for VM-Series firewalls. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/gwlb) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/gwlb) + +## Usage + +For usage see any of the reference architecture examples. + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.0, < 2.0 | +| [azurerm](#requirement\_azurerm) | ~> 3.25 | + +### Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | ~> 3.25 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [azurerm_lb.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb) | resource | +| [azurerm_lb_backend_address_pool.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_backend_address_pool) | resource | +| [azurerm_lb_probe.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_probe) | resource | +| [azurerm_lb_rule.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_rule) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | The name of the gateway load balancer. | `string` | n/a | yes | +| [resource\_group\_name](#input\_resource\_group\_name) | Name of a pre-existing resource group to place resources in. | `string` | n/a | yes | +| [location](#input\_location) | Region to deploy load balancer and related resources in. | `string` | n/a | yes | +| [frontend\_ip\_config](#input\_frontend\_ip\_config) | Frontend IP configuration of the gateway load balancer. Following settings are available:
- `name` - (Optional\|string) Name of the frontend IP configuration. `var.name` by default.
- `private_ip_address_allocation` - (Optional\|string) The allocation method for the private IP address.
- `private_ip_address_version` - (Optional\|string) The IP version for the private IP address.
- `private_ip_address` - (Optional\|string) Private IP address to assign.
- `subnet_id` - (Required\|string) Id of a subnet to associate with the configuration.
- `zones` - (Optional\|list) List of AZs in which the IP address will be located in. | `any` | n/a | yes | +| [health\_probe](#input\_health\_probe) | Health probe configuration for the gateway load balancer backends. Following settings are available:
- `name` - (Optional\|string) Name of the health probe. Defaults to `name` variable value.
- `port` - (Required\|int)
- `protocol` - (Optional\|string)
- `probe_threshold` - (Optional\|int)
- `request_path` - (Optional\|string)
- `interval_in_seconds` - (Optional\|int)
- `number_of_probes` - (Optional\|int)

For details, please refer to [provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_probe#argument-reference). | `map(any)` | n/a | yes | +| [backends](#input\_backends) | Map with backend configurations for the gateway load balancer. Azure GWLB rule can have up to two backends.
Following settings are available:
- `name` - (Optional\|string) Name of the backend. If not specified name is generated from `name` variable and backend key.
- `tunnel_interfaces` - (Required\|map) Map with tunnel interfaces specs.)

Each tunnel interface specification consists of following settings (refer to [provider documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_backend_address_pool#tunnel_interface) for details):
- `identifier` - (Required\|int) Interface identifier.
- `port` - (Required\|int) Interface port.
- `type` - (Required\|string) Either "External" or "Internal".

If one backend is specified, it has to have both external and internal tunnel interfaces specified.
For two backends, each has to have exactly one.

On GWLB inspection enabled VM-Series instance, `identifier` and `port` default to:
- `800`/`2000` for `Internal` tunnel type
- `801`/`2001` for `External` tunnel type
Variable default reflects this configuration on GWLB side. Additionally, for VM-Series tunnel interface protocol is always VXLAN. | `map(any)` |
{
"ext-int": {
"tunnel\_interfaces": {
"external": {
"identifier": 801,
"port": 2001,
"protocol": "VXLAN",
"type": "External"
},
"internal": {
"identifier": 800,
"port": 2000,
"protocol": "VXLAN",
"type": "Internal"
}
}
}
}
| no | +| [lb\_rule](#input\_lb\_rule) | Load balancing rule config. Available options:
- `name` - (Optional\|string) Name for the rule. Defaults to `var.frontend_ip_config.name`.
- `load_distribution` - (Optional\|string) Refer to [provider docs](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/lb_rule#load_distribution). | `map(string)` | `null` | no | +| [tags](#input\_tags) | Azure tags to apply to the created resources. | `map(string)` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [backend\_pool\_ids](#output\_backend\_pool\_ids) | Backend pools' identifiers. | +| [frontend\_ip\_config\_id](#output\_frontend\_ip\_config\_id) | Frontend IP configuration identifier. | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/loadbalancer.md b/products/terraform/docs/swfw/azure/vmseries/modules/loadbalancer.md index 2cd118b6a..7c025dc49 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/loadbalancer.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/loadbalancer.md @@ -22,7 +22,9 @@ A Terraform module for deploying a Load Balancer for VM-Series firewalls. Suppor The module creates a single load balancer and a single backend for it, but it allows multiple frontends. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/loadbalancer) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/loadbalancer) +In case of a public load balancer, reusing the same frontend for inbound and outbound rules is possible - to achieve this, a key in `outbound_rules` has to match a corresponding key from `frontend_ips`. + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/loadbalancer) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/loadbalancer) ## Usage @@ -64,7 +66,7 @@ No modules. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [frontend\_ips](#input\_frontend\_ips) | A map of objects describing LB Frontend IP configurations, inbound and outbound rules. Used for both public or private load balancers.
Keys of the map are names of LB Frontend IP configurations.

Each Frontend IP configuration can have multiple rules assigned. They are defined in a maps called `in_rules` and `out_rules` for inbound and outbound rules respectively. A key in this map is the name of the rule, while value is the actual rule configuration. To understand this structure please see examples below.

**Inbound rules.**

Here is a list of properties supported by each `in_rule`:

- `protocol` : required, communication protocol, either 'Tcp', 'Udp' or 'All'.
- `port` : required, communication port, this is both the front- and the backend port if `backend_port` is not given.
- `backend_port` : optional, this is the backend port to forward traffic to in the backend pool.
- `floating_ip` : optional, defaults to `true`, enables floating IP for this rule.
- `session_persistence` : optional, defaults to 5 tuple (Azure default), see `Session persistence/Load distribution` below for details.

Public LB

- `create_public_ip` : Optional. Set to `true` to create a public IP.
- `public_ip_name` : Ignored if `create_public_ip` is `true`. The existing public IP resource name to use.
- `public_ip_resource_group` : Ignored if `create_public_ip` is `true` or if `public_ip_name` is null. The name of the resource group which holds `public_ip_name`.

Example
frontend\_ips = {
pip\_existing = {
create\_public\_ip = false
public\_ip\_name = "my\_ip"
public\_ip\_resource\_group = "my\_rg\_name"
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
}
}
}
}
Forward to a different port on backend pool
frontend\_ips = {
pip\_existing = {
create\_public\_ip = false
public\_ip\_name = "my\_ip"
public\_ip\_resource\_group = "my\_rg\_name"
in\_rules = {
HTTP = {
port = 80
backend\_port = 8080
protocol = "Tcp"
}
}
}
}
Private LB

- `subnet_id` : Identifier of an existing subnet. This also trigger creation of an internal LB.
- `private_ip_address` : A static IP address of the Frontend IP configuration, has to be in limits of the subnet's (specified by `subnet_id`) address space. When not set, changes the address allocation from `Static` to `Dynamic`.

Example
frontend\_ips = {
internal\_fe = {
subnet\_id = azurerm\_subnet.this.id
private\_ip\_address = "192.168.0.10"
in\_rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
Session persistence/Load distribution

By default the load balancer uses a 5 tuple hash to map traffic to available servers. This can be controlled using `session_persistence` property defined inside a role. Available values are:

- `Default` : this is the 5 tuple hash - this method is also used when no property is defined
- `SourceIP` : a 2 tuple hash is used
- `SourceIPProtocol` : a 3 tuple hash is used

Example
frontend\_ips = {
rule\_1 = {
create\_public\_ip = true
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
session\_persistence = "SourceIP"
}
}
}
}
**Outbound rules.**

Each Frontend IP config can have outbound rules specified. Setting at least one `out_rule` switches the outgoing traffic from SNAT to Outbound rules. Keep in mind that since we use a single backend, and you cannot mix SNAT and Outbound rules traffic in rules using the same backend, setting one `out_rule` switches the outgoing traffic route for **ALL** `in_rules`.

Following properties are available:

- `protocol` : Protocol used by the rule. On of `All`, `Tcp` or `Udp` is accepted.
- `allocated_outbound_ports` : Number of ports allocated per instance. Defaults to `1024`.
- `enable_tcp_reset` : Ignored when `protocol` is set to `Udp`, defaults to `False` (Azure defaults).
- `idle_timeout_in_minutes` : Ignored when `protocol` is set to `Udp`. TCP connection timeout in case the connection is idle. Defaults to 4 minutes (Azure defaults).

Example:
frontend\_ips = {
rule\_1 = {
create\_public\_ip = true
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
session\_persistence = "SourceIP"
}
}
out\_rules = {
"outbound\_tcp" = {
protocol = "Tcp"
allocated\_outbound\_ports = 2048
enable\_tcp\_reset = true
idle\_timeout\_in\_minutes = 10
}
}
}
}
| `any` | n/a | yes | +| [frontend\_ips](#input\_frontend\_ips) | A map of objects describing LB Frontend IP configurations, inbound and outbound rules. Used for both public or private load balancers.
Keys of the map are names of LB Frontend IP configurations.

Each Frontend IP configuration can have multiple rules assigned. They are defined in a maps called `in_rules` and `out_rules` for inbound and outbound rules respectively. A key in this map is the name of the rule, while value is the actual rule configuration. To understand this structure please see examples below.

**Inbound rules.**

Here is a list of properties supported by each `in_rule`:

- `protocol` : required, communication protocol, either 'Tcp', 'Udp' or 'All'.
- `port` : required, communication port, this is both the front- and the backend port if `backend_port` is not given.
- `backend_port` : optional, this is the backend port to forward traffic to in the backend pool.
- `floating_ip` : optional, defaults to `true`, enables floating IP for this rule.
- `session_persistence` : optional, defaults to 5 tuple (Azure default), see `Session persistence/Load distribution` below for details.

Public LB

- `create_public_ip` : Optional. Set to `true` to create a public IP.
- `public_ip_name` : Ignored if `create_public_ip` is `true`. The existing public IP resource name to use.
- `public_ip_resource_group` : Ignored if `create_public_ip` is `true` or if `public_ip_name` is null. The name of the resource group which holds `public_ip_name`.

Example
frontend\_ips = {
pip\_existing = {
create\_public\_ip = false
public\_ip\_name = "my\_ip"
public\_ip\_resource\_group = "my\_rg\_name"
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
}
}
}
}
Forward to a different port on backend pool
frontend\_ips = {
pip\_existing = {
create\_public\_ip = false
public\_ip\_name = "my\_ip"
public\_ip\_resource\_group = "my\_rg\_name"
in\_rules = {
HTTP = {
port = 80
backend\_port = 8080
protocol = "Tcp"
}
}
}
}
Private LB

- `subnet_id` : Identifier of an existing subnet. This also trigger creation of an internal LB.
- `private_ip_address` : A static IP address of the Frontend IP configuration, has to be in limits of the subnet's (specified by `subnet_id`) address space. When not set, changes the address allocation from `Static` to `Dynamic`.

Example
frontend\_ips = {
internal\_fe = {
subnet\_id = azurerm\_subnet.this.id
private\_ip\_address = "192.168.0.10"
in\_rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
Session persistence/Load distribution

By default the Load Balancer uses a 5 tuple hash to map traffic to available servers. This can be controlled using `session_persistence` property defined inside a rule. Available values are:

- `Default` : this is the 5 tuple hash - this method is also used when no property is defined
- `SourceIP` : a 2 tuple hash is used
- `SourceIPProtocol` : a 3 tuple hash is used

Example
frontend\_ips = {
rule\_1 = {
create\_public\_ip = true
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
session\_persistence = "SourceIP"
}
}
}
}
**Outbound rules.**

Each Frontend IP config can have outbound rules specified. Setting at least one `out_rule` switches the outgoing traffic from SNAT to Outbound rules. Keep in mind that since we use a single backend, and you cannot mix SNAT and Outbound rules traffic in rules using the same backend, setting one `out_rule` switches the outgoing traffic route for **ALL** `in_rules`.

Following properties are available:

- `protocol` : Protocol used by the rule. On of `All`, `Tcp` or `Udp` is accepted.
- `allocated_outbound_ports` : Number of ports allocated per instance. Defaults to `1024`.
- `enable_tcp_reset` : Ignored when `protocol` is set to `Udp`, defaults to `False` (Azure defaults).
- `idle_timeout_in_minutes` : Ignored when `protocol` is set to `Udp`. TCP connection timeout in case the connection is idle. Defaults to 4 minutes (Azure defaults).

Example:
frontend\_ips = {
rule\_1 = {
create\_public\_ip = true
in\_rules = {
HTTP = {
port = 80
protocol = "Tcp"
session\_persistence = "SourceIP"
}
}
out\_rules = {
"outbound\_tcp" = {
protocol = "Tcp"
allocated\_outbound\_ports = 2048
enable\_tcp\_reset = true
idle\_timeout\_in\_minutes = 10
}
}
}
}
| `any` | n/a | yes | | [resource\_group\_name](#input\_resource\_group\_name) | Name of a pre-existing Resource Group to place the resources in. | `string` | n/a | yes | | [location](#input\_location) | Region to deploy load balancer and dependencies. | `string` | n/a | yes | | [backend\_name](#input\_backend\_name) | The name of the backend pool to create. All the frontends of the load balancer always use the same single backend. | `string` | `"vmseries_backend"` | no | diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/natgw.md b/products/terraform/docs/swfw/azure/vmseries/modules/natgw.md index d01bd75d7..67a232159 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/natgw.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/natgw.md @@ -18,7 +18,7 @@ title: NAT Gateway module # NAT Gateway module -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/natgw) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/natgw) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/natgw) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/natgw) ## Purpose diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/panorama.md b/products/terraform/docs/swfw/azure/vmseries/modules/panorama.md index 09fa96974..f22930684 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/panorama.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/panorama.md @@ -20,7 +20,7 @@ title: Palo Alto Networks Panorama Module for Azure A terraform module for deploying a working Panorama instance in Azure. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/panorama) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/panorama) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/virtual_network_gateway.md b/products/terraform/docs/swfw/azure/vmseries/modules/virtual_network_gateway.md new file mode 100644 index 000000000..17d6d5398 --- /dev/null +++ b/products/terraform/docs/swfw/azure/vmseries/modules/virtual_network_gateway.md @@ -0,0 +1,92 @@ +--- +hide_title: true +id: virtual_network_gateway +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- azure +pagination_next: null +pagination_prev: null +sidebar_label: Virtual Network Gateway +title: Virtual Network Gateway +--- + +# Virtual Network Gateway + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/virtual_network_gateway) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/virtual_network_gateway) + +## Purpose + +This module is used to automate deployment of Virtual Network Gateway. + + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2, < 2.0 | +| [azurerm](#requirement\_azurerm) | ~> 3.25 | + +### Providers + +| Name | Version | +|------|---------| +| [azurerm](#provider\_azurerm) | ~> 3.25 | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [azurerm_local_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/local_network_gateway) | resource | +| [azurerm_public_ip.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource | +| [azurerm_virtual_network_gateway.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway) | resource | +| [azurerm_virtual_network_gateway_connection.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_gateway_connection) | resource | +| [azurerm_public_ip.exists](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/public_ip) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [resource\_group\_name](#input\_resource\_group\_name) | Name of a pre-existing Resource Group to place the resources in. | `string` | n/a | yes | +| [location](#input\_location) | Region to deploy load balancer and dependencies. | `string` | n/a | yes | +| [name\_prefix](#input\_name\_prefix) | A prefix added to all resource names created by this module | `string` | `""` | no | +| [name\_suffix](#input\_name\_suffix) | A suffix added to all resource names created by this module | `string` | `""` | no | +| [name](#input\_name) | The name of the Virtual Network Gateway. Changing this forces a new resource to be created | `string` | n/a | yes | +| [tags](#input\_tags) | Azure tags to apply to the created resources. | `map(string)` | `{}` | no | +| [enable\_zones](#input\_enable\_zones) | If false, all the subnet-associated frontends and also all created Public IP addresses default to not to use Availability Zones (the `No-Zone` setting). It is intended for the regions that do not yet support Availability Zones. | `bool` | `true` | no | +| [avzones](#input\_avzones) | After provider version 3.x you need to specify in which availability zone(s) you want to place IP.
ie: for zone-redundant with 3 availability zone in current region value will be:
["1","2","3"]
| `list(string)` | `[]` | no | +| [type](#input\_type) | The type of the Virtual Network Gateway. Valid options are Vpn or ExpressRoute. Changing the type forces a new resource to be created | `string` | n/a | yes | +| [vpn\_type](#input\_vpn\_type) | The routing type of the Virtual Network Gateway. Valid options are RouteBased or PolicyBased. Defaults to RouteBased. Changing this forces a new resource to be created. | `string` | `"RouteBased"` | no | +| [sku](#input\_sku) | Configuration of the size and capacity of the virtual network gateway. Valid options are Basic, Standard, HighPerformance, UltraPerformance, ErGw1AZ, ErGw2AZ, ErGw3AZ, VpnGw1, VpnGw2, VpnGw3, VpnGw4,VpnGw5, VpnGw1AZ, VpnGw2AZ, VpnGw3AZ,VpnGw4AZ and VpnGw5AZ and depend on the type, vpn\_type and generation arguments. A PolicyBased gateway only supports the Basic SKU. Further, the UltraPerformance SKU is only supported by an ExpressRoute gateway. | `string` | n/a | yes | +| [active\_active](#input\_active\_active) | If true, an active-active Virtual Network Gateway will be created. An active-active gateway requires a HighPerformance or an UltraPerformance SKU. If false, an active-standby gateway will be created. Defaults to false. | `bool` | `false` | no | +| [default\_local\_network\_gateway\_id](#input\_default\_local\_network\_gateway\_id) | The ID of the local network gateway through which outbound Internet traffic from the virtual network in which the gateway is created will be routed (forced tunnelling) | `string` | n/a | yes | +| [edge\_zone](#input\_edge\_zone) | Specifies the Edge Zone within the Azure Region where this Virtual Network Gateway should exist. | `string` | n/a | yes | +| [enable\_bgp](#input\_enable\_bgp) | If true, BGP (Border Gateway Protocol) will be enabled for this Virtual Network Gateway. Defaults to false | `bool` | `false` | no | +| [generation](#input\_generation) | The Generation of the Virtual Network gateway. Possible values include Generation1, Generation2 or None | `string` | `"Generation1"` | no | +| [private\_ip\_address\_enabled](#input\_private\_ip\_address\_enabled) | Should private IP be enabled on this gateway for connections? | `bool` | n/a | yes | +| [ip\_configuration](#input\_ip\_configuration) | List of IP configurations - every object in the list contains attributes:

- name - name of the IP configuration
- create\_public\_ip - boolean value, true if public IP needs to be created
- public\_ip\_name - name of the public IP resource used, when there is no need to create new one
- private\_ip\_address\_allocation - defines how the private IP address of the gateways virtual interface is assigned. Valid options are Static or Dynamic. Defaults to Dynamic.
- public\_ip\_standard\_sku - defaults to `false`, when set to `true` creates a Standard SKU, statically allocated public IP, otherwise it will be a Basic/Dynamic one.
- subnet\_id - the ID of the gateway subnet of a virtual network in which the virtual network gateway will be created.

Example:

ip\_configuration = [
{
name = "001"
create\_public\_ip = true
subnet\_id = "ID\_for\_subnet\_GatewaySubnet"
},
{
name = "002"
create\_public\_ip = true
subnet\_id = "ID\_for\_subnet\_GatewaySubnet"
}
] | `list(any)` | n/a | yes | +| [vpn\_client\_configuration](#input\_vpn\_client\_configuration) | List of VPN client configurations - every object in the list contains attributes:
- address\_space - the address space out of which IP addresses for vpn clients will be taken. You can provide more than one address space, e.g. in CIDR notation.
- aad\_tenant - AzureAD Tenant URL
- aad\_audience - the client id of the Azure VPN application. See Create an Active Directory (AD) tenant for P2S OpenVPN protocol connections for values
- aad\_issuer - the STS url for your tenant
- root\_certificate - one or more root\_certificate blocks which are defined below. These root certificates are used to sign the client certificate used by the VPN clients to connect to the gateway.
- revoked\_certificate - one or more revoked\_certificate blocks which are defined below.
- radius\_server\_address - the address of the Radius server.
- radius\_server\_secret - the secret used by the Radius server.
- vpn\_client\_protocols - list of the protocols supported by the vpn client. The supported values are SSTP, IkeV2 and OpenVPN. Values SSTP and IkeV2 are incompatible with the use of aad\_tenant, aad\_audience and aad\_issuer.
- vpn\_auth\_types - list of the vpn authentication types for the virtual network gateway. The supported values are AAD, Radius and Certificate. | `list(any)` | n/a | yes | +| [azure\_bgp\_peers\_addresses](#input\_azure\_bgp\_peers\_addresses) | Map of IP addresses used on Azure side for BGP. Map is used to not to duplicate IP address and refer to keys while configuring:
- custom\_bgp\_addresses
- peering\_addresses in local\_bgp\_settings

Example:

azure\_bgp\_peers\_addresses = {
primary\_1 = "169.254.21.2"
secondary\_1 = "169.254.22.2"
primary\_2 = "169.254.21.6"
secondary\_2 = "169.254.22.6"
} | `map(string)` | n/a | yes | +| [local\_bgp\_settings](#input\_local\_bgp\_settings) | Map of BGP settings:
- asn - the Autonomous System Number (ASN) to use as part of the BGP.
- peering\_addresses - a map of peering addresses, which contains 1 (for active-standby) or 2 objects (for active-active) with:
- key is the ip configuration name
- apipa\_addresses is the list of keys for IP addresses defined in variable azure\_bgp\_peers\_addresses
- peer\_weight - the weight added to routes which have been learned through BGP peering. Valid values can be between 0 and 100.

Example:

local\_bgp\_settings = {
asn = "65001"
peering\_addresses = {
"001" = {
apipa\_addresses = ["primary\_1", "primary\_2"]
},
"002" = {
apipa\_addresses = ["secondary\_1", "secondary\_2"]
}
}
} | `any` | n/a | yes | +| [custom\_route](#input\_custom\_route) | List of custom routes - every object in the list contains attributes:
- address\_prefixes - a list of address blocks reserved for this virtual network in CIDR notation as defined below. | `list(any)` | n/a | yes | +| [local\_network\_gateways](#input\_local\_network\_gateways) | Map of local network gateways - every object in the map contains attributes:
- name - the name of the local network gateway.
- connection - the name of the virtual network gateway connection.
- remote\_bgp\_settings - block containing Local Network Gateway's BGP speaker settings:
- asn - the BGP speaker's ASN.
- bgp\_peering\_address - the BGP peering address and BGP identifier of this BGP speaker.
- peer\_weight - the weight added to routes learned from this BGP speaker.
- gateway\_address - the gateway IP address to connect with.
- address\_space - the list of string CIDRs representing the address spaces the gateway exposes.
- custom\_bgp\_addresses - Border Gateway Protocol custom IP Addresses, which can only be used on IPSec / active-active connections. Object contains 2 attributes:
- primary - single IP address that is part of the azurerm\_virtual\_network\_gateway ip\_configuration (first one)
- secondary - single IP address that is part of the azurerm\_virtual\_network\_gateway ip\_configuration (second one)

Example:

local\_network\_gateways = {
"lg1" = {
name = "001"
connection = "001"
gateway\_address = "PUBLIC\_IP\_1"
remote\_bgp\_settings = [{
asn = "65002"
bgp\_peering\_address = "169.254.21.1"
}]
custom\_bgp\_addresses = [
{
primary = "primary\_1"
secondary = "secondary\_1"
}
]
}
"lg2" = {
name = "002"
connection = "002"
gateway\_address = "PUBLIC\_IP\_2"
remote\_bgp\_settings = [{
asn = "65003"
bgp\_peering\_address = "169.254.21.5"
}]
custom\_bgp\_addresses = [
{
primary = "primary\_2"
secondary = "secondary\_2"
}
]
}
"lg3" = {
name = "003"
connection = "003"
gateway\_address = "PUBLIC\_IP\_3"
remote\_bgp\_settings = [{
asn = "65002"
bgp\_peering\_address = "169.254.22.1"
}]
custom\_bgp\_addresses = [
{
primary = "primary\_1"
secondary = "secondary\_1"
}
]
}
"lg4" = {
name = "004"
connection = "004"
gateway\_address = "PUBLIC\_IP\_4"
remote\_bgp\_settings = [{
asn = "65003"
bgp\_peering\_address = "169.254.22.5"
}]
custom\_bgp\_addresses = [
{
primary = "primary\_2"
secondary = "secondary\_2"
}
]
}
} | `any` | n/a | yes | +| [ipsec\_shared\_key](#input\_ipsec\_shared\_key) | The shared IPSec key. | `string` | n/a | yes | +| [connection\_mode](#input\_connection\_mode) | Connection mode to use. Possible values are Default, InitiatorOnly and ResponderOnly. Defaults to Default. Changing this value will force a resource to be created. | `string` | n/a | yes | +| [ipsec\_policy](#input\_ipsec\_policy) | IPsec policy used for Virtual Network Connection with attributes:
- dh\_group - The DH group used in IKE phase 1 for initial SA. Valid options are DHGroup1, DHGroup14, DHGroup2, DHGroup2048, DHGroup24, ECP256, ECP384, or None.
- ike\_encryption - The IKE encryption algorithm. Valid options are AES128, AES192, AES256, DES, DES3, GCMAES128, or GCMAES256.
- ike\_integrity - The IKE integrity algorithm. Valid options are GCMAES128, GCMAES256, MD5, SHA1, SHA256, or SHA384.
- ipsec\_encryption - The IPSec encryption algorithm. Valid options are AES128, AES192, AES256, DES, DES3, GCMAES128, GCMAES192, GCMAES256, or None.
- ipsec\_integrity - The IPSec integrity algorithm. Valid options are GCMAES128, GCMAES192, GCMAES256, MD5, SHA1, or SHA256.
- pfs\_group - The DH group used in IKE phase 2 for new child SA. Valid options are ECP256, ECP384, PFS1, PFS14, PFS2, PFS2048, PFS24, PFSMM, or None.
- sa\_datasize - The IPSec SA payload size in KB. Must be at least 1024 KB. Defaults to 102400000 KB.
- sa\_lifetime - The IPSec SA lifetime in seconds. Must be at least 300 seconds. Defaults to 27000 seconds.

Example:

ipsec\_policy = [
{
dh\_group = "ECP384"
ike\_encryption = "AES256"
ike\_integrity = "SHA256"
ipsec\_encryption = "AES256"
ipsec\_integrity = "SHA256"
pfs\_group = "ECP384"
sa\_datasize = "102400000"
sa\_lifetime = "27000"
}
] | `any` | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| [public\_ip](#output\_public\_ip) | Public IP addresses for Virtual Network Gateway | +| [ipsec\_policy](#output\_ipsec\_policy) | IPsec policy used for Virtual Network Gateway connection | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/vmseries.md b/products/terraform/docs/swfw/azure/vmseries/modules/vmseries.md index 778c70499..4692103e3 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/vmseries.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/vmseries.md @@ -21,7 +21,7 @@ title: Palo Alto Networks VM-Series Module for Azure A Terraform module for deploying a VM-Series firewall in Azure cloud. The module is not intended for use with Scale Sets. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/vmseries) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/vmseries) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/vmss.md b/products/terraform/docs/swfw/azure/vmseries/modules/vmss.md index bdcfb2c92..12da71391 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/vmss.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/vmss.md @@ -35,7 +35,7 @@ provider "azurerm" { } ``` -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/vmss) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/vmss) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/vmss) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/vmss) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/vnet.md b/products/terraform/docs/swfw/azure/vmseries/modules/vnet.md index 4cfdc9067..362681d0f 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/vnet.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/vnet.md @@ -20,7 +20,7 @@ title: Palo Alto Networks VNet Module for Azure A terraform module for deploying a Virtual Network and its components required for the VM-Series firewalls in Azure. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/vnet) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/vnet) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/vnet) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/vnet) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/modules/vnet_peering.md b/products/terraform/docs/swfw/azure/vmseries/modules/vnet_peering.md index 28ce171ab..87ebd2f27 100644 --- a/products/terraform/docs/swfw/azure/vmseries/modules/vnet_peering.md +++ b/products/terraform/docs/swfw/azure/vmseries/modules/vnet_peering.md @@ -20,7 +20,7 @@ title: Palo Alto Networks VNet Peering Module for Azure A terraform module for deploying a Virtual Network Peering and its components required for the VM-Series firewalls in Azure. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/vnet_peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/vnet_peering) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/modules/vnet_peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/submodules/vnet_peering) ## Usage diff --git a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/b10403f9-795a-4501-a189-3c21d44fc9e7.png b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/b10403f9-795a-4501-a189-3c21d44fc9e7.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0ab69bfb73b67af58de072be37a41afad52f14 GIT binary patch literal 143283 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
natgws = {
"natgw" = {
name = "public-natgw"
vnet\_key = "transit-vnet"
subnet\_keys = ["public"]
zone = 1
}
}
| `any` | `{}` | no | -| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `network_security_group_name`: (public LB) a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | +| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `nsg_vnet_key`: (public LB) defaults to `null`, a key describing a vnet (as defined in `vnet` variable) that hold an NSG we will update with an ingress rule for each listener.
- `nsg_key`: (public LB) defaults to `null`, a key describing an NSG (as defined in `vnet` variable, under `nsg_vnet_key`) we will update with an ingress rule for each listener.
- `network_security_group_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | | [vmseries\_version](#input\_vmseries\_version) | VM-Series PAN-OS version - list available with `az vm image list -o table --all --publisher paloaltonetworks`. It's also possible to specify the Pan-OS version per firewall, see `var.vmseries` variable. | `string` | n/a | yes | | [vmseries\_vm\_size](#input\_vmseries\_vm\_size) | Azure VM size (type) to be created. Consult the *VM-Series Deployment Guide* as only a few selected sizes are supported. It's also possible to specify the the VM size per firewall, see `var.vmseries` variable. | `string` | n/a | yes | | [vmseries\_sku](#input\_vmseries\_sku) | VM-Series SKU - list available with `az vm image list -o table --all --publisher paloaltonetworks` | `string` | `"byol"` | no | | [vmseries\_username](#input\_vmseries\_username) | Initial administrative username to use for all systems. | `string` | `"panadmin"` | no | | [vmseries\_password](#input\_vmseries\_password) | Initial administrative password to use for all systems. Set to null for an auto-generated password. | `string` | `null` | no | -| [availability\_set](#input\_availability\_set) | A map defining availability sets. Can be used to provide infrastructure high availability when zones cannot be used.

Following properties are supported:
- `name` - name of the Application Insights.
- `update_domain_count` - specifies the number of update domains that are used, defaults to 5 (Azure defaults).
- `fault_domain_count` - specifies the number of fault domains that are used, defaults to 3 (Azure defaults).

Please keep in mind that Azure defaults are not working for each region (especially the small ones, w/o any Availability Zones). Please verify how many update and fault domain are supported in a region before deploying this resource. | `any` | `{}` | no | +| [availability\_sets](#input\_availability\_sets) | A map defining availability sets. Can be used to provide infrastructure high availability when zones cannot be used.

Following properties are supported:
- `name` - name of the Application Insights.
- `update_domain_count` - specifies the number of update domains that are used, defaults to 5 (Azure defaults).
- `fault_domain_count` - specifies the number of fault domains that are used, defaults to 3 (Azure defaults).

Please keep in mind that Azure defaults are not working for each region (especially the small ones, w/o any Availability Zones). Please verify how many update and fault domain are supported in a region before deploying this resource. | `any` | `{}` | no | | [application\_insights](#input\_application\_insights) | A map defining Azure Application Insights. There are three ways to use this variable:

* when the value is set to `null` (default) no AI is created
* when the value is a map containing `name` key (other keys are optional) a single AI instance will be created under the name that is the value of the `name` key
* when the value is an empty map or a map w/o the `name` key, an AI instance per each VMSeries VM will be created. All instances will share the same configuration. All instances will have names corresponding to their VM name.

Names for all AI instances are prefixed with `var.name_prefix`.

Properties supported (for details on each property see [modules documentation](../../modules/application\_insights)):

- `name` : (optional, string) a name of a single AI instance
- `workspace_mode` : (optional, bool) defaults to `true`, use AI Workspace mode instead of the Classical (deprecated)
- `workspace_name` : (optional, string) defaults to AI name suffixed with `-wrkspc`, name of the Log Analytics Workspace created when AI is deployed in Workspace mode
- `workspace_sku` : (optional, string) defaults to PerGB2018, SKU used by WAL, see module documentation for details
- `metrics_retention_in_days` : (optional, number) defaults to current Azure default value, see module documentation for details

Example of an AIs created per VM, in Workspace mode, with metrics retention set to 1 year:
vmseries = {
'vm-1' = {
....
}
'vm-2' = {
....
}
}

application\_insights = {
metrics\_retention\_in\_days = 365
}
| `map(string)` | `null` | no | -| [bootstrap\_storage](#input\_bootstrap\_storage) | A map defining Azure Storage Accounts used to host file shares for bootstrapping NGFWs. This variable defines only Storage Accounts, file shares are defined per each VM. See `vmseries` variable, `bootstrap_storage` property.

Following properties are supported (except for name, all are optional):

- `name` : name of the Storage Account. Please keep in mind that storage account name has to be globally unique. This name will not be prefixed with the value of `var.name_prefix`.
- `create_storage_account` : (defaults to `true`) create or source (when `false`) an existing Storage Account.
- `resource_group_name` : (defaults to `var.resource_group_name`) name of the Resource Group hosting the Storage Account (existing or newly created). The RG has to exist.
- `storage_acl` : (defaults to `false`) enables network ACLs on the Storage Account. If this is enabled - `storage_allow_vnet_subnets` and `storage_allow_inbound_public_ips` options become available. The ACL defaults to default `Deny`.
- `storage_allow_vnet_subnets` : (defaults to `[]`) whitelist containing the allowed vnet and associated subnets that are allowed to access the Storage Account. Note that the respective subnets require `enable_storage_service_endpoint` set to `true` to work properly.
- `storage_allow_inbound_public_ips` : (defaults to `[]`) whitelist containing the allowed public IP subnets that can access the Storage Account. Note that the code automatically tries to query [https://ifconfig.me/ip](https://ifconfig.me/ip) to obtain the public IP address of the machine executing the code so that the bootstrap files can be successfully uploaded to the Storage Account.

The properties below do not directly change anything in the Storage Account settings. They can be used to control common parts of the `DAY0` configuration (used only when full bootstrap is used). These properties can also be specified per firewall, but when specified here they tak higher precedence:
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes). | `any` | `{}` | no | -| [vmseries](#input\_vmseries) | Map of virtual machines to create to run VM-Series - inbound firewalls. Following properties are supported:

- `name` : name of the VMSeries virtual machine.
- `vm_size` : size of the VMSeries virtual machine, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map. This value will be used during network interfaces creation.
- `add_to_appgw_backend` : bool, `false` by default, set this to `true` to add this backend to an Application Gateway.
- `avzone`: the Azure Availability Zone identifier ("1", "2", "3"). Default is "1".
- `availability_set_name` : a name of an Availability Set as declared in `availability_set` property. Specify when HA is required but cannot go for zonal deployment.

- `bootstrap_options` : string, optional bootstrap options to pass to VM-Series instances, semicolon separated values. When defined this precedence over `bootstrap_storage`
- `bootstrap_storage` : a map containing definition of the bootstrap package content. When present triggers a creation of a File Share in an existing Storage Account, following properties supported:
- `name` : a name of a key in `var.bootstrap_storage` variable defining a Storage Account
- `static_files` : a map where key is a path to a file, value is the location of the file in the bootstrap package (file share). All files in this map are copied 1:1 to the bootstrap package
- `template_bootstrap_xml` : path to the `bootstrap.xml` template. When defined it will trigger creation of the `bootstrap.xml` file and the file will be uploaded to the storage account. This is a simple `day 0` configuration file that should set up only basic networking. Specifying this property forces additional properties that are required to properly template the file. They can be defined per each VM or globally for all VMs (in this case place them in the bootstrap storage definition). The properties are listed below.
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes).

- `interfaces` : configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name`: string that will form the NIC name
- `subnet_key` : (string) a key of a subnet as defined in `var.vnets`
- `create_pip` : (boolean) flag to create Public IP for an interface, defaults to `false`
- `public_ip_name` : (string) when `create_pip` is set to `false` a name of a Public IP resource that should be associated with this Network Interface
- `public_ip_resource_group` : (string) when associating an existing Public IP resource, name of the Resource Group the IP is placed in, defaults to the `var.resource_group_name`
- `load_balancer_key` : (string) key of a Load Balancer defined in the `var.loadbalancers` variable, defaults to `null`
- `private_ip_address` : (string) a static IP address that should be assigned to an interface, defaults to `null` (in that case DHCP is used)

Example:
{
"fw01" = {
name = "firewall01"
bootstrap\_storage = {
name = "storageaccountname"
static\_files = { "files/init-cfg.txt" = "config/init-cfg.txt" }
template\_bootstrap\_xml = "templates/bootstrap\_common.tmpl"
public\_snet\_key = "public"
private\_snet\_key = "private"
}
avzone = 1
vnet\_key = "trust"
interfaces = [
{
name = "mgmt"
subnet\_key = "mgmt"
create\_pip = true
private\_ip\_address = "10.0.0.1"
},
{
name = "trust"
subnet\_key = "private"
private\_ip\_address = "10.0.1.1"
load\_balancer\_key = "private\_lb"
},
{
name = "untrust"
subnet\_key = "public"
private\_ip\_address = "10.0.2.1"
load\_balancer\_key = "public\_lb"
public\_ip\_name = "existing\_public\_ip"
}
]
}
}
| `any` | n/a | yes | +| [bootstrap\_storage](#input\_bootstrap\_storage) | A map defining Azure Storage Accounts used to host file shares for bootstrapping NGFWs. This variable defines only Storage Accounts, file shares are defined per each VM. See `vmseries` variable, `bootstrap_storage` property.

Following properties are supported (except for name, all are optional):

- `name` : name of the Storage Account. Please keep in mind that storage account name has to be globally unique. This name will not be prefixed with the value of `var.name_prefix`.
- `create_storage_account` : (defaults to `true`) create or source (when `false`) an existing Storage Account.
- `resource_group_name` : (defaults to `var.resource_group_name`) name of the Resource Group hosting the Storage Account (existing or newly created). The RG has to exist.
- `storage_acl` : (defaults to `false`) enables network ACLs on the Storage Account. If this is enabled - `storage_allow_vnet_subnets` and `storage_allow_inbound_public_ips` options become available. The ACL defaults to default `Deny`.
- `storage_allow_vnet_subnets` : (defaults to `[]`) whitelist containing the allowed vnet and associated subnets that are allowed to access the Storage Account. Note that the respective subnets require `enable_storage_service_endpoint` set to `true` to work properly.
- `storage_allow_inbound_public_ips` : (defaults to `[]`) whitelist containing the allowed public IP subnets that can access the Storage Account. Note that the code automatically tries to query https://ifconfig.me/ip to obtain the public IP address of the machine executing the code so that the bootstrap files can be successfully uploaded to the Storage Account.

The properties below do not directly change anything in the Storage Account settings. They can be used to control common parts of the `DAY0` configuration (used only when full bootstrap is used). These properties can also be specified per firewall, but when specified here they tak higher precedence:
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes). | `any` | `{}` | no | +| [vmseries](#input\_vmseries) | Map of virtual machines to create to run VM-Series - inbound firewalls. Following properties are supported:

- `name` : name of the VMSeries virtual machine.
- `vm_size` : size of the VMSeries virtual machine, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map. This value will be used during network interfaces creation.
- `add_to_appgw_backend` : bool, `false` by default, set this to `true` to add this backend to an Application Gateway.
- `avzone`: the Azure Availability Zone identifier ("1", "2", "3"). Default is "1".
- `availability_set_key` : a key of an Availability Set as declared in `availability_sets` property. Specify when HA is required but cannot go for zonal deployment.

- `bootstrap_options` : string, optional bootstrap options to pass to VM-Series instances, semicolon separated values. When defined this precedence over `bootstrap_storage`
- `bootstrap_storage` : a map containing definition of the bootstrap package content. When present triggers a creation of a File Share in an existing Storage Account, following properties supported:
- `name` : a name of a key in `var.bootstrap_storage` variable defining a Storage Account
- `static_files` : a map where key is a path to a file, value is the location of the file in the bootstrap package (file share). All files in this map are copied 1:1 to the bootstrap package
- `template_bootstrap_xml` : path to the `bootstrap.xml` template. When defined it will trigger creation of the `bootstrap.xml` file and the file will be uploaded to the storage account. This is a simple `day 0` configuration file that should set up only basic networking. Specifying this property forces additional properties that are required to properly template the file. They can be defined per each VM or globally for all VMs (in this case place them in the bootstrap storage definition). The properties are listed below.
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes).

- `interfaces` : configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name`: string that will form the NIC name
- `subnet_key` : (string) a key of a subnet as defined in `var.vnets`
- `create_pip` : (boolean) flag to create Public IP for an interface, defaults to `false`
- `public_ip_name` : (string) when `create_pip` is set to `false` a name of a Public IP resource that should be associated with this Network Interface
- `public_ip_resource_group` : (string) when associating an existing Public IP resource, name of the Resource Group the IP is placed in, defaults to the `var.resource_group_name`
- `load_balancer_key` : (string) key of a Load Balancer defined in the `var.loadbalancers` variable, defaults to `null`
- `private_ip_address` : (string) a static IP address that should be assigned to an interface, defaults to `null` (in that case DHCP is used)

Example:
{
"fw01" = {
name = "firewall01"
bootstrap\_storage = {
name = "storageaccountname"
static\_files = { "files/init-cfg.txt" = "config/init-cfg.txt" }
template\_bootstrap\_xml = "templates/bootstrap\_common.tmpl"
public\_snet\_key = "public"
private\_snet\_key = "private"
}
avzone = 1
vnet\_key = "trust"
interfaces = [
{
name = "mgmt"
subnet\_key = "mgmt"
create\_pip = true
private\_ip\_address = "10.0.0.1"
},
{
name = "trust"
subnet\_key = "private"
private\_ip\_address = "10.0.1.1"
load\_balancer\_key = "private\_lb"
},
{
name = "untrust"
subnet\_key = "public"
private\_ip\_address = "10.0.2.1"
load\_balancer\_key = "public\_lb"
public\_ip\_name = "existing\_public\_ip"
}
]
}
}
| `any` | n/a | yes | | [appgws](#input\_appgws) | A map defining all Application Gateways in the current deployment.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults and the `rules` property refer to [module documentation](../../modules/appgw).

Following properties are supported:
- `name` : name of the Application Gateway.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `zones` : for zonal deployment this is a list of all zones in a region - this property is used by both: the Application Gateway and the Public IP created in front of the AppGW.
- `capacity` : (optional) number of Application Gateway instances, not used when autoscalling is enabled (see `capacity_min`)
- `capacity_min` : (optional) when set enables autoscaling and becomes the minimum capacity
- `capacity_max` : (optional) maximum capacity for autoscaling
- `enable_http2` : enable HTTP2 support on the Application Gateway
- `waf_enabled` : (optional) enables WAF Application Gateway, defining WAF rules is not supported, defaults to `false`
- `vmseries_public_nic_name` : name of the public VMSeries interface as defined in `interfaces` property.
- `managed_identities` : (optional) a list of existing User-Assigned Managed Identities, which Application Gateway uses to retrieve certificates from Key Vault
- `ssl_policy_type` : (optional) type of an SSL policy, defaults to `Predefined`
- `ssl_policy_name` : (optional) name of an SSL policy, for `ssl_policy_type` set to `Predefined`
- `ssl_policy_min_protocol_version` : (optional) minimum version of the TLS protocol for SSL Policy, for `ssl_policy_type` set to `Custom`
- `ssl_policy_cipher_suites` : (optional) a list of accepted cipher suites, for `ssl_policy_type` set to `Custom`
- `ssl_profiles` : (optional) a map of SSL profiles that can be later on referenced in HTTPS listeners by providing a name of the profile in the `ssl_profile_name` property | `map` | `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/common_vmseries_and_autoscale.md b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/common_vmseries_and_autoscale.md new file mode 100644 index 000000000..a5267bdfd --- /dev/null +++ b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/common_vmseries_and_autoscale.md @@ -0,0 +1,227 @@ +--- +hide_title: true +id: common_vmseries_and_autoscale +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- azure +pagination_next: null +pagination_prev: null +sidebar_label: Common Firewall Option with Autoscaling +title: 'Reference Architecture with Terraform: VM-Series in Azure, Centralized Architecture, + Common NGFW Option with Autoscaling' +--- + +# Reference Architecture with Terraform: VM-Series in Azure, Centralized Architecture, Common NGFW Option with Autoscaling + +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 Azure based on a centralized design with common VM-Series with autoscaling(Virtual Machine Scale Sets); for a discussion of other options, please see the design guide from [the reference architecture guides](https://www.paloaltonetworks.com/resources/reference-architectures). + +Virtual Machine Scale Sets (VMSS) are used for autoscaling to run the Next Generation Firewalls, with custom data plane oriented metrics published by PanOS it is possible to adjust the number of firewall appliances to the current workload (data plane utilization). Since firewalls are added or removed automatically, they cannot be managed in a classic way. To ease licensing, management and updates a Panorama appliance is suggested. Deployment of a Panorama instance is not covered in this example, but a [dedicated one exists](../standalone_panorama). + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-azurerm-vmseries-modules/tree/main/examples/common_vmseries_and_autoscale) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/azurerm/latest/examples/common_vmseries_and_autoscale) + +## Reference Architecture Design + +![simple](a7c2452d-f926-49da-bf21-9d840282a0a2.png) + +This code implements: +- a _centralized design_, a hub-and-spoke topology with a Transit VNet 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 +- _auto scaling_ for the VM-Series, where a Virtual Machine Scale Set (VMSS) is used to provision VM-Series that will scale in and out dynamically, as workload demands fluctuate + +## Detailed Architecture and Design + +### Centralized Design + +This design uses a Transit VNet. Application functions and resources are deployed across multiple VNets that are connected in a hub-and-spoke topology. The hub of the topology, or transit VNet, is the central point of connectivity for all inbound, outbound, east-west, and enterprise traffic. You deploy all VM-Series firewalls within the transit VNet. + +### 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 smaller scale deployments because inbound and outbound traffic flows occur on the same set of firewalls. However, the technical integration complexity is high. + +![Common-VMSeries-with-autoscaling](b10403f9-795a-4501-a189-3c21d44fc9e7.png) + +This reference architecture consists of: + +* a VNET containing: + * 4 subnets: + * 3 of them dedicated to the firewalls: management, private and public + * one dedicated to an Application Gateway + * Route Tables and Network Security Groups +* 1 Virtual Machine Scale set: + * deployed across availability zones + * for inbound, outbound and east-west traffic + * with 3 network interfaces: management, public, private + * with public IP addresses assigned to: + * management interface + * public interface - due to use of a public Load Balancer this public IP is used mainly for outgoing traffic +* 2 Load Balancers: + * public - with a public IP address assigned, in front of the public interfaces of the firewalls in VMSS, for incoming traffic + * private - in front of the private interfaces of the firewalls in VMSS, for outgoing and east-west traffic +* an Application Insights, used to store the custom PanOS metrics sent from firewalls in scale set +* an Application Gateway, serving as a reverse proxy for incoming traffic, with a sample rule setting the XFF header properly + +_DISCLAIMER_ - Public IP addresses are assigned to management interfaces in this example in order to simplify the deployment. With a private Panorama connectivity in place and Panorama Software Firewall License plugin you can bootstrap the firewalls without public IPs assigned to the management interfaces. You should also enable [Automatically push content when software device registers to Panorama](https://docs.paloaltonetworks.com/pan-os/10-2/pan-os-new-features/panorama-features/automatic-content-push-for-vm-series-and-cn-series-firewalls) on the template stack and [schedule content updates using Panorama](https://docs.paloaltonetworks.com/pan-os/10-2/pan-os-upgrade/upgrade-panorama/deploy-updates-to-firewalls-log-collectors-and-wildfire-appliances-using-panorama/schedule-a-content-update-using-panorama). Alternatively content updates can be configured to be fetched via data plane interfaces with service routes. + +### Auto Scaling VM-Series + +Auto scaling: Public-cloud environments focus on scaling out a deployment instead of scaling up. This architectural difference stems primarily from the capability of public-cloud environments to dynamically increase or decrease the number of resources allocated to your environment. Using native Azure services like Virtual Machine Scale Sets (VMSS), Application Insights and VM-Series automation features, the guide implements VM-Series that will scale in and out dynamically, as your protected workload demands fluctuate. The VM-Series firewalls are deployed in a Virtual Machine Scale Set for inbound and outbound/east-west firewalls in common option, and are automatically registered to Azure Load Balancers. + +## Prerequisites + +A list of requirements might vary depending on the platform used to deploy the infrastructure but a minimum one includes: + +* (in case of non cloud shell deployment) credentials and (optionally) tools required to authenticate against Azure Cloud, see [AzureRM provider documentation for details](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#authenticating-to-azure) +* [supported](#requirements) version of [`Terraform`]() +* if you have not run Palo Alto NGFW images in a subscription it might be necessary to accept the license first ([see this note](../../modules/vmseries#accept-azure-marketplace-terms)) + +A non-platform requirement would be a running Panorama instance. For full automation you might want to consider the following requirements: + +* a template and a template stack with `DAY0` configuration +* a device group with security configuration (`DAY1` [iron skillet](https://github.com/PaloAltoNetworks/iron-skillet) for example) + any security and NAT rules of your choice +* a [Panorama Software Firewall License](https://docs.paloaltonetworks.com/vm-series/9-1/vm-series-deployment/license-the-vm-series-firewall/use-panorama-based-software-firewall-license-management) plugin to automatically manage licenses on newly created devices +* a [VM-Series](https://docs.paloaltonetworks.com/panorama/9-1/panorama-admin/panorama-plugins/plugins-types/install-the-vm-series-plugin-on-panorama) plugin to enable additional template options (custom metrics) + +**NOTE:** + +* after the deployment the firewalls remain not configured and not licensed. +* this example contains some **files** that **can contain sensitive data**. Keep in mind that **this code** is **only an example**. It's main purpose is to introduce the Terraform modules. + +## Usage + +### Deployment Steps + +* checkout the code locally (if you haven't done so yet) +* copy the [`example.tfvars`](./example.tfvars) file, rename it to `terraform.tfvars` and adjust it to your needs (take a closer look at the `TODO` markers). If you already have a configured Panorama (with at least minimum configuration described above) you might want to also adjust the `bootstrap_options` for the scale set ([common](./example.tfvars#L205) . +* (optional) authenticate to AzureRM, switch to the Subscription of your choice if necessary +* initialize the Terraform module: + + terraform init + +* (optional) plan you infrastructure to see what will be actually deployed: + + terraform plan + +* deploy the infrastructure (you will have to confirm it with typing in `yes`): + + terraform apply + + The deployment takes couple of minutes. Observe the output. At the end you should see a summary similar to this: + + Apply complete! Resources: 43 added, 0 changed, 0 destroyed. + + Outputs: + + lb_frontend_ips = { + "private" = { + "ha-ports" = "1.2.3.4" + } + "public" = { + "palo-lb-app1-pip" = "1.2.3.4" + } + } + metrics_instrumentation_keys = + password = + username = "panadmin" + +* at this stage you have to wait couple of minutes for the firewalls to bootstrap. + +### Post deploy + +The most important post-deployment action is (for deployments with auto scaling and Panorama) to retrieve the Application Insights instrumentation keys. This can be done by looking up the AI resources in the Azure portal, or directly from Terraform outputs: + +```sh +terraform output metrics_instrumentation_keys +``` + +The retrieved keys should be put into appropriate templates in Panorama and pushed to the devices. From this moment on, custom metrics are being sent to Application Insights and retrieved by the Virtual Machine Scale Set to trigger scale-in and scale-out operations. + +Although firewalls in a Scale Set are not meant to be managed directly, they are still configured with password authentication. To retrieve the initial credentials run: + +* for username: + + terraform output username + +* for password: + + terraform output password + +### Cleanup + +To remove the deployed infrastructure run: + +```sh +terraform destroy +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2, < 2.0 | + +### Providers + +| Name | Version | +|------|---------| +| [random](#provider\_random) | n/a | +| [azurerm](#provider\_azurerm) | n/a | + +### Modules + +| Name | Source | Version | +|------|--------|---------| +| [vnet](#module\_vnet) | ../../modules/vnet | n/a | +| [natgw](#module\_natgw) | ../../modules/natgw | n/a | +| [load\_balancer](#module\_load\_balancer) | ../../modules/loadbalancer | n/a | +| [ai](#module\_ai) | ../../modules/application_insights | n/a | +| [appgw](#module\_appgw) | ../../modules/appgw | n/a | +| [vmss](#module\_vmss) | ../../modules/vmss | n/a | + +### Resources + +| Name | Type | +|------|------| +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [random_password.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | +| [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/resource_group) | data source | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [tags](#input\_tags) | Map of tags to assign to the created resources. | `map(string)` | `{}` | no | +| [location](#input\_location) | The Azure region to use. | `string` | n/a | yes | +| [name\_prefix](#input\_name\_prefix) | A prefix that will be added to all created resources.
There is no default delimiter applied between the prefix and the resource name. Please include the delimiter in the actual prefix.

Example:
name\_prefix = "test-"
NOTICE. This prefix is not applied to existing resources. If you plan to reuse i.e. a VNET please specify it's full name, even if it is also prefixed with the same value as the one in this property. | `string` | `""` | no | +| [create\_resource\_group](#input\_create\_resource\_group) | When set to `true` it will cause a Resource Group creation. Name of the newly specified RG is controlled by `resource_group_name`.
When set to `false` the `resource_group_name` parameter is used to specify a name of an existing Resource Group. | `bool` | `true` | no | +| [resource\_group\_name](#input\_resource\_group\_name) | Name of the Resource Group. | `string` | n/a | yes | +| [enable\_zones](#input\_enable\_zones) | If `true`, enable zone support for resources. | `bool` | `true` | no | +| [vnets](#input\_vnets) | A map defining VNETs.

For detailed documentation on each property refer to [module documentation](../../modules/vnet)

- `name` : A name of a VNET.
- `create_virtual_network` : (default: `true`) when set to `true` will create a VNET, `false` will source an existing VNET, in both cases the name of the VNET is specified with `name`
- `address_space` : a list of CIDRs for VNET
- `resource_group_name` : (default: current RG) a name of a Resource Group in which the VNET will reside

- `create_subnets` : (default: `true`) if true, create the Subnets inside the Virtual Network, otherwise use pre-existing subnets
- `subnets` : map of Subnets to create

- `network_security_groups` : map of Network Security Groups to create
- `route_tables` : map of Route Tables to create. | `any` | n/a | yes | +| [natgws](#input\_natgws) | A map defining Nat Gateways.

Please note that a NatGW is a zonal resource, this means it's always placed in a zone (even when you do not specify one explicitly). Please refer to Microsoft documentation for notes on NatGW's zonal resiliency.

Following properties are supported:

- `name` : a name of the newly created NatGW.
- `create_natgw` : (default: `true`) create or source (when `false`) an existing NatGW. Created or sourced: the NatGW will be assigned to a subnet created by the `vnet` module.
- `resource_group_name : name of a Resource Group hosting the NatGW (newly create or the existing one).
- `zone` : Availability Zone in which the NatGW will be placed, when skipped AzureRM will pick a zone.
- `idle\_timeout` : connection IDLE timeout in minutes, for newly created resources
- `vnet\_key` : a name (key value) of a VNET defined in `var.vnets` that hosts a subnet this NatGW will be assigned to.
- `subnet\_keys` : a list of subnets (key values) the NatGW will be assigned to, defined in `var.vnets` for a VNET described by `vnet\_name`.
- `create\_pip` : (default: `true`) create a Public IP that will be attached to a NatGW
- `existing\_pip\_name` : when `create\_pip` is set to `false`, source and attach and existing Public IP to the NatGW
- `existing\_pip\_resource\_group\_name` : when `create\_pip` is set to `false`, name of the Resource Group hosting the existing Public IP
- `create\_pip\_prefix` : (default: `false`) create a Public IP Prefix that will be attached to the NatGW.
- `pip\_prefix\_length` : length of the newly created Public IP Prefix, can bet between 0 and 31 but this actually supported value depends on the Subscription.
- `existing\_pip\_prefix\_name` : when `create\_pip\_prefix` is set to `false`, source and attach and existing Public IP Prefix to the NatGW
- `existing\_pip\_prefix\_resource\_group\_name` : when `create\_pip\_prefix` is set to `false`, name of the Resource Group hosting the existing Public IP Prefix.

Example:
`
natgws = {
"natgw" = {
name = "public-natgw"
vnet\_key = "transit-vnet"
subnet\_keys = ["public"]
zone = 1
}
}
| `any` | `{}` | no | +| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `nsg_vnet_key`: (public LB) defaults to `null`, a key describing a vnet (as defined in `vnet` variable) that hold an NSG we will update with an ingress rule for each listener.
- `nsg_key`: (public LB) defaults to `null`, a key describing an NSG (as defined in `vnet` variable, under `nsg_vnet_key`) we will update with an ingress rule for each listener.
- `network_security_group_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | +| [application\_insights](#input\_application\_insights) | A map defining Azure Application Insights. There are three ways to use this variable:

* when the value is set to `null` (default) no AI is created
* when the value is a map containing `name` key (other keys are optional) a single AI instance will be created under the name that is the value of the `name` key
* when the value is an empty map or a map w/o the `name` key, an AI instance per each VMSeries VM will be created. All instances will share the same configuration. All instances will have names corresponding to their VM name.

Names for all AI instances are prefixed with `var.name_prefix`.

Properties supported (for details on each property see [modules documentation](../../modules/application\_insights)):

- `name` : (optional, string) a name of a single AI instance
- `workspace_mode` : (optional, bool) defaults to `true`, use AI Workspace mode instead of the Classical (deprecated)
- `workspace_name` : (optional, string) defaults to AI name suffixed with `-wrkspc`, name of the Log Analytics Workspace created when AI is deployed in Workspace mode
- `workspace_sku` : (optional, string) defaults to PerGB2018, SKU used by WAL, see module documentation for details
- `metrics_retention_in_days` : (optional, number) defaults to current Azure default value, see module documentation for details

Example of an AIs created per VM, in Workspace mode, with metrics retention set to 1 year:
vmseries = {
'vm-1' = {
....
}
'vm-2' = {
....
}
}

application\_insights = {
metrics\_retention\_in\_days = 365
}
| `map(string)` | `null` | no | +| [vmseries\_version](#input\_vmseries\_version) | VM-Series PAN-OS version - list available with `az vm image list -o table --all --publisher paloaltonetworks`. It's also possible to specify the Pan-OS version per Scale Set, see `var.vmss` variable. | `string` | n/a | yes | +| [vmseries\_vm\_size](#input\_vmseries\_vm\_size) | Azure VM size (type) to be created. Consult the *VM-Series Deployment Guide* as only a few selected sizes are supported. It's also possible to specify the the VM size per Scale Set, see `var.vmss` variable. | `string` | n/a | yes | +| [vmseries\_sku](#input\_vmseries\_sku) | VM-Series SKU - list available with `az vm image list -o table --all --publisher paloaltonetworks` | `string` | `"byol"` | no | +| [vmseries\_username](#input\_vmseries\_username) | Initial administrative username to use for all systems. | `string` | `"panadmin"` | no | +| [vmseries\_password](#input\_vmseries\_password) | Initial administrative password to use for all systems. Set to null for an auto-generated password. | `string` | `null` | no | +| [vmss](#input\_vmss) | A map defining all Virtual Machine Scale Sets.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults refer to [module documentation](../../modules/vmss)

Following properties are available:
- `name` : (string\|required) name of the Virtual Machine Scale Set.
- `vm_size` : size of the VMSeries virtual machines created with this Scale Set, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : (string\|required) a key of a VNET defined in the `var.vnets` map.
- `bootstrap_options` : (string\|`''`) bootstrap options passed to every VM instance upon creation.
- `zones` : (list(string)\|`[]`) a list of Availability Zones to use for Zone redundancy
- `encryption_at_host_enabled` : (bool\|`null` - Azure defaults) should all of the disks attached to this Virtual Machine be encrypted
- `overprovision` : (bool\|`null` - module defaults) when provisioning new VM, multiple will be provisioned but the 1st one to run will be kept
- `platform_fault_domain_count` : (number\|`null` - Azure defaults) number of fault domains to use
- `proximity_placement_group_id` : (string\|`null`) ID of a proximity placement group the VMSS should be placed in
- `scale_in_policy` : (string\|`null` - Azure defaults) policy of removing VMs when scaling in
- `scale_in_force_deletion` : (bool\|`null` - module default) forces (`true`) deletion of VMs during scale in
- `single_placement_group` : (bool\|`null` - Azure defaults) limit the Scale Set to one Placement Group
- `storage_account_type` : (string\|`null` - module defaults) type of managed disk that will be used on all VMs
- `disk_encryption_set_id` : (string\|`null`) the ID of the Disk Encryption Set which should be used to encrypt this Data Disk
- `accelerated_networking` : (bool\|`null`- module defaults) enable Azure accelerated networking for all dataplane network interfaces
- `use_custom_image` : (bool\|`false`)
- `custom_image_id` : (string\|reqquired when `use_custom_image` is `true`) absolute ID of your own Custom Image to be used for creating new VM-Series
- `application_insights_id` : (string\|`null`) ID of Application Insights instance that should be used to provide metrics for autoscaling
- `interfaces` : (list(string)\|`[]`) configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name` : (string\|required) string that will form the NIC name
- `subnet_key` : (string\|required) a key of a subnet as defined in `var.vnets`
- `create_pip` : (bool\|`false`) flag to create Public IP for an interface, defaults to `false`
- `load_balancer_key` : (string\|`null`) key of a Load Balancer defined in the `var.loadbalancers` variable
- `application_gateway_key` : (string\|`null`) key of an Application Gateway defined in the `var.appgws`
- `pip_domain_name_label` : (string\|`null`) prefix which should be used for the Domain Name Label for each VM instance
- `autoscale_config` : (map\|`{}`) map containing basic autoscale configuration
- `count_default` : (number\|`null` - module defaults) default number or instances when autoscalling is not available
- `count_minimum` : (number\|`null` - module defaults) minimum number of instances to reach when scaling in
- `count_maximum` : (number\|`null` - module defaults) maximum number of instances when scaling out
- `notification_emails` : (list(string)\|`null` - module defaults) a list of e-mail addresses to notify about scaling events
- `autoscale_metrics` : (map\|`{}`) metrics and thresholds used to trigger scaling events, see module documentation for details
- `scaleout_config` : (map\|`{}`) scale out configuration, for details see module documentation
- `statistic` : (string\|`null` - module defaults) aggregation method for statistics coming from different VMs
- `time_aggregation` : (string\|`null` - module defaults) aggregation method applied to statistics in time window
- `window_minutes` : (string\|`null` - module defaults) time windows used to analyze statistics
- `cooldown_minutes` : (string\|`null` - module defaults) time to wait after a scaling event before analyzing the statistics again
- `scalein_config` : (map\|`{}`) scale in configuration, same properties supported as for `scaleout_config`

Example, no auto scaling:
{
"vmss" = {
name = "ngfw-vmss"
vnet\_key = "transit"
bootstrap\_options = "type=dhcp-client"

interfaces = [
{
name = "management"
subnet\_key = "management"
},
{
name = "private"
subnet\_key = "private"
},
{
name = "public"
subnet\_key = "public"
load\_balancer\_key = "public"
application\_gateway\_key = "public"
}
]
}
| `any` | `{}` | no | +| [appgws](#input\_appgws) | A map defining all Application Gateways in the current deployment.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults and the `rules` property refer to [module documentation](../../modules/appgw).

Following properties are supported:
- `name` : name of the Application Gateway.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `zones` : for zonal deployment this is a list of all zones in a region - this property is used by both: the Application Gateway and the Public IP created in front of the AppGW.
- `capacity` : (optional) number of Application Gateway instances, not used when autoscalling is enabled (see `capacity_min`)
- `capacity_min` : (optional) when set enables autoscaling and becomes the minimum capacity
- `capacity_max` : (optional) maximum capacity for autoscaling
- `enable_http2` : enable HTTP2 support on the Application Gateway
- `waf_enabled` : (optional) enables WAF Application Gateway, defining WAF rules is not supported, defaults to `false`
- `vmseries_public_nic_name` : name of the public VMSeries interface as defined in `interfaces` property.
- `managed_identities` : (optional) a list of existing User-Assigned Managed Identities, which Application Gateway uses to retrieve certificates from Key Vault
- `ssl_policy_type` : (optional) type of an SSL policy, defaults to `Predefined`
- `ssl_policy_name` : (optional) name of an SSL policy, for `ssl_policy_type` set to `Predefined`
- `ssl_policy_min_protocol_version` : (optional) minimum version of the TLS protocol for SSL Policy, for `ssl_policy_type` set to `Custom`
- `ssl_policy_cipher_suites` : (optional) a list of accepted cipher suites, for `ssl_policy_type` set to `Custom`
- `ssl_profiles` : (optional) a map of SSL profiles that can be later on referenced in HTTPS listeners by providing a name of the profile in the `ssl_profile_name` property | `map` | `{}` | no | + +### Outputs + +| Name | Description | +|------|-------------| +| [username](#output\_username) | Initial administrative username to use for VM-Series. | +| [password](#output\_password) | Initial administrative password to use for VM-Series. | +| [metrics\_instrumentation\_keys](#output\_metrics\_instrumentation\_keys) | The Instrumentation Key of the created instance(s) of Azure Application Insights. | +| [lb\_frontend\_ips](#output\_lb\_frontend\_ips) | IP Addresses of the load balancers. | + \ No newline at end of file diff --git a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries.md b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries.md index 00db111f5..192453d82 100644 --- a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries.md +++ b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries.md @@ -207,16 +207,16 @@ terraform destroy | [enable\_zones](#input\_enable\_zones) | If `true`, enable zone support for resources. | `bool` | `true` | no | | [vnets](#input\_vnets) | A map defining VNETs.

For detailed documentation on each property refer to [module documentation](../../modules/vnet)

- `name` : A name of a VNET.
- `create_virtual_network` : (default: `true`) when set to `true` will create a VNET, `false` will source an existing VNET, in both cases the name of the VNET is specified with `name`
- `address_space` : a list of CIDRs for VNET
- `resource_group_name` : (default: current RG) a name of a Resource Group in which the VNET will reside

- `create_subnets` : (default: `true`) if true, create the Subnets inside the Virtual Network, otherwise use pre-existing subnets
- `subnets` : map of Subnets to create

- `network_security_groups` : map of Network Security Groups to create
- `route_tables` : map of Route Tables to create. | `any` | n/a | yes | | [natgws](#input\_natgws) | A map defining Nat Gateways.

Please note that a NatGW is a zonal resource, this means it's always placed in a zone (even when you do not specify one explicitly). Please refer to Microsoft documentation for notes on NatGW's zonal resiliency.

Following properties are supported:

- `name` : a name of the newly created NatGW.
- `create_natgw` : (default: `true`) create or source (when `false`) an existing NatGW. Created or sourced: the NatGW will be assigned to a subnet created by the `vnet` module.
- `resource_group_name : name of a Resource Group hosting the NatGW (newly create or the existing one).
- `zone` : Availability Zone in which the NatGW will be placed, when skipped AzureRM will pick a zone.
- `idle\_timeout` : connection IDLE timeout in minutes, for newly created resources
- `vnet\_key` : a name (key value) of a VNET defined in `var.vnets` that hosts a subnet this NatGW will be assigned to.
- `subnet\_keys` : a list of subnets (key values) the NatGW will be assigned to, defined in `var.vnets` for a VNET described by `vnet\_name`.
- `create\_pip` : (default: `true`) create a Public IP that will be attached to a NatGW
- `existing\_pip\_name` : when `create\_pip` is set to `false`, source and attach and existing Public IP to the NatGW
- `existing\_pip\_resource\_group\_name` : when `create\_pip` is set to `false`, name of the Resource Group hosting the existing Public IP
- `create\_pip\_prefix` : (default: `false`) create a Public IP Prefix that will be attached to the NatGW.
- `pip\_prefix\_length` : length of the newly created Public IP Prefix, can bet between 0 and 31 but this actually supported value depends on the Subscription.
- `existing\_pip\_prefix\_name` : when `create\_pip\_prefix` is set to `false`, source and attach and existing Public IP Prefix to the NatGW
- `existing\_pip\_prefix\_resource\_group\_name` : when `create\_pip\_prefix` is set to `false`, name of the Resource Group hosting the existing Public IP Prefix.

Example:
`
natgws = {
"natgw" = {
name = "public-natgw"
vnet\_key = "transit-vnet"
subnet\_keys = ["public"]
zone = 1
}
}
| `any` | `{}` | no | -| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `network_security_group_name`: (public LB) a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | +| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `nsg_vnet_key`: (public LB) defaults to `null`, a key describing a vnet (as defined in `vnet` variable) that hold an NSG we will update with an ingress rule for each listener.
- `nsg_key`: (public LB) defaults to `null`, a key describing an NSG (as defined in `vnet` variable, under `nsg_vnet_key`) we will update with an ingress rule for each listener.
- `network_security_group_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | | [vmseries\_version](#input\_vmseries\_version) | VM-Series PAN-OS version - list available with `az vm image list -o table --all --publisher paloaltonetworks`. It's also possible to specify the Pan-OS version per firewall, see `var.vmseries` variable. | `string` | n/a | yes | | [vmseries\_vm\_size](#input\_vmseries\_vm\_size) | Azure VM size (type) to be created. Consult the *VM-Series Deployment Guide* as only a few selected sizes are supported. It's also possible to specify the the VM size per firewall, see `var.vmseries` variable. | `string` | n/a | yes | | [vmseries\_sku](#input\_vmseries\_sku) | VM-Series SKU - list available with `az vm image list -o table --all --publisher paloaltonetworks` | `string` | `"byol"` | no | | [vmseries\_username](#input\_vmseries\_username) | Initial administrative username to use for all systems. | `string` | `"panadmin"` | no | | [vmseries\_password](#input\_vmseries\_password) | Initial administrative password to use for all systems. Set to null for an auto-generated password. | `string` | `null` | no | -| [availability\_set](#input\_availability\_set) | A map defining availability sets. Can be used to provide infrastructure high availability when zones cannot be used.

Following properties are supported:
- `name` - name of the Application Insights.
- `update_domain_count` - specifies the number of update domains that are used, defaults to 5 (Azure defaults).
- `fault_domain_count` - specifies the number of fault domains that are used, defaults to 3 (Azure defaults).

Please keep in mind that Azure defaults are not working for each region (especially the small ones, w/o any Availability Zones). Please verify how many update and fault domain are supported in a region before deploying this resource. | `any` | `{}` | no | +| [availability\_sets](#input\_availability\_sets) | A map defining availability sets. Can be used to provide infrastructure high availability when zones cannot be used.

Following properties are supported:
- `name` - name of the Application Insights.
- `update_domain_count` - specifies the number of update domains that are used, defaults to 5 (Azure defaults).
- `fault_domain_count` - specifies the number of fault domains that are used, defaults to 3 (Azure defaults).

Please keep in mind that Azure defaults are not working for each region (especially the small ones, w/o any Availability Zones). Please verify how many update and fault domain are supported in a region before deploying this resource. | `any` | `{}` | no | | [application\_insights](#input\_application\_insights) | A map defining Azure Application Insights. There are three ways to use this variable:

* when the value is set to `null` (default) no AI is created
* when the value is a map containing `name` key (other keys are optional) a single AI instance will be created under the name that is the value of the `name` key
* when the value is an empty map or a map w/o the `name` key, an AI instance per each VMSeries VM will be created. All instances will share the same configuration. All instances will have names corresponding to their VM name.

Names for all AI instances are prefixed with `var.name_prefix`.

Properties supported (for details on each property see [modules documentation](../../modules/application\_insights)):

- `name` : (optional, string) a name of a single AI instance
- `workspace_mode` : (optional, bool) defaults to `true`, use AI Workspace mode instead of the Classical (deprecated)
- `workspace_name` : (optional, string) defaults to AI name suffixed with `-wrkspc`, name of the Log Analytics Workspace created when AI is deployed in Workspace mode
- `workspace_sku` : (optional, string) defaults to PerGB2018, SKU used by WAL, see module documentation for details
- `metrics_retention_in_days` : (optional, number) defaults to current Azure default value, see module documentation for details

Example of an AIs created per VM, in Workspace mode, with metrics retention set to 1 year:
vmseries = {
'vm-1' = {
....
}
'vm-2' = {
....
}
}

application\_insights = {
metrics\_retention\_in\_days = 365
}
| `map(string)` | `null` | no | -| [bootstrap\_storage](#input\_bootstrap\_storage) | A map defining Azure Storage Accounts used to host file shares for bootstrapping NGFWs. This variable defines only Storage Accounts, file shares are defined per each VM. See `vmseries` variable, `bootstrap_storage` property.

Following properties are supported (except for name, all are optional):

- `name` : name of the Storage Account. Please keep in mind that storage account name has to be globally unique. This name will not be prefixed with the value of `var.name_prefix`.
- `create_storage_account` : (defaults to `true`) create or source (when `false`) an existing Storage Account.
- `resource_group_name` : (defaults to `var.resource_group_name`) name of the Resource Group hosting the Storage Account (existing or newly created). The RG has to exist.
- `storage_acl` : (defaults to `false`) enables network ACLs on the Storage Account. If this is enabled - `storage_allow_vnet_subnets` and `storage_allow_inbound_public_ips` options become available. The ACL defaults to default `Deny`.
- `storage_allow_vnet_subnets` : (defaults to `[]`) whitelist containing the allowed vnet and associated subnets that are allowed to access the Storage Account. Note that the respective subnets require `enable_storage_service_endpoint` set to `true` to work properly.
- `storage_allow_inbound_public_ips` : (defaults to `[]`) whitelist containing the allowed public IP subnets that can access the Storage Account. Note that the code automatically tried to query https://ifconfig.me/ip to obtain the public IP address of the machine executing the code so that the bootstrap files are succuessfuly uploaded to the Storage Account.


The properties below do not directly change anything in the Storage Account settings. They can be used to control common parts of the `DAY0` configuration (used only when full bootstrap is used). These properties can also be specified per firewall, but when specified here they tak higher precedence:
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes). | `any` | `{}` | no | -| [vmseries](#input\_vmseries) | Map of virtual machines to create to run VM-Series - inbound firewalls. Following properties are supported:

- `name` : name of the VMSeries virtual machine.
- `vm_size` : size of the VMSeries virtual machine, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map. This value will be used during network interfaces creation.
- `add_to_appgw_backend` : bool, `false` by default, set this to `true` to add this backend to an Application Gateway.
- `avzone`: the Azure Availability Zone identifier ("1", "2", "3"). Default is "1".
- `availability_set_name` : a name of an Availability Set as declared in `availability_set` property. Specify when HA is required but cannot go for zonal deployment.

- `bootstrap_options` : string, optional bootstrap options to pass to VM-Series instances, semicolon separated values. When defined this precedence over `bootstrap_storage`
- `bootstrap_storage` : a map containing definition of the bootstrap package content. When present triggers a creation of a File Share in an existing Storage Account, following properties supported:
- `name` : a name of a key in `var.bootstrap_storage` variable defining a Storage Account
- `static_files` : a map where key is a path to a file, value is the location of the file in the bootstrap package (file share). All files in this map are copied 1:1 to the bootstrap package
- `template_bootstrap_xml` : path to the `bootstrap.xml` template. When defined it will trigger creation of the `bootstrap.xml` file and the file will be uploaded to the storage account. This is a simple `day 0` configuration file that should set up only basic networking. Specifying this property forces additional properties that are required to properly template the file. They can be defined per each VM or globally for all VMs (in this case place them in the bootstrap storage definition). The properties are listed below.
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes).

- `interfaces` : configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name`: string that will form the NIC name
- `subnet_key` : (string) a key of a subnet as defined in `var.vnets`
- `create_pip` : (boolean) flag to create Public IP for an interface, defaults to `false`
- `public_ip_name` : (string) when `create_pip` is set to `false` a name of a Public IP resource that should be associated with this Network Interface
- `public_ip_resource_group` : (string) when associating an existing Public IP resource, name of the Resource Group the IP is placed in, defaults to the `var.resource_group_name`
- `load_balancer_key` : (string) key of a Load Balancer defined in the `var.loadbalancers` variable, defaults to `null`
- `private_ip_address` : (string) a static IP address that should be assigned to an interface, defaults to `null` (in that case DHCP is used)

Example:
{
"fw01" = {
name = "firewall01"
bootstrap\_storage = {
name = "storageaccountname"
static\_files = { "files/init-cfg.txt" = "config/init-cfg.txt" }
template\_bootstrap\_xml = "templates/bootstrap\_common.tmpl"
public\_snet\_key = "public"
private\_snet\_key = "private"
}
avzone = 1
vnet\_key = "trust"
interfaces = [
{
name = "mgmt"
subnet\_key = "mgmt"
create\_pip = true
private\_ip\_address = "10.0.0.1"
},
{
name = "trust"
subnet\_key = "private"
private\_ip\_address = "10.0.1.1"
load\_balancer\_key = "private\_lb"
},
{
name = "untrust"
subnet\_key = "public"
private\_ip\_address = "10.0.2.1"
load\_balancer\_key = "public\_lb"
public\_ip\_name = "existing\_public\_ip"
}
]
}
}
| `any` | n/a | yes | +| [bootstrap\_storage](#input\_bootstrap\_storage) | A map defining Azure Storage Accounts used to host file shares for bootstrapping NGFWs. This variable defines only Storage Accounts, file shares are defined per each VM. See `vmseries` variable, `bootstrap_storage` property.

Following properties are supported (except for name, all are optional):

- `name` : name of the Storage Account. Please keep in mind that storage account name has to be globally unique. This name will not be prefixed with the value of `var.name_prefix`.
- `create_storage_account` : (defaults to `true`) create or source (when `false`) an existing Storage Account.
- `resource_group_name` : (defaults to `var.resource_group_name`) name of the Resource Group hosting the Storage Account (existing or newly created). The RG has to exist.
- `storage_acl` : (defaults to `false`) enables network ACLs on the Storage Account. If this is enabled - `storage_allow_vnet_subnets` and `storage_allow_inbound_public_ips` options become available. The ACL defaults to default `Deny`.
- `storage_allow_vnet_subnets` : (defaults to `[]`) whitelist containing the allowed vnet and associated subnets that are allowed to access the Storage Account. Note that the respective subnets require `enable_storage_service_endpoint` set to `true` to work properly.
- `storage_allow_inbound_public_ips` : (defaults to `[]`) whitelist containing the allowed public IP subnets that can access the Storage Account. Note that the code automatically tried to query https://ifconfig.me/ip to obtain the public IP address of the machine executing the code so that the bootstrap files are successfully uploaded to the Storage Account.


The properties below do not directly change anything in the Storage Account settings. They can be used to control common parts of the `DAY0` configuration (used only when full bootstrap is used). These properties can also be specified per firewall, but when specified here they tak higher precedence:
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes). | `any` | `{}` | no | +| [vmseries](#input\_vmseries) | Map of virtual machines to create to run VM-Series - inbound firewalls. Following properties are supported:

- `name` : name of the VMSeries virtual machine.
- `vm_size` : size of the VMSeries virtual machine, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map. This value will be used during network interfaces creation.
- `add_to_appgw_backend` : bool, `false` by default, set this to `true` to add this backend to an Application Gateway.
- `avzone`: the Azure Availability Zone identifier ("1", "2", "3"). Default is "1".
- `availability_set_key` : a key of an Availability Set as declared in `availability_sets` property. Specify when HA is required but cannot go for zonal deployment.

- `bootstrap_options` : string, optional bootstrap options to pass to VM-Series instances, semicolon separated values. When defined this precedence over `bootstrap_storage`
- `bootstrap_storage` : a map containing definition of the bootstrap package content. When present triggers a creation of a File Share in an existing Storage Account, following properties supported:
- `name` : a name of a key in `var.bootstrap_storage` variable defining a Storage Account
- `static_files` : a map where key is a path to a file, value is the location of the file in the bootstrap package (file share). All files in this map are copied 1:1 to the bootstrap package
- `template_bootstrap_xml` : path to the `bootstrap.xml` template. When defined it will trigger creation of the `bootstrap.xml` file and the file will be uploaded to the storage account. This is a simple `day 0` configuration file that should set up only basic networking. Specifying this property forces additional properties that are required to properly template the file. They can be defined per each VM or globally for all VMs (in this case place them in the bootstrap storage definition). The properties are listed below.
- `public_snet_key` : required, name of the key in `var.vnets` map defining a public subnet, required to calculate the Azure router IP for the public subnet.
- `private_snet_key` : required, name of the key in `var.vnets` map defining a private subnet, required to calculate the Azure router IP for the private subnet.
- `intranet_cidr` : optional, CIDR of the private networks required to build a general static route to resources protected by this firewall, when skipped the 1st CIDR from `vnet_name` address space will be used.
- `ai_update_interval` : if Application Insights are used this property can override the default metrics update interval (in minutes).

- `interfaces` : configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name`: string that will form the NIC name
- `subnet_key` : (string) a key of a subnet as defined in `var.vnets`
- `create_pip` : (boolean) flag to create Public IP for an interface, defaults to `false`
- `public_ip_name` : (string) when `create_pip` is set to `false` a name of a Public IP resource that should be associated with this Network Interface
- `public_ip_resource_group` : (string) when associating an existing Public IP resource, name of the Resource Group the IP is placed in, defaults to the `var.resource_group_name`
- `load_balancer_key` : (string) key of a Load Balancer defined in the `var.loadbalancers` variable, defaults to `null`
- `private_ip_address` : (string) a static IP address that should be assigned to an interface, defaults to `null` (in that case DHCP is used)

Example:
{
"fw01" = {
name = "firewall01"
bootstrap\_storage = {
name = "storageaccountname"
static\_files = { "files/init-cfg.txt" = "config/init-cfg.txt" }
template\_bootstrap\_xml = "templates/bootstrap\_common.tmpl"
public\_snet\_key = "public"
private\_snet\_key = "private"
}
avzone = 1
vnet\_key = "trust"
interfaces = [
{
name = "mgmt"
subnet\_key = "mgmt"
create\_pip = true
private\_ip\_address = "10.0.0.1"
},
{
name = "trust"
subnet\_key = "private"
private\_ip\_address = "10.0.1.1"
load\_balancer\_key = "private\_lb"
},
{
name = "untrust"
subnet\_key = "public"
private\_ip\_address = "10.0.2.1"
load\_balancer\_key = "public\_lb"
public\_ip\_name = "existing\_public\_ip"
}
]
}
}
| `any` | n/a | yes | | [appgws](#input\_appgws) | A map defining all Application Gateways in the current deployment.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults and the `rules` property refer to [module documentation](../../modules/appgw).

Following properties are supported:
- `name` : name of the Application Gateway.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `zones` : for zonal deployment this is a list of all zones in a region - this property is used by both: the Application Gateway and the Public IP created in front of the AppGW.
- `capacity` : (optional) number of Application Gateway instances, not used when autoscalling is enabled (see `capacity_min`)
- `capacity_min` : (optional) when set enables autoscaling and becomes the minimum capacity
- `capacity_max` : (optional) maximum capacity for autoscaling
- `enable_http2` : enable HTTP2 support on the Application Gateway
- `waf_enabled` : (optional) enables WAF Application Gateway, defining WAF rules is not supported, defaults to `false`
- `vmseries_public_nic_name` : name of the public VMSeries interface as defined in `interfaces` property.
- `managed_identities` : (optional) a list of existing User-Assigned Managed Identities, which Application Gateway uses to retrieve certificates from Key Vault
- `ssl_policy_type` : (optional) type of an SSL policy, defaults to `Predefined`
- `ssl_policy_name` : (optional) name of an SSL policy, for `ssl_policy_type` set to `Predefined`
- `ssl_policy_min_protocol_version` : (optional) minimum version of the TLS protocol for SSL Policy, for `ssl_policy_type` set to `Custom`
- `ssl_policy_cipher_suites` : (optional) a list of accepted cipher suites, for `ssl_policy_type` set to `Custom`
- `ssl_profiles` : (optional) a map of SSL profiles that can be later on referenced in HTTPS listeners by providing a name of the profile in the `ssl_profile_name` property | `map` | `{}` | no | ### Outputs diff --git a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries_and_autoscale.md b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries_and_autoscale.md index afa20c4ba..bbcb794ee 100644 --- a/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries_and_autoscale.md +++ b/products/terraform/docs/swfw/azure/vmseries/reference-architectures/dedicated_vmseries_and_autoscale.md @@ -204,14 +204,14 @@ terraform destroy | [enable\_zones](#input\_enable\_zones) | If `true`, enable zone support for resources. | `bool` | `true` | no | | [vnets](#input\_vnets) | A map defining VNETs.

For detailed documentation on each property refer to [module documentation](../../modules/vnet)

- `name` : A name of a VNET.
- `create_virtual_network` : (default: `true`) when set to `true` will create a VNET, `false` will source an existing VNET, in both cases the name of the VNET is specified with `name`
- `address_space` : a list of CIDRs for VNET
- `resource_group_name` : (default: current RG) a name of a Resource Group in which the VNET will reside

- `create_subnets` : (default: `true`) if true, create the Subnets inside the Virtual Network, otherwise use pre-existing subnets
- `subnets` : map of Subnets to create

- `network_security_groups` : map of Network Security Groups to create
- `route_tables` : map of Route Tables to create. | `any` | n/a | yes | | [natgws](#input\_natgws) | A map defining Nat Gateways.

Please note that a NatGW is a zonal resource, this means it's always placed in a zone (even when you do not specify one explicitly). Please refer to Microsoft documentation for notes on NatGW's zonal resiliency.

Following properties are supported:

- `name` : a name of the newly created NatGW.
- `create_natgw` : (default: `true`) create or source (when `false`) an existing NatGW. Created or sourced: the NatGW will be assigned to a subnet created by the `vnet` module.
- `resource_group_name : name of a Resource Group hosting the NatGW (newly create or the existing one).
- `zone` : Availability Zone in which the NatGW will be placed, when skipped AzureRM will pick a zone.
- `idle\_timeout` : connection IDLE timeout in minutes, for newly created resources
- `vnet\_key` : a name (key value) of a VNET defined in `var.vnets` that hosts a subnet this NatGW will be assigned to.
- `subnet\_keys` : a list of subnets (key values) the NatGW will be assigned to, defined in `var.vnets` for a VNET described by `vnet\_name`.
- `create\_pip` : (default: `true`) create a Public IP that will be attached to a NatGW
- `existing\_pip\_name` : when `create\_pip` is set to `false`, source and attach and existing Public IP to the NatGW
- `existing\_pip\_resource\_group\_name` : when `create\_pip` is set to `false`, name of the Resource Group hosting the existing Public IP
- `create\_pip\_prefix` : (default: `false`) create a Public IP Prefix that will be attached to the NatGW.
- `pip\_prefix\_length` : length of the newly created Public IP Prefix, can bet between 0 and 31 but this actually supported value depends on the Subscription.
- `existing\_pip\_prefix\_name` : when `create\_pip\_prefix` is set to `false`, source and attach and existing Public IP Prefix to the NatGW
- `existing\_pip\_prefix\_resource\_group\_name` : when `create\_pip\_prefix` is set to `false`, name of the Resource Group hosting the existing Public IP Prefix.

Example:
`
natgws = {
"natgw" = {
name = "public-natgw"
vnet\_key = "transit-vnet"
subnet\_keys = ["public"]
zone = 1
}
}
| `any` | `{}` | no | -| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `network_security_group_name`: (public LB) a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | +| [load\_balancers](#input\_load\_balancers) | A map containing configuration for all (private and public) Load Balancer that will be created in this deployment.

Following properties are available (for details refer to module's documentation):

- `name`: name of the Load Balancer resource.
- `nsg_vnet_key`: (public LB) defaults to `null`, a key describing a vnet (as defined in `vnet` variable) that hold an NSG we will update with an ingress rule for each listener.
- `nsg_key`: (public LB) defaults to `null`, a key describing an NSG (as defined in `vnet` variable, under `nsg_vnet_key`) we will update with an ingress rule for each listener.
- `network_security_group_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a security group, an ingress rule will be created in that NSG for each listener. **NOTE** this is the FULL NAME of the NSG (including prefixes).
- `network_security_group_rg_name`: (public LB) defaults to `null`, in case of a brownfield deployment (no possibility to depend on `vnet` variable), a name of a resource group for the security group, to be used when the NSG is hosted in a different RG than the one described in `var.resource_group_name`.
- `network_security_allow_source_ips`: (public LB) a list of IP addresses that will used in the ingress rules.
- `avzones`: (both) for regional Load Balancers, a list of supported zones (this has different meaning for public and private LBs - please refer to module's documentation for details).
- `frontend_ips`: (both) a map configuring both a listener and a load balancing rule, key is the name that will be used as an application name inside LB config as well as to create a rule in NSG (for public LBs), value is an object with the following properties:
- `create_public_ip`: (public LB) defaults to `false`, when set to `true` a Public IP will be created and associated with a listener
- `public_ip_name`: (public LB) defaults to `null`, when `create_public_ip` is set to `false` this property is used to reference an existing Public IP object in Azure
- `public_ip_resource_group`: (public LB) defaults to `null`, when using an existing Public IP created in a different Resource Group than the currently used use this property is to provide the name of that RG
- `private_ip_address`: (private LB) defaults to `null`, specify a static IP address that will be used by a listener
- `vnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a vnet's key (as defined in `vnet` variable). This will be the VNET hosting this Load Balancer
- `subnet_key`: (private LB) defaults to `null`, when `private_ip_address` is set specifies a subnet's key (as defined in `vnet` variable) to which the LB will be attached, in case of VMSeries this should be a internal/trust subnet
- `rules` - a map configuring the actual rules load balancing rules, a key is a rule name, a value is an object with the following properties:
- `protocol`: protocol used by the rule, can be one the following: `TCP`, `UDP` or `All` when creating an HA PORTS rule
- `port`: port used by the rule, for HA PORTS rule set this to `0`

Example of a public Load Balancer:
"public\_lb" = {
name = "https\_app\_lb"
network\_security\_group\_name = "untrust\_nsg"
network\_security\_allow\_source\_ips = ["1.2.3.4"]
avzones = ["1", "2", "3"]
frontend\_ips = {
"https\_app\_1" = {
create\_public\_ip = true
rules = {
"balanceHttps" = {
protocol = "Tcp"
port = 443
}
}
}
}
}
Example of a private Load Balancer with HA PORTS rule:
"private\_lb" = {
name = "ha\_ports\_internal\_lb
frontend\_ips = {
"ha-ports" = {
vnet\_key = "trust\_vnet"
subnet\_key = "trust\_snet"
private\_ip\_address = "10.0.0.1"
rules = {
HA\_PORTS = {
port = 0
protocol = "All"
}
}
}
}
}
| `map` | `{}` | no | | [application\_insights](#input\_application\_insights) | A map defining Azure Application Insights. There are three ways to use this variable:

* when the value is set to `null` (default) no AI is created
* when the value is a map containing `name` key (other keys are optional) a single AI instance will be created under the name that is the value of the `name` key
* when the value is an empty map or a map w/o the `name` key, an AI instance per each VMSeries VM will be created. All instances will share the same configuration. All instances will have names corresponding to their VM name.

Names for all AI instances are prefixed with `var.name_prefix`.

Properties supported (for details on each property see [modules documentation](../../modules/application\_insights)):

- `name` : (optional, string) a name of a single AI instance
- `workspace_mode` : (optional, bool) defaults to `true`, use AI Workspace mode instead of the Classical (deprecated)
- `workspace_name` : (optional, string) defaults to AI name suffixed with `-wrkspc`, name of the Log Analytics Workspace created when AI is deployed in Workspace mode
- `workspace_sku` : (optional, string) defaults to PerGB2018, SKU used by WAL, see module documentation for details
- `metrics_retention_in_days` : (optional, number) defaults to current Azure default value, see module documentation for details

Example of an AIs created per VM, in Workspace mode, with metrics retention set to 1 year:
vmseries = {
'vm-1' = {
....
}
'vm-2' = {
....
}
}

application\_insights = {
metrics\_retention\_in\_days = 365
}
| `map(string)` | `null` | no | | [vmseries\_version](#input\_vmseries\_version) | VM-Series PAN-OS version - list available with `az vm image list -o table --all --publisher paloaltonetworks`. It's also possible to specify the Pan-OS version per Scale Set, see `var.vmss` variable. | `string` | n/a | yes | | [vmseries\_vm\_size](#input\_vmseries\_vm\_size) | Azure VM size (type) to be created. Consult the *VM-Series Deployment Guide* as only a few selected sizes are supported. It's also possible to specify the the VM size per Scale Set, see `var.vmss` variable. | `string` | n/a | yes | | [vmseries\_sku](#input\_vmseries\_sku) | VM-Series SKU - list available with `az vm image list -o table --all --publisher paloaltonetworks` | `string` | `"byol"` | no | | [vmseries\_username](#input\_vmseries\_username) | Initial administrative username to use for all systems. | `string` | `"panadmin"` | no | | [vmseries\_password](#input\_vmseries\_password) | Initial administrative password to use for all systems. Set to null for an auto-generated password. | `string` | `null` | no | -| [vmss](#input\_vmss) | A map defining all Virtual Machine Scale Sets.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults refer to [module documentation](../../modules/vmss)

Following properties are available:
- `name` : (string\|required) name of the Virtual Machine Scale Set.
- `vm_size` : size of the VMSeries virtual machines created with this Scale Set, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : (string\|required) a key of a VNET defined in the `var.vnets` map.
- `bootstrap_options` : (string\|`''`) bootstrap options passed to every VM instance upon creation.
- `zones` : (list(string)\|`[]`) a list of Availability Zones to use for Zone redundancy
- `encryption_at_host_enabled` : (bool\|`null` - Azure defaults) should all of the disks attached to this Virtual Machine be encrypted
- `overprovision` : (bool\|`null` - module defaults) when provisioning new VM, multiple will be provisioned but the 1st one to run will be kept
- `platform_fault_domain_count` : (number\|`null` - Azure defaults) number of fault domains to use
- `proximity_placement_group_id` : (string\|`null`) ID of a proximity placement group the VMSS should be placed in
- `scale_in_policy` : (string\|`null` - Azure defaults) policy of removing VMs when scaling in
- `scale_in_force_deletion` : (bool\|`null` - module default) forces (`true`) deletion of VMs during scale in
- `single_placement_group` : (bool\|`null` - Azure defaults) limit the Scale Set to one Placement Group
- `storage_account_type` : (string\|`null` - module defaults) type of managed disk that will be used on all VMs
- `disk_encryption_set_id` : (string\|`null`) the ID of the Disk Encryption Set which should be used to encrypt this Data Disk
- `accelerated_networking` : (bool\|`null`- module defaults) enable Azure accelerated networking for all dataplane network interfaces
- `use_custom_image` : (bool\|`false`)
- `custom_image_id` : (string\|reqquired when `use_custom_image` is `true`) absolute ID of your own Custom Image to be used for creating new VM-Series
- `application_insights_id` : (string\|`null`) ID of Application Insights instance that should be used to provide metrics for autoscaling
- `interfaces` : (list(string)\|`[]`) configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name` : (string\|required) string that will form the NIC name
- `subnet_key` : (string\|required) a key of a subnet as defined in `var.vnets`
- `create_pip` : (bool\|`false`) flag to create Public IP for an interface, defaults to `false`
- `load_balancer_key` : (string\|`null`) key of a Load Balancer defined in the `var.loadbalancers` variable
- `application_gateway_key` : (string\|`null`) key of an Application Gateway defined in the `var.appgws`
- `pip_domain_name_label` : (string\|`null`) prefix which should be used for the Domain Name Label for each VM instance
- `autoscale_config` : (map\|`{}`) map containing basic autoscale configuration
- `count_default` : (number\|`null` - module defaults) default number or instances when autoscalling is not available
- `count_minimum` : (number\|`null` - module defaults) minimum number of instances to reach when scaling in
- `count_maximum` : (number\|`null` - module defaults) maximum number of instances when scaling out
- `notification_emails` : (list(string)\|`null` - module defaults) a list of e-mail addresses to notify about scaling events
- `autoscale_metrics` : (map\|`{}`) metrics and thresholds used to trigger scaling events, see module documentation for details
- `scaleout_config` : (map\|`{}`) scale out configuration, for details see module documentation
- `statistic` : (string\|`null` - module defaults) aggregation method for statistics coming from different VMs
- `time_aggregation` : (string\|`null` - module defaults) aggregation method applied to statistics in time window
- `window_minutes` : (string\|`null` - module defaults) time windows used to analyze statistics
- `cooldown_minutes` : (string\|`null` - module defaults) time to wait after a scaling event before analyzing the statistics again
- `scalein_config` : (map\|`{}`) scale in configuration, same properties supported as for `scaleout_config`

Example, no auto scaling:
{
"vmss" = {
name = "ngfw-vmss"
vnet\_key = "transit"
bootstrap\_options = "type=dhcp"

interfaces = [
{
name = "management"
subnet\_key = "management"
},
{
name = "private"
subnet\_key = "private"
},
{
name = "public"
subnet\_key = "public"
load\_balancer\_key = "public"
application\_gateway\_key = "public"
}
]
}
| `any` | `{}` | no | +| [vmss](#input\_vmss) | A map defining all Virtual Machine Scale Sets.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults refer to [module documentation](../../modules/vmss)

Following properties are available:
- `name` : (string\|required) name of the Virtual Machine Scale Set.
- `vm_size` : size of the VMSeries virtual machines created with this Scale Set, when specified overrides `var.vmseries_vm_size`.
- `version` : PanOS version, when specified overrides `var.vmseries_version`.
- `vnet_key` : (string\|required) a key of a VNET defined in the `var.vnets` map.
- `bootstrap_options` : (string\|`''`) bootstrap options passed to every VM instance upon creation.
- `zones` : (list(string)\|`[]`) a list of Availability Zones to use for Zone redundancy
- `encryption_at_host_enabled` : (bool\|`null` - Azure defaults) should all of the disks attached to this Virtual Machine be encrypted
- `overprovision` : (bool\|`null` - module defaults) when provisioning new VM, multiple will be provisioned but the 1st one to run will be kept
- `platform_fault_domain_count` : (number\|`null` - Azure defaults) number of fault domains to use
- `proximity_placement_group_id` : (string\|`null`) ID of a proximity placement group the VMSS should be placed in
- `scale_in_policy` : (string\|`null` - Azure defaults) policy of removing VMs when scaling in
- `scale_in_force_deletion` : (bool\|`null` - module default) forces (`true`) deletion of VMs during scale in
- `single_placement_group` : (bool\|`null` - Azure defaults) limit the Scale Set to one Placement Group
- `storage_account_type` : (string\|`null` - module defaults) type of managed disk that will be used on all VMs
- `disk_encryption_set_id` : (string\|`null`) the ID of the Disk Encryption Set which should be used to encrypt this Data Disk
- `accelerated_networking` : (bool\|`null`- module defaults) enable Azure accelerated networking for all dataplane network interfaces
- `use_custom_image` : (bool\|`false`)
- `custom_image_id` : (string\|reqquired when `use_custom_image` is `true`) absolute ID of your own Custom Image to be used for creating new VM-Series
- `application_insights_id` : (string\|`null`) ID of Application Insights instance that should be used to provide metrics for autoscaling
- `interfaces` : (list(string)\|`[]`) configuration of all NICs assigned to a VM. A list of maps, each map is a NIC definition. Notice that the order DOES matter. NICs are attached to VMs in Azure in the order they are defined in this list, therefore the management interface has to be defined first. Following properties are available:
- `name` : (string\|required) string that will form the NIC name
- `subnet_key` : (string\|required) a key of a subnet as defined in `var.vnets`
- `create_pip` : (bool\|`false`) flag to create Public IP for an interface, defaults to `false`
- `load_balancer_key` : (string\|`null`) key of a Load Balancer defined in the `var.loadbalancers` variable
- `application_gateway_key` : (string\|`null`) key of an Application Gateway defined in the `var.appgws`
- `pip_domain_name_label` : (string\|`null`) prefix which should be used for the Domain Name Label for each VM instance
- `autoscale_config` : (map\|`{}`) map containing basic autoscale configuration
- `count_default` : (number\|`null` - module defaults) default number or instances when autoscalling is not available
- `count_minimum` : (number\|`null` - module defaults) minimum number of instances to reach when scaling in
- `count_maximum` : (number\|`null` - module defaults) maximum number of instances when scaling out
- `notification_emails` : (list(string)\|`null` - module defaults) a list of e-mail addresses to notify about scaling events
- `autoscale_metrics` : (map\|`{}`) metrics and thresholds used to trigger scaling events, see module documentation for details
- `scaleout_config` : (map\|`{}`) scale out configuration, for details see module documentation
- `statistic` : (string\|`null` - module defaults) aggregation method for statistics coming from different VMs
- `time_aggregation` : (string\|`null` - module defaults) aggregation method applied to statistics in time window
- `window_minutes` : (string\|`null` - module defaults) time windows used to analyze statistics
- `cooldown_minutes` : (string\|`null` - module defaults) time to wait after a scaling event before analyzing the statistics again
- `scalein_config` : (map\|`{}`) scale in configuration, same properties supported as for `scaleout_config`

Example, no auto scaling:
{
"vmss" = {
name = "ngfw-vmss"
vnet\_key = "transit"
bootstrap\_options = "type=dhcp-client"

interfaces = [
{
name = "management"
subnet\_key = "management"
},
{
name = "private"
subnet\_key = "private"
},
{
name = "public"
subnet\_key = "public"
load\_balancer\_key = "public"
application\_gateway\_key = "public"
}
]
}
| `any` | `{}` | no | | [appgws](#input\_appgws) | A map defining all Application Gateways in the current deployment.

For detailed documentation on how to configure this resource, for available properties, especially for the defaults and the `rules` property refer to [module documentation](../../modules/appgw).

Following properties are supported:
- `name` : name of the Application Gateway.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `vnet_key` : a key of a VNET defined in the `var.vnets` map.
- `subnet_key` : a key of a subnet as defined in `var.vnets`. This has to be a subnet dedicated to Application Gateways v2.
- `zones` : for zonal deployment this is a list of all zones in a region - this property is used by both: the Application Gateway and the Public IP created in front of the AppGW.
- `capacity` : (optional) number of Application Gateway instances, not used when autoscalling is enabled (see `capacity_min`)
- `capacity_min` : (optional) when set enables autoscaling and becomes the minimum capacity
- `capacity_max` : (optional) maximum capacity for autoscaling
- `enable_http2` : enable HTTP2 support on the Application Gateway
- `waf_enabled` : (optional) enables WAF Application Gateway, defining WAF rules is not supported, defaults to `false`
- `vmseries_public_nic_name` : name of the public VMSeries interface as defined in `interfaces` property.
- `managed_identities` : (optional) a list of existing User-Assigned Managed Identities, which Application Gateway uses to retrieve certificates from Key Vault
- `ssl_policy_type` : (optional) type of an SSL policy, defaults to `Predefined`
- `ssl_policy_name` : (optional) name of an SSL policy, for `ssl_policy_type` set to `Predefined`
- `ssl_policy_min_protocol_version` : (optional) minimum version of the TLS protocol for SSL Policy, for `ssl_policy_type` set to `Custom`
- `ssl_policy_cipher_suites` : (optional) a list of accepted cipher suites, for `ssl_policy_type` set to `Custom`
- `ssl_profiles` : (optional) a map of SSL profiles that can be later on referenced in HTTPS listeners by providing a name of the profile in the `ssl_profile_name` property | `map` | `{}` | no | ### Outputs From 115152a5f4bc8c5cdb646a4f373ee5529088087d Mon Sep 17 00:00:00 2001 From: "create-pr-on-fork-for-pan-dev[bot]" <135888023+create-pr-on-fork-for-pan-dev[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:28:14 +0100 Subject: [PATCH 3/3] Sync gcp Terraform module documentation (#474) Co-authored-by: pan-dev-content-sync-trigger[bot] --- .../swfw/gcp/vmseries/modules/autoscale.md | 19 +- .../swfw/gcp/vmseries/modules/bootstrap.md | 2 +- .../vmseries/modules/iam_service_account.md | 2 +- .../swfw/gcp/vmseries/modules/lb_external.md | 2 +- .../vmseries/modules/lb_http_ext_global.md | 2 +- .../swfw/gcp/vmseries/modules/lb_internal.md | 3 +- .../swfw/gcp/vmseries/modules/panorama.md | 2 +- .../swfw/gcp/vmseries/modules/vmseries.md | 2 +- .../swfw/gcp/vmseries/modules/vpc-peering.md | 2 +- .../docs/swfw/gcp/vmseries/modules/vpc.md | 2 +- .../docs/swfw/gcp/vmseries/modules/vpn.md | 270 ++++++++++++++++++ 11 files changed, 297 insertions(+), 11 deletions(-) create mode 100644 products/terraform/docs/swfw/gcp/vmseries/modules/vpn.md diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/autoscale.md b/products/terraform/docs/swfw/gcp/vmseries/modules/autoscale.md index 9733e902a..f94274baf 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/autoscale.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/autoscale.md @@ -18,7 +18,7 @@ title: Auto-Scaling for Palo Alto Networks VM-Series # Auto-Scaling for Palo Alto Networks VM-Series -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/autoscale) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/autoscale) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/autoscale) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/autoscale) ## Reference @@ -33,7 +33,9 @@ title: Auto-Scaling for Palo Alto Networks VM-Series | Name | Version | |------|---------| +| [archive](#provider\_archive) | n/a | | [google](#provider\_google) | ~> 4.54 | +| [random](#provider\_random) | n/a | ### Modules @@ -43,14 +45,27 @@ No modules. | Name | Type | |------|------| +| [google_cloudfunctions2_function.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloudfunctions2_function) | resource | | [google_compute_autoscaler.zonal](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_autoscaler) | resource | | [google_compute_instance_group_manager.zonal](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_group_manager) | resource | | [google_compute_instance_template.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_instance_template) | resource | | [google_compute_region_autoscaler.regional](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_region_autoscaler) | resource | | [google_compute_region_instance_group_manager.regional](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_region_instance_group_manager) | resource | +| [google_logging_project_sink.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/logging_project_sink) | resource | +| [google_project_iam_member.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource | +| [google_project_iam_member.delicensing_cfn_invoker](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/project_iam_member) | resource | | [google_pubsub_subscription.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription) | resource | | [google_pubsub_subscription_iam_member.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_subscription_iam_member) | resource | +| [google_pubsub_topic.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_topic) | resource | | [google_pubsub_topic.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_topic) | resource | +| [google_pubsub_topic_iam_member.pubsub_sink_member](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/pubsub_topic_iam_member) | resource | +| [google_secret_manager_secret.delicensing_cfn_pano_creds](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/secret_manager_secret) | resource | +| [google_service_account.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/service_account) | resource | +| [google_storage_bucket.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket) | resource | +| [google_storage_bucket_object.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket_object) | resource | +| [google_vpc_access_connector.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/vpc_access_connector) | resource | +| [random_id.postfix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | +| [archive_file.delicensing_cfn](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source | | [google_compute_default_service_account.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_default_service_account) | data source | | [google_compute_zones.main](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/compute_zones) | data source | @@ -61,6 +76,7 @@ No modules. | [autoscaler\_metrics](#input\_autoscaler\_metrics) | A 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`, `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/panSessionThroughputKbps": {
"target": 700000
},
"custom.googleapis.com/VMSeries/panSessionUtilization": {
"target": 70
}
}
| no | | [cooldown\_period](#input\_cooldown\_period) | The number of seconds that the autoscaler should wait before it starts collecting information from a new VM-Series. This prevents the autoscaler from collecting information when the VM-Series is initializing, during which the collected usage would not be reliable. Virtual machine initialization times might vary because of numerous factors. | `number` | `480` | no | | [create\_pubsub\_topic](#input\_create\_pubsub\_topic) | Set to `true` to create a Pub/Sub topic and subscription. The Panorama Google Cloud Plugin can use this Pub/Sub to trigger actions when the VM-Series Instance Group descales. Actions include, removal of VM-Series from Panorama and automatic delicensing (if VM-Series BYOL licensing is used). For more information, please see [Autoscaling the VM-Series on GCP](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). | `bool` | `true` | 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
- `panorama2_address` - Panorama 2 IP address/FQDN. Set if Panorama is in HA mode
- `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\_address = "1.1.1.1"
panorama2\_address = ""
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 | | [disk\_type](#input\_disk\_type) | The disk type that is attached to the instances of the VM-Series firewalls. | `string` | `"pd-ssd"` | no | | [image](#input\_image) | 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` | `"https://www.googleapis.com/compute/v1/projects/paloaltonetworksgcp-public/global/images/vmseries-byol-1014"` | no | | [machine\_type](#input\_machine\_type) | The instance type for the VM-Series firewalls. | `string` | `"n2-standard-4"` | no | @@ -71,6 +87,7 @@ No modules. | [name](#input\_name) | The name of the VM-Series deployed. This value will be used as the `base_instance_name` and will be used as a prepended prefix for other created resources. | `string` | n/a | yes | | [named\_ports](#input\_named\_ports) | A list of named port configurations. The name identifies the backend port to receive the traffic
from the global load balancers.
named\_ports = [
{
name = "http"
port = "80"
},
{
name = "app42"
port = "4242"
},
]
| `list` | `[]` | no | | [network\_interfaces](#input\_network\_interfaces) | List of the network interface specifications.

Available options:
- `subnetwork` - (Required\|string) Self-link of a subnetwork to create interface in.
- `create_public_ip` - (Optional\|boolean) Whether to reserve public IP for the interface. | `list(any)` | n/a | yes | +| [project\_id](#input\_project\_id) | GCP Project ID to contain the created cloud resources. | `string` | `null` | no | | [region](#input\_region) | The Google Cloud region for the resources. If null, provider region will be used. | `string` | `null` | no | | [regional\_mig](#input\_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` | n/a | yes | | [scale\_in\_control\_replicas\_fixed](#input\_scale\_in\_control\_replicas\_fixed) | Fixed number of VM-Series instances that can be killed within the scale-in time window. See `scale_in_control` in the [provider doc](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_autoscaler). | `number` | `1` | no | diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/bootstrap.md b/products/terraform/docs/swfw/gcp/vmseries/modules/bootstrap.md index d1e4569b9..fe5c9da17 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/bootstrap.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/bootstrap.md @@ -18,7 +18,7 @@ title: Google Cloud Storage Bucket For Initial Boot Of Palo Alto Networks VM-Ser # Google Cloud Storage Bucket For Initial Boot Of Palo Alto Networks VM-Series -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/bootstrap) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/bootstrap) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/bootstrap) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/iam_service_account.md b/products/terraform/docs/swfw/gcp/vmseries/modules/iam_service_account.md index 0bb07721c..066826474 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/iam_service_account.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/iam_service_account.md @@ -25,7 +25,7 @@ The account produced by this module is intended to have minimal required permiss [Google Cloud Docs](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#best_practices) -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/iam_service_account) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/iam_service_account) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/iam_service_account) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/iam_service_account) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_external.md b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_external.md index 10b6036ad..7865b2307 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_external.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_external.md @@ -26,7 +26,7 @@ title: Externally-Facing Regional TCP/UDP Network Load Balancer on GCP - Can only use the nic0 (the base interface) of an instance. - Cannot serve as a next hop in a GCP custom routing table entry. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/lb_external) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/lb_external) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_external) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/lb_external) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_http_ext_global.md b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_http_ext_global.md index 18bf0e6b3..7979b1bea 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_http_ext_global.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_http_ext_global.md @@ -21,7 +21,7 @@ title: Google Cloud HTTP/HTTPS External Global Load Balancer A simplified GLB, which assumes that all participating instances are equally capable and that all participating groups are equally capable as well. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/lb_http_ext_global) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/lb_http_ext_global) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_http_ext_global) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/lb_http_ext_global) ## Example diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_internal.md b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_internal.md index 6a48ed0a6..c109a6e6e 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/lb_internal.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/lb_internal.md @@ -18,7 +18,7 @@ title: Internally-Facing Regional TCP/UDP Load Balancer on GCP # Internally-Facing Regional TCP/UDP Load Balancer on GCP -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/lb_internal) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/lb_internal) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/lb_internal) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/lb_internal) ## Reference @@ -47,7 +47,6 @@ No modules. | [google-beta_google_compute_region_backend_service.this](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_compute_region_backend_service) | resource | | [google_compute_forwarding_rule.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_forwarding_rule) | resource | | [google_compute_health_check.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_health_check) | resource | -| [google_client_config.this](https://registry.terraform.io/providers/hashicorp/google/latest/docs/data-sources/client_config) | data source | ### Inputs diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/panorama.md b/products/terraform/docs/swfw/gcp/vmseries/modules/panorama.md index 2358a2aa1..1c22821f3 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/panorama.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/panorama.md @@ -20,7 +20,7 @@ title: Palo Alto Networks Panorama Module for Google Clooud Platform A Terraform module for deploying a Panorama instance in the Google Cloud Platform. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/panorama) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/panorama) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/panorama) ## Usage diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/vmseries.md b/products/terraform/docs/swfw/gcp/vmseries/modules/vmseries.md index 3ea60ceb6..449dff1aa 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/vmseries.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/vmseries.md @@ -24,7 +24,7 @@ When troubleshooting you can use this module also with a good ol' Linux image. I - One cannot connect to `nic1` of Linux, because GCP DHCP doesn't ever furnish it with a default route. Connect to the primary interface (the `nic0`) for both data traffic and management traffic. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/vmseries) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vmseries) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/vmseries) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/vpc-peering.md b/products/terraform/docs/swfw/gcp/vmseries/modules/vpc-peering.md index f5d54e4d0..4c16df957 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/vpc-peering.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/vpc-peering.md @@ -22,7 +22,7 @@ The module allows to create VPC peering between two networks in both directions. By default, no routes are exported/imported for each direction, every option has to be explicitely enabled by setting appropriate value to `true`. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/vpc-peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/vpc-peering) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc-peering) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/vpc-peering) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/vpc.md b/products/terraform/docs/swfw/gcp/vmseries/modules/vpc.md index 72919d4c4..f4b313968 100644 --- a/products/terraform/docs/swfw/gcp/vmseries/modules/vpc.md +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/vpc.md @@ -29,7 +29,7 @@ Any existing networks/subnetworks can work equally well, independent on how they For Terraform 0.13+, a viable alternative is to use [Goggle-authored Terraform modules](https://registry.terraform.io/modules/terraform-google-modules/network) and employ `for_each` or `count` parameters when needed. -[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/examples/vpc) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/examples/vpc) +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpc) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/vpc) ## Reference diff --git a/products/terraform/docs/swfw/gcp/vmseries/modules/vpn.md b/products/terraform/docs/swfw/gcp/vmseries/modules/vpn.md new file mode 100644 index 000000000..1f1ede24d --- /dev/null +++ b/products/terraform/docs/swfw/gcp/vmseries/modules/vpn.md @@ -0,0 +1,270 @@ +--- +hide_title: true +id: vpn +keywords: +- pan-os +- panos +- firewall +- configuration +- terraform +- vmseries +- vm-series +- gcp +pagination_next: null +pagination_prev: null +sidebar_label: Vpn +title: VPN +--- + +# VPN + +This module makes it easy to deploy either GCP-to-GCP or GCP-to-On-prem VPN using [Cloud HA VPN](https://cloud.google.com/vpn/docs/concepts/overview#ha-vpn) including HA VPN Gateway itself. VPN includes one or more VPN instances (connections). + +Each created VPN instance is represented by 1..4 VPN tunnels that taget remote VPN gateway(s) located in a single remote location. Remote VPN gateway(s) might have singe IP address (`redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT"`) or 2 IP addresses (`redundancy_type = "TWO_IPS_REDUNDANCY"`). + +[![GitHub Logo](/img/view_on_github.png)](https://github.com/PaloAltoNetworks/terraform-google-vmseries-modules/tree/main/modules/vpn) [![Terraform Logo](/img/view_on_terraform_registry.png)](https://registry.terraform.io/modules/PaloAltoNetworks/vmseries-modules/google/latest/submodules/vpn) + +## Example + +```hcl +data "google_compute_network" "test" { + name = "" + project = "" +} + +module "vpn" { + source = "../../../modules/vpn" + + project = "" + region = "us-central1" + + vpn_gateway_name = "my-test-gateway" + router_name = "my-test-router" + network = data.google_compute_network.test.self_link + + vpn_config = { + router_asn = 65000 + local_network = "vpc-vpn" + + router_advertise_config = { + ip_ranges = { + "10.10.0.0/16" : "GCP range 1" + } + mode = "CUSTOM" + groups = null + } + + instances = { + vpn-to-onprem1 = { + name = "vpn-to-onprem1", + peer_external_gateway = { + redundancy_type = "SINGLE_IP_INTERNALLY_REDUNDANT" + interfaces = [{ + id = 0 + ip_address = "1.1.1.1" + }] + }, + tunnels = { + remote0 = { + bgp_peer = { + address = "169.254.1.2" + asn = 65001 + } + bgp_peer_options = null + bgp_session_range = "169.254.1.1/30" + ike_version = 2 + vpn_gateway_interface = 0 + peer_external_gateway_interface = 0 + shared_secret = "secret" + } + remote1 = { + bgp_peer = { + address = "169.254.1.6" + asn = 65001 + } + bgp_peer_options = null + bgp_session_range = "169.254.1.5/30" + ike_version = 2 + vpn_gateway_interface = 1 + peer_external_gateway_interface = null + shared_secret = "secret" + } + } + } + vpn-to-onprem2 = { + name = "vpn-to-onprem2", + peer_external_gateway = { + redundancy_type = "TWO_IPS_REDUNDANCY" + interfaces = [{ + id = 0 + ip_address = "3.3.3.3" + }, { + id = 1 + ip_address = "4.4.4.4" + }] + }, + tunnels = { + remote0 = { + bgp_peer = { + address = "169.254.2.2" + asn = 65002 + } + bgp_peer_options = null + bgp_session_range = "169.254.2.1/30" + ike_version = 2 + vpn_gateway_interface = 0 + peer_external_gateway_interface = 0 + shared_secret = "secret" + } + remote1 = { + bgp_peer = { + address = "169.254.2.6" + asn = 65002 + } + bgp_peer_options = null + bgp_session_range = "169.254.2.5/30" + ike_version = 2 + vpn_gateway_interface = 1 + peer_external_gateway_interface = 1 + shared_secret = "secret" + } + } + } + vpn-to-gcp = { + name = "vpn-to-gcp", + + peer_gcp_gateway = "https://www.googleapis.com/compute/v1/projects//regions//vpnGateways/" + + tunnels = { + remote0 = { + bgp_peer = { + address = "169.254.3.2" + asn = 65003 + } + bgp_peer_options = null + bgp_session_range = "169.254.3.1/30" + ike_version = 2 + vpn_gateway_interface = 0 + peer_external_gateway_interface = null + shared_secret = "secret" + } + remote1 = { + bgp_peer = { + address = "169.254.3.6" + asn = 65003 + } + bgp_peer_options = null + bgp_session_range = "169.254.3.5/30" + ike_version = 2 + vpn_gateway_interface = 1 + peer_external_gateway_interface = 1 + shared_secret = "secret" + } + } + } + } + } +} +``` + +## Reference + +### Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2, < 2.0 | +| [google](#requirement\_google) | >= 4.58 | + +### Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | >= 4.58 | +| [google-beta](#provider\_google-beta) | n/a | +| [random](#provider\_random) | n/a | + +### Modules + +No modules. + +### Resources + +| Name | Type | +|------|------| +| [google-beta_google_compute_vpn_tunnel.tunnels](https://registry.terraform.io/providers/hashicorp/google-beta/latest/docs/resources/google_compute_vpn_tunnel) | resource | +| [google_compute_external_vpn_gateway.external_gateway](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_external_vpn_gateway) | resource | +| [google_compute_ha_vpn_gateway.ha_gateway](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ha_vpn_gateway) | resource | +| [google_compute_router.router](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_router) | resource | +| [google_compute_router_interface.router_interface](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_router_interface) | resource | +| [google_compute_router_peer.bgp_peer](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_router_peer) | resource | +| [random_id.secret](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource | + +### Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [labels](#input\_labels) | Labels for VPN components | `map(string)` | `{}` | no | +| [network](#input\_network) | VPC network ID that should be used for deployment | `string` | n/a | yes | +| [project](#input\_project) | n/a | `string` | `null` | no | +| [region](#input\_region) | Region to deploy VPN gateway in | `string` | n/a | yes | +| [router\_name](#input\_router\_name) | Cloud router name. The router is created by the module | `string` | `null` | no | +| [vpn\_config](#input\_vpn\_config) | VPN configuration from GCP to on-prem or from GCP to GCP.
If you'd like secrets to be randomly generated set `shared_secret` to empty string ("").

Example:
vpn\_config = {
router\_asn = 65000
local\_network = "vpc-vpn"

router\_advertise\_config = {
ip\_ranges = {
"10.10.0.0/16" : "GCP range 1"
}
mode = "CUSTOM"
groups = null
}

instances = {
vpn-to-onprem = {
name = "vpn-to-onprem",
peer\_external\_gateway = {
redundancy\_type = "TWO\_IPS\_REDUNDANCY"
interfaces = [{
id = 0
ip\_address = "1.1.1.1"
}, {
id = 1
ip\_address = "2.2.2.2"
}]
},
tunnels = {
remote0 = {
bgp\_peer = {
address = "169.254.1.2"
asn = 65001
}
bgp\_peer\_options = null
bgp\_session\_range = "169.254.1.1/30"
ike\_version = 2
vpn\_gateway\_interface = 0
peer\_external\_gateway\_interface = 0
shared\_secret = "secret"
}
remote1 = {
bgp\_peer = {
address = "169.254.1.6"
asn = 65001
}
bgp\_peer\_options = null
bgp\_session\_range = "169.254.1.5/30"
ike\_version = 2
vpn\_gateway\_interface = 1
peer\_external\_gateway\_interface = 1
shared\_secret = "secret"
}
}
}
}
}
| `any` | n/a | yes | +| [vpn\_gateway\_name](#input\_vpn\_gateway\_name) | VPN gateway name. Gateway created by the module | `string` | n/a | yes | + +### Outputs + +| Name | Description | +|------|-------------| +| [random\_secret](#output\_random\_secret) | HA VPN IPsec tunnels secret that has been randomly generated | +| [vpn\_gw\_local\_address\_1](#output\_vpn\_gw\_local\_address\_1) | HA VPN gateway IP address 1 | +| [vpn\_gw\_local\_address\_2](#output\_vpn\_gw\_local\_address\_2) | HA VPN gateway IP address 2 | +| [vpn\_gw\_name](#output\_vpn\_gw\_name) | HA VPN gateway name | +| [vpn\_gw\_self\_link](#output\_vpn\_gw\_self\_link) | HA VPN gateway self\_link | + + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.2, < 2.0 | +| [google](#requirement\_google) | == 4.58 | + +## Providers + +| Name | Version | +|------|---------| +| [google](#provider\_google) | == 4.58 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [vpn\_ha](#module\_vpn\_ha) | terraform-google-modules/vpn/google | 3.0.1 | + +## Resources + +| Name | Type | +|------|------| +| [google_compute_ha_vpn_gateway.ha_gateway](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_ha_vpn_gateway) | resource | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [project](#input\_project) | n/a | `string` | `null` | no | +| [region](#input\_region) | Region to deploy VPN gateway in | `string` | n/a | yes | +| [vpc\_network\_id](#input\_vpc\_network\_id) | VPC network ID that should be used for deployment | `string` | n/a | yes | +| [vpn](#input\_vpn) | VPN configuration from GCP to on-prem or from GCP to GCP.
If you'd like secrets to be randomly generated set `shared_secret` to empty string ("").

Example:
vpn = {
router\_asn = 65000
local\_network = "vpc-vpn"

router\_advertise\_config = {
ip\_ranges = {
"10.10.0.0/16" : "GCP range 1"
}
mode = "CUSTOM"
groups = null
}

instances = {
vpn-to-onprem = {
name = "vpn-to-onprem",
peer\_external\_gateway = {
redundancy\_type = "TWO\_IPS\_REDUNDANCY"
interfaces = [{
id = 0
ip\_address = "1.1.1.1"
}, {
id = 1
ip\_address = "2.2.2.2"
}]
},
tunnels = {
remote0 = {
bgp\_peer = {
address = "169.254.1.2"
asn = 65001
}
bgp\_peer\_options = null
bgp\_session\_range = "169.254.1.1/30"
ike\_version = 2
vpn\_gateway\_interface = 0
peer\_external\_gateway\_interface = 0
shared\_secret = "secret"
}
remote1 = {
bgp\_peer = {
address = "169.254.1.6"
asn = 65001
}
bgp\_peer\_options = null
bgp\_session\_range = "169.254.1.5/30"
ike\_version = 2
vpn\_gateway\_interface = 1
peer\_external\_gateway\_interface = 1
shared\_secret = "secret"
}
}
}
}
| `any` | n/a | yes | +| [vpn\_gateway\_name](#input\_vpn\_gateway\_name) | VPN gateway name | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [local\_ipsec\_gw2\_address\_2](#output\_local\_ipsec\_gw2\_address\_2) | HA VPN gateway IP address 2 | +| [local\_ipsec\_gw\_address\_1](#output\_local\_ipsec\_gw\_address\_1) | HA VPN gateway IP address 1 | +| [random\_secrets\_map](#output\_random\_secrets\_map) | HA VPN IPsec tunnels secrets that were randomly generated | +| [vpn\_gateway\_name](#output\_vpn\_gateway\_name) | HA VPN gateway name | +| [vpn\_gateway\_self\_link](#output\_vpn\_gateway\_self\_link) | HA VPN gateway self\_link | + \ No newline at end of file

;Hp+-DL}1hOrg@{{K6G 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 [enable\_zones](#input\_enable\_zones) | If `true`, enable zone support for resources. | `bool` | `true` | no | | [vnets](#input\_vnets) | A map defining VNETs.

For detailed documentation on each property refer to [module documentation](../../modules/vnet)

- `name` : A name of a VNET.
- `create_virtual_network` : (default: `true`) when set to `true` will create a VNET, `false` will source an existing VNET, in both cases the name of the VNET is specified with `name`
- `address_space` : a list of CIDRs for VNET
- `resource_group_name` : (default: current RG) a name of a Resource Group in which the VNET will reside

- `create_subnets` : (default: `true`) if true, create the Subnets inside the Virtual Network, otherwise use pre-existing subnets
- `subnets` : map of Subnets to create

- `network_security_groups` : map of Network Security Groups to create
- `route_tables` : map of Route Tables to create. | `any` | n/a | yes | | [natgws](#input\_natgws) | A map defining Nat Gateways.

Please note that a NatGW is a zonal resource, this means it's always placed in a zone (even when you do not specify one explicitly). Please refer to Microsoft documentation for notes on NatGW's zonal resiliency.

Following properties are supported:

- `name` : a name of the newly created NatGW.
- `create_natgw` : (default: `true`) create or source (when `false`) an existing NatGW. Created or sourced: the NatGW will be assigned to a subnet created by the `vnet` module.
- `resource_group_name : name of a Resource Group hosting the NatGW (newly create or the existing one).
- `zone` : Availability Zone in which the NatGW will be placed, when skipped AzureRM will pick a zone.
- `idle\_timeout` : connection IDLE timeout in minutes, for newly created resources
- `vnet\_key` : a name (key value) of a VNET defined in `var.vnets` that hosts a subnet this NatGW will be assigned to.
- `subnet\_keys` : a list of subnets (key values) the NatGW will be assigned to, defined in `var.vnets` for a VNET described by `vnet\_name`.
- `create\_pip` : (default: `true`) create a Public IP that will be attached to a NatGW
- `existing\_pip\_name` : when `create\_pip` is set to `false`, source and attach and existing Public IP to the NatGW
- `existing\_pip\_resource\_group\_name` : when `create\_pip` is set to `false`, name of the Resource Group hosting the existing Public IP
- `create\_pip\_prefix` : (default: `false`) create a Public IP Prefix that will be attached to the NatGW.
- `pip\_prefix\_length` : length of the newly created Public IP Prefix, can bet between 0 and 31 but this actually supported value depends on the Subscription.
- `existing\_pip\_prefix\_name` : when `create\_pip\_prefix` is set to `false`, source and attach and existing Public IP Prefix to the NatGW
- `existing\_pip\_prefix\_resource\_group\_name` : when `create\_pip\_prefix` is set to `false`, name of the Resource Group hosting the existing Public IP Prefix.

Example:
`