Skip to main content

Information Gathering Tasks

With this Terraform code, you will gather information from a PAN-OS next-generation firewall. This is useful on its own in order to gather data, but the gathered data can also be used to feed into other Terraform operations.

Assumptions

This tutorial/guide assumes:

  • you have a working installation of Terraform (see example instructions here)
  • you have working connectivity to the firewall and/or Panorama
  • you have administrative credentials capable of performing the relevant operations on the firewall and/or Panorama

Important - Work in a Lab Environment First

With all of the tutorials and guides presented on this website, please ensure that you attempt the tasks in a lab or a similar safe and non-production environment first. In public cloud scenarios, this should be a non-production cloud account which contains no production assets or data. Confirm the tasks behave as expected and perform the operations you require, before using them in production or other live environments.

Getting Terraform Ready

This Terraform operation gathers a number of system information items from a PAN-OS next-generation firewall.

  1. Create a file called get-security-policies.tf and paste in the following content:
terraform {
required_providers {
panos = {
source = "paloaltonetworks/panos"
version = "~> 1.11.0"
}
}
}

provider "panos" {
hostname = var.panos_hostname
username = var.panos_username
password = var.panos_password
}

variable "panos_hostname" {
type = string
default = "192.168.1.1"
}

variable "panos_username" {
type = string
default = "admin"
}

variable "panos_password" {
type = string
default = "admin"
}
  1. Edit the variable sections of the file, replacing the values for panos_hostname, panos_username and panos_password with relevant values for your environment. For example:
.
.

variable "panos_hostname" {
type = string
default = "172.16.14.5"
}

variable "panos_username" {
type = string
default = "firewall_admin"
}

variable "panos_password" {
type = string
default = "a_pa55word_l1ke_th1s"
}
.
.
caution

The PAN-OS credentials are being stored within the code and on disk unencrypted. This is not a production-level solution, and other solutions for managing secrets should be considered for real-world deployments. Hashicorp (owners of Terraform) and many others have solutions for this.

  1. Initialize Terraform with the following command, which will download the PAN-OS provider:
terraform init
  1. The output should look something like this:
Initializing the backend...

Initializing provider plugins...
- Finding paloaltonetworks/panos versions matching "~> 1.11.0"...
- Installing paloaltonetworks/panos v1.11.0...
- Installed paloaltonetworks/panos v1.11.0 (signed by a HashiCorp partner, key ID D5D93F98EFA33E83)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Gathering the rulebase information

  1. First you will gather information about the rulebase as a whole. When there are multiple rulebases in a Panorama-enabled architecture, this step is especially important. Add the following code to the bottom of the existing get-security-policies.tf file:
data "panos_security_rules" "security_policy_rules" {}

output "security_policy_rules" {
value = data.panos_security_rules.security_policy_rules
}

output "number_of_security_rules" {
value = data.panos_security_rules.security_policy_rules.total
}

output "security_policy_rulenames" {
value = data.panos_security_rules.security_policy_rules.listing
}
  1. Instruct Terraform to inspect the firewall and gather data by executing the following command:
terraform plan
  1. The output should look something like this (the order may differ):
Changes to Outputs:
+ security_policy_rules = {
+ device_group = "shared"
+ id = "shared:pre-rulebase:vsys1"
+ listing = [
+ "RULE1",
+ "RULE2",
+ "Test rule",
+ "example rule 1",
+ "example rule 2",
]
+ rulebase = "pre-rulebase"
+ total = 5
+ vsys = "vsys1"
}
+ number_of_security_rules = 5
+ security_policy_rulenames = [
+ "RULE1",
+ "RULE2",
+ "Test rule",
+ "example rule 1",
+ "example rule 2",
]

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Gathering the rule details

  1. Next you will get the details of the rules themselves; for each rule, you will get the source, the destination, the action, etc. You will use the data gathered in the first step (data.panos_security_rules.security_policy_rules.listing) as an input to this step. Using that information, the list of rulenames, with the for_each function, you will be able to gather the detailed information about each rule in the rulebase. Add the following code to the bottom of the existing get-security-policies.tf file:
data "panos_security_rule" "example" {
for_each = toset(data.panos_security_rules.security_policy_rules.listing)
name = each.key
}

output "rule_output" {
value = data.panos_security_rule.example
}
  1. Instruct Terraform to inspect the firewall and gather data by executing the following command:
terraform plan
  1. The output should look something like this (truncated for brevity):
Changes to Outputs:
+ security_policy_rules = {
+ device_group = "shared"
+ id = "shared:pre-rulebase:vsys1"
+ listing = [
+ "RULE1",
+ "RULE2",
+ "Test rule",
+ "example rule 1",
+ "example rule 2",
]
+ rulebase = "pre-rulebase"
+ total = 5
+ vsys = "vsys1"
}
+ number_of_security_rules = 5
+ security_policy_rulenames = [
+ "RULE1",
+ "RULE2",
+ "Test rule",
+ "example rule 1",
+ "example rule 2",
]
+ rule_output = {
+ RULE1 = {
+ device_group = "shared"
+ id = "shared:pre-rulebase:vsys1:RULE1"
+ name = "RULE1"
+ rule = [
+ {
+ action = "allow"
+ applications = [
+ "any",
]
+ audit_comment = ""
+ categories = [
+ "any",
]
+ data_filtering = ""
+ description = ""
+ destination_addresses = [
+ "any",
]
+ destination_devices = [
+ "any",
]
+ destination_zones = [
+ "any",
]
+ disable_server_response_inspection = false
+ disabled = false
+ file_blocking = ""
+ group = ""
+ group_tag = ""
+ hip_profiles = []
+ icmp_unreachable = false
+ log_end = true
+ log_setting = ""
+ log_start = false
+ name = "RULE1"
+ negate_destination = false
+ negate_source = false
+ negate_target = false
+ schedule = ""
+ services = [
+ "application-default",
]
+ source_addresses = [
+ "any",
]
+ source_devices = [
+ "any",
]
+ source_users = [
+ "any",
]
+ source_zones = [
+ "any",
]
+ spyware = ""
+ tags = []
+ target = []
+ type = ""
+ url_filtering = ""
+ uuid = "11df5a2a-1d93-48f7-8d7e-50aab84ee0e4"
+ virus = ""
+ vulnerability = ""
+ wildfire_analysis = ""
},
]
+ rulebase = "pre-rulebase"
+ vsys = "vsys1"
}
+ RULE2 = {
+ device_group = "shared"
+ id = "shared:pre-rulebase:vsys1:RULE2"
+ name = "RULE2"
+ rule = [
+ {
+ action = "allow"
+ applications = [
+ "any",
]
+ audit_comment = ""
.
.
.
.
.
+ uuid = "f5140c7c-b28a-4786-bdf9-e02eb54084c9"
+ virus = ""
+ vulnerability = ""
+ wildfire_analysis = ""
},
]
+ rulebase = "pre-rulebase"
+ vsys = "vsys1"
}
}

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

Final code

Putting all the sections together, the code in entirety looks like this:

# Define required Terraform providers
terraform {
required_providers {
panos = {
source = "paloaltonetworks/panos"
version = "~> 1.11.0"
}
}
}

# Configure the PAN-OS provider for Terraform
provider "panos" {
hostname = var.panos_hostname
username = var.panos_username
password = var.panos_password
}

variable "panos_hostname" {
type = string
default = "vm-series-test.jamoi.xyz"
}

variable "panos_username" {
type = string
default = "admin"
}

variable "panos_password" {
type = string
default = "Commit123!"
}


# Define the data we want to gather, the rules in the security policy
data "panos_security_rules" "security_policy_rules" {}

# Output data for the rulebase in its entirety
output "security_policy_rules" {
value = data.panos_security_rules.security_policy_rules
}

# Output the number of rules in the rulebase
output "number_of_security_rules" {
value = data.panos_security_rules.security_policy_rules.total
}

# Output just the names of the rules
output "security_policy_rulenames" {
value = data.panos_security_rules.security_policy_rules.listing
}


# Use the names of the rules from the previous data gathering, and gather the detailed information for each rule
data "panos_security_rule" "example" {
for_each = toset(data.panos_security_rules.security_policy_rules.listing)
name = each.key
}

# Out the detailed information of each rule in the rulebase
output "rule_output" {
value = data.panos_security_rule.example
}

Closing notes

  • Note that when working with Terraform at scale and in production, the code would likely be split into several .tf files for the provider section, the variable section, and the rest of the code. For the purposes of this learning tutorial, keeping the code in a single file works fine.
  • The PAN-OS credentials are being stored within the code and on disk unencrypted. This is not a production-level solution, and other solutions for managing secrets should be considered for real-world deployments. Hashicorp (owners of Terraform) and many others have solutions for this.
  • Almost all values were defined within the code; names of configuration items, IP addresses, and more. This is very suitable for a learning tutorial, but this approach does not scale well in production, and using variables instead is something to consider as you operationalize Terraform within your organization.