I'm exploring Terraform for automated creation of Palo Alto firewall security rules using the panos_security_policy resource.
Having all security rules like this in the main.tf works as expected when adding / modifying / deleting the rules.
resource "panos_security_policy" "rules" {
rule {
name = "Rule-1"
audit_comment = "Initial config"
source_zones = [panos_zone.dmz.name]
source_addresses = [panos_panorama_address_group.addgrp1.name]
source_users = ["any"]
destination_zones = [panos_zone.internet.name]
destination_addresses = ["any"]
applications = ["ssh"]
services = ["application-default"]
categories = ["any"]
action = "allow"
}
rule {
name = "Rule-2"
audit_comment = "Initial config"
source_zones = [panos_zone.dmz.name]
source_addresses = [panos_panorama_address_group.addgrp1.name]
source_users = ["any"]
destination_zones = [panos_zone.internet.name]
destination_addresses = ["any"]
applications = ["any"]
services = ["any"]
categories = ["any"]
action = "deny"
}
lifecycle {
create_before_destroy = true
}
}
But I dont want to keep all details about the rules in the main.tf Especialy if the rulebase contains hundreds of rules. I want to keep them in the variables file. I've created something like this:
resource "panos_security_policy" "CreateSecurityRules" {
for_each = var.securityRules
rule {
name = each.value.name
source_zones = each.value.source_zones
source_addresses = each.value.source_addresses
source_users = each.value.source_users
destination_zones = each.value.destination_zones
destination_addresses = each.value.destination_addresses
applications = each.value.applications
services = each.value.services
categories = each.value.categories
action = each.value.action
}
lifecycle {
create_before_destroy = true
}
}
variable securityRules {
type = map(object({
name = string
source_zones = list(string)
source_addresses = list(string)
source_users = list(string)
destination_zones = list(string)
destination_addresses = list(string)
applications = list(string)
services = list(string)
categories = list(string)
action = string
}))
}
rule1 = {
name = "First rule"
source_zones = ["Inside"]
source_addresses = ["any"]
source_users = ["any"]
destination_zones = ["Outside"]
destination_addresses = ["any"]
applications = ["any"]
services = ["application-default"]
categories = ["any"]
action = "allow"
}
rule2 = {
name = "Second rule"
source_zones = ["Inside"]
source_addresses = ["any"]
source_users = ["any"]
destination_zones = ["DMZ"]
destination_addresses = ["any"]
applications = ["any"]
services = ["application-default"]
categories = ["any"]
action = "allow"
}
rule3 = {
name = "Third rule"
source_zones = ["DMZ"]
source_addresses = ["any"]
source_users = ["any"]
destination_zones = ["Outside"]
destination_addresses = ["any"]
applications = ["any"]
services = ["application-default"]
categories = ["any"]
action = "allow"
}
}
Unfortunately, I don't have any luck with this code. Initially, Terraform manages to create the rules on the firewall, but not in the right order - something which is very important. If I rerun Terraform again, the expectation is that no changes are needed, but it does make some - either delete some rules or assign null values.
I assume the issue is with the logic behind the map looping (p.s. I tried with lists as well, again with no success).
Could you please help me solve this problem?
Thank you for your response, but the solution here was to use "Dynamic Block":
resource "panos_security_policy" "CreateSecurityRules" {
dynamic "rule" {
for_each = var.securityRules
content {
name = rule.value.name
description = rule.value.description
audit_comment = rule.value.audit_comment
source_zones = rule.value.source_zones
source_addresses = rule.value.source_addresses
source_users = rule.value.source_users
destination_zones = rule.value.destination_zones
destination_addresses = rule.value.destination_addresses
applications = rule.value.applications
services = rule.value.services
categories = rule.value.categories
group = rule.value.group
action = rule.value.action
}
}
lifecycle {
create_before_destroy = true
}
}