Я изучаю Terraform для автоматического создания правил NAT на брандмауэре Пало-Альто, используя ресурс panos_nat_rule_group.
Правило NAT имеет несколько вариантов «Переведенного пакета». Мы можем преобразовать IP-адрес «Источника» и/или «Назначения» пакета. Кроме того, существует несколько вариантов перевода этих IP-адресов.
Можно ли создать переменную, включающую все возможные параметры, например:
variable natRules {
description = "Variable for the NAT rules"
type = list(object({
name = string
description = string
audit_comment = string
original_packet = object({
source_zones = list(string)
destination_zone = string
destination_interface = string
service = string
source_addresses = list(string)
destination_addresses = list(string)
})
translated_packet = object({
source = object({
static_ip = object({
translated_address = string
bi_directional = bool
})
dynamic_ip_and_port = object({
translated_address = object({
translated_addresses = list(string)
})
interface_address = object({
interface = string
ip_address = string
})
})
dynamic_ip = object({
translated_addresses = list(string)
})
})
destination = object({
static_translation = object({
address = string
port = number
})
dynamic_translation = object({
address = string
port = number
distribution = string
})
})
})
}))
}
Затем в «terraform.tfvars» поместите значения различных правил NAT, но заполняйте только то, что необходимо для конкретного правила. Например, если мы хотим преобразовать только исходный IP-адрес в определенный статический IP-адрес, чтобы заполнить в переменной только необходимые объекты, а остальные оставить пустыми. Если мы хотим сделать еще один перевод, снова поместите только необходимые значения.
natRules = [
{
name = "Static-IP-Port"
description = "Test nat rule"
audit_comment = ""
original_packet = {
source_zones = ["Inside"]
destination_zone = "Outside"
destination_interface = "any"
service = "any"
source_addresses = ["any"]
destination_addresses = ["any"]
}
translated_packet = {
source = {
static_ip = {
translated_address = "10.1.1.1"
bi_directional = false
}
dynamic_ip_and_port = {
translated_address = {
translated_addresses = [""]
}
interface_address = {
interface = ""
ip_address = ""
}
}
dynamic_ip = {
translated_addresses = [""]
}
}
destination = {
static_translation = {
address = ""
port = null
}
dynamic_translation = {
address = ""
port = null
distribution = ""
}
}
}
},
{
name = "Dynamic-IP-Port"
description = "Test nat rule"
audit_comment = ""
original_packet = {
source_zones = ["Inside"]
destination_zone = "Outside"
destination_interface = "any"
service = "any"
source_addresses = ["any"]
destination_addresses = ["any"]
}
translated_packet = {
source = {
static_ip = {
translated_address = ""
bi_directional = false
}
dynamic_ip_and_port = {
translated_address = {
translated_addresses = [""]
}
interface_address = {
interface = "ethernet1/1"
ip_address = "11.11.11.1/24"
}
}
dynamic_ip = {
translated_addresses = [""]
}
}
destination = {
static_translation = {
address = ""
port = null
}
dynamic_translation = {
address = ""
port = null
distribution = ""
}
}
}
}
]
Затем в main.tf должен быть только один ресурс, который будет проверять, какие переменные установлены, и на основе этого применять только эту часть ресурса. Какую условную проверку можно реализовать?
resource "panos_nat_rule_group" "CreateNATRules" {
dynamic "rule" {
for_each = var.natRules
content {
name = rule.value.name
description = rule.value.description
audit_comment = rule.value.audit_comment
original_packet {
source_zones = rule.value.original_packet.source_zones
destination_zone = rule.value.original_packet.destination_zone
destination_interface = rule.value.original_packet.destination_interface
service = rule.value.original_packet.service
source_addresses = rule.value.original_packet.source_addresses
destination_addresses = rule.value.original_packet.destination_addresses
}
translated_packet {
source {
static_ip {
translated_address = rule.value.translated_packet.source.static_ip.translated_address
bi_directional = rule.value.translated_packet.source.static_ip.bi_directional
}
dynamic_ip_and_port {
interface_address {
interface = rule.value.translated_packet.source.dynamic_ip_and_port.interface_address.interface
ip_address = rule.value.translated_packet.source.dynamic_ip_and_port.interface_address.ip_address
}
}
dynamic_ip {
translated_addresses = rule.value.translated_packet.source.dynamic_ip.translated_addresses
}
}
destination {
}
}
}
}
lifecycle {
create_before_destroy = true
}
}
В определении типа переменной добавьте необязательный модификатор к атрибутам объектов, которые не требуются в каждом сценарии, со значением по умолчанию, установленным на null
.
Затем в tfvars укажите только те значения, которые необходимы в конкретном случае использования. Не задавайте им пустые строки, не указывайте их вообще.
На уровне ресурса используйте вложенные динамические блоки с условием в операторе for_each
для перевода только необходимых значений:
for_each = <SOME_OBJECT_ATTRIBUTE> != null ? {SOME_MAP_FROM_VAR} : {}
Пустой {}
означает ничего не делать, если результат условия ложный.
Спасибо, это помогло!
variable natRules {
type = list(object({
name = string
description = string
audit_comment = string
original_packet = object({
source_zones = list(string)
destination_zone = string
destination_interface = string
service = string
source_addresses = list(string)
destination_addresses = list(string)
})
translated_packet = object({
source = object({
static_ip = optional(object({
translated_address = string
bi_directional = bool
}))
dynamic_ip_and_port = optional(object({
translated_address = optional(object({
translated_addresses = list(string)
}))
interface_address = optional(object({
interface = string
ip_address = string
}))
}))
dynamic_ip = optional(object({
translated_addresses = list(string)
}))
})
destination = object({
static_translation = optional(object({
address = string
port = optional(number)
}))
dynamic_translation = optional(object({
address = string
port = optional(number)
distribution = string
}))
})
})
}))
}
resource "panos_nat_rule_group" "CreateNATRules" {
dynamic "rule" {
for_each = var.natRules
content {
name = rule.value.name
description = rule.value.description
audit_comment = rule.value.audit_comment
original_packet {
source_zones = rule.value.original_packet.source_zones
destination_zone = rule.value.original_packet.destination_zone
destination_interface = rule.value.original_packet.destination_interface
service = rule.value.original_packet.service
source_addresses = rule.value.original_packet.source_addresses
destination_addresses = rule.value.original_packet.destination_addresses
}
translated_packet {
source {
dynamic "static_ip" {
for_each = rule.value.translated_packet.source.static_ip != null ? [rule.value.translated_packet.source.static_ip] : []
content {
translated_address = static_ip.value.translated_address
bi_directional = static_ip.value.bi_directional
}
}
dynamic "dynamic_ip_and_port" {
for_each = rule.value.translated_packet.source.dynamic_ip_and_port != null ? [rule.value.translated_packet.source.dynamic_ip_and_port] : []
content {
dynamic "translated_address" {
for_each = rule.value.translated_packet.source.dynamic_ip_and_port.translated_address != null ? [rule.value.translated_packet.source.dynamic_ip_and_port.translated_address] : []
content {
translated_addresses = dynamic_ip_and_port.value.translated_address.translated_addresses
}
}
dynamic "interface_address" {
for_each = rule.value.translated_packet.source.dynamic_ip_and_port.interface_address != null ? [rule.value.translated_packet.source.dynamic_ip_and_port.interface_address] : []
content {
interface = dynamic_ip_and_port.value.interface_address.interface
ip_address = dynamic_ip_and_port.value.interface_address.ip_address
}
}
}
}
dynamic "dynamic_ip" {
for_each = rule.value.translated_packet.source.dynamic_ip != null ? [rule.value.translated_packet.source.dynamic_ip] : []
content {
translated_addresses = dynamic_ip.value.translated_addresses
}
}
}
destination {
dynamic "static_translation" {
for_each = rule.value.translated_packet.destination.static_translation != null ? [rule.value.translated_packet.destination.static_translation] : []
content {
address = static_translation.value.address
port = static_translation.value.port
}
}
dynamic "dynamic_translation" {
for_each = rule.value.translated_packet.destination.dynamic_translation != null ? [rule.value.translated_packet.destination.dynamic_translation] : []
content {
address = dynamic_translation.value.address
port = dynamic_translation.value.port
distribution = dynamic_translation.value.distribution
}
}
}
}
}
}
}