security - philip - Docker y contraseñas de seguridad
fundamentos de marketing philip kotler y gary armstrong pdf (10)
He estado experimentando con Docker recientemente en la creación de algunos servicios para jugar y una cosa que no deja de molestarme ha sido poner contraseñas en un archivo Docker. Soy un desarrollador, por lo que almacenar contraseñas en la fuente se siente como un golpe en la cara. ¿Debería ser esto una preocupación? ¿Hay alguna buena convención sobre cómo manejar contraseñas en Dockerfiles?
Aunque estoy totalmente de acuerdo, no hay una solución simple. Sigue habiendo un único punto de falla. Ya sea el archivo docker, etc., etc. Apcera tiene un plan que parece compinche: autenticación dual. En otras palabras, dos contenedores no pueden hablar a menos que haya una regla de configuración de Apcera. En su demo el uid / pwd estaba en claro y no podía ser reutilizado hasta que el administrador configuró el enlace. Para que esto funcione, sin embargo, probablemente signifique el parcheo de Docker o al menos el complemento de red (si existe tal cosa).
Como alternativa al uso de variables de entorno, que pueden ser complicadas si tiene muchas, es usar volúmenes para hacer que un directorio en el host esté accesible en el contenedor.
Si coloca todas sus credenciales como archivos en esa carpeta, el contenedor puede leer los archivos y usarlos como lo desee.
Por ejemplo:
$ echo "secret" > /root/configs/password.txt
$ docker run -v /root/configs:/cfg ...
In the Docker container:
# echo Password is `cat /cfg/password.txt`
Password is secret
Muchos programas pueden leer sus credenciales desde un archivo separado, por lo que de esta manera puede apuntar el programa a uno de los archivos.
Con Docker v1.9 puede usar la instrucción ARG para recuperar argumentos pasados por línea de comando a la imagen en la acción de compilación . Simplemente use el indicador --build-arg . De modo que puede evitar guardar contraseñas explícitas (u otra información sensible) en el archivo Docker y pasarlas sobre la marcha.
fuente: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg
Ejemplo:
Dockerfile
FROM busybox
ARG user
RUN echo "user is $user"
construir comando de imagen
docker build --build-arg user=capuccino -t test_arguments -f path/to/dockerfile .
durante la compilación, imprima
$ docker build --build-arg user=capuccino -t test_arguments -f ./test_args.Dockerfile .
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM busybox
---> c51f86c28340
Step 2 : ARG user
---> Running in 43a4aa0e421d
---> f0359070fc8f
Removing intermediate container 43a4aa0e421d
Step 3 : RUN echo "user is $user"
---> Running in 4360fb10d46a
**user is capuccino**
---> 1408147c1cb9
Removing intermediate container 4360fb10d46a
Successfully built 1408147c1cb9
¡Espero eso ayude! Adiós.
Docker ahora (versión 1.13 o 17.06 y superior) tiene soporte para administrar información secreta. Aquí hay una overview y documentation más detallada
Característica similar existe en kubernetes y kubernetes
Hay un nuevo comando de acoplador [1] para la administración de "secretos", pero eso solo funciona para los clústeres de enjambre.
docker service create
--name my-iis
--publish target=8000,port=8000
--secret src=homepage,target="/inetpub/wwwroot/index.html"
microsoft/iis:nanoserver
[1] documentation
Mi enfoque parece funcionar, pero probablemente sea ingenuo. Dime por qué está mal.
Los ARG configurados durante la construcción del acoplador están expuestos por el subcomando de historial, por lo que no debe ir allí. Sin embargo, cuando se ejecuta un contenedor, las variables de entorno dadas en el comando de ejecución están disponibles para el contenedor, pero no son parte de la imagen.
Entonces, en el archivo Docker, haga una configuración que no involucre datos secretos. Establezca un CMD de algo como /root/finish.sh
. En el comando ejecutar, use variables de entorno para enviar datos secretos al contenedor. finish.sh
usa las variables esencialmente para terminar las tareas de compilación.
Para facilitar la administración de los datos secretos, --env-file
en un archivo que --env-file
carga con el --env-file
. Por supuesto, mantén el archivo en secreto. .gitignore
y tal.
Para mí, finish.sh
ejecuta un programa de Python. Comprueba para asegurarse de que no se haya ejecutado antes, luego finaliza la configuración (por ejemplo, copia el nombre de la base de datos en settings.py
de Django).
Nuestro equipo evita colocar credenciales en los repositorios, lo que significa que no están permitidos en Dockerfile
. Nuestra mejor práctica dentro de las aplicaciones es usar creds de variables de entorno.
Resolvemos esto usando docker-compose
.
Dentro de docker-compose.yml
, puede especificar un archivo que contenga las variables de entorno para el contenedor:
env_file:
- .env
Asegúrese de agregar .env
a .gitignore
, luego configure las credenciales dentro del archivo .env
como:
SOME_USERNAME=myUser
SOME_PWD_VAR=myPwd
Almacene el archivo .env
localmente o en una ubicación segura donde el resto del equipo pueda tomarlo.
Ver: https://docs.docker.com/compose/environment-variables/#/the-env-file
Nunca debe agregar credenciales a un contenedor a menos que esté bien difundir las credenciales a cualquiera que pueda descargar la imagen. En particular, hacer y ADD creds
y luego RUN rm creds
no es seguro porque el archivo creds permanece en la imagen final en una capa intermedia del sistema de archivos. Es fácil para cualquier persona que tenga acceso a la imagen extraerla.
La solución típica que he visto cuando necesitas creds para realizar compras en dependencias es utilizar un contenedor para construir otro. Es decir, normalmente tiene algún entorno de compilación en su contenedor base y necesita invocarlo para crear su contenedor de aplicaciones. Entonces, la solución simple es agregar su fuente de la aplicación y luego RUN
los comandos de compilación. Esto no es seguro si necesita creds en ese RUN
. En cambio, lo que hace es colocar su fuente en un directorio local, ejecutar (como en la docker run
) el contenedor para realizar el paso de compilación con el directorio de origen local montado como volumen y las crónicas ya sea inyectadas o montadas como otro volumen. Una vez que se completa el paso de compilación, construye su contenedor final simplemente ADD
el directorio de origen local que ahora contiene los artefactos construidos.
¡Espero que Docker agregue algunas características para simplificar todo esto!
Actualización: parece que el método en adelante será tener compilaciones anidadas. En resumen, el archivo docker describiría un primer contenedor que se usa para construir el entorno de tiempo de ejecución y luego una segunda construcción de contenedor anidado que puede ensamblar todas las piezas en el contenedor final. De esta forma, las cosas del tiempo de compilación no están en el segundo contenedor. Esto es una aplicación Java donde necesitas el JDK para construir la aplicación, pero solo el JRE para ejecutarlo. Se están discutiendo varias propuestas, es mejor comenzar desde https://github.com/docker/docker/issues/7115 y seguir algunos de los enlaces para propuestas alternativas.
tiempo de ejecución única solución
docker-compose también proporciona una solución en modo no enjambre (desde v1.11: Secrets usando bind montajes ).
Los secretos se montan como archivos debajo /run/secrets/
by docker-compose. Esto resuelve el problema en tiempo de ejecución (ejecutar el contenedor), pero no en tiempo de compilación (creación de la imagen), porque /run/secrets/
no está montado en tiempo de compilación. Además, este comportamiento depende de ejecutar el contenedor con Docker-Componer.
Ejemplo:
Dockerfile
FROM alpine
RUN cat /run/secrets/password
CMD sleep inifinity
docker-compose.yml
version: ''3.1''
services:
app:
build: .
secrets:
- password
secrets:
password:
file: password.txt
Para construir, ejecuta:
docker-compose up -d
Otras lecturas:
Definitivamente es una preocupación. Los archivos Docker se registran comúnmente en los repositorios y se comparten con otras personas. Una alternativa es proporcionar credenciales (nombres de usuario, contraseñas, tokens, cualquier cosa sensible) como variables de entorno en tiempo de ejecución . Esto es posible mediante el argumento -e
(para vars individuales en la CLI) o --env-file
argumento --env-file
(para múltiples variables en un archivo) en la docker run
.
Usar --env-file
es definitivamente una opción más segura ya que esto protege contra los secretos que aparecen en ps
o en registros si uno usa set -x
.
Sin embargo, los archivos no son particularmente seguros tampoco. Son visibles a través de docker inspect
y, por lo tanto, están disponibles para cualquier usuario que pueda ejecutar comandos de docker
. (Por supuesto, cualquier usuario que tenga acceso a docker
en el host también tiene root de todos modos).
Mi patrón preferido es usar un script de envoltura como ENTRYPOINT
o CMD
. El script de contenedor puede primero importar secretos desde una ubicación externa en el contenedor en tiempo de ejecución, luego ejecutar la aplicación, proporcionando los secretos. La mecánica exacta de esto varía según su entorno de tiempo de ejecución. En AWS, puede usar una combinación de funciones de IAM, el Servicio de administración de claves y S3 para almacenar secretos encriptados en un depósito S3. Algo como HashiCorp Vault o credstash es otra opción.
AFAIK no hay un patrón óptimo para usar datos confidenciales como parte del proceso de compilación. De hecho, tengo una pregunta SO sobre este tema. Puede usar docker-squash para eliminar capas de una imagen. Pero no hay ninguna funcionalidad nativa en Docker para este propósito.
Puede encontrar comentarios útiles sobre la configuración en contenedores .