Durante casi un año mi casa tuvo dos VLANs y una sola rule entre ellas que decía: todo lo que venga del Wi-Fi (VLAN20) puede hablar con todo lo del laboratorio (VLAN11). Accept. Ni siquiera con log. Los televisores, la secadora, la Alexa, el portátil de mi esposa, el PC del trabajo, todos con pase libre al API de Kubernetes, al NAS, a los Pi-hole.

Yo lo sabía. Tenía la tarea en tududi hacía meses. Lo que me frenaba no era el firewall. Era el miedo de dañar la casa a las 8 de la noche y que Sandra me preguntara por qué no carga Jellyfin mientras yo estoy en una reunión.

Así que lo hice por fases. Esto fue cada fase y lo que salió mal.

La fase A fue solo mirar

El primer cambio no fue un cambio. Puse una rule pequeña encima de la rule general, Wi-Fi hacia los Pi-hole para DNS, y le prendí el log a la general. Y no toqué nada más en una semana.

El Sophos manda sus logs a Loki en mi cluster, así que a los ocho días saqué cada línea que había pegado en esa rule. 9.595 líneas. Armé una matriz de flujos: origen, destino, puerto, cuántas veces.

El resultado fue casi aburrido. Exactamente un dispositivo usaba el laboratorio para algo distinto a DNS. Mi Mac personal. El ingress por 443, el kube-apiserver por 6443, Loki por 3100. Todo lo demás del Wi-Fi, cada televisor, cada cámara, cada celular, solo pedía DNS.

Hubo un misterio. El Echo le mandaba UDP a los nodos de Talos. ¿Para qué una Alexa le habla a un nodo de Kubernetes? No le hablaba. Estaba haciendo ping a las IPs del balanceador de los Pi-hole, que nunca responden ICMP porque Cilium no lo hace, y entonces los nodos de Talos respondían “host unreachable” por esa conexión. El log le echaba la culpa al lado equivocado.

Fase B, solo reglas de allow

Con la matriz en la mano ya sabía exactamente qué permitir. Creé un objeto V20_Trusted con tres equipos: mi Mac, mi Galaxy y el iPad. El PC y el celular del trabajo los dejé por fuera a propósito. Esos no son míos para confiar en ellos.

Luego tres rules encima de la general: los equipos de confianza llegan a la VLAN11, cualquier equipo del Wi-Fi llega al ingress del laboratorio por HTTP y HTTPS, y cualquier equipo del Wi-Fi llega a los Pi-hole para DNS y ping. La general siguió en Accept. Con log.

Cada escritura al firewall fue por el API XML con una cuenta dedicada y permisos mínimos. Get, reenviar como no-op para probar que el API no me dañaba nada, Set, Get otra vez, diff. Lento, pero ojo: un Set del Sophos reemplaza la entidad completa, y la entidad del DHCP trae todas las reservas estáticas.

Esa misma semana agregué una rule que bota cualquier DNS que salga del Wi-Fi directo a internet, puerto 53 y 853 para DNS over TLS, para que nada se saltara los Pi-hole.

Con esa rule fue que la embarré.

La regresión que yo mismo causé

Dos días después el PC del trabajo, los eero, el Galaxy y las cajitas de streaming empezaron con timeouts de DNS. Intermitentes. De esos que recargas y funciona.

Mi primera sospecha fue el modo DPI que acababa de activar en la rule principal. No era. La segunda fue el filtro web. Tampoco.

La causa real: el scope DHCP de la VLAN20 estaba heredando la lista de DNS del propio appliance, y esa lista traía OpenDNS como tercer resolver. Los clientes recibían tres servidores DNS por DHCP, los dos Pi-hole y OpenDNS. Mi rule nueva botaba el tercero. Cualquier cliente que rotara hacia él se quedaba esperando el timeout.

El arreglo fue un solo campo. Apagar “usar la configuración DNS del appliance” en ese scope para que entregue únicamente los dos Pi-hole. Primero probé que el reenvío no-op no perdía nada, 16 reservas intactas, y después cambié el campo.

La lección que me anoté: antes de botar un puerto de salida, revisa qué está entregando tu propio DHCP.

Fase C, el flip, conmigo en la casa

Programé el flip para un domingo, conmigo físicamente en la casa. Esa mañana me lo bloquearon dos cosas.

Primero, un equipo sin identificar seguía pegándole todos los días a la rule general con SMB hacia el NAS. MAC aleatoria, así que la tabla de leases no servía. Lo identifiqué por su historial de consultas en Pi-hole: Apple push, CloudKit, krisp.ai, WhatsApp de escritorio, Avast. Ese es el MacBook de Sandra haciendo Time Machine. Le puse reserva DHCP, un host record en Pi-hole, y una rule angosta: su Mac hacia el NAS por el puerto 445 y nada más.

Segundo, los drops hacia OpenDNS nunca llegaron a cero, y yo lo tenía como métrica de puerta. Desglosado por origen eran los tres eero probándose a sí mismos por 53 y 853. Ruido de infraestructura. Esa métrica nunca iba a dar cero y dejé de esperarla.

Entonces cambié Vlan20to11 a Drop con log. La llamada al API dio timeout en la lectura HTTP. Pero se aplicó. No la reenvié, leí la rule de vuelta y revisé la acción. Eso ya me ha mordido dos veces.

Luego me di una vuelta por la casa. La Alexa pone música. Las cámaras Tapo cargan. Mi Mac llega a todo lo que llegaba antes. Catorce horas después, las únicas denegaciones eran el Mac de Sandra intentando el puerto 139 hacia el NAS. Fallback viejo de NetBIOS. Time Machine iba perfecto por 445, 411 conexiones permitidas contra 14 denegadas por 139.

Fase D, limpieza, y lo que dijeron las 48 horas

La ventana de 48 horas cerró con 97 denegaciones en total, todas ese mismo flujo del puerto 139. Un log de drops que es 100 por ciento un flujo conocido e inofensivo es un log que dejas de leer, así que le agregué el 139 al objeto de servicio SMB en vez de crear otra rule.

Después la limpieza. La rule vieja hacia la VLAN de administración quedó restringida al objeto de confianza, con un deny explícito debajo. Una rule muerta, dos objetos de hosts de portátiles que ya no tengo, un usuario de prueba de VPN, todo fuera. El servidor DHCP por defecto, deshabilitado desde la interfaz, porque el API responde 200 y lo ignora en silencio.

Lo que todavía se fuga

La rule de bypass de DNS pasó de unos 1.650 drops al día a 100 o 200. Casi todo lo que queda son los tres eero revisando el DNS de Google y OpenDNS por la noche.

Dos equipos, un Chromecast y un televisor LG, tenían 8.8.8.8 quemado. Armé mi primera rule de DNAT redirigiendo uno de ellos a un Pi-hole y dejé el otro como control. Los dos se callaron el mismo día, así que la prueba no demostró nada. Dejé la rule porque no hace daño, y además estaba equivocado en que nunca llegaban a Pi-hole. Le consultan todos los días. El 8.8.8.8 era solo un fallback.

Pendientes: la actualización de firmware del Sophos está bloqueada por una contraseña de admin que se me olvidó, y la malla de eero es una cadena en serie que nadie en esta casa me va a dejar recablear.