feat: multi-site scalability, locals refactor, README

This commit is contained in:
Xavier Lario
2026-04-20 10:16:49 +02:00
parent 881d0ac5b8
commit 8ff53503db
23 changed files with 1155 additions and 740 deletions
+3 -4
View File
@@ -25,9 +25,8 @@ y deben aplicarse directamente en el Meraki Dashboard.
## OWE (Opportunistic Wireless Encryption) — SSID EQT-CORPO
> **Note:** This is not a provider limitation. The provider manages `auth_mode = "open-enhanced"` correctly.
**Dashboard:** Wireless → SSIDs → EQT-CORPO → Edit settings → Security
Activar manualmente **"Opportunistic Wireless Encryption"**.
> Terraform gestiona `auth_mode = "open-enhanced"` correctamente, pero la
> activación inicial de OWE puede requerir confirmación manual en el Dashboard.
After the first `terraform apply`, verify that **"Opportunistic Wireless Encryption"** is active in the Dashboard. In some cases Meraki requires a one-time manual confirmation click to enable OWE on a new SSID, even though Terraform has already pushed the correct configuration.
-15
View File
@@ -1,15 +0,0 @@
# Configuración de puertos LAN del firewall MX
# port_id: número del puerto físico en el MX
# type: "trunk" o "access"
# vlan: VLAN nativa (untagged) en trunk, o VLAN de acceso en access
appliance_ports = [
{
# Puerto 7: trunk hacia el stack de switches
# VLAN nativa 109 (MANAGEMENT), permite todas las VLANs
port_id = "7"
enabled = true
type = "trunk"
vlan = 109 # MANAGEMENT - VLAN nativa (untagged)
allowed_vlans = "all"
},
]
+13
View File
@@ -0,0 +1,13 @@
locals {
appliance_ports = [
{
# Port 7: trunk toward the switch stack
# Native VLAN 109 (MANAGEMENT), allows all VLANs
port_id = "7"
enabled = true
type = "trunk"
vlan = 109 # MANAGEMENT — native (untagged) VLAN
allowed_vlans = "all"
},
]
}
-68
View File
@@ -1,68 +0,0 @@
# Reglas de firewall L3
firewall_rules = [
{
# Permite que los switches (VLAN MANAGEMENT) lleguen a internet para acceder al Dashboard de Meraki
comment = "Permitir MANAGEMENT a internet (acceso Dashboard Meraki)"
policy = "allow"
protocol = "any"
src_cidr = "10.2.55.0/24" # VLAN 109 - MANAGEMENT
src_port = "any"
dest_cidr = "any"
dest_port = "any"
syslog_enabled = false
},
{
# Permite que los APs (VLAN APs) lleguen a internet para acceder al Dashboard de Meraki
comment = "Permitir APs a internet (acceso Dashboard Meraki)"
policy = "allow"
protocol = "any"
src_cidr = "10.2.54.0/24" # VLAN 108 - APs
src_port = "any"
dest_cidr = "any"
dest_port = "any"
syslog_enabled = false
},
{
# Permite que los clientes GUEST (VLAN GUEST) lleguen a internet
comment = "Permitir GUEST a internet"
policy = "allow"
protocol = "any"
src_cidr = "10.2.40.0/21" # VLAN 101 - GUEST
src_port = "any"
dest_cidr = "any"
dest_port = "any"
syslog_enabled = false
},
{
# Permite que los clientes SERVERS (VLAN SERVERS) lleguen a internet
comment = "Permitir SERVERS a internet"
policy = "allow"
protocol = "any"
src_cidr = "10.2.56.0/24" # VLAN 102 - SERVERS
src_port = "any"
dest_cidr = "any"
dest_port = "any"
syslog_enabled = false
},
{
# Permite que los clientes GUEST a SERVERS, TEMPORAL
comment = "Permitir GUEST a SERVERS"
policy = "allow"
protocol = "any"
src_cidr = "10.2.40.0/21" # VLAN 101 - GUEST
src_port = "any"
dest_cidr = "10.2.56.0/24" # VLAN 102 - SERVERS
dest_port = "any"
syslog_enabled = false
},
{
comment = "Denegar el resto del trafico de salida"
policy = "deny"
protocol = "any"
src_cidr = "any"
src_port = "any"
dest_cidr = "any"
dest_port = "any"
syslog_enabled = false
}
]
+46
View File
@@ -0,0 +1,46 @@
locals {
firewall_rules = [
{
comment = "Allow MANAGEMENT to internet (Meraki Dashboard access)"
policy = "allow"
protocol = "any"
src_cidr = "10.2.55.0/24" # VLAN 109 - MANAGEMENT
dest_cidr = "any"
},
{
comment = "Allow APs to internet (Meraki Dashboard access)"
policy = "allow"
protocol = "any"
src_cidr = "10.2.54.0/24" # VLAN 108 - APs
dest_cidr = "any"
},
{
comment = "Allow GUEST to internet"
policy = "allow"
protocol = "any"
src_cidr = "10.2.40.0/21" # VLAN 101 - GUEST
dest_cidr = "any"
},
{
comment = "Allow SERVERS to internet"
policy = "allow"
protocol = "any"
src_cidr = "10.2.56.0/24" # VLAN 110 - SERVERS
dest_cidr = "any"
},
{
comment = "Allow GUEST to SERVERS (temporary)"
policy = "allow"
protocol = "any"
src_cidr = "10.2.40.0/21" # VLAN 101 - GUEST
dest_cidr = "10.2.56.0/24" # VLAN 110 - SERVERS
},
{
comment = "Deny all other outbound traffic"
policy = "deny"
protocol = "any"
src_cidr = "any"
dest_cidr = "any"
},
]
}
+22 -32
View File
@@ -1,42 +1,32 @@
# Configuración de Terraform y Provider
terraform {
required_version = ">= 1.5.0"
required_providers {
meraki = {
source = "CiscoDevNet/meraki"
version = "1.9.0"
}
}
backend "s3" {
bucket = "eqt-terraform-state-629066559706-us-east-1-an"
key = "BCN01-LAB/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
backend "s3" {} # Config injected via -backend-config in CI (see backend.hcl at repo root)
# required_version and required_providers are declared once in modules/meraki-site/main.tf
}
provider "meraki" {}
# Llamada al módulo meraki-site
locals {
organization_name = "Adevinta Information Services SLU"
network_name = "BCN01-LAB"
}
module "bcn01_lab" {
source = "../../modules/meraki-site"
organization_name = var.organization_name
network_name = var.network_name
switch_vlans = var.switch_vlans
firewall_rules = var.firewall_rules
wireless_ssids = var.wireless_ssids
radius_secret = var.radius_secret
switch_access_policies = var.switch_access_policies
switch_port_configs = var.switch_port_configs
switch_stack_port_configs = var.switch_stack_port_configs
switch_named_port_configs = var.switch_named_port_configs
switch_management_vlan = var.switch_management_vlan
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
organization_name = local.organization_name
network_name = local.network_name
switch_vlans = local.switch_vlans
firewall_rules = local.firewall_rules
wireless_ssids = local.wireless_ssids
radius_secret = var.radius_secret
wifi_password_psk = var.wifi_password_psk
switch_access_policies = local.switch_access_policies
switch_port_configs = local.switch_port_configs
switch_stack_port_configs = local.switch_stack_port_configs
switch_named_port_configs = local.switch_named_port_configs
switch_management_vlan = local.switch_management_vlan
stack_routing_interfaces = local.stack_routing_interfaces
appliance_ports = local.appliance_ports
mx_wan_uplinks = local.mx_wan_uplinks
mx_warm_spare = local.mx_warm_spare
}
-57
View File
@@ -1,57 +0,0 @@
# SSIDs wireless - BCN01
# NOTA: El shared secret de RADIUS NO está aquí.
# Se pasa como variable de entorno TF_VAR_radius_secret (GitHub secret: RADIUS_SECRET)
wireless_ssids = [
{
number = 0
name = "EQT-CORPO"
enabled = true
auth_mode = "open-enhanced" # OWE (Opportunistic Wireless Encryption)
# Meraki API utiliza "open-enhanced" para indicar Enhanced Open / OWE.
# Este valor refleja exactamente lo que está configurado en el Dashboard.
wpa_encryption_mode = "WPA3 only"
splash_page = "Password-protected with custom RADIUS"
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 100
redirect_url = "https://www.adevinta.com"
radius_servers = [
{
host = "15.15.15.15"
port = 1912
}
]
},
{
number = 2
name = "EQT-CORPO-OWE-OK"
enabled = true
visible = false # SSID oculto — no hace broadcast del nombre
auth_mode = "open"
wpa_encryption_mode = null # open no admite wpa_encryption_mode
splash_page = "Password-protected with custom RADIUS"
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 100
redirect_url = "https://www.adevinta.com"
radius_servers = [
{
host = "15.15.15.15"
port = 1912
}
]
},
{
number = 1
name = "EQT-GUEST"
enabled = true
auth_mode = "psk" # Modo para contraseña compartida
encryption_mode = "wpa" # Requerido por la API Meraki para PSK
wpa_encryption_mode = "WPA3 Transition Mode"
# psk se inyecta via TF_VAR_wifi_password_psk (GitHub secret WIFI_PASSWORD_PSK)
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 101
}
]
+46
View File
@@ -0,0 +1,46 @@
locals {
wireless_ssids = [
{
number = 0
name = "EQT-CORPO"
enabled = true
auth_mode = "open-enhanced" # OWE (Opportunistic Wireless Encryption)
wpa_encryption_mode = "WPA3 only"
splash_page = "Password-protected with custom RADIUS"
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 100
redirect_url = "https://www.adevinta.com"
radius_servers = [
{ host = "15.15.15.15", port = 1912 }
]
},
{
number = 2
name = "EQT-CORPO-OWE-OK"
enabled = true
visible = false # Hidden SSID — no broadcast
auth_mode = "open"
splash_page = "Password-protected with custom RADIUS"
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 100
redirect_url = "https://www.adevinta.com"
radius_servers = [
{ host = "15.15.15.15", port = 1912 }
]
},
{
number = 1
name = "EQT-GUEST"
enabled = true
auth_mode = "psk"
encryption_mode = "wpa"
wpa_encryption_mode = "WPA3 Transition Mode"
# Password injected via TF_VAR_wifi_password_psk (GitHub Secret: WIFI_PASSWORD_PSK)
ip_assignment_mode = "Bridge mode"
use_vlan_tagging = true
default_vlan_id = 101
},
]
}
-210
View File
@@ -1,210 +0,0 @@
# Configuración de switches MS - BCN01-LAB
# El shared secret de RADIUS se pasa via TF_VAR_radius_secret (GitHub secret: RADIUS_SECRET)
# --- POLÍTICAS DE ACCESO 802.1X ---
switch_access_policies = [
{
name = "DOT1X-CORPO"
access_policy_type = "Hybrid authentication"
host_mode = "Multi-Auth"
radius_accounting_enabled = false
radius_re_authentication_interval = 0
url_redirect_walled_garden_enabled = false
# VLAN a la que cae el puerto si el RADIUS no responde
radius_failed_auth_vlan_id = 101 # GUEST
radius_servers = [
{
host = "15.15.15.15"
port = 1912
}
]
}
]
# --- PUERTOS DE SWITCH ---
# El serial aparece en Dashboard > Switches > nombre del switch > Overview.
# access_policy_number: número auto-asignado por Meraki a la política creada arriba
# (visible en Dashboard > Switches > Switch settings > Access policies)
#
# Ejemplo con los tres tipos de puerto:
# switch_port_configs = [
#
# # Puertos de acceso general con 802.1X (PCs, portátiles)
# # Autenticación: 802.1X → MAB → VLAN GUEST si falla RADIUS
# # La VLAN final la asigna Okta dinámicamente; vlan=100 es el fallback estático
# {
# serial = "XXXX-XXXX-XXXX"
# port_range = "1-20"
# type = "access"
# vlan = 100 # ACCESS - fallback si Okta no devuelve VLAN
# access_policy_type = "Custom access policy"
# access_policy_number = 1 # id de la política DOT1X-CORPO
# },
#
# # Puertos designados para impresoras (sin 802.1X)
# # VLAN asignada estáticamente en el puerto - las Group Policies en switches no asignan VLAN
# {
# serial = "XXXX-XXXX-XXXX"
# port_range = "21-24"
# type = "access"
# vlan = 103 # PRINTERS - VLAN fija en el puerto
# access_policy_type = "Open"
# },
#
# # Puertos designados para APs (sin 802.1X)
# # Igual que impresoras: VLAN fija en el puerto
# {
# serial = "XXXX-XXXX-XXXX"
# port_range = "25-27"
# type = "access"
# vlan = 108 # APs - VLAN fija en el puerto
# access_policy_type = "Open"
# },
#
# # Puerto de uplink (trunk, sin autenticación)
# {
# serial = "XXXX-XXXX-XXXX"
# port_range = "28"
# type = "trunk"
# access_policy_type = "Open"
# },
#
# ]
switch_port_configs = []
# --- PUERTOS DE STACK ---
# Terraform resuelve automáticamente los seriales de todos los miembros del stack.
# El stack_name debe coincidir exactamente con el nombre en Dashboard > Switches > Stacks.
# Terraform aplicará el mismo port_range a CADA switch del stack (ambos de 48 puertos).
#
# Ejemplo para bnc01-lab-stack01 (2x 48 puertos):
# switch_stack_port_configs = [
#
# # Puertos 1-44: acceso general con 802.1X (PCs, portátiles)
# {
# stack_name = "bnc01-lab-stack01"
# port_range = "1-44"
# type = "access"
# vlan = 100 # ACCESS - fallback si Okta no devuelve VLAN
# access_policy_type = "Custom access policy"
# access_policy_number = 1 # id de la política DOT1X-CORPO
# },
#
# # Puertos 45-46: impresoras (VLAN fija, sin 802.1X)
# {
# stack_name = "bnc01-lab-stack01"
# port_range = "45-46"
# type = "access"
# vlan = 103 # PRINTERS
# access_policy_type = "Open"
# },
#
# # Puertos 47-48: APs (VLAN fija, sin 802.1X)
# {
# stack_name = "bnc01-lab-stack01"
# port_range = "47-48"
# type = "access"
# vlan = 108 # APs
# access_policy_type = "Open"
# },
#
# ]
switch_stack_port_configs = [
{
stack_name = "bcn01-lab-stack01"
port_range = "6"
type = "access"
vlan = 101 # GUEST
access_policy_type = "Open"
},
{
# Puerto 44: ISP router (acceso WAN)
stack_name = "bcn01-lab-stack01"
port_range = "44"
name = "ISP router 1"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
# Puerto 45: WAN1 del MX primary
stack_name = "bcn01-lab-stack01"
port_range = "45"
name = "WAN 1 BCN01-F04-MX01"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
# Puerto 46: WAN1 del MX spare
stack_name = "bcn01-lab-stack01"
port_range = "46"
name = "WAN 1 BCN01-F04-MX02"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
# Puerto 47: uplink LAN del MX primary
stack_name = "bcn01-lab-stack01"
port_range = "47"
name = "UPLINK LAN BCN01-F04-MX01"
type = "trunk"
vlan = 109 # MANAGEMENT - VLAN nativa (untagged)
allowed_vlans = "all"
access_policy_type = "Open"
},
{
# Puerto 48: uplink LAN del MX spare
stack_name = "bcn01-lab-stack01"
port_range = "48"
name = "UPLINK LAN BCN01-F04-MX02"
type = "trunk"
vlan = 109 # MANAGEMENT - VLAN nativa (untagged)
allowed_vlans = "all"
access_policy_type = "Open"
},
]
# Puertos de un switch concreto (miembro individual del stack)
# El serial se encuentra en: Dashboard > Switches > eqt-lab-st01-sw01 > Overview
switch_named_port_configs = [
{
# Puerto 1 de eqt-lab-st01-sw01 → VLAN SERVERS (estática, sin autenticación)
switch_name = "eqt-lab-st01-sw01"
port_range = "1"
name = "Servers"
type = "access"
vlan = 101 # SERVERS
access_policy_type = "Open"
},
{
# Puertos 2 y 3 de eqt-lab-st01-sw01 → APs (trunk, nativa 108 APs, tageadas 100 ACCESS y 101 GUEST)
switch_name = "eqt-lab-st01-sw01"
port_range = "2,3"
name = "AP"
type = "trunk"
vlan = 108 # APs - VLAN nativa (untagged)
allowed_vlans = "100,101,108" # ACCESS + GUEST + APs
access_policy_type = "Open"
},
]
# VLAN de gestión de los switches del site
switch_management_vlan = 109
# Interfaces L3 en el stack para acceso de gestión al Dashboard de Meraki
stack_routing_interfaces = [
{
stack_name = "bcn01-lab-stack01"
name = "MANAGEMENT"
vlan_id = 109
ip_address = "10.2.55.2"
subnet = "10.2.55.0/24"
default_gateway = "10.2.55.1"
dns1 = "8.8.8.8"
dns2 = "8.8.4.4"
},
]
+121
View File
@@ -0,0 +1,121 @@
locals {
# 802.1X access policies
# The RADIUS shared secret is injected from var.radius_secret — never put it here.
switch_access_policies = [
{
name = "DOT1X-CORPO"
access_policy_type = "Hybrid authentication"
host_mode = "Multi-Auth"
radius_accounting_enabled = false
radius_re_authentication_interval = 0
url_redirect_walled_garden_enabled = false
radius_failed_auth_vlan_id = 101 # Fallback to GUEST if RADIUS unreachable
radius_servers = [
{ host = "15.15.15.15", port = 1912 }
]
},
]
# Ports by explicit serial — use when targeting a switch directly by serial number
# Example:
# switch_port_configs = [
# {
# serial = "XXXX-XXXX-XXXX"
# port_range = "1-20"
# type = "access"
# vlan = 100 # ACCESS — fallback if RADIUS doesn't assign a VLAN
# access_policy_type = "Custom access policy"
# access_policy_number = 1 # references DOT1X-CORPO above
# },
# ]
switch_port_configs = []
# Ports by stack name — Terraform resolves serials for all stack members automatically.
# The same port_range is applied to EVERY switch in the stack.
switch_stack_port_configs = [
{
stack_name = "bcn01-lab-stack01"
port_range = "6"
type = "access"
vlan = 101 # GUEST
access_policy_type = "Open"
},
{
stack_name = "bcn01-lab-stack01"
port_range = "44"
name = "ISP router 1"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
stack_name = "bcn01-lab-stack01"
port_range = "45"
name = "WAN 1 BCN01-F04-MX01"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
stack_name = "bcn01-lab-stack01"
port_range = "46"
name = "WAN 1 BCN01-F04-MX02"
type = "access"
vlan = 111 # WAN
access_policy_type = "Open"
},
{
stack_name = "bcn01-lab-stack01"
port_range = "47"
name = "UPLINK LAN BCN01-F04-MX01"
type = "trunk"
vlan = 109 # MANAGEMENT — native (untagged) VLAN
allowed_vlans = "all"
access_policy_type = "Open"
},
{
stack_name = "bcn01-lab-stack01"
port_range = "48"
name = "UPLINK LAN BCN01-F04-MX02"
type = "trunk"
vlan = 109 # MANAGEMENT — native (untagged) VLAN
allowed_vlans = "all"
access_policy_type = "Open"
},
]
# Ports by switch display name — targets a specific stack member without knowing its serial
switch_named_port_configs = [
{
switch_name = "eqt-lab-st01-sw01"
port_range = "1"
name = "Servers"
type = "access"
vlan = 101 # SERVERS
access_policy_type = "Open"
},
{
switch_name = "eqt-lab-st01-sw01"
port_range = "2,3"
name = "AP"
type = "trunk"
vlan = 108 # APs — native (untagged) VLAN
allowed_vlans = "100,101,108" # ACCESS + GUEST + APs
access_policy_type = "Open"
},
]
switch_management_vlan = 109
# L3 routing interfaces on the stack (SVIs for management access to Meraki Dashboard)
stack_routing_interfaces = [
{
stack_name = "bcn01-lab-stack01"
name = "MANAGEMENT"
vlan_id = 109
ip_address = "10.2.55.2"
subnet = "10.2.55.0/24"
default_gateway = "10.2.55.1"
},
]
}
+7 -201
View File
@@ -1,209 +1,15 @@
# Definición de la Organización
variable "organization_name" {
type = string
description = "Nombre exacto de tu organización en el Dashboard de Meraki"
}
# Sensitive variables — injected via TF_VAR_* environment variables (GitHub Secrets).
# Never put values for these in any .tf file.
# Definición de la Red
variable "network_name" {
type = string
description = "Nombre de la red (Network) donde reside el switch"
}
# Reglas de firewall L3
variable "firewall_rules" {
type = list(object({
comment = string
policy = string
protocol = string
src_cidr = string
src_port = string
dest_cidr = string
dest_port = string
syslog_enabled = optional(bool, false)
}))
default = []
description = "Lista de reglas de firewall L3 para el site"
}
# SSIDs wireless
variable "wireless_ssids" {
type = list(object({
number = number
name = string
enabled = optional(bool, true)
auth_mode = string
psk = optional(string, null)
encryption_mode = optional(string, null) # "wpa" para PSK; null para open/OWE
splash_page = optional(string, "None")
wpa_encryption_mode = optional(string, "WPA3 only")
ip_assignment_mode = optional(string, "Bridge mode")
use_vlan_tagging = optional(bool, false)
default_vlan_id = optional(number, null)
redirect_url = optional(string, "")
radius_servers = optional(list(object({
host = string
port = number
})), [])
}))
default = []
description = "Lista de SSIDs wireless a configurar en el site"
}
variable "wifi_password_psk" {
type = string
description = "Password para la SSID WPA2 desde GitHub Secrets"
sensitive = true
}
# Shared secret para servidores RADIUS (sensible, no incluir en tfvars)
variable "radius_secret" {
type = string
sensitive = true
default = ""
description = "Shared secret para autenticación RADIUS. Pasar via TF_VAR_radius_secret"
description = "RADIUS shared secret. Pass via TF_VAR_radius_secret (GitHub Secret: RADIUS_SECRET)."
}
# Definición de VLANs
variable "switch_vlans" {
type = map(object({
name = string
subnet = optional(string, null)
appliance_ip = optional(string, null)
dhcp_handling = optional(string, "Run a DHCP server")
reserved_ip_ranges = optional(list(object({
comment = string
id = string
start = string
end = string
})), [])
}))
description = "Mapa de configuraciones de VLAN. La clave del mapa será el ID de la VLAN"
}
# Políticas de acceso 802.1X para switches
variable "switch_access_policies" {
type = list(object({
name = string
access_policy_type = optional(string, "802.1x")
host_mode = optional(string, "Multi-Auth")
radius_accounting_enabled = optional(bool, false)
radius_testing_enabled = optional(bool, false)
radius_coa_support_enabled = optional(bool, false)
radius_failed_auth_vlan_id = optional(number, null)
radius_re_authentication_interval = optional(number, 0)
url_redirect_walled_garden_enabled = optional(bool, false)
radius_servers = list(object({
host = string
port = number
}))
}))
default = []
description = "Políticas de acceso 802.1X para switches MS"
}
# Configuración de puertos de switch
variable "switch_port_configs" {
type = list(object({
serial = string
port_range = string
name = optional(string, "")
type = optional(string, "access")
vlan = optional(number, null)
allowed_vlans = optional(string, "all")
access_policy_type = optional(string, "Open")
access_policy_number = optional(number, null)
}))
default = []
description = "Puertos de switch a configurar con 802.1X. Requiere serial del switch."
}
variable "switch_stack_port_configs" {
type = list(object({
stack_name = string
port_range = string
name = optional(string, "")
type = optional(string, "access")
vlan = optional(number, null)
allowed_vlans = optional(string, "all")
access_policy_type = optional(string, "Open")
access_policy_number = optional(number, null)
}))
default = []
description = "Puertos de stack a configurar por nombre. Terraform resuelve los seriales automáticamente."
}
variable "switch_named_port_configs" {
type = list(object({
switch_name = string
port_range = string
name = optional(string, "")
type = optional(string, "access")
vlan = optional(number, null)
allowed_vlans = optional(string, "all")
access_policy_type = optional(string, "Open")
access_policy_number = optional(number, null)
}))
default = []
description = "Puertos de switch a configurar por nombre de dispositivo. Terraform resuelve el serial automáticamente."
}
variable "switch_management_vlan" {
type = number
default = null
description = "VLAN ID de gestión para los switches del site."
}
variable "stack_routing_interfaces" {
type = list(object({
stack_name = string
name = string
vlan_id = number
ip_address = string
subnet = string
default_gateway = optional(string, null)
dns1 = optional(string, null)
dns2 = optional(string, null)
}))
default = []
description = "Interfaces L3 (SVIs) en stacks de switches para acceso de gestión al Dashboard."
}
variable "appliance_ports" {
type = list(object({
port_id = string
enabled = optional(bool, true)
type = optional(string, "access")
vlan = optional(number, null)
allowed_vlans = optional(string, "all")
drop_untagged_traffic = optional(bool, false)
}))
default = []
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)
virtual_ip2 = 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
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. El serial se resuelve automáticamente por nombre de dispositivo."
variable "wifi_password_psk" {
type = string
sensitive = true
description = "PSK Wi-Fi password. Pass via TF_VAR_wifi_password_psk (GitHub Secret: WIFI_PASSWORD_PSK)."
}
-97
View File
@@ -1,97 +0,0 @@
# Nombre exacto que aparece en tu Dashboard de Meraki
organization_name = "Adevinta Information Services SLU"
network_name = "BCN01-LAB"
# Configuración de las VLANs (L3)
# La clave (ej. "10") es el ID de la VLAN
switch_vlans = {
"100" = {
name = "ACCESS"
subnet = "10.2.32.0/21"
appliance_ip = "10.2.32.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.32.1", end = "10.2.32.49" }
]
}
"101" = {
name = "GUEST"
subnet = "10.2.40.0/21"
appliance_ip = "10.2.40.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.40.1", end = "10.2.40.49" }
]
}
"102" = {
name = "VC"
subnet = "10.2.48.0/24"
appliance_ip = "10.2.48.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.48.1", end = "10.2.48.49" }
]
}
"103" = {
name = "PRINTERS"
subnet = "10.2.49.0/24"
appliance_ip = "10.2.49.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.49.1", end = "10.2.49.49" }
]
}
"104" = {
name = "DISPLAYS"
subnet = "10.2.50.0/24"
appliance_ip = "10.2.50.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.50.1", end = "10.2.50.49" }
]
}
"105" = {
name = "BOOKING"
subnet = "10.2.51.0/24"
appliance_ip = "10.2.51.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.51.1", end = "10.2.51.49" }
]
}
"106" = {
name = "BADGE_READERS"
subnet = "10.2.52.0/24"
appliance_ip = "10.2.52.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.52.1", end = "10.2.52.49" }
]
}
"107" = {
name = "CCTV"
subnet = "10.2.53.0/24"
appliance_ip = "10.2.53.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.53.1", end = "10.2.53.49" }
]
}
"108" = {
name = "APs"
subnet = "10.2.54.0/24"
appliance_ip = "10.2.54.1"
reserved_ip_ranges = [
{ comment = "Estáticas reservadas", id = "static", start = "10.2.54.1", end = "10.2.54.49" }
]
}
"109" = {
name = "MANAGEMENT"
subnet = "10.2.55.0/24"
appliance_ip = "10.2.55.1"
dhcp_handling = "Do not respond to DHCP requests"
}
"110" = {
name = "SERVERS"
subnet = "10.2.56.0/24"
appliance_ip = "10.2.56.1"
dhcp_handling = "Do not respond to DHCP requests"
}
"111" = {
name = "WAN"
dhcp_handling = "Do not respond to DHCP requests"
# Sin L3: sin subnet ni appliance_ip (VLAN de switching puro hacia el ISP)
}
}
+93
View File
@@ -0,0 +1,93 @@
locals {
switch_vlans = {
"100" = {
name = "ACCESS"
subnet = "10.2.32.0/21"
appliance_ip = "10.2.32.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.32.1", end = "10.2.32.49" }
]
}
"101" = {
name = "GUEST"
subnet = "10.2.40.0/21"
appliance_ip = "10.2.40.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.40.1", end = "10.2.40.49" }
]
}
"102" = {
name = "VC"
subnet = "10.2.48.0/24"
appliance_ip = "10.2.48.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.48.1", end = "10.2.48.49" }
]
}
"103" = {
name = "PRINTERS"
subnet = "10.2.49.0/24"
appliance_ip = "10.2.49.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.49.1", end = "10.2.49.49" }
]
}
"104" = {
name = "DISPLAYS"
subnet = "10.2.50.0/24"
appliance_ip = "10.2.50.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.50.1", end = "10.2.50.49" }
]
}
"105" = {
name = "BOOKING"
subnet = "10.2.51.0/24"
appliance_ip = "10.2.51.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.51.1", end = "10.2.51.49" }
]
}
"106" = {
name = "BADGE_READERS"
subnet = "10.2.52.0/24"
appliance_ip = "10.2.52.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.52.1", end = "10.2.52.49" }
]
}
"107" = {
name = "CCTV"
subnet = "10.2.53.0/24"
appliance_ip = "10.2.53.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.53.1", end = "10.2.53.49" }
]
}
"108" = {
name = "APs"
subnet = "10.2.54.0/24"
appliance_ip = "10.2.54.1"
reserved_ip_ranges = [
{ comment = "Static reserved", id = "static", start = "10.2.54.1", end = "10.2.54.49" }
]
}
"109" = {
name = "MANAGEMENT"
subnet = "10.2.55.0/24"
appliance_ip = "10.2.55.1"
dhcp_handling = "Do not respond to DHCP requests"
}
"110" = {
name = "SERVERS"
subnet = "10.2.56.0/24"
appliance_ip = "10.2.56.1"
dhcp_handling = "Do not respond to DHCP requests"
}
"111" = {
name = "WAN"
dhcp_handling = "Do not respond to DHCP requests"
# No subnet or appliance_ip — L2-only switching VLAN toward the ISP
}
}
}
-32
View File
@@ -1,32 +0,0 @@
# 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
virtual_ip2 = "10.212.160.40" # VIP WAN2
}
mx_wan_uplinks = [
{
# MX Primary
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
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"]
},
]
+29
View File
@@ -0,0 +1,29 @@
locals {
# Warm Spare (HA) — floating VIP between primary and spare MX
mx_warm_spare = {
enabled = true
spare_name = "BCN01-F04-MX02"
uplink_mode = "virtual"
virtual_ip1 = "213.229.159.148" # Floating VIP on WAN1
virtual_ip2 = "10.212.160.40" # Floating VIP on WAN2
}
# Static WAN1 configuration for each MX
# Device serials are resolved automatically from the display name
mx_wan_uplinks = [
{
name = "BCN01-F04-MX01"
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"]
},
{
name = "BCN01-F04-MX02"
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"]
},
]
}