# ============================================================ # lab-00-base — el laboratorio de referencia del curso # ------------------------------------------------------------ # Cinco piezas, dos redes y una regla: NADA de esto sale a # internet salvo el proxy, y el proxy solo escucha en tu propia # maquina (127.0.0.1). Si un contenedor de este laboratorio # puede alcanzar un host de terceros, el laboratorio esta mal # montado y hay que arreglarlo antes de seguir. # # host (tu maquina) # └── 127.0.0.1:8080 ──► proxy ──┐ # │ lab_interna (internal: true) # ┌────────────┼────────────┬─────────────┐ # ▼ ▼ ▼ ▼ # app db monitor atacante # # docker compose up -d levantar # docker compose ps ver que corre # docker compose logs -f seguir los logs # docker compose down -v destruir, incluidos los volumenes # ============================================================ name: lab-00-base networks: # Red con salida: solo el proxy la toca. Es la unica frontera # entre el laboratorio y el resto del mundo. lab_borde: driver: bridge # internal: true significa que Docker NO crea ruta de salida. # Los contenedores de esta red no llegan a internet aunque # quieran. Es la diferencia entre practicar y ser un problema. lab_interna: driver: bridge internal: true volumes: db_datos: services: # --- unico punto de entrada ------------------------------- proxy: image: nginx:1.27-alpine container_name: lab00-proxy # El binding a 127.0.0.1 es deliberado: sin el, "8080:80" # publica el puerto en TODAS las interfaces y tu laboratorio # vulnerable queda expuesto a la red local (el wifi del cafe # incluido). ports: - "127.0.0.1:8080:80" volumes: - ./conf/proxy.conf:/etc/nginx/conf.d/default.conf:ro networks: - lab_borde - lab_interna depends_on: - app restart: unless-stopped # --- aplicacion objetivo ---------------------------------- app: image: nginx:1.27-alpine container_name: lab00-app volumes: - ./app:/usr/share/nginx/html:ro networks: - lab_interna # Sin "ports": la app NO es alcanzable desde el host salvo a # traves del proxy. Eso es la frontera de confianza dibujada # en YAML. restart: unless-stopped # --- base de datos ---------------------------------------- db: image: postgres:16-alpine container_name: lab00-db environment: POSTGRES_PASSWORD: laboratorio_local POSTGRES_USER: lab POSTGRES_DB: lab volumes: - db_datos:/var/lib/postgresql/data networks: - lab_interna restart: unless-stopped # --- observabilidad --------------------------------------- # Sin logs no hay defensa: la mitad del curso consiste en mirar # aqui despues de atacar. monitor: image: alpine:3.20 container_name: lab00-monitor command: ["sh", "-c", "apk add --no-cache curl bind-tools >/dev/null && sleep infinity"] networks: - lab_interna restart: unless-stopped # --- puesto del atacante ---------------------------------- # Desde aqui se lanzan las pruebas. Vive en la red interna, asi # que solo puede hablar con el resto del laboratorio. atacante: image: alpine:3.20 container_name: lab00-atacante command: ["sh", "-c", "apk add --no-cache curl bind-tools netcat-openbsd nmap >/dev/null && sleep infinity"] networks: - lab_interna restart: unless-stopped