Fundamentos · Lección 04

Zero Trust y separación de responsabilidades

Durante treinta años, estar dentro de la red fue una credencial. Funcionaba porque “dentro” era un edificio con cables. Hoy “dentro” incluye un portátil en un aeropuerto, un contenedor efímero de un proveedor de nube y un pipeline que despliega solo. Zero Trust es la respuesta a eso, y no es un producto: es la decisión de verificar cada petición en vez de heredar la confianza del sitio desde el que llega. En esta lección vas a ver por qué el lab-00-base es un castillo con foso de manual, vas a moverte lateralmente dentro de él, y vas a reescribirlo para que ese movimiento deje de ser gratis. Y luego, la mitad que casi nunca se cuenta: la misma idea aplicada a las personas y a los pipelines.

Al terminar sabrás

  • Explicar qué sustituye Zero Trust exactamente, y qué no resuelve.
  • Reconocer un modelo de perímetro aunque esté repartido en veinte servicios.
  • Demostrar un movimiento lateral en tu laboratorio y medir cuánto cuesta impedirlo.
  • Distinguir microsegmentación de verificación por petición, que es donde empieza Zero Trust de verdad.
  • Aplicar mínimo conocimiento a una respuesta de API, a un log y a una variable de entorno.
  • Diseñar separación de responsabilidades en un pipeline, incluido el camino de emergencia.

1Por qué importa

En f01-principios aprendiste a preguntar qué pasa el minuto después de que se cruce una frontera. Esta lección responde a la versión más incómoda de esa pregunta: ¿qué pasa cuando el atacante ya está dentro y su siguiente movimiento no encuentra ninguna frontera más? Ese es el estado por defecto de casi cualquier arquitectura que no lo haya decidido explícitamente, incluido el laboratorio de este curso.

El modelo de perímetro fue razonable mientras el perímetro existía. Hoy el número de formas de llegar “dentro” ha crecido tanto —una credencial reutilizada, una dependencia con código añadido, un contenedor de un proveedor, un portátil personal— que asumir el interior como confiable es asumir el escenario que más veces ocurre. Zero Trust no dice que el interior sea hostil por dramatismo: lo dice porque la probabilidad de que haya alguien dentro dejó de ser despreciable.

La otra mitad de la lección es aún más vieja y se olvida más. La separación de responsabilidades es la idea de que ninguna identidad única debería poder completar sola una acción crítica. Aparece en contabilidad desde antes de que existieran los ordenadores, y en ingeniería se rompe todos los días de la misma forma: hay un pipeline con permisos para todo, y quien controle ese pipeline controla producción sin pasar por ninguna revisión. La verificación por petición y la separación de responsabilidades son la misma idea aplicada a máquinas y a personas, y por eso van juntas.

El objetivo real

El entregable de esta lección es una frase que puedas decir en una reunión sin que suene a folleto: “aquí la ubicación de red no autoriza nada, y esta acción no la puede completar una sola identidad”. Si tu arquitectura no permite decir ninguna de las dos cosas, ya sabes qué diseñar el trimestre que viene.

2Conceptos

Los seis términos
  • Zero Trust: ninguna confianza implícita por ubicación de red. Cada petición se autentica, se autoriza y se registra con su propio contexto.
  • Movimiento lateral: pasar de un recurso comprometido al siguiente sin volver a atravesar el perímetro. Es lo que Zero Trust ataca directamente.
  • Microsegmentación: reducir las rutas de red al par exacto que necesita hablar. Es un paso hacia Zero Trust, no Zero Trust.
  • Identidad de carga de trabajo: cada servicio tiene una identidad propia y verificable, no una contraseña compartida en un fichero.
  • Mínimo conocimiento: cada parte recibe solo los datos que necesita para su función. Aplica a respuestas, a logs y a variables de entorno.
  • Separación de responsabilidades: quien propone no aprueba, y quien aprueba no ejecuta. Ninguna identidad completa sola una acción crítica.

3Explicación profunda

Empecemos por lo que Zero Trust sustituye, porque la definición popular —“no confíes en nadie”— es inútil: sin confianza en algo no hay sistema posible. Lo que se retira es una credencial concreta y muy mala: la ubicación de red. Durante décadas, poder abrir una conexión desde cierto segmento equivalía a estar autorizado. Esa credencial no se puede rotar, no se puede revocar por usuario, no caduca, y se obtiene entera con el primer equipo comprometido de la oficina.

En su lugar, cada petición se evalúa con tres entradas: quién la hace —identidad verificable, no una dirección—, qué pide —recurso y verbo concretos— y en qué contexto —estado del dispositivo, hora, comportamiento reciente—. La decisión se toma cada vez, no una vez al entrar. Esa es toda la idea. Lo demás son detalles de implementación.

Conviene ser preciso con algo que se vende mal. Microsegmentar no es Zero Trust. Partir una red grande en veinte redes pequeñas reduce muchísimo el movimiento lateral, y merece la pena, pero sigue siendo confianza basada en ubicación: solo que la ubicación ahora es más pequeña. Zero Trust empieza cuando el servicio de destino no acepta una petición por venir de la red correcta, sino que exige una credencial de la carga de trabajo que llama y comprueba si esa identidad puede hacer eso concreto. Un sistema puede estar microsegmentado y seguir siendo un perímetro; y puede tener una red plana y ser Zero Trust, aunque sea una mala idea por otras razones.

Esto nos lleva al eslabón que sostiene el resto: la identidad de carga de trabajo. Si todos los servicios comparten una contraseña —como pasa en el lab-00-base, donde POSTGRES_PASSWORD es la misma para quien la necesita y para quien no— entonces no hay nada que autorizar por petición, porque no hay forma de saber quién llamó. Una credencial compartida convierte cualquier política en teatro. Las propiedades que hacen útil una identidad de carga de trabajo son cuatro: es por servicio, es de vida corta, tiene alcance —sirve para hablar con un destino y no con todos— y es verificable por el destino sin preguntarle a quien la presenta.

El principio de mínimo conocimiento es la versión de los datos del mínimo privilegio, y se rompe en sitios menos vigilados. Una respuesta de API que devuelve el objeto entero porque “el frontend ya filtra” está entregando datos que nadie necesitaba; un log que imprime el cuerpo completo de la petición está creando una segunda copia de datos sensibles en un sistema con controles más flojos; una variable de entorno con una contraseña presente en un contenedor que jamás se conecta a esa base de datos está regalando una credencial a quien comprometa ese contenedor. Ninguno de los tres es una vulnerabilidad en sentido estricto. Los tres aumentan enormemente el impacto de la primera que aparezca.

Y la separación de responsabilidades, que es donde este modelo toca a las personas. La regla es que ninguna identidad complete sola una acción crítica: quien escribe el cambio no lo aprueba, quien lo aprueba no lo despliega a mano, quien administra el sistema de registro no puede borrar sus propias huellas. En ingeniería moderna esto se rompe casi siempre por el mismo sitio: el pipeline. Se construye una automatización con permisos para desplegar en producción, y a partir de ese momento cualquiera que pueda modificar la definición del pipeline —normalmente cualquiera que pueda enviar código— tiene esos permisos. La separación que existía en la revisión de código desaparece por debajo, y el organigrama sigue diciendo que está todo bien.

Una opinión de diseño, marcada como tal: Zero Trust es caro y no siempre merece la pena entero. Implementar verificación por petición con identidades de vida corta en toda una organización cuesta años y consume el presupuesto que quizá hacía más falta en gestión de parches. El orden que yo defiendo es: primero cortar las rutas que nadie usa, que es barato y da la mayor parte de la reducción del movimiento lateral; después dar identidad propia a los servicios que tocan datos valiosos; y solo entonces, si el modelo de amenaza lo justifica, verificación por petición en todas partes. El contraejemplo honesto: en una organización donde el acceso inicial se da por descontado —muchos proveedores, muchos dispositivos ajenos— ese orden se invierte, porque el perímetro ya no existe ni siquiera como ficción útil.

4Ejemplo sencillo

# Dos edificios. La misma persona intentando entrar en el archivo.

CASTILLO Y FOSO
  recepcion    identificas al entrar, te dan una tarjeta
  pasillos     nadie vuelve a preguntarte nada
  archivo      la puerta esta abierta: estas dentro, luego puedes
  resultado    quien entre UNA vez, entra a todo

ZERO TRUST
  recepcion    no existe como frontera; no hay "dentro"
  pasillos     cada puerta lee tu tarjeta y consulta tu permiso
  archivo      comprueba quien eres, que pides y desde donde, cada vez
  resultado    quien entre una vez, ha entrado a UNA cosa

# Y la separacion de responsabilidades, en el mismo archivo

quien pide un expediente   no es quien autoriza sacarlo
quien autoriza             no es quien lo saca del estante
quien lleva el registro    no puede borrar su propia linea
El coste del modelo de la derecha es evidente: hay que comprobar en cada puerta. Ese coste es exactamente lo que compra que la primera credencial robada no lo abra todo.

El detalle que más se olvida está en la última línea. La separación de responsabilidades incluye al registro: si el administrador de los logs puede editar los logs, la evidencia solo sirve mientras el incidente no le implique a él. Es la razón de que los registros de auditoría se escriban en un sistema con distinto dueño y sin permiso de borrado.

5Ejemplo técnico

El lab-00-base es un castillo con foso de libro de texto. El foso es internal: true y está muy bien hecho: nada sale a internet. Dentro, sin embargo, no hay ni una sola puerta. Cuatro contenedores comparten una red plana, y la única credencial de la base de datos está escrita en el mismo fichero que describe todo lo demás.

Pregunta de Zero TrustRespuesta del laboratorio hoyQué haría falta
¿Quién hace esta petición?Nadie lo sabe: no hay identidad de servicioCredencial por servicio, no compartida
¿Está autorizado a este recurso?Sí, por estar en lab_internaAutorización por par origen-destino
¿Se verifica cada vez?Solo la contraseña, una vez por conexiónCredencial de vida corta y con alcance
¿Queda registrado quién fue?No: postgres registra el usuario lab, que son todosUn rol distinto por servicio y registro de conexiones
¿Quién necesita esa contraseña?Solo app; la tienen todos los que miren el composeMínimo conocimiento: el secreto solo donde se usa

La consecuencia es fácil de demostrar y por eso es un buen ejercicio: desde el contenedor atacante, que existe para simular un puesto ya comprometido, la base de datos está a un comando de distancia. No hace falta ningún exploit: hace falta leer un fichero y abrir una conexión.

movimiento lateral sin exploit
docker compose exec atacante sh -c "nc -z -w 3 db 5432 && echo alcanzable" alcanzable docker compose exec atacante sh -c "nc -z -w 3 monitor 22; echo salida=$?" salida=1 # no hay puerto ahi, pero la RUTA existe: el limite es lo que escucha, # no una politica. Eso es confianza por ubicacion, en una linea.

Fíjate en el segundo comando: falla porque no hay nada escuchando, no porque algo lo impida. Esa distinción es la lección entera. En un modelo de perímetro, la superficie alcanzable la decide qué servicios se han levantado; en Zero Trust la decide una política que alguien escribió a propósito.

6Diagrama

A la izquierda, un perímetro donde todos los servicios se alcanzan entre sí; a la derecha, rutas reducidas al par exacto y una comprobación de identidad en cada arista perimetro · confianza por ubicacion app db monitor atacante 6 rutas. Ninguna esta declarada: existen porque nadie las quito. zero trust · verificacion por peticion app db monitor atacante id id sin ruta ni identidad 2 rutas declaradas, cada una con comprobacion de identidad propia.
Lo que cambia no es el número de cajas, es de dónde salen las aristas: a la izquierda existen por omisión, a la derecha porque alguien las escribió. Un puesto comprometido a la derecha no hereda nada.
Ver el mismo diagrama como código Mermaid (editable)
flowchart LR
    subgraph PERIMETRO[perimetro]
        A1[app] --- D1[db]
        A1 --- M1[monitor]
        X1[atacante] --- D1
        X1 --- A1
        M1 --- D1
    end
    subgraph ZEROTRUST[zero trust]
        A2[app] -->|identidad| D2[db]
        A2 -->|identidad| M2[monitor]
        X2[atacante]
    end

7Código

El primer paso, el barato, es cortar las rutas que nadie usa. En un compose eso se escribe declarando una red por par de servicios que necesita hablar, en vez de una red común para todos:

# docker-compose.yml — de una red plana a rutas declaradas
networks:
  lab_borde:
    driver: bridge
  red_proxy_app:            # el proxy habla con la app
    driver: bridge
    internal: true
  red_app_db:               # la app habla con la base
    driver: bridge
    internal: true
  red_puesto:               # el puesto de pruebas solo ve el proxy
    driver: bridge
    internal: true

services:
  proxy:
    networks: [lab_borde, red_proxy_app, red_puesto]
  app:
    networks: [red_proxy_app, red_app_db]
  db:
    networks: [red_app_db]     # ya no la alcanza nadie mas
  monitor:
    networks: [red_puesto]
  atacante:
    networks: [red_puesto]     # solo llega al proxy

Eso reduce las rutas de seis a dos y se nota inmediatamente en el ejercicio de movimiento lateral. Pero es microsegmentación, no Zero Trust: la base de datos sigue aceptando a cualquiera que llegue por red_app_db con la contraseña correcta. El segundo paso es darle identidad a cada servicio, y aquí lo importante es el contrato, no el producto que lo implemente:

# contrato minimo de una identidad de carga de trabajo
identidad: servicio/app
emitida_por: autoridad interna, tras verificar la carga de trabajo
vida: 15m                  # si se filtra, caduca sola
audiencia: servicio/db        # solo vale para hablar con la base
alcance: [facturas.leer]     # y solo para eso
verificable: si                # el destino la valida sin preguntar al emisor

# Compara con lo que hay hoy en el laboratorio:
#   POSTGRES_PASSWORD: laboratorio_local
#   vida: infinita · audiencia: cualquiera · alcance: todo · quien la uso: nadie sabe

Los cuatro campos que faltan en la contraseña compartida son exactamente los cuatro que hacen útil una identidad. vida convierte un robo en una ventana; audiencia impide reutilizar la credencial contra otro servicio; alcance limita el daño de un uso legítimo mal intencionado; y verificable es lo que permite registrar quién hizo qué, que es la carencia que arrastras desde la primera lección de esta fase.

8Qué puede salir mal

Los cuatro errores clásicos

Comprar Zero Trust. Es una propiedad de la arquitectura, no un producto. Un túnel nuevo que sigue concediendo acceso a un rango de red completo tras autenticar una vez es exactamente el modelo anterior con otro nombre y otra factura.

Microsegmentar y declarar victoria. Reduce el movimiento lateral y merece la pena, pero mientras el destino autorice por origen de red sigues confiando en la ubicación. La pregunta de control es: si alguien consigue estar en la red correcta, ¿le basta con eso?

El secreto que viaja a donde no hace falta. Una variable de entorno con la contraseña de la base de datos definida a nivel global llega a contenedores que jamás la usan. Cada uno de ellos es ahora un sitio desde el que se filtra. Mínimo conocimiento se rompe casi siempre por comodidad de configuración.

El pipeline con permisos de dios. Se implanta revisión de dos personas para el código y a la vez existe una automatización que despliega a producción y cuya definición vive en el mismo repositorio. Quien pueda modificar esa definición ha saltado la revisión sin tocarla. La separación de responsabilidades se mide por el camino más corto, no por el previsto.

9Cómo lo abusaría un atacante

Vista desde el otro lado

El primer acceso casi nunca cae donde está el valor. Cae en un servicio secundario, un contenedor auxiliar, el portátil de alguien de soporte. Todo el trabajo real está en el segundo movimiento, y en un modelo de perímetro ese movimiento es gratis: la credencial que hace falta —estar dentro— ya la tiene por haber entrado. Por eso los informes de intrusión miden el tiempo entre el acceso inicial y el primer salto, y por eso ese número es tan corto.

La segunda cosa que busca es una credencial reutilizable. Una contraseña compartida sin caducidad ni destino es el objeto más valioso de cualquier sistema, porque funciona desde cualquier sitio, sirve contra todos los destinos y no deja constancia de quién la usó. Que esté en un fichero de configuración del repositorio, en una variable de entorno o en la memoria de un proceso solo cambia cuánto tarda en encontrarla.

Y el tercer objetivo, cuando el atacante es paciente, es el camino que salta la separación de responsabilidades. No hace falta convencer a nadie de aprobar un cambio malicioso: basta con modificar la parte del proceso que se ejecuta sin revisión —un script de compilación, una dependencia de desarrollo, una acción del pipeline referenciada por una etiqueta móvil— y esperar a que la organización despliegue el cambio por ti, con sus propias credenciales y con todos los formularios firmados.

10Cómo defenderlo

Qué hacer con esto mañana
  • Empieza por cortar rutas: enumera qué par de servicios necesita hablar y borra todo lo demás. Es lo más barato y lo que más movimiento lateral elimina.
  • Sustituye las credenciales compartidas por una identidad por servicio, aunque al principio sea solo un usuario distinto por cada uno en la base de datos.
  • Exige a cada credencial vida corta, audiencia y alcance. Sin los tres campos, una política de autorización no puede ser algo más que un adorno.
  • Aplica mínimo conocimiento a tres sitios concretos: la respuesta de la API, lo que se escribe en los logs y las variables de entorno de cada contenedor.
  • Comprueba la separación de responsabilidades por el camino más corto: pregunta qué identidad podría llevar un cambio a producción sin que otra persona lo mire.
  • Registra la identidad de quien llama en cada salto. Sin eso no hay detección posible de movimiento lateral, solo una lista de conexiones anónimas.

11Laboratorio

Estado: laboratorio local lab-00-base
Targethttp://localhost:8080
Autorizaciónsistema local creado por ti para entrenamiento
Todo lo que se practica en este curso se practica aquí dentro. Ninguna técnica de este material debe apuntarse a un sistema que no sea tuyo o para el que no tengas autorización escrita.

Última vuelta al mismo laboratorio. Aquí lo vas a usar en dos tiempos: primero medir cuánto vale estar dentro, y después quitarle ese valor.

cd cursos/seguridad/labs/lab-00-base docker compose up -d docker compose exec atacante sh -c "nmap -sT -p 80,5432 app db proxy monitor"

Ese barrido es el mapa de rutas del modelo de perímetro. Ahora usa la credencial que está escrita en el compose, desde el puesto que no debería tenerla:

la contraseña compartida, usada por quien no debe
docker compose exec atacante sh -c "nc -z -w 3 db 5432 && echo ruta abierta" ruta abierta docker compose exec db psql -U lab -d lab -c "select usename, client_addr from pg_stat_activity" usename | client_addr ---------+------------- lab | lab | # todas las sesiones son el mismo usuario: no hay forma de saber # cual era la app y cual el puesto comprometido

Segundo tiempo. Aplica el bloque de redes de la sección de código al compose, recrea el laboratorio y vuelve a medir. La misma orden que antes devolvía “ruta abierta” debe fallar ahora, y la aplicación debe seguir funcionando:

docker compose up -d --force-recreate docker compose exec atacante sh -c "nc -z -w 3 db 5432 || echo sin ruta, correcto" curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/

Si lo segundo imprime el mensaje y lo tercero devuelve 200, has eliminado cuatro rutas de movimiento lateral sin coste funcional. Revierte el compose y destruye el laboratorio:

docker compose down -v

12Ejercicios

Perímetro o Zero Trust

Clasifica cada afirmación y justifica en una línea: (1) “La base de datos solo acepta conexiones desde la red de aplicaciones”; (2) “Cada servicio presenta un certificado propio y el destino comprueba a qué puede llamar”; (3) “Una vez que entras por el túnel corporativo, alcanzas todos los sistemas internos”; (4) “Cada petición al panel de administración revalida la sesión y el estado del dispositivo”; (5) “Partimos la red en veinte segmentos”; (6) “Los tokens de servicio caducan a los quince minutos y sirven para un solo destino”.

La pregunta para cada frase es: si consigo estar en el sitio correcto, ¿me basta con eso para que me dejen pasar?
Hay una frase que parece Zero Trust y no lo es, porque solo hace el perímetro más pequeño. Reducir el tamaño de la zona de confianza no elimina la confianza por ubicación.
Busca en cada frase las tres entradas de una decisión Zero Trust: quién, qué pide y en qué contexto. Si falta “quién”, es perímetro.
Solución

Perímetro: (1), porque la autorización es la red de origen; (3), que es el caso puro; y (5), que es microsegmentación —mejor que una red plana, pero sigue autorizando por ubicación—. Zero Trust: (2), porque hay identidad verificable y política por destino; (4), porque revalida por petición e incorpora contexto; y (6), porque la credencial tiene vida y audiencia.

Clave: 3 y 3. La frase que separa a la gente que ha entendido la lección de la que no es la (5): es una mejora real y no es Zero Trust, y las dos cosas son ciertas a la vez.

Corta las rutas y mide la diferencia

Aplica al lab-00-base el esquema de redes por par de la sección de código. Antes y después, ejecuta el mismo barrido desde atacante y guarda las dos salidas. Escribe la tabla de rutas antes y después, di cuántas eliminaste, y responde a la pregunta importante: ¿qué sigue pudiendo hacer el puesto comprometido y por qué eso todavía no es Zero Trust? Revierte al terminar.

Una ruta existe si el nombre del otro servicio se resuelve y hay conectividad. Comprueba las dos cosas por separado: primero el nombre, después el puerto.
Compose solo resuelve por nombre los servicios que comparten alguna red con quien pregunta. Ese detalle hace la mitad del trabajo de segmentación por ti.
Después del cambio, el puesto sigue alcanzando el proxy. Pregúntate qué le pediría el proxy para dejarle pasar, y verás dónde sigue faltando la identidad.
Solución

Antes hay seis rutas entre los cuatro servicios internos; después quedan dos declaradas más la del puesto al proxy. El nombre db deja de resolverse desde atacante, así que ni siquiera hay que llegar al intento de conexión. La aplicación sigue funcionando porque su ruta a la base está declarada.

Lo que sigue pudiendo hacer el puesto es hablar con el proxy, y el proxy le atiende sin preguntarle nada: no hay identidad, no hay política, solo hay ruta. Por eso esto es microsegmentación. Sería Zero Trust cuando el proxy exigiera una credencial verificable de quien llama y comprobara si esa identidad puede pedir ese recurso concreto.

Clave: el entregable son las dos salidas del barrido y la frase que explica el hueco restante. Si tu conclusión fue “ya está segmentado, ya es Zero Trust”, vuelve a la sección de explicación.

Qué ata una identidad de carga de trabajo

Investiga fuera de esta lección un mecanismo real de identidad de carga de trabajo: cómo se le entrega la primera credencial a un proceso que aún no tiene ninguna, y qué impide que otro proceso de la misma máquina pida la suya haciéndose pasar por él. Explica después qué campos de la credencial hacen que robarla sirva de poco, y cuál es el problema que ese diseño no resuelve.

El problema tiene nombre propio: cómo se autentica algo que todavía no tiene con qué autenticarse. Busca por “el problema del primer secreto”.
Las soluciones reales se apoyan en algo que el proceso no puede falsificar: atestación de la plataforma, propiedades del orquestador, o hardware. Busca proyectos de identidad de carga de trabajo y sus documentos de arquitectura.
Compara el contrato del ejemplo de la lección —vida, audiencia, alcance, verificable— con los campos reales de un token de servicio de un orquestador moderno.
Solución

La primera credencial no se le da al proceso: se le da a algo que la plataforma puede verificar por su cuenta —qué imagen corre, en qué nodo, bajo qué cuenta de servicio— y a partir de esa atestación se emite una credencial de vida corta. Lo que impide la suplantación no es un secreto compartido, sino que el emisor comprueba propiedades que el solicitante no controla. Los campos que hacen que robarla sirva de poco son la caducidad corta, la audiencia —solo vale contra el destino declarado— y el alcance.

Lo que ese diseño no resuelve: si el proceso legítimo está comprometido, la credencial legítima se usa de forma ilegítima y ninguna cantidad de criptografía lo distingue. La identidad de carga de trabajo reduce el radio y la duración del daño; no impide el abuso desde dentro del propio servicio. Ahí es donde vuelven a hacer falta el alcance y la detección.

Clave: la respuesta tiene que nombrar el problema del primer secreto y terminar con la limitación. Una descripción que solo diga “cada servicio tiene su certificado” se ha saltado la pregunta.

Red Team · muévete lateralmente hasta los datos

Dentro del lab-00-base, y solo dentro de él: partiendo del contenedor atacante como único punto de control, llega hasta el contenido de la base de datos. Documenta cada salto y, para cada uno, escribe qué te lo permitió: una ruta, una credencial o la ausencia de una comprobación. Después mide cuántos de esos saltos sobreviven al esquema de redes por par.

No busques un fallo del software. Los tres ingredientes que necesitas están escritos en ficheros que ya has leído en esta fase.
El contenedor trae cliente de red pero no cliente de postgres. Piensa qué puedes instalar dentro del laboratorio, que sigue siendo tuyo y sigue sin salir a internet: quizá tengas que apoyarte en otro contenedor.
Empieza demostrando la ruta con nc -z, después consigue un cliente, y usa las credenciales tal cual están en el compose.
Solución

Salto 1: atacante resuelve el nombre db y alcanza su puerto. Lo permite una ruta que existe por omisión. Salto 2: autenticarse con el usuario y la contraseña del compose. Lo permite una credencial compartida, sin audiencia ni caducidad. Salto 3: leer y escribir sin restricción una vez dentro. Lo permite la ausencia de comprobación: un único rol con todos los permisos sobre todo.

Con el esquema de redes por par, el salto 1 desaparece y con él los otros dos, sin haber tocado la contraseña. Ese es el argumento a favor de empezar por cortar rutas: es el cambio más barato y el que invalida la cadena entera. Pero fíjate en que la credencial sigue siendo igual de mala, y que app —que sí conserva la ruta— la sigue usando: si el comprometido hubiera sido app, la segmentación no habría cambiado nada.

Clave: el entregable es la tabla salto → qué lo permitió. Y la conclusión honesta: segmentar salva del puesto lateral, no del servicio legítimo comprometido.

Blue Team · ¿quién se conectó a la base de datos?

Reproduce el movimiento lateral del ejercicio anterior y después intenta responder, únicamente con los logs del laboratorio, a tres preguntas: qué sesiones hubo, cuáles eran de la aplicación y cuál era del puesto comprometido. Enumera qué falta para poder distinguirlas y propón el cambio mínimo —sin añadir ninguna herramienta nueva— que lo haría posible.

Mira primero qué registra postgres por defecto sobre las conexiones: docker compose logs db. Compara con lo que necesitarías saber.
Postgres tiene parámetros para registrar conexiones y desconexiones, y un formato de línea de registro configurable donde caben el usuario y el origen.
Ningún formato de registro te va a salvar si todos usan el mismo usuario. El cambio mínimo tiene dos mitades y una es crear roles distintos.
Solución

Por defecto no hay forma de responder: las conexiones ni siquiera se registran, y aunque se registraran, todas llegarían como el mismo usuario desde direcciones que cambian en cada recreación del laboratorio. Falta lo de siempre: identidad. Es exactamente la misma carencia que anotaste en la primera lección de esta fase, ahora en otra capa.

Cambio mínimo, en dos mitades. Primera: un rol distinto por servicio, con los permisos que cada uno necesita y ninguno más —la aplicación no necesita crear tablas—. Segunda: activar el registro de conexiones y desconexiones e incluir usuario y origen en el formato de línea. Con las dos, una sesión del puesto comprometido aparece como un rol que no debería estar conectándose, y eso sí es una regla de detección escribible.

Clave: el entregable es la lista de lo que falta más las dos mitades del cambio. Si tu propuesta solo toca el formato del log, no has resuelto el problema: has mejorado la descripción de algo que sigue siendo anónimo.

Architecture Challenge · un despliegue que nadie pueda completar solo

Diseña la separación de responsabilidades de un pipeline que despliega a producción. Define quién puede proponer, quién aprueba, qué identidad ejecuta el despliegue y de dónde saca sus credenciales. Enumera después los caminos que saltarían tu diseño —modificar la definición del pipeline, una dependencia de compilación, un acceso administrativo directo al proveedor— y di cómo los cierras. Termina diseñando el camino de emergencia: cómo se despliega a las tres de la madrugada con una sola persona disponible.

Si la definición del pipeline vive en el mismo repositorio y se ejecuta desde la rama que se propone, quien propone ya controla lo que se ejecuta.
Separa dos cosas que se confunden: los permisos de la automatización y los permisos de quien la dispara. Los primeros no deberían estar disponibles para la segunda.
Un camino de emergencia que no existe se inventa en el peor momento y se queda para siempre. Diséñalo tú, con caducidad automática y revisión posterior obligatoria.
Solución

Una propuesta razonable: la definición del pipeline vive en un lugar que la rama propuesta no puede modificar, o al menos el trabajo con permisos de producción solo se ejecuta desde la rama principal ya fusionada. Las credenciales de despliegue no las tiene ninguna persona: las obtiene la automatización mediante una identidad de vida corta, ligada al repositorio y al entorno concreto. La aprobación es de una persona distinta de quien propone, y el despliegue lo ejecuta la automatización, no un humano con acceso directo.

Caminos que lo saltan y sus cierres: dependencias de compilación, fijadas por huella y no por etiqueta móvil; acceso administrativo directo al proveedor, retirado por completo y sustituido por el camino de emergencia; y el propio registro, escrito en un sistema donde ni quien despliega ni quien administra pueden borrar. El camino de emergencia: una identidad de un solo uso que se activa dejando constancia, caduca en horas, notifica en el momento a un canal que no controla quien la usa, y obliga a una revisión posterior con nombre y fecha.

Clave: no hay una única respuesta. Se evalúa que el camino de emergencia exista y sea ruidoso, que las credenciales de producción no estén en manos de personas, y que hayas nombrado al menos un camino que salta tu propio diseño.

13Preguntas de comprensión

Comprobación

Dentro de lab_interna, cualquier contenedor alcanza a db y le basta la contraseña del compose. ¿Qué modelo describe eso?

Una contraseña compartida por todos no identifica a nadie. El único requisito real para llegar a la base es estar en la red correcta.

¿Qué sustituye Zero Trust por verificación en cada petición?

La ubicación es una credencial que no caduca, no se revoca por usuario y se obtiene entera con el primer equipo comprometido.

Todos los servicios comparten la misma contraseña de la base de datos. ¿Qué se rompe antes que ninguna otra cosa?

Sin identidad no hay autorización por petición ni detección posible: solo una lista de conexiones anónimas indistinguibles.

¿Qué garantiza la separación de responsabilidades en un pipeline de despliegue?

Y se mide por el camino más corto: si modificar la definición del pipeline salta la revisión, la separación no existe aunque esté en el organigrama.

0 / 4

14Reto adicional

Aplica mínimo conocimiento a tres sitios a la vez

Toma un endpoint que devuelve el perfil de un usuario con todos sus campos —incluidos correo, teléfono, dirección, identificador interno y marca de administrador— y que además registra el cuerpo completo de cada petición. Rediseña las tres capas: qué devuelve la respuesta, qué se escribe en el log y qué variables de entorno tiene el contenedor que lo sirve. Para cada decisión, escribe qué ataque concreto encarece.

Empieza por preguntar quién consume cada campo. Un campo que solo usa una pantalla no tiene por qué venir en la respuesta general.
El identificador interno y la marca de administrador no son datos personales, pero son munición para el siguiente paso: uno permite enumerar, el otro permite elegir objetivo.
Para el log, la regla útil no es “no registres datos sensibles” sino “registra referencias, no contenidos”: un identificador de la petición vale más que su cuerpo.
Solución

Respuesta: solo los campos que consume quien llama, y por vista, no un objeto único reutilizado en todas partes. Fuera el identificador interno secuencial, que permite enumerar usuarios, y fuera la marca de administrador, que le ahorra al atacante elegir a quién atacar primero. Eso encarece la enumeración y la selección de objetivo, que son los dos pasos previos a casi cualquier ataque dirigido.

Log: identificador de correlación, identidad de quien llama, recurso y resultado de la autorización; nunca el cuerpo. Un log con cuerpos completos es una segunda base de datos de datos personales, guardada en un sistema con menos controles y más lectores. Entorno: solo los secretos que ese contenedor usa de verdad; los demás se quitan, porque cada uno multiplica lo que se filtra el día que ese proceso caiga.

Clave: lo que se evalúa es que cada decisión venga con el ataque que encarece. “Devolver menos campos” sin decir qué ataque dificulta es higiene, no diseño.

15Resumen

Puntos clave
  • Zero Trust retira una credencial concreta y muy mala: la ubicación de red, que no caduca, no se revoca y se obtiene entera con el primer equipo comprometido.
  • Cada petición se decide con tres entradas: quién, qué pide y en qué contexto. Cada vez, no una vez al entrar.
  • Microsegmentar no es Zero Trust: reduce el movimiento lateral y sigue autorizando por ubicación, solo que la ubicación es más pequeña.
  • Sin identidad de carga de trabajo no hay política posible: una credencial compartida convierte cualquier autorización en teatro.
  • Las cuatro propiedades que hacen útil una identidad: por servicio, vida corta, audiencia y alcance, verificable por el destino.
  • Mínimo conocimiento se rompe en tres sitios poco vigilados: la respuesta de la API, el log y las variables de entorno.
  • La separación de responsabilidades se mide por el camino más corto a producción, y ese camino casi siempre pasa por el pipeline.
¿Qué credencial concreta retira Zero Trust?
La ubicación de red. Es una credencial que no se puede rotar ni revocar por usuario, no caduca, y se obtiene entera con el primer equipo comprometido.
¿Por qué microsegmentar no es Zero Trust?
Porque el destino sigue autorizando por origen de red: la zona de confianza es más pequeña, pero la confianza sigue viniendo de la ubicación y no de una identidad verificada.
¿Qué cuatro propiedades hacen útil una identidad de carga de trabajo?
Que sea por servicio, de vida corta, con audiencia y alcance declarados, y verificable por el destino sin preguntarle a quien la presenta.
¿Por dónde se rompe casi siempre la separación de responsabilidades en ingeniería?
Por el pipeline: una automatización con permisos de producción cuya definición puede modificar cualquiera que envíe código, saltando la revisión sin tocarla.

16Mis notas

Cierre de la lección

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.