From 7fdb3e956ec8ef275dfa4628c2827c04d2dc171d Mon Sep 17 00:00:00 2001 From: Jose Martinez Date: Thu, 26 Mar 2026 20:50:14 +0100 Subject: [PATCH 1/5] feat: configure static WAN1 IP for primary and spare MX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Añade recurso meraki_device_management_interface para configurar IP estática en el puerto WAN1 de ambos firewalls MX: - Primary: 213.229.159.145/28 (255.255.255.240), GW 213.229.159.147 - Spare: 213.229.159.146/28 (255.255.255.240), GW 213.229.159.147 Los seriales del MX deben reemplazarse en wan.auto.tfvars. Co-Authored-By: Claude Sonnet 4.6 --- modules/meraki-site/main.tf | 12 ++++++++++++ modules/meraki-site/variables.tf | 14 ++++++++++++++ sites/BCN01-LAB/main.tf | 3 ++- sites/BCN01-LAB/variables.tf | 13 +++++++++++++ sites/BCN01-LAB/wan.auto.tfvars | 22 ++++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 sites/BCN01-LAB/wan.auto.tfvars diff --git a/modules/meraki-site/main.tf b/modules/meraki-site/main.tf index be2a189..10c92e9 100755 --- a/modules/meraki-site/main.tf +++ b/modules/meraki-site/main.tf @@ -186,6 +186,18 @@ resource "meraki_appliance_l3_firewall_rules" "reglas_firewall" { rules = var.firewall_rules } +# 4b. Configuración WAN estática de los MX (primary y spare) +resource "meraki_device_management_interface" "mx_wan" { + for_each = { for mx in var.mx_wan_uplinks : mx.serial => mx } + + serial = each.key + interfaces_wan1_enabled = each.value.interfaces_wan1_enabled + wan1_static_ip = each.value.wan1_static_ip + wan1_static_subnet_mask = each.value.wan1_static_subnet_mask + wan1_static_gateway_ip = each.value.wan1_static_gateway_ip + wan1_static_dns = each.value.wan1_static_dns +} + # --- CONFIGURACIÓN SWITCHES (MS) --- # 5. Políticas de acceso 802.1X diff --git a/modules/meraki-site/variables.tf b/modules/meraki-site/variables.tf index ceb1403..8ecf07e 100755 --- a/modules/meraki-site/variables.tf +++ b/modules/meraki-site/variables.tf @@ -184,6 +184,20 @@ variable "stack_routing_interfaces" { description = "Interfaces L3 (SVIs) en stacks de switches para acceso de gestión al Dashboard de Meraki." } +# Configuración WAN de los firewalls MX (primary y spare) +variable "mx_wan_uplinks" { + type = list(object({ + serial = string + interfaces_wan1_enabled = optional(bool, true) + wan1_static_ip = optional(string, null) + wan1_static_subnet_mask = optional(string, null) + wan1_static_gateway_ip = optional(string, null) + wan1_static_dns = optional(list(string), null) + })) + default = [] + description = "Configuración de interfaz WAN1 estática para cada MX (primary y spare)." +} + # Puertos del firewall MX variable "appliance_ports" { type = list(object({ diff --git a/sites/BCN01-LAB/main.tf b/sites/BCN01-LAB/main.tf index c4f0b92..158389f 100755 --- a/sites/BCN01-LAB/main.tf +++ b/sites/BCN01-LAB/main.tf @@ -36,5 +36,6 @@ module "bcn01_lab" { switch_management_vlan = var.switch_management_vlan stack_routing_interfaces = var.stack_routing_interfaces appliance_ports = var.appliance_ports - wifi_password_psk = var.wifi_password_psk + mx_wan_uplinks = var.mx_wan_uplinks + wifi_password_psk = var.wifi_password_psk } diff --git a/sites/BCN01-LAB/variables.tf b/sites/BCN01-LAB/variables.tf index c1ba7c4..9802f2c 100755 --- a/sites/BCN01-LAB/variables.tf +++ b/sites/BCN01-LAB/variables.tf @@ -183,3 +183,16 @@ variable "appliance_ports" { default = [] description = "Configuración de puertos LAN del firewall MX." } + +variable "mx_wan_uplinks" { + type = list(object({ + serial = string + interfaces_wan1_enabled = optional(bool, true) + wan1_static_ip = optional(string, null) + wan1_static_subnet_mask = optional(string, null) + wan1_static_gateway_ip = optional(string, null) + wan1_static_dns = optional(list(string), null) + })) + default = [] + description = "Configuración WAN1 estática de los MX (primary y spare)." +} diff --git a/sites/BCN01-LAB/wan.auto.tfvars b/sites/BCN01-LAB/wan.auto.tfvars new file mode 100644 index 0000000..2303b6b --- /dev/null +++ b/sites/BCN01-LAB/wan.auto.tfvars @@ -0,0 +1,22 @@ +# Configuración WAN1 estática de los firewalls MX +# Los seriales se encuentran en: Dashboard > Security & SD-WAN > Appliance > Overview +mx_wan_uplinks = [ + { + # MX Primary + serial = "XXXX-XXXX-XXXX" # TODO: reemplazar con serial del MX primary + interfaces_wan1_enabled = true + wan1_static_ip = "213.229.159.145" + wan1_static_subnet_mask = "255.255.255.240" # /28 + wan1_static_gateway_ip = "213.229.159.147" + wan1_static_dns = ["8.8.8.8", "8.8.4.4"] + }, + { + # MX Spare (Warm Spare / HA) + serial = "YYYY-YYYY-YYYY" # TODO: reemplazar con serial del MX spare + interfaces_wan1_enabled = true + wan1_static_ip = "213.229.159.146" + wan1_static_subnet_mask = "255.255.255.240" # /28 + wan1_static_gateway_ip = "213.229.159.147" + wan1_static_dns = ["8.8.8.8", "8.8.4.4"] + }, +] From 5d0f0435038158137bc74259ecb83f41f336043a Mon Sep 17 00:00:00 2001 From: Jose Martinez Date: Thu, 26 Mar 2026 20:52:29 +0100 Subject: [PATCH 2/5] refactor: resolve MX serial by device name instead of hardcoded serial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Igual que con los switches, el serial del MX se resuelve dinámicamente usando data.meraki_network_devices (device_serials local). El tfvars ahora usa el campo 'name' en lugar de 'serial'. Co-Authored-By: Claude Sonnet 4.6 --- modules/meraki-site/main.tf | 6 ++++-- modules/meraki-site/variables.tf | 4 ++-- sites/BCN01-LAB/variables.tf | 4 ++-- sites/BCN01-LAB/wan.auto.tfvars | 11 ++++++----- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/meraki-site/main.tf b/modules/meraki-site/main.tf index 10c92e9..ce7a121 100755 --- a/modules/meraki-site/main.tf +++ b/modules/meraki-site/main.tf @@ -187,10 +187,12 @@ resource "meraki_appliance_l3_firewall_rules" "reglas_firewall" { } # 4b. Configuración WAN estática de los MX (primary y spare) +# El serial se resuelve dinámicamente a partir del nombre del dispositivo +# usando el mismo data source meraki_network_devices que ya se usa para los switches resource "meraki_device_management_interface" "mx_wan" { - for_each = { for mx in var.mx_wan_uplinks : mx.serial => mx } + for_each = { for mx in var.mx_wan_uplinks : mx.name => mx } - serial = each.key + serial = local.device_serials[each.key] interfaces_wan1_enabled = each.value.interfaces_wan1_enabled wan1_static_ip = each.value.wan1_static_ip wan1_static_subnet_mask = each.value.wan1_static_subnet_mask diff --git a/modules/meraki-site/variables.tf b/modules/meraki-site/variables.tf index 8ecf07e..e4a2489 100755 --- a/modules/meraki-site/variables.tf +++ b/modules/meraki-site/variables.tf @@ -187,7 +187,7 @@ variable "stack_routing_interfaces" { # Configuración WAN de los firewalls MX (primary y spare) variable "mx_wan_uplinks" { type = list(object({ - serial = string + name = string # Nombre del dispositivo en el Dashboard interfaces_wan1_enabled = optional(bool, true) wan1_static_ip = optional(string, null) wan1_static_subnet_mask = optional(string, null) @@ -195,7 +195,7 @@ variable "mx_wan_uplinks" { wan1_static_dns = optional(list(string), null) })) default = [] - description = "Configuración de interfaz WAN1 estática para cada MX (primary y spare)." + description = "Configuración de interfaz WAN1 estática para cada MX. El serial se resuelve automáticamente por nombre de dispositivo." } # Puertos del firewall MX diff --git a/sites/BCN01-LAB/variables.tf b/sites/BCN01-LAB/variables.tf index 9802f2c..965f785 100755 --- a/sites/BCN01-LAB/variables.tf +++ b/sites/BCN01-LAB/variables.tf @@ -186,7 +186,7 @@ variable "appliance_ports" { variable "mx_wan_uplinks" { type = list(object({ - serial = string + name = string # Nombre del dispositivo en el Dashboard interfaces_wan1_enabled = optional(bool, true) wan1_static_ip = optional(string, null) wan1_static_subnet_mask = optional(string, null) @@ -194,5 +194,5 @@ variable "mx_wan_uplinks" { wan1_static_dns = optional(list(string), null) })) default = [] - description = "Configuración WAN1 estática de los MX (primary y spare)." + description = "Configuración WAN1 estática de los MX. El serial se resuelve automáticamente por nombre de dispositivo." } diff --git a/sites/BCN01-LAB/wan.auto.tfvars b/sites/BCN01-LAB/wan.auto.tfvars index 2303b6b..6af2d8b 100644 --- a/sites/BCN01-LAB/wan.auto.tfvars +++ b/sites/BCN01-LAB/wan.auto.tfvars @@ -1,21 +1,22 @@ # Configuración WAN1 estática de los firewalls MX -# Los seriales se encuentran en: Dashboard > Security & SD-WAN > Appliance > Overview +# El nombre debe coincidir exactamente con el nombre del dispositivo en el Dashboard +# Dashboard > Security & SD-WAN > Appliance > nombre del dispositivo mx_wan_uplinks = [ { # MX Primary - serial = "XXXX-XXXX-XXXX" # TODO: reemplazar con serial del MX primary + name = "eqt-lab-fw01-mx01" # TODO: ajustar al nombre real en el Dashboard interfaces_wan1_enabled = true wan1_static_ip = "213.229.159.145" - wan1_static_subnet_mask = "255.255.255.240" # /28 + wan1_static_subnet_mask = "255.255.255.240" # /28 wan1_static_gateway_ip = "213.229.159.147" wan1_static_dns = ["8.8.8.8", "8.8.4.4"] }, { # MX Spare (Warm Spare / HA) - serial = "YYYY-YYYY-YYYY" # TODO: reemplazar con serial del MX spare + name = "eqt-lab-fw01-mx02" # TODO: ajustar al nombre real en el Dashboard interfaces_wan1_enabled = true wan1_static_ip = "213.229.159.146" - wan1_static_subnet_mask = "255.255.255.240" # /28 + wan1_static_subnet_mask = "255.255.255.240" # /28 wan1_static_gateway_ip = "213.229.159.147" wan1_static_dns = ["8.8.8.8", "8.8.4.4"] }, From 4a2eeb6c17b6c559089665ddb07d13d7a20ef10f Mon Sep 17 00:00:00 2001 From: Jose Martinez Date: Thu, 26 Mar 2026 20:59:20 +0100 Subject: [PATCH 3/5] feat: add Warm Spare (HA) with VIP for MX appliances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Configura meraki_appliance_warm_spare con VIP flotante en WAN1: - Spare: BCN01-F04-MX02 (serial resuelto por nombre) - Uplink mode: virtual - VIP WAN1: 213.229.159.148 La IP de salida del tráfico será siempre la VIP (.148), independientemente de qué MX esté activo. Co-Authored-By: Claude Sonnet 4.6 --- modules/meraki-site/main.tf | 11 +++++++++++ modules/meraki-site/variables.tf | 12 ++++++++++++ sites/BCN01-LAB/main.tf | 1 + sites/BCN01-LAB/variables.tf | 11 +++++++++++ sites/BCN01-LAB/wan.auto.tfvars | 14 ++++++++++++-- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/modules/meraki-site/main.tf b/modules/meraki-site/main.tf index ce7a121..e8962cf 100755 --- a/modules/meraki-site/main.tf +++ b/modules/meraki-site/main.tf @@ -200,6 +200,17 @@ resource "meraki_device_management_interface" "mx_wan" { wan1_static_dns = each.value.wan1_static_dns } +# 4c. Warm Spare (HA) — VIP flotante entre primary y spare +resource "meraki_appliance_warm_spare" "ha" { + count = var.mx_warm_spare != null ? 1 : 0 + + network_id = local.network_id + enabled = var.mx_warm_spare.enabled + spare_serial = local.device_serials[var.mx_warm_spare.spare_name] + uplink_mode = var.mx_warm_spare.uplink_mode + virtual_ip1 = var.mx_warm_spare.virtual_ip1 +} + # --- CONFIGURACIÓN SWITCHES (MS) --- # 5. Políticas de acceso 802.1X diff --git a/modules/meraki-site/variables.tf b/modules/meraki-site/variables.tf index e4a2489..38754a0 100755 --- a/modules/meraki-site/variables.tf +++ b/modules/meraki-site/variables.tf @@ -198,6 +198,18 @@ variable "mx_wan_uplinks" { description = "Configuración de interfaz WAN1 estática para cada MX. El serial se resuelve automáticamente por nombre de dispositivo." } +# Warm Spare (HA) del firewall MX +variable "mx_warm_spare" { + type = object({ + enabled = optional(bool, true) + spare_name = string # Nombre del MX spare en el Dashboard + uplink_mode = optional(string, "virtual") + virtual_ip1 = optional(string, null) # VIP WAN1 + }) + default = null + description = "Configuración Warm Spare (HA) del MX. El serial del spare se resuelve por nombre." +} + # Puertos del firewall MX variable "appliance_ports" { type = list(object({ diff --git a/sites/BCN01-LAB/main.tf b/sites/BCN01-LAB/main.tf index 158389f..c93df61 100755 --- a/sites/BCN01-LAB/main.tf +++ b/sites/BCN01-LAB/main.tf @@ -37,5 +37,6 @@ module "bcn01_lab" { stack_routing_interfaces = var.stack_routing_interfaces appliance_ports = var.appliance_ports mx_wan_uplinks = var.mx_wan_uplinks + mx_warm_spare = var.mx_warm_spare wifi_password_psk = var.wifi_password_psk } diff --git a/sites/BCN01-LAB/variables.tf b/sites/BCN01-LAB/variables.tf index 965f785..81450bd 100755 --- a/sites/BCN01-LAB/variables.tf +++ b/sites/BCN01-LAB/variables.tf @@ -184,6 +184,17 @@ variable "appliance_ports" { description = "Configuración de puertos LAN del firewall MX." } +variable "mx_warm_spare" { + type = object({ + enabled = optional(bool, true) + spare_name = string + uplink_mode = optional(string, "virtual") + virtual_ip1 = optional(string, null) + }) + default = null + description = "Configuración Warm Spare (HA) del MX." +} + variable "mx_wan_uplinks" { type = list(object({ name = string # Nombre del dispositivo en el Dashboard diff --git a/sites/BCN01-LAB/wan.auto.tfvars b/sites/BCN01-LAB/wan.auto.tfvars index 6af2d8b..71e1e1d 100644 --- a/sites/BCN01-LAB/wan.auto.tfvars +++ b/sites/BCN01-LAB/wan.auto.tfvars @@ -1,10 +1,20 @@ # Configuración WAN1 estática de los firewalls MX # El nombre debe coincidir exactamente con el nombre del dispositivo en el Dashboard # Dashboard > Security & SD-WAN > Appliance > nombre del dispositivo + +# Warm Spare (HA): VIP flotante entre primary y spare +# La IP de salida del tráfico será siempre la VIP +mx_warm_spare = { + enabled = true + spare_name = "BCN01-F04-MX02" + uplink_mode = "virtual" + virtual_ip1 = "213.229.159.148" # VIP WAN1 +} + mx_wan_uplinks = [ { # MX Primary - name = "eqt-lab-fw01-mx01" # TODO: ajustar al nombre real en el Dashboard + name = "BCN01-F04-MX01" # TODO: ajustar al nombre real en el Dashboard interfaces_wan1_enabled = true wan1_static_ip = "213.229.159.145" wan1_static_subnet_mask = "255.255.255.240" # /28 @@ -13,7 +23,7 @@ mx_wan_uplinks = [ }, { # MX Spare (Warm Spare / HA) - name = "eqt-lab-fw01-mx02" # TODO: ajustar al nombre real en el Dashboard + name = "BCN01-F04-MX02" # TODO: ajustar al nombre real en el Dashboard interfaces_wan1_enabled = true wan1_static_ip = "213.229.159.146" wan1_static_subnet_mask = "255.255.255.240" # /28 From c171ebee5f88c977f055e1eb37080c88f2d29247 Mon Sep 17 00:00:00 2001 From: Jose Martinez Date: Thu, 26 Mar 2026 21:02:55 +0100 Subject: [PATCH 4/5] fix: remove unsupported interfaces_wan1_enabled from device_management_interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El campo no está expuesto en el provider CiscoDevNet/meraki v1.9.0. Solo se usan los campos de IP estática soportados por el recurso. Co-Authored-By: Claude Sonnet 4.6 --- modules/meraki-site/main.tf | 1 - modules/meraki-site/variables.tf | 1 - sites/BCN01-LAB/variables.tf | 1 - sites/BCN01-LAB/wan.auto.tfvars | 10 ++++------ 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/modules/meraki-site/main.tf b/modules/meraki-site/main.tf index e8962cf..afcb9e9 100755 --- a/modules/meraki-site/main.tf +++ b/modules/meraki-site/main.tf @@ -193,7 +193,6 @@ resource "meraki_device_management_interface" "mx_wan" { for_each = { for mx in var.mx_wan_uplinks : mx.name => mx } serial = local.device_serials[each.key] - interfaces_wan1_enabled = each.value.interfaces_wan1_enabled wan1_static_ip = each.value.wan1_static_ip wan1_static_subnet_mask = each.value.wan1_static_subnet_mask wan1_static_gateway_ip = each.value.wan1_static_gateway_ip diff --git a/modules/meraki-site/variables.tf b/modules/meraki-site/variables.tf index 38754a0..2b52c3e 100755 --- a/modules/meraki-site/variables.tf +++ b/modules/meraki-site/variables.tf @@ -188,7 +188,6 @@ variable "stack_routing_interfaces" { variable "mx_wan_uplinks" { type = list(object({ name = string # Nombre del dispositivo en el Dashboard - interfaces_wan1_enabled = optional(bool, true) wan1_static_ip = optional(string, null) wan1_static_subnet_mask = optional(string, null) wan1_static_gateway_ip = optional(string, null) diff --git a/sites/BCN01-LAB/variables.tf b/sites/BCN01-LAB/variables.tf index 81450bd..6c094be 100755 --- a/sites/BCN01-LAB/variables.tf +++ b/sites/BCN01-LAB/variables.tf @@ -198,7 +198,6 @@ variable "mx_warm_spare" { variable "mx_wan_uplinks" { type = list(object({ name = string # Nombre del dispositivo en el Dashboard - interfaces_wan1_enabled = optional(bool, true) wan1_static_ip = optional(string, null) wan1_static_subnet_mask = optional(string, null) wan1_static_gateway_ip = optional(string, null) diff --git a/sites/BCN01-LAB/wan.auto.tfvars b/sites/BCN01-LAB/wan.auto.tfvars index 71e1e1d..f2505ad 100644 --- a/sites/BCN01-LAB/wan.auto.tfvars +++ b/sites/BCN01-LAB/wan.auto.tfvars @@ -14,18 +14,16 @@ mx_warm_spare = { mx_wan_uplinks = [ { # MX Primary - name = "BCN01-F04-MX01" # TODO: ajustar al nombre real en el Dashboard - interfaces_wan1_enabled = true - wan1_static_ip = "213.229.159.145" + name = "BCN01-F04-MX01" # TODO: ajustar al nombre real en el Dashboard + wan1_static_ip = "213.229.159.145" wan1_static_subnet_mask = "255.255.255.240" # /28 wan1_static_gateway_ip = "213.229.159.147" wan1_static_dns = ["8.8.8.8", "8.8.4.4"] }, { # MX Spare (Warm Spare / HA) - name = "BCN01-F04-MX02" # TODO: ajustar al nombre real en el Dashboard - interfaces_wan1_enabled = true - wan1_static_ip = "213.229.159.146" + name = "BCN01-F04-MX02" # TODO: ajustar al nombre real en el Dashboard + wan1_static_ip = "213.229.159.146" wan1_static_subnet_mask = "255.255.255.240" # /28 wan1_static_gateway_ip = "213.229.159.147" wan1_static_dns = ["8.8.8.8", "8.8.4.4"] From 632205f997b6754febf2376b941f7c9eaca644d6 Mon Sep 17 00:00:00 2001 From: Jose Martinez Date: Thu, 26 Mar 2026 21:10:30 +0100 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20sync=20dashboard=20drift=20=E2=80=94?= =?UTF-8?q?=20Javi=20synology=20rule=20+=20Servers=20port=20VLAN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Añade regla firewall "Acceso Javi a synology" (posición 4): allow GUEST (10.2.40.0/21) → 10.2.56.0/24 - Corrige VLAN del puerto Servers (eqt-lab-st01-sw01:1): 110 → 101 para coincidir con el estado actual del Dashboard Co-Authored-By: Claude Sonnet 4.6 --- sites/BCN01-LAB/firewall.auto.tfvars | 10 ++++++++++ sites/BCN01-LAB/switch.auto.tfvars | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/sites/BCN01-LAB/firewall.auto.tfvars b/sites/BCN01-LAB/firewall.auto.tfvars index 6c49c55..55d752e 100755 --- a/sites/BCN01-LAB/firewall.auto.tfvars +++ b/sites/BCN01-LAB/firewall.auto.tfvars @@ -33,6 +33,16 @@ firewall_rules = [ dest_port = "any" syslog_enabled = false }, + { + comment = "Acceso Javi a synology" + policy = "allow" + protocol = "any" + src_cidr = "10.2.40.0/21" # VLAN 101 - GUEST + src_port = "any" + dest_cidr = "10.2.56.0/24" + dest_port = "any" + syslog_enabled = false + }, { comment = "Bloqueo temporal switch a 8.8.8.8" policy = "deny" diff --git a/sites/BCN01-LAB/switch.auto.tfvars b/sites/BCN01-LAB/switch.auto.tfvars index 694f391..a044f7e 100644 --- a/sites/BCN01-LAB/switch.auto.tfvars +++ b/sites/BCN01-LAB/switch.auto.tfvars @@ -141,7 +141,7 @@ switch_named_port_configs = [ port_range = "1" name = "Servers" type = "access" - vlan = 110 # SERVERS + vlan = 101 # SERVERS access_policy_type = "Open" }, {