TL;DR
- Usa Batfish para análisis de red pre-deployment—valida routing, ACLs y alcanzabilidad antes de tocar cualquier dispositivo
- Prueba reglas de firewall como código: define reglas allow/deny esperadas, luego verifica con InSpec o assertions personalizadas
- Implementa tests de topología de red que verifiquen rutas de conectividad, no solo existencia de recursos individuales
Ideal para: Equipos gestionando VPCs cloud, redes multi-cloud o configuraciones on-premise complejas No recomendado si: Tu red es una VPC simple con routing por defecto (usa herramientas integradas del proveedor cloud) Tiempo de lectura: 14 minutos
Los errores de configuración de red causan más outages de lo que la mayoría de equipos cree. Un security group mal configurado, una entrada incorrecta en route table o una regla de firewall faltante puede tumbar producción—y los enfoques de testing tradicionales detectan estos problemas demasiado tarde. Esta guía cubre testing proactivo de red que valida configuraciones antes del deployment.
Para contexto más amplio sobre testing de infraestructura, consulta Testing de Infrastructure as Code y Estrategias de Testing de Terraform.
Enfoques Asistidos por IA
Las herramientas de IA destacan generando tests de validación de red a partir de requisitos y debuggeando problemas complejos de routing.
Generando queries de Batfish desde requisitos:
Necesito validar estos requisitos de red usando Batfish:
1. Subnet de producción (10.0.1.0/24) puede alcanzar subnet de base de datos (10.0.2.0/24) en puerto 5432
2. Ninguna subnet puede alcanzar 0.0.0.0/0 excepto a través del NAT gateway
3. Subnet del load balancer debe ser alcanzable desde internet en puertos 80 y 443
4. Subnet de management (10.0.10.0/24) NO debe ser alcanzable desde ninguna otra subnet
Genera código Python con pybatfish con assertions apropiadas y mensajes de error claros.
Incluye creación de snapshot e inicialización de red.
Debuggeando problemas de routing:
Mi VPC tiene conectividad inesperada. Configuración:
- VPC CIDR: 10.0.0.0/16
- Subnet pública: 10.0.1.0/24 con ruta a IGW
- Subnet privada: 10.0.2.0/24 con ruta a NAT
- Subnet de base de datos: 10.0.3.0/24 (debe estar aislada)
Problema: Subnet de base de datos puede alcanzar internet, pero no debería.
Route tables adjuntas son: [pegar configs de route table]
Usa análisis de traceroute para identificar dónde existe la ruta no deseada.
Creando tests InSpec para reglas de firewall:
Escribe controles InSpec para verificar estas reglas de security group de AWS:
1. SG del tier web permite inbound 443 solo desde SG del ALB
2. SG del tier app permite inbound 8080 solo desde SG del tier web
3. SG del tier DB permite inbound 5432 solo desde SG del tier app
4. Ningún security group permite inbound 22 desde 0.0.0.0/0
Incluye búsqueda de recursos por tag y condiciones skip apropiadas
para recursos faltantes.
Cuándo Usar Diferentes Enfoques de Testing
Framework de Decisión de Estrategia de Testing
| Tipo de Test | Herramienta | Cuándo Ejecutar | Qué Detecta |
|---|---|---|---|
| Análisis de configuración | Batfish | Antes de deployment | Loops de routing, hosts inalcanzables, conflictos de ACL |
| Checks de compliance | InSpec/Checkov | Pipeline CI/CD | Violaciones de política, falta de encriptación |
| Tests de integración | Terratest | Después de deployment | Conectividad real, resolución DNS |
| Pruebas de conectividad | Smoke tests | Post-deployment | Validación de flujo de tráfico real |
| Análisis de impacto de cambios | Batfish diferencial | Antes de cambios | Efectos secundarios no intencionales |
Usa Batfish Cuando
- Validación pre-deployment es crítica: Detectar problemas antes de tocar producción
- Entornos multi-vendor: Analizar configs de Cisco, Juniper, AWS, Azure juntos
- Routing complejo: Configuraciones BGP, OSPF o VRF necesitan validación
- Compliance requiere pruebas: Generar reportes de alcanzabilidad para auditores
Usa Terratest/InSpec Cuando
- Infraestructura cloud-native: VPCs AWS/GCP/Azure con routing simple
- Verificación de security groups: Confirmar que estado real de firewall coincide con esperado
- Testing de integración: Verificar que recursos funcionan juntos después del deployment
Batfish para Análisis de Red
Configurando Batfish
# Ejecutar servidor Batfish en Docker
docker run -d -p 9997:9997 -p 9996:9996 batfish/batfish
# Instalar cliente pybatfish
pip install pybatfish
Análisis Básico de Snapshot de Red
from pybatfish.client.commands import bf_init_snapshot, bf_set_network
from pybatfish.question import bfq
from pybatfish.question.question import load_questions
# Inicializar
load_questions()
bf_set_network("my-network")
bf_init_snapshot("./configs", name="current-config")
# Analizar problemas de configuración
issues = bfq.initIssues().answer().frame()
print(issues[["Type", "Issue_Type", "Details"]])
# Verificar referencias indefinidas
undefined = bfq.undefinedReferences().answer().frame()
assert len(undefined) == 0, f"Se encontraron referencias indefinidas: {undefined}"
Testing de Alcanzabilidad
def test_web_to_database_connectivity():
"""Verificar que tier web puede alcanzar base de datos en puerto PostgreSQL."""
result = bfq.reachability(
pathConstraints=PathConstraints(
startLocation="web-server",
endLocation="database-server"
),
headers=HeaderConstraints(
dstPorts="5432",
ipProtocols=["TCP"]
),
actions="SUCCESS"
).answer().frame()
assert len(result) > 0, "No se encontró ruta de web a base de datos en puerto 5432"
def test_database_internet_isolation():
"""Verificar que base de datos no puede alcanzar internet."""
result = bfq.reachability(
pathConstraints=PathConstraints(
startLocation="database-server",
endLocation="internet"
),
headers=HeaderConstraints(
dstIps="0.0.0.0/0"
),
actions="SUCCESS"
).answer().frame()
assert len(result) == 0, "Base de datos tiene acceso a internet no deseado"
Análisis Diferencial para Cambios
def test_route_change_impact():
"""Analizar impacto de cambios de route table antes de aplicar."""
# Cargar configs actuales y propuestas
bf_init_snapshot("./configs/current", name="current")
bf_init_snapshot("./configs/proposed", name="proposed")
# Comparar alcanzabilidad
diff = bfq.differentialReachability(
pathConstraints=PathConstraints(
startLocation="/production.*/",
endLocation="/database.*/"
)
).answer(
snapshot="proposed",
reference_snapshot="current"
).frame()
# Fallar si alguna ruta existente se rompe
reduced = diff[diff["Snapshot_Action"] == "DENIED"]
assert len(reduced) == 0, f"Cambio propuesto rompe rutas: {reduced}"
Testing de VPC con Terraform
Testing de Configuración VPC con Terratest
package test
import (
"testing"
"github.com/gruntwork-io/terratest/modules/aws"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)
func TestVPCConfiguration(t *testing.T) {
t.Parallel()
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../modules/vpc",
Vars: map[string]interface{}{
"vpc_cidr": "10.0.0.0/16",
"environment": "test",
"enable_nat": true,
},
})
defer terraform.Destroy(t, terraformOptions)
terraform.InitAndApply(t, terraformOptions)
// Verificar VPC creada con CIDR correcto
vpcID := terraform.Output(t, terraformOptions, "vpc_id")
vpc := aws.GetVpcById(t, vpcID, "us-east-1")
assert.Equal(t, "10.0.0.0/16", *vpc.CidrBlock)
// Verificar configuraciones DNS
assert.True(t, aws.IsVpcDnsEnabled(t, vpcID, "us-east-1"))
assert.True(t, aws.IsVpcDnsHostnamesEnabled(t, vpcID, "us-east-1"))
}
Testing de Routing de Subnets
func TestSubnetRouting(t *testing.T) {
t.Parallel()
// Después de terraform apply...
publicSubnetID := terraform.Output(t, terraformOptions, "public_subnet_id")
privateSubnetID := terraform.Output(t, terraformOptions, "private_subnet_id")
// Verificar que subnet pública tiene ruta a internet gateway
publicRoutes := aws.GetRouteTableForSubnet(t, publicSubnetID, "us-east-1")
hasIGWRoute := false
for _, route := range publicRoutes.Routes {
if route.GatewayId != nil && strings.HasPrefix(*route.GatewayId, "igw-") {
hasIGWRoute = true
break
}
}
assert.True(t, hasIGWRoute, "Subnet pública sin ruta IGW")
// Verificar que subnet privada tiene ruta a NAT gateway
privateRoutes := aws.GetRouteTableForSubnet(t, privateSubnetID, "us-east-1")
hasNATRoute := false
for _, route := range privateRoutes.Routes {
if route.NatGatewayId != nil {
hasNATRoute = true
break
}
}
assert.True(t, hasNATRoute, "Subnet privada sin ruta NAT")
}
Testing de Security Groups
Controles InSpec para AWS Security Groups
# controls/security_groups.rb
control 'web-tier-sg' do
impact 1.0
title 'Security group del tier web solo permite tráfico esperado'
web_sg = aws_security_group(group_name: 'web-tier-sg')
describe web_sg do
it { should exist }
it { should allow_in(port: 443, ipv4_range: '0.0.0.0/0') }
it { should allow_in(port: 80, ipv4_range: '0.0.0.0/0') }
it { should_not allow_in(port: 22, ipv4_range: '0.0.0.0/0') }
it { should_not allow_in(port: 3389, ipv4_range: '0.0.0.0/0') }
end
end
control 'database-tier-sg' do
impact 1.0
title 'Tier de base de datos solo accesible desde tier app'
db_sg = aws_security_group(group_name: 'database-tier-sg')
app_sg = aws_security_group(group_name: 'app-tier-sg')
describe db_sg do
it { should exist }
it { should allow_in_only(port: 5432, security_group: app_sg.group_id) }
it { should_not allow_in(ipv4_range: '0.0.0.0/0') }
end
end
control 'no-wide-open-egress' do
impact 0.7
title 'Security groups no deben permitir todo egress'
aws_security_groups.group_ids.each do |sg_id|
describe aws_security_group(group_id: sg_id) do
it { should_not allow_out(ipv4_range: '0.0.0.0/0', port: '0-65535') }
end
end
end
Integración en Pipeline CI/CD
Workflow de GitHub Actions
name: Network Configuration Tests
on:
pull_request:
paths:
- 'terraform/networking/**'
- 'configs/network/**'
jobs:
batfish-analysis:
runs-on: ubuntu-latest
services:
batfish:
image: batfish/batfish
ports:
- 9997:9997
- 9996:9996
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Instalar pybatfish
run: pip install pybatfish pytest
- name: Ejecutar análisis Batfish
run: |
pytest tests/network/ -v --tb=short
env:
BATFISH_HOST: localhost
terraform-tests:
runs-on: ubuntu-latest
needs: batfish-analysis
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
- name: Configurar credenciales AWS
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Terraform Validate
run: terraform validate
working-directory: terraform/networking/
- name: Ejecutar Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/networking/
framework: terraform
check: CKV_AWS_23,CKV_AWS_24,CKV_AWS_25
Midiendo el Éxito
| Métrica | Antes del Testing | Después del Testing | Cómo Rastrear |
|---|---|---|---|
| Outages relacionados con red | 3-4/mes | <1/trimestre | Reportes de incidentes |
| Misconfiguraciones de SG | Encontradas en auditorías | Detectadas en CI | Métricas de pipeline |
| Rollbacks de cambios | 20% de cambios | <5% de cambios | Logs de deployment |
| Tiempo medio de detección | Días | Minutos | Timestamps de alertas |
Señales de que tu testing de red no funciona:
- Aún encontrando misconfiguraciones en producción
- Tests pasan pero conectividad falla después del deployment
- Batfish y realidad divergen (snapshots desactualizados)
- Security groups tienen reglas inexplicables
Conclusión
El testing efectivo de configuración de red requiere múltiples capas:
- Análisis pre-deployment con Batfish detecta problemas de routing y ACL antes de llegar a dispositivos
- Testing de compliance con InSpec/Checkov valida políticas de seguridad
- Testing de integración con Terratest confirma conectividad real
- Monitoreo continuo detecta drift del estado deseado
La idea clave: prueba la red como sistema, no solo componentes individuales. Un security group puede estar configurado correctamente en aislamiento pero crear problemas en combinación con route tables y NACLs.
Ver También
- Testing de Infrastructure as Code - Conceptos fundamentales de testing IaC
- Estrategias de Testing de Terraform - Pirámide completa de testing Terraform
- Testing de Infraestructura AWS con LocalStack - Testing local de AWS
- Testing de Security Groups - Profundización en validación de reglas de firewall
- Estrategias de Testing de Kubernetes - Network policies en K8s
