1Por qué importa
Las dos mitades de esta lección parecen no tener nada que ver y son la misma idea vista desde dos ángulos: saber en qué estado está tu sistema. El reset garantiza que el laboratorio empieza donde crees que empieza. El firewall garantiza que la superficie de ataque de tu máquina es la que crees que es. En los dos casos el enemigo es el mismo, y no es un atacante: es la diferencia entre lo que configuraste y lo que hay.
El reset importa por una razón muy concreta que vas a sufrir si no lo interiorizas. Los ejercicios de este curso dependen de un estado inicial conocido. Cuando un ataque “ya no funciona” o funciona sin que hayas hecho nada, la causa casi nunca es interesante: es un volumen que sobrevivió, un contenedor huérfano de otro proyecto o una imagen que se reconstruyó a medias. Horas de depuración imaginaria.
Y el firewall importa porque cierra el círculo de la fase. Has aprendido a no publicar puertos y a usar redes internas. Falta la última capa, la que te protege de tus propios olvidos: si un día publicas algo sin dirección delante, un firewall bien puesto es lo que debería salvarte. La mala noticia —y el motivo de que esto sea una lección y no una nota al pie— es que con Docker en Linux, por defecto, no te salva.
Al terminar tienes que tener dos comandos memorizados y una comprobación. El comando que destruye del todo, el que reconstruye desde cero, y la comprobación que te dice qué escucha tu máquina ahora mismo. Con eso, ningún ejercicio del curso te va a mentir sobre su estado inicial.
2Conceptos
- Idempotencia: ejecutar el procedimiento dos veces deja el mismo resultado que ejecutarlo una. Sin ella, un reset es una lotería.
- Contenedor huérfano: contenedor de un proyecto que ya no está declarado en el compose actual. Sigue vivo y sigue en la red.
- Denegar por defecto: se bloquea todo y se abre por excepción. Lo contrario —permitir y bloquear excepciones— es una lista que nunca está completa.
- Firewall con estado: sigue las conexiones, así que la respuesta a algo que tú iniciaste se permite sin escribir ninguna regla de entrada.
- Capa 3/4: filtrado por dirección, puerto y protocolo. Capa 7: filtrado por lo que dice el contenido, como el nombre de dominio o la ruta.
- Entrada y salida: quién puede llegarte y a dónde puedes llegar tú. Casi todo el mundo controla lo primero y nadie controla lo segundo.
- Cadena de reenvío: el punto donde el núcleo decide qué hacer con el tráfico que atraviesa la máquina hacia un contenedor. Es ahí donde Docker escribe.
3Explicación profunda
Los seis estados que sobreviven
“Reiniciar el laboratorio” no significa nada hasta que enumeras qué puede quedar vivo. Son seis cosas, y cada comando borra un subconjunto distinto:
| Estado | Sobrevive a… | Se elimina con |
|---|---|---|
| Contenedores del proyecto | stop, restart | down |
| Redes del proyecto | stop | down |
| Volúmenes nombrados | down | down -v |
| Contenedores huérfanos | down, down -v | down --remove-orphans |
| Imágenes construidas | todo lo anterior | down --rmi local |
| Caché de construcción | todo lo anterior | docker builder prune |
Los dos que más daño hacen son el tercero y el cuarto. El volumen ya lo viste: es la causa número uno de un ejercicio que no reproduce. El huérfano es más traicionero: aparece cuando cambias el compose y eliminas o renombras un servicio. El contenedor antiguo no se borra, sigue conectado a la red del proyecto y sigue respondiendo a su nombre. Depurar por qué un servicio devuelve contenido viejo cuando lo has reescrito entero es una experiencia que se tiene una vez.
La caché de construcción merece una nota aparte porque es el estado que produce el error más desconcertante. Si el laboratorio construye una imagen, Docker reutiliza capas mientras crea que nada cambió. Sus heurísticas son buenas pero no perfectas, y cuando fallan reconstruyes “desde cero” una imagen que trae dentro archivos de hace tres días.
De ahí sale el procedimiento completo, que no es un comando sino tres, y en este orden:
# 1) destruir del todo: contenedores, redes, volumenes y huerfanos docker compose down -v --remove-orphans # 2) comprobar que no queda nada del proyecto docker compose ps -a docker volume ls docker network ls # 3) reconstruir sin reutilizar nada dudoso docker compose up -d --force-recreate --build
El paso 2 es el que casi todo el mundo salta y el que convierte el procedimiento en verificable. Un reset que no se comprueba es una intención, exactamente igual que en la lección de instantáneas: si no miras, no sabes.
Un aviso sobre la motosierra: docker system prune -a borra todo lo no
utilizado de toda tu máquina, incluidas imágenes y volúmenes de proyectos que no
tienen nada que ver con el curso. Funciona, sí, igual que funciona formatear. Para un
laboratorio, la versión acotada al proyecto siempre es preferible.
Firewall: cuatro distinciones que casi nadie hace
“Tengo el firewall activado” es una frase tan poco informativa como “está cifrado”. Estas cuatro distinciones son las que convierten esa frase en algo que se puede verificar.
Con estado o sin estado. Un firewall sin estado mira cada paquete aislado: para permitir una navegación web tendrías que abrir la entrada de los puertos altos, porque la respuesta llega por ahí. Un firewall con estado mantiene una tabla de conexiones vivas y reconoce la respuesta a algo que tú iniciaste. Es lo que permite la configuración que quieres: salida abierta, entrada cerrada, sin que se rompa nada. Todos los firewalls de sistema modernos tienen estado, pero conviene saber por qué la regla “permitir establecidas y relacionadas” está siempre la primera.
Capa 3/4 o capa 7. El firewall del sistema filtra por dirección, puerto y protocolo. No sabe qué dominio pediste ni qué ruta HTTP. Filtrar por nombre de dominio requiere mirar el contenido, y eso vive en un proxy, no en el núcleo. Es una limitación real y explica por qué “bloquear un sitio web con el firewall” funciona mal: el nombre puede resolver a direcciones que cambian, y varios servicios comparten dirección.
Entrada o salida. Denegar por defecto en entrada es fácil y casi gratis: es la configuración por defecto de cualquier sistema de escritorio decente. Denegar por defecto en salida es lo que de verdad estorba a un atacante —corta la exfiltración y el canal de mando y control— y es lo que casi nadie hace, porque obliga a enumerar cada destino legítimo y rompe cosas cada semana. La honestidad obliga a decirlo: en una máquina de trabajo es un dolor sostenido; en un servidor con una función clara, es de las medidas con mejor relación entre coste y efecto que existen.
Dónde se evalúa. Un paquete dirigido a tu propia máquina y uno que la atraviesa hacia un contenedor no pasan por el mismo sitio. El primero se filtra en la cadena de entrada; el segundo, en la de reenvío. Es una distinción de fontanería que resultaría aburrida si no fuera exactamente la causa del problema siguiente.
El puerto que tu firewall no cierra
Este es el punto que justifica la lección. En Linux, cuando publicas un puerto, Docker programa la traducción de direcciones y las reglas de aceptación necesarias directamente en la cadena de reenvío, y lo hace en sus propias cadenas, que se evalúan antes que las reglas que tú añades con las herramientas habituales de administración de firewall.
Consecuencia práctica: puedes tener el firewall configurado para denegar todo lo
entrante, ver que dice que el puerto 8080 está cerrado, y que un contenedor publicado
en 8080:80 siga siendo perfectamente alcanzable desde otra máquina de tu
red. No es un fallo de tu configuración ni del firewall: es que tu regla está mirando
un camino por el que el paquete no pasa.
# El paquete que va a TU maquina red --> [ cadena de ENTRADA ] --> proceso local ^ aqui SI estan tus reglas # El paquete que va a un CONTENEDOR publicado red --> [ traduccion de direcciones ] --> [ cadena de REENVIO ] --> contenedor ^ aqui escribe Docker, y sus cadenas van primero
Hay tres respuestas correctas y conviene tenerlas ordenadas por preferencia. La
primera y la que este curso convierte en obligatoria: publica siempre en
127.0.0.1. Si el puerto solo escucha en la interfaz local, la
discusión sobre cadenas desaparece, porque no hay tráfico externo que reenviar. La
segunda: si de verdad necesitas publicar hacia fuera, escribe las reglas en la cadena
específica que Docker deja reservada para el administrador, que sí se consulta antes de
aceptar. La tercera, para casos concretos: desactivar la manipulación automática de
reglas por parte del motor, con la advertencia de que entonces la conectividad de los
contenedores pasa a ser tu problema entero.
En macOS y en Windows el mecanismo es distinto —el motor corre dentro de una máquina
virtual ligera y quien publica el puerto en tu sistema es un proceso del propio
Docker—, pero la conclusión operativa no cambia ni un milímetro: el firewall de tu
sistema no es lo que decide si tu laboratorio está expuesto. Lo decide la dirección que
escribes en ports.
Comprobar en vez de creer
La comprobación que cierra la fase no es leer configuración: es preguntarle al sistema qué está escuchando. Los sockets en estado de escucha son la verdad; todo lo demás es lo que alguien quiso que pasara.
# que escucha, en que direccion, y quien lo abrio ss -tulpn | grep LISTEN # lo que importa es la columna de direccion local: # 127.0.0.1:8080 solo esta maquina -> bien # 0.0.0.0:8080 todas las interfaces -> revisar YA # [::]:8080 todas las interfaces, otra familia -> revisar YA # y la version corta para Docker docker ps --format "{{.Names}}\t{{.Ports}}"
Esa segunda familia de direcciones es un detalle que muerde de verdad. Es habitual proteger cuidadosamente una familia de direcciones y dejar la otra abierta de par en par, porque la configuración se escribió pensando solo en una. Cuando audites, mira siempre las dos.
4Ejemplo sencillo
# Reset: la diferencia entre parecido e identico restart apaga y enciende estado: intacto down quita contenedores y redes estado: volumenes vivos down -v anade los volumenes estado: huerfanos vivos down -v --remove-orphans ya no queda nada del proyecto # Firewall: dos puertas y una sola cerradura puerta 1 trafico hacia TU maquina -> tu firewall la vigila puerta 2 trafico hacia un CONTENEDOR -> Docker abrio esta, y va primero # Por eso la cerradura buena no esta en el firewall: # esta en escribir 127.0.0.1: delante del puerto.
5Ejemplo técnico
El experimento que demuestra el problema del firewall, hecho entero dentro de tu máquina y sin tocar la red de nadie. Copia el laboratorio, cambia una línea y observa:
Nueve caracteres de diferencia y dos posturas de seguridad opuestas. Fíjate en que el servicio funciona exactamente igual en los dos casos: no hay ningún error, ninguna advertencia y ninguna señal de que algo haya cambiado. Los fallos de exposición son silenciosos por naturaleza, y por eso la comprobación tiene que ser un hábito y no una reacción.
Sobre el firewall en sí: si estás en Linux y quieres comprobar el efecto, añade una regla que deniegue el 8080 con tu herramienta habitual y repite el escaneo desde otra máquina de tu propia red. El puerto seguirá abierto. Esa demostración vale más que cualquier párrafo, y es la razón de que la protección de este curso viva en el compose.
6Diagrama
Ver el mismo diagrama como código Mermaid (editable)
flowchart LR
P[paquete] --> IN[cadena de entrada]
P --> FW[cadena de reenvio]
IN --> L[proceso local]
FW --> C[contenedor publicado]
7Código
El reset y la comprobación de exposición se escriben una vez y se ejecutan siempre. Un script así vive junto al laboratorio y su valor está en que falla cuando algo no está como debe:
#!/usr/bin/env sh # reset.sh — devuelve el laboratorio a su estado inicial y lo verifica set -eu # 1) destruir del todo docker compose down -v --remove-orphans # 2) verificar que no queda estado del proyecto if [ -n "$(docker compose ps -aq)" ]; then echo "quedan contenedores del proyecto" >&2; exit 1 fi # 3) reconstruir sin reutilizar nada dudoso docker compose up -d --force-recreate --build # 4) puerta de salida: ningun puerto publicado fuera de la interfaz local expuestos=$(docker compose ps --format '{{.Ports}}' \ | tr ',' '\n' | grep '->' | grep -v '^127\.0\.0\.1:' || true) if [ -n "$expuestos" ]; then echo "PUERTOS EXPUESTOS FUERA DE LA INTERFAZ LOCAL:" >&2 echo "$expuestos" >&2 docker compose down exit 1 fi echo "laboratorio listo · sin exposicion fuera de la interfaz local"
Lo interesante del paso 4 no es la comprobación en sí, es qué hace cuando falla: tira el laboratorio abajo. Un aviso que se puede ignorar se ignora. Un laboratorio que se niega a quedarse arriba mal configurado enseña la lección la primera vez y no hace falta repetirla.
8Qué puede salir mal
Confiar en restart como reset. No borra absolutamente nada: los
mismos contenedores, con los mismos volúmenes y el mismo estado que tenían.
Olvidar los huérfanos. Cambias un servicio de nombre y el antiguo sigue vivo, en la red, respondiendo. Es la causa de los diagnósticos más absurdos de un laboratorio.
Creer que el firewall cubre los puertos publicados. En Linux no lo hace por defecto, porque las reglas de Docker se evalúan en otra cadena y por delante de las tuyas. La comprobación honesta es escanear desde otra máquina tuya.
Auditar una sola familia de direcciones. Es fácil cerrar cuidadosamente una y dejar la otra escuchando en todas las interfaces, porque la configuración se escribió pensando en un solo formato de dirección.
Reglas de salida escritas por nombre de dominio. El firewall del sistema trabaja en capa 3/4 y no entiende nombres. La regla se convierte en una lista de direcciones que caducan y que además comparten otros servicios: falsos permisos y falsos bloqueos a la vez.
La motosierra. Limpiar el sistema entero para arreglar un laboratorio borra imágenes y volúmenes de otros proyectos. Funciona y cuesta una tarde de descargas.
9Cómo lo abusaría un atacante
En una red compartida —una oficina, un coworking, una universidad— el trabajo de reconocimiento es literalmente barrer los puertos altos y ver qué contesta. Los entornos de desarrollo son el mejor hallazgo posible: sin autenticación, con datos de prueba que resultan ser datos reales, y con versiones antiguas porque nadie actualiza lo que “es solo local”.
Lo que hace especialmente rentable el descuido de Docker es que la víctima tiene la sensación de estar protegida. Ha activado el firewall, ha comprobado que el puerto figura como cerrado, y por eso no vuelve a mirar. Un control que se cree activo y no lo está es peor que ninguno, porque además elimina la vigilancia.
Sobre el estado que no se limpia, el ángulo es distinto y más sutil. Un volumen que sobrevive entre sesiones acumula lo que fuiste escribiendo: credenciales de prueba que resultaron ser reales, volcados de bases de datos, tokens pegados en un archivo de configuración para salir del paso. Ese volumen no aparece en ninguna copia de seguridad ni en ningún inventario, y sigue en tu disco meses después de que olvidaras el proyecto.
Y la salida sin control es el multiplicador de todo lo anterior. Sin restricciones de salida, cualquier ejecución dentro de un contenedor puede descargar la siguiente etapa, abrir un canal de vuelta y sacar datos. Denegar por defecto en salida es molesto precisamente porque es efectivo: rompe las mismas conexiones oportunistas que un atacante necesita.
10Cómo defenderlo
- Un solo comando de destrucción, siempre el mismo:
down -v --remove-orphans. No hay versión corta aceptable. - Verifica el reset con
ps -a,volume lsynetwork ls. Un reset sin comprobación es una suposición. - La exposición se controla en el compose, no en el firewall:
127.0.0.1:delante de cada puerto publicado. - Firewall local con denegar por defecto en entrada igualmente, como red de seguridad para todo lo que no es Docker.
- Escanea tu propia máquina desde otra máquina tuya de vez en cuando. Es la única comprobación que no se puede engañar a sí misma.
- Considera denegar por defecto en salida en los sistemas con una función clara. Empieza registrando lo que sale para saber qué vas a romper.
- Automatiza la puerta de salida: que el script de arranque tire el laboratorio abajo si detecta un puerto publicado fuera de la interfaz local.
11Laboratorio
Primero, comprueba qué escucha tu máquina antes de levantar nada:
ss -tulpn | grep LISTEN
cd cursos/seguridad/labs/lab-00-base
docker compose up -d
ss -tulpn | grep 8080
Ahora demuestra el ciclo de estado. Escribe algo, aplica cada nivel de reset y observa qué sobrevive a cada uno:
Segundo, el huérfano. Copia el laboratorio a un directorio propio, renombra el
servicio monitor a observador y levanta con
up -d sin más. El contenedor antiguo sigue vivo: compruébalo con
docker compose ps -a y elimínalo con --remove-orphans.
Tercero, la exposición. Sobre tu copia, cambia 127.0.0.1:8080:80
por 8080:80, recrea y vuelve a mirar. Después revierte el cambio.
Cuando termines, cierra la fase con el reset completo:
docker compose down -v --remove-orphans
docker compose ps -a
docker volume ls
12Ejercicios
Empareja comando y estado
Para cada uno de los seis estados de la sección 3, di cuál es el comando mínimo que lo elimina. Después responde: ¿cuál de los seis puede hacer que un ataque parezca funcionar cuando en realidad ya no debería, y por qué?
down, por muchos modificadores que le pongas.
Contenedores y redes del proyecto: down. Volúmenes nombrados:
down -v. Huérfanos: down --remove-orphans. Imágenes
construidas localmente: down --rmi local. Caché de construcción:
docker builder prune, que no es parte de down.
El que engaña es el volumen. Si un ataque anterior escribió un usuario, una tabla o un archivo, ese resultado sigue ahí y el siguiente intento parece tener éxito inmediato. Es la trampa que convierte una sesión de práctica en una confusión de dos horas.
Clave: memoriza el comando completo, down -v --remove-orphans, y no uses versiones cortas. La disciplina aquí es literalmente no pensar.
Escribe tu puerta de salida
Adapta el script de la sección 7 a tu sistema y añádele dos comprobaciones más: que
ningún servicio use network_mode: host y que ningún montaje apunte
fuera del directorio del laboratorio. Pruébalo contra el lab-00-base
—debe pasar— y contra tres copias rotas, una por cada regla.
La base es docker compose config --format json: sobre esa
estructura, cada regla es una comprobación directa. Puertos: cada entrada debe
traer una dirección local. Modo de red: ningún servicio debe declarar el modo
anfitrión. Montajes: para cada montaje de tipo enlace, la ruta de origen
resuelta tiene que empezar por la ruta del laboratorio.
Las tres copias rotas son la parte del ejercicio que la gente se salta y la que de verdad enseña: un verificador que nunca has visto fallar no sabes si funciona. Escribe además el mensaje de error de cada regla diciendo qué servicio falla y cuál es la forma correcta.
Clave: lo evaluable es que las tres copias rotas fallen con mensajes distintos y accionables. Un “configuración inválida” genérico se ignora a la tercera vez.
Denegar por defecto en salida, con honestidad
Investiga cómo aplicarías denegar por defecto en salida al laboratorio: qué destinos habría que permitir para que siga funcionando, cómo los descubrirías sin adivinar, y qué pasa con las reglas que dependen de nombres de dominio. Escribe también la parte incómoda: en qué casos esta medida no compensa.
El procedimiento correcto tiene tres fases: registrar la salida durante un tiempo representativo, convertir ese registro en una lista de destinos legítimos, y solo entonces cambiar la política a denegar y abrir por excepción. Saltarse la primera fase es garantizar que algo se rompe y que la medida se revierte entera al día siguiente.
Con los nombres de dominio, la respuesta honesta es que el firewall del sistema no sirve: las direcciones cambian y se comparten. Lo que funciona es obligar a que la salida pase por un proxy que sí lee la petición y decide por nombre, con la ventaja añadida de que ese proxy registra. El coste es un componente más que mantener y un punto por el que pasa todo.
Cuándo no compensa: en máquinas de desarrollo de propósito general, donde la lista de destinos legítimos cambia cada día y la fricción hace que alguien termine desactivándolo entero. Un control desactivado protege menos que un control moderado que sigue puesto.
Clave: se evalúa el orden —medir, listar, bloquear— y que reconozcas el caso en el que la medida no compensa. Una respuesta que solo dice “hay que bloquear la salida” no ha entendido el coste.
Red Team · encuentra tu propio laboratorio desde otra máquina tuya
Sobre tu copia del laboratorio con el puerto publicado sin dirección, ponte en el papel del vecino de red: desde otro equipo tuyo, o desde una máquina virtual en modo puente controlada por ti, localiza el servicio y accede. Documenta cuántos pasos te costó. Después revierte a la forma correcta y repite exactamente los mismos pasos.
Con el puerto publicado sin dirección son dos pasos: un barrido de la red local y un escaneo de puertos habituales. El servicio responde y suele identificarse solo por su portada. Con la forma correcta, el segundo paso ya no encuentra nada: el socket no escucha en ninguna interfaz alcanzable, así que no hay conexión que rechazar ni banner que leer.
La conclusión que importa es el coste asimétrico. La protección cuesta nueve caracteres escritos una vez; el ataque cuesta dos comandos que cualquiera puede ejecutar sin saber lo que hace. Cuando una defensa es tan barata y una amenaza tan trivial, no hay conversación de intercambio que tener.
Clave: el entregable es la comparación de pasos, con la forma correcta y sin ella. Y el laboratorio vuelve a la forma correcta antes de cerrar el ejercicio, sin excepciones.
Blue Team · ¿te enteraste de la exposición?
Repite el ejercicio anterior mirando los logs del proxy y los eventos del sistema. Responde: ¿qué señal habrías tenido de que tu laboratorio estaba expuesto, sin escanear? Después diseña la detección que sí lo habría dicho, y decide dónde vive: en el arranque, periódica, o las dos.
Sin escanear, la señal es ninguna hasta que alguien visita el servicio, y para entonces ya ocurrió. En los logs del proxy verías una petición desde una dirección que no es la tuya, y ese es precisamente el detalle que se puede convertir en detección: alertar sobre cualquier petición cuyo origen no sea local.
La detección buena, sin embargo, es de estado y no de tráfico: comprobar los sockets en escucha y alertar sobre cualquiera que no esté acotado a la interfaz local. Debe vivir en los dos sitios. En el arranque, porque es el momento en que se introduce el error; y periódica, porque un servicio recreado a mitad de sesión no vuelve a pasar por el arranque.
Clave: la distinción evaluable es detección de estado frente a detección de tráfico. La de tráfico llega tarde por construcción.
Architecture Challenge · higiene de entornos efímeros en una empresa
Diseña la política de entornos efímeros de una empresa de cincuenta personas que desarrolla con contenedores. Define: cuánto vive un entorno como máximo, quién lo destruye y cómo, cómo garantizas que ninguno queda expuesto a la red corporativa, qué se conserva cuando se destruye, y cómo mides que la política se cumple sin preguntarle a nadie.
Una propuesta razonable: caducidad por defecto —un entorno se apaga solo a las veinticuatro horas y prolongarlo es una acción explícita y registrada—, y destrucción automática asociada al cierre de la rama o de la petición de cambio que lo creó. Nada depende de que alguien se acuerde.
Exposición: verificación en el pipeline sobre la forma expandida del manifiesto, que bloquea si hay puertos publicados fuera de la interfaz local, más un escaneo periódico del rango corporativo que compara lo que ve con lo que la política permite. El escaneo es la parte que no se puede falsear: mide la realidad, no las intenciones.
Conservación: los artefactos y los registros se exportan al destruir; los datos del entorno no se conservan nunca, precisamente para que nadie tenga la tentación de tratarlo como un sistema permanente. Y el indicador que se publica cada semana es uno solo: entornos vivos por encima de su caducidad.
Clave: no hay una única respuesta. Se evalúan tres cosas: caducidad automática, una medida observada desde fuera y una separación clara entre lo que se conserva y lo que se destruye.
13Preguntas de comprensión
En Linux, tu firewall deniega todo lo entrante y el puerto 8080 figura como cerrado. Un contenedor publicado en 8080:80 sigue siendo alcanzable desde otra máquina. ¿Por qué?
Tu regla vigila el camino hacia procesos locales; el paquete va por el camino de reenvío hacia el contenedor. Nunca se encuentran.
¿Qué te permite hacer un firewall con estado que uno sin estado no permite?
Sin estado tendrías que abrir la entrada de los puertos altos para recibir respuestas, y ahí se acaba el “denegar por defecto”.
¿Cuál es el procedimiento que devuelve el laboratorio a un estado idéntico al inicial?
La primera no borra nada. La tercera borra de más, incluidos otros proyectos. La segunda es la acotada al proyecto y completa.
¿Qué es denegar por defecto en salida y por qué casi nadie lo aplica?
Es molesto precisamente porque es efectivo: rompe las mismas conexiones oportunistas de las que depende un atacante.
14Reto adicional
Audita la exposición real de tu máquina
Haz el inventario completo de lo que tu equipo de trabajo escucha ahora mismo: cada socket, en qué dirección, qué proceso lo abrió y si es necesario. Incluye las dos familias de direcciones. Para cada entrada que escuche fuera de la interfaz local, decide una de tres: acotarla, cerrarla o justificarla por escrito. Repite el inventario una semana después y compara.
El resultado típico sorprende: entre cinco y quince sockets escuchando fuera de la interfaz local en un portátil normal, casi ninguno puesto ahí a propósito. Compartición de archivos e impresoras, descubrimiento de dispositivos, servicios de sincronización, alguna herramienta de desarrollo que arrancó con el sistema y un par de contenedores olvidados.
La decisión por entrada casi siempre es acotar: la mayoría de esos servicios funcionan igual escuchando solo en la interfaz local, y muchos ni siquiera se usan. Cerrar del todo es la segunda mejor opción. Justificar por escrito debería ser la excepción, y el hecho de tener que escribirlo ya filtra la mitad de los casos.
Clave: el segundo inventario, una semana después, es lo que convierte esto en un hábito. La superficie de ataque de una máquina no es un estado, es una película.
15Resumen
- Seis estados sobreviven a un laboratorio: contenedores, redes, volúmenes, huérfanos, imágenes construidas y caché de construcción.
- El comando de reset es uno y completo:
down -v --remove-orphans, seguido deup -d --force-recreate. - Un reset sin comprobación es una suposición. Verifica con
ps -a,volume lsynetwork ls. - Un firewall con estado permite cerrar la entrada por completo sin romper nada, porque reconoce las respuestas a lo que tú iniciaste.
- El firewall del sistema trabaja en capa 3/4: no entiende nombres de dominio. Para eso hace falta algo que lea la petición.
- Las reglas de Docker van por delante de las tuyas. Un puerto publicado sin dirección sigue abierto aunque tu firewall diga lo contrario.
- La protección efectiva no está en el firewall sino en el compose:
127.0.0.1:delante de cada puerto publicado. - Comprueba lo que escucha, no lo que configuraste, y mira las dos familias de direcciones.
--remove-orphans.16Mis notas
Estas notas se guardan solo en este navegador. No se envían a ningún servidor. Expórtalas desde el panel de progreso si cambias de máquina.
17Recursos
Los comentarios se cargan solo si los pides, desde GitHub Discussions. No se carga nada de terceros mientras no pulses.