commit 266d20f1949f34b7a4f44c983b89709219c31b45 Author: Jose Martinez Date: Fri Mar 13 14:01:53 2026 +0100 Initial commit: meraki network configuration diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..974644a Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..820c217 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +# Estado de Terraform - nunca en git +*.tfstate +*.tfstate.backup + +# Directorio de trabajo de Terraform (binarios del provider) +.terraform/ + diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl new file mode 100644 index 0000000..ca0370f --- /dev/null +++ b/.terraform.lock.hcl @@ -0,0 +1,25 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/ciscodevnet/meraki" { + version = "1.9.0" + constraints = "~> 1.9.0" + hashes = [ + "h1:KmWz0JvCHdDd3AtuawxUwmW0VN3fooGw4CRaxiKHT5Y=", + "zh:0b9a7d32f331998a2a1531811667be44f799dfc03f6929f1414d2cab69f659f2", + "zh:179f791e2aa0ca6353541d90956548033b9ee0c880a096e48ce3ae3fe8a1862e", + "zh:2a1a32c6a8068c194e19859a7d88e0b95d0d9cbcf31444454b055ed62ace715a", + "zh:491812b74919d131f4ef3ba968d10b678275ed201428e2af7f53df40fd7e8cee", + "zh:4f5043f5165ee5199a61e4c15230d9f973ed0211a06600d75638f8369bac73fa", + "zh:5679d5a0d5dd370ff5d9321913f293f76be8f7ebc25e5cf1b45ceed9de803348", + "zh:58e1faba3d322bca68efb5cdac1ebe4e6d6f92834ebe5ccff8e491685620185c", + "zh:861b04ee4a498070cfb581488ddc3e90b25be895d35861c2a03a3b224d28e9b5", + "zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f", + "zh:92ee52e0dd3372e6dc2ed21bf5b21124b646c4c1037477e66eae87614d814036", + "zh:a3a851a3ce0c32b17506da0b9370f9d31df8e9d5ed4b422dc09ff5337d4b4192", + "zh:cdac168b00fa658ec68862677cb0b00f356095654e6b1d0df823c330492fa753", + "zh:dc454d6b1051891c99051b92e61015d244eb320a5a491cbffb770a005e448898", + "zh:f14317688e068e40dc11f609c4dc4f81cfa50fbaa43dcbe0117725f1149e9d89", + "zh:fe0544ac117d0c643559f042996fa32f243988bc48d4d49875abad6b326f0e2e", + ] +} diff --git a/modules/.DS_Store b/modules/.DS_Store new file mode 100644 index 0000000..eb16e4e Binary files /dev/null and b/modules/.DS_Store differ diff --git a/modules/meraki-site/main.tf b/modules/meraki-site/main.tf new file mode 100644 index 0000000..0c86489 --- /dev/null +++ b/modules/meraki-site/main.tf @@ -0,0 +1,41 @@ +# Búsqueda automática de IDs (Data Sources) +data "meraki_organization" "org" { + name = var.organization_name +} + +data "meraki_networks" "net" { + organization_id = data.meraki_organization.org.id +} + +# Local para extraer el network_id exacto de la lista de redes +locals { + network_id = [for n in data.meraki_networks.net.items : n.id if n.name == var.network_name][0] +} + +# --- CONFIGURACIÓN GATEWAY (MX) --- + +# 1. Activar VLANs en el Appliance (MX) +resource "meraki_appliance_vlans_settings" "activate_vlans" { + network_id = local.network_id + vlans_enabled = true +} + +# 2. Crear las interfaces L3 y VLANs en el MX +resource "meraki_appliance_vlan" "mx_gateways" { + for_each = var.switch_vlans + depends_on = [meraki_appliance_vlans_settings.activate_vlans] + + network_id = local.network_id + vlan_id = each.key + name = each.value.name + subnet = each.value.subnet + appliance_ip = each.value.appliance_ip + reserved_ip_ranges = each.value.reserved_ip_ranges + dhcp_handling = each.value.dhcp_handling +} + +# 3. Reglas de firewall L3 +resource "meraki_appliance_l3_firewall_rules" "reglas_firewall" { + network_id = local.network_id + rules = var.firewall_rules +} diff --git a/modules/meraki-site/outputs.tf b/modules/meraki-site/outputs.tf new file mode 100644 index 0000000..cd3928e --- /dev/null +++ b/modules/meraki-site/outputs.tf @@ -0,0 +1,17 @@ +# ID de la red Meraki gestionada +output "network_id" { + description = "ID interno de la red Meraki" + value = local.network_id +} + +# IDs de las VLANs creadas en el MX +output "vlan_ids" { + description = "Mapa de VLAN ID => ID de recurso creado en el MX" + value = { for k, v in meraki_appliance_vlan.mx_gateways : k => v.vlan_id } +} + +# Nombre del perfil de VLANs creado +output "vlan_profile_name" { + description = "Nombre del perfil de VLANs asignado al site" + value = meraki_network_vlan_profile.site_profile.name +} diff --git a/modules/meraki-site/variables.tf b/modules/meraki-site/variables.tf new file mode 100644 index 0000000..ec4a72a --- /dev/null +++ b/modules/meraki-site/variables.tf @@ -0,0 +1,54 @@ +# Definición de la Organización +variable "organization_name" { + type = string + description = "Nombre exacto de tu organización en el Dashboard de Meraki" +} + +# Definición de la Red +variable "network_name" { + type = string + description = "Nombre de la red (Network)" +} + + +# 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 = "Reglas de firewall L3 para el site. Se aplican en orden, antes de la regla allow-all implícita de Meraki" +} + +# Definición del mapa de VLANs +variable "switch_vlans" { + type = map(object({ + name = string + subnet = string + appliance_ip = string + dhcp_handling = optional(string, "Run a DHCP server") + reserved_ip_ranges = optional(list(object({ + comment = string + id = string + start = string + end = string + })), []) + })) + description = "VLANs para el site" + + validation { + condition = alltrue([ + for v in values(var.switch_vlans) : + contains(["Run a DHCP server", "Relay DHCP to another server", "Do not respond to DHCP requests"], v.dhcp_handling) + ]) + error_message = "dhcp_handling debe ser uno de: 'Run a DHCP server', 'Relay DHCP to another server', 'Do not respond to DHCP requests'." + } +} + diff --git a/sites/.DS_Store b/sites/.DS_Store new file mode 100644 index 0000000..a0955ca Binary files /dev/null and b/sites/.DS_Store differ diff --git a/sites/bcn01/firewall.auto.tfvars b/sites/bcn01/firewall.auto.tfvars new file mode 100644 index 0000000..66467ee --- /dev/null +++ b/sites/bcn01/firewall.auto.tfvars @@ -0,0 +1,33 @@ +# Reglas de firewall L3 +firewall_rules = [ + { + comment = "Bloqueo temporal switch a 8.8.8.8" + policy = "deny" + protocol = "any" + src_cidr = "192.168.8.50/32" + src_port = "any" + dest_cidr = "8.8.8.8/32" + dest_port = "any" + syslog_enabled = true + }, + { + comment = "Bloqueo especifico DNS Cloudflare 1.1.1.1 desde VC" + policy = "deny" + protocol = "any" + src_cidr = "10.2.48.0/24" # VLAN 102 - VC + src_port = "any" + dest_cidr = "1.1.1.1/32" + 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 + } +] diff --git a/sites/bcn01/main.tf b/sites/bcn01/main.tf new file mode 100644 index 0000000..0ec04c9 --- /dev/null +++ b/sites/bcn01/main.tf @@ -0,0 +1,22 @@ +# Configuración de Terraform y Provider +terraform { + required_version = ">= 1.5.0" + required_providers { + meraki = { + source = "CiscoDevNet/meraki" + version = "1.9.0" + } + } +} + +provider "meraki" {} + +# Llamada al módulo meraki-site +module "bcn01" { + source = "../../modules/meraki-site" + + organization_name = var.organization_name + network_name = var.network_name + switch_vlans = var.switch_vlans + firewall_rules = var.firewall_rules +} diff --git a/sites/bcn01/variables.tf b/sites/bcn01/variables.tf new file mode 100644 index 0000000..74c05b5 --- /dev/null +++ b/sites/bcn01/variables.tf @@ -0,0 +1,46 @@ +# Definición de la Organización +variable "organization_name" { + type = string + description = "Nombre exacto de tu organización en el Dashboard de Meraki" +} + +# 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" +} + +# Definición de VLANs +variable "switch_vlans" { + type = map(object({ + name = string + subnet = string + appliance_ip = string + 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" +} + diff --git a/sites/bcn01/vlans.auto.tfvars b/sites/bcn01/vlans.auto.tfvars new file mode 100644 index 0000000..189cfae --- /dev/null +++ b/sites/bcn01/vlans.auto.tfvars @@ -0,0 +1,92 @@ +# 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" + } +} \ No newline at end of file