He estado experimentando con Docker recientemente en la construcción de algunos servicios para jugar y una cosa que me molesta constantemente ha sido poner contraseñas en un Dockerfile. Soy un desarrollador, por lo que almacenar contraseñas en la fuente se siente como un golpe en la cara. ¿Debería esto ser una preocupación? ¿Hay alguna buena convención sobre cómo manejar las contraseñas en Dockerfiles?
162
Respuestas:
Definitivamente es una preocupación. Los archivos Docker se registran comúnmente en repositorios y se comparten con otras personas. Una alternativa es proporcionar las credenciales (nombres de usuario, contraseñas, tokens, cualquier cosa sensible) como variables de entorno en tiempo de ejecución . Esto es posible a través del
-e
argumento (para--env-file
variables individuales en la CLI) o argumento (para múltiples variables en un archivo)docker run
. Lea esto para usar el medio ambiente con docker-compose.El uso
--env-file
es definitivamente una opción más segura ya que esto protege contra los secretos que aparecenps
en los registros si se usaset -x
.Sin embargo, los entornos tampoco son particularmente seguros. Son visibles a través de
docker inspect
y, por lo tanto, están disponibles para cualquier usuario que pueda ejecutardocker
comandos. (Por supuesto, cualquier usuario al que tenga accesodocker
en el host también tiene root de todos modos).Mi patrón preferido es usar un script de envoltura como
ENTRYPOINT
oCMD
. El script de envoltura puede importar primero secretos desde una ubicación externa al contenedor en tiempo de ejecución, luego ejecutar la aplicación, proporcionando los secretos. La mecánica exacta de esto varía según el entorno de tiempo de ejecución. En AWS, puede usar una combinación de roles de IAM, el Servicio de administración de claves y S3 para almacenar secretos cifrados en un depósito de S3. Algo como HashiCorp Vault o credstash es otra opción.AFAIK no existe 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 funcionalidad nativa en Docker para este propósito.
Puede encontrar útiles los comentarios de shykes sobre config en contenedores .
fuente
.config
archivo.docker inspect
.docker inspect
. Si el atacante ya puede sudo, quitar su contraseña de la inspección de la ventana acoplable probablemente sea bastante baja en su lista de cosas que ahora pueden salir mal. Este detalle en particular me parece un riesgo aceptable.Nuestro equipo evita poner credenciales en los repositorios, lo que significa que no están permitidos
Dockerfile
. Nuestra mejor práctica dentro de las aplicaciones es usar créditos de variables de entorno.Resolvemos esto usando
docker-compose
.Dentro
docker-compose.yml
, puede especificar un archivo que contenga las variables de entorno para el contenedor:Asegúrese de agregar
.env
a.gitignore
, luego configure las credenciales dentro del.env
archivo como:Almacene el
.env
archivo localmente o en un lugar seguro donde el resto del equipo pueda tomarlo.Ver: https://docs.docker.com/compose/environment-variables/#/the-env-file
fuente
.gitignore
para que el.env
archivo con información confidencial no se registre en GitHub. Estoy bastante seguro de que esto no funcionará si lo añade.dockerignore
.env
archivo y realizo una implementación en un servidor en las instalaciones, ¿sugieres crear el.env
archivo nuevamente en el servidor manualmente?Docker ahora (versión 1.13 o 17.06 y superior) tiene soporte para administrar información secreta. Aquí hay una descripción general y documentación más detallada
Existe alguna característica similar en kubernetes y DCOS
fuente
docker secret create
:: crear un secretodocker secret inspect
: mostrar información detallada sobre un secretodocker secret ls
: ver todos los secretosdocker secret rm
: eliminar un--secret
indicador secreto específico paradocker service create
: crear un secreto durante la creación del servicio--secret-add
y--secret-rm
banderas paradocker service update
: actualizar el valor de un secreto o eliminar un secreto durante la tarea de actualización del servicio. Los secretos de Docker están protegidos en reposo en los nodos de administrador y aprovisionados a los nodos de trabajo cuando se inicia el contenedor.Nunca debe agregar credenciales a un contenedor a menos que esté bien transmitiendo los créditos a quien pueda descargar la imagen. En particular, hacer y
ADD creds
más tardeRUN 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 con acceso a la imagen extraerla.La solución típica que he visto cuando necesitas créditos para pagar dependencias y es usar un contenedor para construir otro. Es decir, normalmente tiene un entorno de compilación en su contenedor base y necesita invocarlo para construir su contenedor de aplicaciones. Entonces, la solución simple es agregar el origen de su aplicación y luego
RUN
los comandos de compilación. Esto es inseguro si necesitas credibilidad en esoRUN
. En cambio, lo que debe hacer es colocar su fuente en un directorio local, ejecutar (como endocker run
) el contenedor para realizar el paso de compilación con el directorio de origen local montado como volumen y las credenciales inyectadas o montadas como otro volumen. Una vez que se completa el paso de compilación, construye su contenedor final simplementeADD
usando el directorio de origen local que ahora contiene los artefactos construidos.¡Espero que Docker agregue algunas funciones para simplificar todo esto!
Actualización: parece que el método en el futuro será tener compilaciones anidadas. En resumen, el dockerfile 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 manera, el material de tiempo de construcción no está en el segundo contenedor. Se trata de una aplicación Java donde necesita el JDK para compilar la aplicación pero solo el JRE para ejecutarla. Se están discutiendo una serie de propuestas, lo mejor es comenzar desde https://github.com/docker/docker/issues/7115 y seguir algunos de los enlaces para propuestas alternativas.
fuente
Una alternativa al uso de variables de entorno, que pueden ser complicadas si tiene muchas de ellas, es usar volúmenes para hacer que un directorio en el host sea accesible en el contenedor.
Si coloca todas sus credenciales como archivos en esa carpeta, entonces el contenedor puede leer los archivos y usarlos como desee.
Por ejemplo:
Muchos programas pueden leer sus credenciales desde un archivo separado, por lo que de esta manera solo puede apuntar el programa a uno de los archivos.
fuente
solución de tiempo de ejecución solamente
docker-compose también proporciona una solución de modo sin enjambre (desde v1.11: Secretos que utilizan montajes de enlace ).
Los secretos se montan como archivos a continuación
/run/secrets/
por docker-compose. Esto resuelve el problema en tiempo de ejecución (ejecutando el contenedor), pero no en tiempo de compilación (compilando la imagen), porque/run/secrets/
no está montado en tiempo de compilación. Además, este comportamiento depende de ejecutar el contenedor con docker-compose.Ejemplo:
Dockerfile
docker-compose.yml
Para construir, ejecute:
Otras lecturas:
fuente
Con Docker v1.9 puede usar la instrucción ARG para buscar argumentos pasados por línea de comando a la imagen en la acción de compilación . Simplemente use --build-arg bandera . Por lo tanto, puede evitar mantener una contraseña explícita (u otra información sensible) en el Dockerfile y pasarlas sobre la marcha.
fuente: https://docs.docker.com/engine/reference/commandline/build/ http://docs.docker.com/engine/reference/builder/#arg
Ejemplo:
Dockerfile
compilar comando de imagen
durante la construcción imprimir
¡Espero eso ayude! Adiós.
fuente
--build-arg var=secret
para pasar una clave privada SSH a una imagen, no hay justificación documentada. ¿Alguien puede explicarlo?docker history
exponebuild-arg
/ARG
variables. Uno puede extraer cualquier imagen, inspeccionarla y ver los secretos pasados durante la construcción como un parámetrobuild-arg
/ARG
.Mi enfoque parece funcionar, pero probablemente sea ingenuo. Dime por qué está mal.
El subcomando de historial expone los ARG establecidos durante la construcción de Docker, por lo que no hay que ir allí. Sin embargo, cuando se ejecuta un contenedor, las variables de entorno proporcionadas en el comando de ejecución están disponibles para el contenedor, pero no forman parte de la imagen.
Entonces, en el Dockerfile, realice una configuración que no implique datos secretos. Establecer un CMD de algo así
/root/finish.sh
. En el comando de ejecución, use variables de entorno para enviar datos secretos al contenedor.finish.sh
utiliza las variables esencialmente para terminar las tareas de compilación.Para facilitar la administración de los datos secretos, colóquelos en un archivo cargado por Docker Run con el
--env-file
interruptor. Por supuesto, mantenga el archivo en secreto..gitignore
y tal.Para mí,
finish.sh
ejecuta un programa Python. Comprueba para asegurarse de que no se ha ejecutado antes, luego finaliza la configuración (por ejemplo, copia el nombre de la base de datos en Djangosettings.py
).fuente
Hay un nuevo comando docker para la gestión de "secretos". Pero eso solo funciona para grupos de enjambre.
fuente
La metodología de la aplicación de 12 factores dice que cualquier configuración debe almacenarse en variables de entorno.
Docker compose podría realizar una sustitución de variables en la configuración, por lo que podría usarse para pasar contraseñas de host a docker.
fuente
Si bien estoy totalmente de acuerdo, no hay una solución simple. Sigue habiendo un solo punto de falla. O el dockerfile, etcd, y así sucesivamente. Apcera tiene un plan que parece un 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 demostración, el uid / pwd estaba limpio y no podía reutilizarse hasta que el administrador configurara el enlace. Para que esto funcione, sin embargo, probablemente significó parchear Docker o al menos el complemento de red (si existe).
fuente