Search code examples
terraform

Maintaining Palo Alto Security Policy with Terraform


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?


Solution

  • 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
    }
    

    }