Un fallo en el servidor de la tienda
Alguien encuentra un fallo en el programa que sirve las páginas de una tienda. Ahora puede hacer que ese programa haga cosas.
Lo que alcanza después depende de con qué usuario corre el programa. Depende también de qué más hay en la imagen y de lo que está escrito en ella.
Al terminar esta lección
Nota
Puedo decir qué hace segura una imagen para entregarla y arreglar un Dockerfile inseguro.
Palabras clave
| Palabra | Qué significa | Ejemplo |
|---|---|---|
| Root | el usuario que puede cambiar cualquier cosa del sistema | uid=0 |
| Usuario sin privilegios | un usuario normal con derechos limitados | |
| Etiqueta fija | una etiqueta de imagen que nombra una versión exacta | nginx:1.27-alpine |
| Secreto | una contraseña o clave que solo el programa debe conocer | |
| Superficie de ataque | todo lo de una imagen que un atacante podría usar |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Corre con un usuario que puede poco
Si no se dice otra cosa, el programa de un contenedor corre como root. Root puede cambiar cualquier archivo donde el contenedor pueda escribir, incluido un volumen montado.
Un usuario sin privilegios no puede. Si atacan al programa, el daño es menor. Compara los dos servicios principales de tu laboratorio.
¿Con qué usuario corre web?
docker exec web idSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
¿Con qué usuario corre cache?
docker exec cache idSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Deja que cache intente escribir en /etc
docker exec cache touch /etc/probeSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Deja que web intente lo mismo
docker exec web touch /etc/probeSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Crear un usuario en un Dockerfile
FROM python:3.12-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
RUN adduser -D -u 10001 shop
USER shop
CMD ["python", "app.py"]
Un error frecuente
Advertencia
Mucha gente cree que root dentro de un contenedor no importa, porque el contenedor está aislado. Los muros tienen fallos, y un volumen montado son datos reales. Añade un usuario y cambia a él con USER, como hace el cache del laboratorio.
Menos en la imagen, menos que atacar
Cada programa de una imagen es un posible fallo más. Cada herramienta es una herramienta más para un atacante.
Una base ligera, como una imagen Alpine, lleva mucho menos. La etiqueta decide qué versión recibes. Una etiqueta como latest se mueve: reconstruir el mes que viene puede dar otra imagen.
Ejemplo resuelto: dos etiquetas de una imagen
| Etiqueta | Tamaño en nuestra máquina de prueba | Qué significa |
|---|---|---|
| nginx:1.27 | 284 MB | un sistema completo debajo |
| nginx:1.27-alpine | 76,8 MB | un sistema pequeño debajo |
| nginx:latest | no se midió | lo más nuevo cuando construyes |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
¿Qué etiqueta fija cache?
docker inspect --format '{{.Config.Image}}' cacheSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un secreto escrito en una imagen se queda
Una imagen se comparte. Se sube a un registro, se copia a servidores y se pasa a compañeros. Lo que hay en una capa viaja con ella.
Una contraseña en un Dockerfile queda en las capas para siempre, aunque un paso posterior borre el archivo. Deja los secretos fuera de la imagen y dáselos al contenedor al arrancar.
Un Dockerfile con un secreto, no copiar
FROM alpine:3.20
ENV API_KEY=abc123-not-real
RUN echo hello
Ejemplo resuelto: dónde apareció un secreto
| Cómo se fijó | Dónde lo volvimos a leer | Lo que mostró |
|---|---|---|
| ENV en el Dockerfile | docker history --no-trunc | la línea ENV API_KEY=abc123-not-real |
| -e al arrancar el contenedor | docker inspect, Config.Env | DB_PASSWORD=hunter2 en la lista |
| Ninguna de las dos | nada en la imagen ni en los ajustes | un secreto entregado al ejecutar |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Lee todo lo que se dijo a cache
docker inspect --format '{{json .Config.Env}}' cacheSe muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Para ir más lejos
Toma el Dockerfile que tiene un secreto. Reescríbelo para que fije su etiqueta, corra como un usuario y no guarde ningún secreto.
Después ejecuta las tres funciones del trabajo sobre la versión vieja y sobre la tuya. La nueva debe salir limpia.