Palo Alto Networks Panorama example
A Terraform example for deploying a one or more instances of Panorama in one or more VPCs in AWS Cloud.
NOTE: Panorama will take a serveral minutes to bootup during the initial setup.
Topology
The topology consists of :
- VPC with 2 subnets in 2 availability zones
- 2 Panorama instances with a public IP addresses and static private IP addresses

PAN-OS software version
Example was prepared for PAN-OS in 10.2.3 version as described in AWS Deployment Guide. For more information about recommended software versions see Support PAN-OS Software Release Guidance.
Prerequisites
- Prepare panorama license
- Configure the Terraform AWS provider
Usage
- Access AWS CloudShell or any other environment which has access to your AWS account
- Clone the repository:
git clone https://github.com/PaloAltoNetworks/terraform-aws-swfw-modules - Go to Panorama example:
cd terraform-aws-swfw-modules/examples/panorama_standalone - Copy
example.tfvarsintoterraform.tfvars - Review
terraform.tfvarsfile, especially with lines commented by# TODO: update here - Initialize Terraform:
terraform init - Prepare plan:
terraform plan - Deploy infrastructure:
terraform apply -auto-approve - Destroy infrastructure if needed:
terraform destroy -auto-approve
Configuration
- Get public IP for each Panorama instance(s):
terraform output panorama_public_ips - Connect to the Panorama instance(s) via SSH using your associated private key:
ssh admin@x.x.x.x -i /PATH/TO/YOUR/KEY/id_rsa - Set
adminpassword:
> configure
# set mgt-config users admin password
Access Panorama
Use a web browser to access https://x.x.x.x and login with admin and your previously configured password
Reference
Requirements
| Name | Version |
|---|---|
| terraform | >= 1.5.0, < 2.0.0 |
| aws | ~> 5.17 |
Providers
| Name | Version |
|---|---|
| aws | ~> 5.17 |
Modules
| Name | Source | Version |
|---|---|---|
| panorama | ../../modules/panorama | n/a |
| subnet_sets | ../../modules/subnet_set | n/a |
| vpc | ../../modules/vpc | n/a |
| vpc_routes | ../../modules/vpc_route | n/a |
Resources
| Name | Type |
|---|---|
| aws_iam_instance_profile.this | resource |
| aws_iam_role.this | resource |
| aws_iam_role_policy.this | resource |
| aws_caller_identity.this | data source |
| aws_partition.this | data source |
Inputs
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| global_tags | Global tags configured for all provisioned resources | map(any) | {} | no |
| name_prefix | Prefix used in names for the resources (VPCs, EC2 instances, autoscaling groups etc.) | string | "" | no |
| 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)- subnet_group - key of the subnet group- 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 instanceExample:{ 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" subnet_group = "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 subnet_group = string security_group = string create_public_ip = bool }) ebs = object({ volumes = list(object({ name = string ebs_device_name = string ebs_size = string })) encrypted = bool kms_key_alias = string }) iam = object({ create_role = bool role_name = string }) enable_imdsv2 = bool })) | {} | no |
| region | AWS region used to deploy whole infrastructure | string | n/a | yes |
| 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 | 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- subnet_group: identity of the same purpose subnets group such as management- routes: map of routes with properties:- vpc: key of VPC- subnet_group - key of the subnet group- 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_endpointExample:{ 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", subnet_group = "mgmt" } "10.100.64.0/24" = { az = "eu-central-1b", subnet_group = "mgmt" } } routes = { mgmt_default = { vpc = "security_vpc subnet_group = "mgmt" to_cidr = "0.0.0.0/0" next_hop_key = "security_vpc" next_hop_type = "internet_gateway" } } } } | 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 = optional(string) to_port = optional(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 subnet_group = string nacl = optional(string) create_subnet = optional(bool, true) create_route_table = optional(bool, true) existing_route_table_id = optional(string) associate_route_table = optional(bool, true) route_table_name = optional(string) local_tags = optional(map(string), {}) })) routes = map(object({ vpc = string subnet_group = string to_cidr = string next_hop_key = string next_hop_type = string })) })) | {} | no |
Outputs
| Name | Description |
|---|---|
| panorama_private_ips | Map of private IPs for Panorama instances. |
| panorama_public_ips | Map of public IPs for Panorama instances. |
| panorama_urls | Map of URLs for Panorama instances. |