¿Qué hace Validación de Configuración de Red?
Use esta habilidad para revisar la configuración de red antes de una ventana de cambio o antes de que una automatización toque dispositivos en producción.
Cuándo Usarla
- Revisar fragmentos de configuración estilo Cisco IOS o IOS-XE antes del despliegue.
- Auditar configuraciones generadas por scripts o plantillas.
- Buscar comandos peligrosos, direcciones IP duplicadas o superposición de subredes.
- Verificar si ACLs, route-maps, prefix-lists o políticas de línea están referenciadas pero no definidas.
- Construir scripts prevuelo ligeros para automatización de red.
Cómo Funciona
Trate la validación de configuración como evidencia en capas, no como un analizador completo. Las comprobaciones con expresiones regulares son útiles para advertencias prevuelo, pero la aprobación final aún necesita que un ingeniero de red revise la intención, la sintaxis de la plataforma y los pasos de reversión.
Valide en este orden:
- Comandos destructivos.
- Exposición de credenciales y del plano de gestión.
- Direcciones duplicadas y superposición de subredes.
- Referencias obsoletas a ACLs, route-maps, prefix-lists e interfaces.
- Higiene operativa como NTP, marcas de tiempo, registro remoto y banners.
Detección de Comandos Peligrosos
import re
DANGEROUS_PATTERNS: list[tuple[re.Pattern[str], str]] = [
(re.compile(r"\breload\b", re.I), "reload causa tiempo de inactividad"),
(re.compile(r"\berase\s+(startup|nvram|flash)", re.I), "borra almacenamiento persistente"),
(re.compile(r"\bformat\b", re.I), "formatea un sistema de archivos del dispositivo"),
(re.compile(r"\bno\s+router\s+(bgp|ospf|eigrp)\b", re.I), "elimina un proceso de enrutamiento"),
(re.compile(r"\bno\s+interface\s+\S+", re.I), "elimina la configuración de la interfaz"),
(re.compile(r"\baaa\s+new-model\b", re.I), "cambia el comportamiento de autenticación"),
(re.compile(r"\bcrypto\s+key\s+(zeroize|generate)\b", re.I), "cambia las claves SSH del dispositivo"),
]
def find_dangerous_commands(lines: list[str]) -> list[dict[str, str | int]]:
findings = []
for line_number, line in enumerate(lines, start=1):
stripped = line.strip()
for pattern, reason in DANGEROUS_PATTERNS:
if pattern.search(stripped):
findings.append({
"line": line_number,
"command": stripped,
"reason": reason,
})
return findings
IPs Duplicadas y Superposición de Subredes
import ipaddress
import re
from collections import Counter
IP_ADDRESS_RE = re.compile(
r"^\s*ip address\s+"
r"(?P<ip>\d{1,3}(?:\.\d{1,3}){3})\s+"
r"(?P<mask>\d{1,3}(?:\.\d{1,3}){3})\b",
re.I | re.M,
)
def extract_interfaces(config: str) -> list[dict[str, str]]:
results = []
current = None
for line in config.splitlines():
if line.startswith("interface "):
current = line.split(maxsplit=1)[1]
continue
match = IP_ADDRESS_RE.match(line)
if current and match:
ip = match.group("ip")
mask = match.group("mask")
network = ipaddress.ip_interface(f"{ip}/{mask}").network
results.append({"interface": current, "ip": ip, "network": str(network)})
return results
def find_duplicate_ips(config: str) -> list[str]:
ips = [entry["ip"] for entry in extract_interfaces(config)]
counts = Counter(ips)
return sorted(ip for ip, count in counts.items() if count > 1)
def find_subnet_overlaps(config: str) -> list[tuple[str, str]]:
networks = [ipaddress.ip_network(entry["network"]) for entry in extract_interfaces(config)]
overlaps = []
for index, left in enumerate(networks):
for right in networks[index + 1:]:
if left.overlaps(right):
overlaps.append((str(left), str(right)))
return overlaps
Comprobaciones del Plano de Gestión
Analice los bloques VTY por sección para que las comprobaciones de access-class no se extiendan a líneas no relacionadas.
import re
def iter_blocks(config: str, starts_with: str) -> list[str]:
blocks = []
current: list[str] = []
for line in config.splitlines():
if line.startswith(starts_with):
if current:
blocks.append("\n".join(current))
current = [line]
continue
if current:
if line and not line.startswith(" "):
blocks.append("\n".join(current))
current = []
else:
current.append(line)
if current:
blocks.append("\n".join(current))
return blocks
def check_vty_blocks(config: str) -> list[str]:
issues = []
for block in iter_blocks(config, "line vty"):
if re.search(r"transport\s+input\s+.*telnet", block, re.I):
issues.append("VTY permite Telnet; requiere solo SSH.")
if not re.search(r"\baccess-class\s+\S+\s+in\b", block, re.I):
issues.append("El bloque VTY no tiene restricción de access-class de entrada.")
if not re.search(r"\bexec-timeout\s+\d+\s+\d+\b", block, re.I):
issues.append("El bloque VTY no tiene un exec-timeout explícito.")
return issues
Comprobaciones de Higiene de Seguridad
SECURITY_PATTERNS = [
(re.compile(r"\bsnmp-server community\s+(public|private)\b", re.I),
"comunidad SNMP por defecto configurada"),
(re.compile(r"\bsnmp-server community\s+\S+", re.I),
"cadena de comunidad SNMPv2 configurada; prefiera SNMPv3 authPriv"),
(re.compile(r"\bip ssh version 1\b", re.I),
"SSH versión 1 habilitado"),
(re.compile(r"\benable password\b", re.I),
"contraseña enable presente; use enable secret"),
(re.compile(r"\busername\s+\S+\s+password\b", re.I),
"usuario local usa password en lugar de secret"),
]
BEST_PRACTICE_PATTERNS = [
(re.compile(r"\bntp server\b", re.I), "servidor NTP"),
(re.compile(r"\bservice timestamps\b", re.I), "marcas de tiempo de registro"),
(re.compile(r"\blogging\s+\S+", re.I), "destino o búfer de registro"),
(re.compile(r"\bsnmp-server group\s+\S+\s+v3\s+priv\b", re.I), "grupo SNMPv3 authPriv"),
(re.compile(r"\bbanner\s+(login|motd)\b", re.I), "banner de inicio de sesión"),
]
def check_security(config: str) -> list[str]:
return [message for pattern, message in SECURITY_PATTERNS if pattern.search(config)]
def check_missing_hygiene(config: str) -> list[str]:
return [
f"Falta {description}"
for pattern, description in BEST_PRACTICE_PATTERNS
if not pattern.search(config)
]
Ejemplos
Prevuelo de Ventana de Cambio
- Ejecute comprobaciones de comandos peligrosos sobre el fragmento exacto que se va a pegar.
- Ejecute comprobaciones de IP duplicadas y superposición de subredes contra la configuración candidata completa.
- Confirme que cada ACL, route-map y prefix-list referenciada existe.
- Confirme los comandos de reversión y el acceso fuera de banda antes de cualquier cambio en el plano de gestión.
Prevuelo de Automatización
Use la validación como una puerta de bloqueo antes de que la automatización con Netmiko, NAPALM, Ansible o API de proveedor empuje una configuración generada. Falle de forma segura ante comandos peligrosos y credenciales. Advierta sobre brechas de mejores prácticas que estén fuera del alcance del cambio.
Anti-Patrones
- Tratar la validación con regex como un analizador de dispositivos.
- Aplicar una configuración generada sin una comparación de dry-run.
- Recomendar cadenas de comunidad SNMPv2 como requisito de monitoreo.
- Revisar bloques VTY con regex que pueda abarcar accidentalmente secciones no relacionadas.
- Probar el comportamiento del cortafuegos deshabilitando ACLs en lugar de leer contadores/registros.
Ver También
- Agente:
network-config-reviewer - Agente:
network-troubleshooter - Habilidad:
network-interface-health