Moby: Reenviar el agente de clave ssh al contenedor

Creado en 13 jun. 2014  ·  190Comentarios  ·  Fuente: moby/moby

Sería bueno poder reenviar un agente clave ssh a un contenedor durante un run o build .
Con frecuencia necesitamos compilar código fuente que existe en un repositorio privado donde el acceso está controlado por la clave ssh.

Agregar el archivo de claves al contenedor es una mala idea ya que:

  1. Acabas de perder el control de tu clave ssh
  2. Es posible que deba desbloquear su clave mediante una frase de contraseña
  3. Es posible que su clave no esté en ningún archivo y que solo se pueda acceder a ella a través del agente de claves.

Podrías hacer algo como:

# docker run -t -i -v "$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" fedora ssh-add -l
2048 82:58:b6:82:c8:89:da:45:ea:9a:1a:13:9c:c3:f9:52 phemmer<strong i="15">@whistler</strong> (RSA)

Pero:

  1. Esto solo funciona para docker run , no para build .
  2. Esto solo funciona si el demonio de la ventana acoplable se ejecuta en el mismo host que el cliente.

La solución ideal es que el cliente reenvíe el socket del agente clave como puede hacerlo ssh .
Sin embargo, la dificultad en esto es que requeriría la construcción de API remota y adjuntar llamadas para admitir el proxy de un número arbitrario de flujos de sockets. Simplemente hacer un flujo de 2 vías no sería suficiente ya que el agente de clave ssh es un socket de dominio Unix y puede tener múltiples conexiones simultáneas.

aresecurity exintermediate kinfeature

Comentario más útil

@ kienpham2000 , ¿por qué esta solución no mantendría la clave en la capa de imagen? Las acciones de copiar y eliminar la clave se realizan en comandos separados, por lo que hay una capa que debería tener la clave.
Nuestro equipo estaba usando la solución suya hasta ayer, pero encontramos una solución mejorada:

  • Generamos una URL de firma previa para acceder a la clave con aws s3 cli, y limitamos el acceso durante unos 5 minutos, guardamos esta URL de firma previa en un archivo en el directorio repo, luego en dockerfile la agregamos a la imagen.
  • En dockerfile tenemos un comando RUN que hace todos estos pasos: use la URL previa para obtener la clave ssh, ejecute npm install y elimine la clave ssh.
    Al hacer esto en un solo comando, la clave ssh no se almacenaría en ninguna capa, pero se almacenará la URL de firma previa, y esto no es un problema porque la URL no será válida después de 5 minutos.

El script de construcción se ve así:

# build.sh
aws s3 presign s3://my_bucket/my_key --expires-in 300 > ./pre_sign_url
docker build -t my-service .

Dockerfile tiene este aspecto:

FROM node

COPY . .

RUN eval "$(ssh-agent -s)" && \
    wget -i ./pre_sign_url -q -O - > ./my_key && \
    chmod 700 ./my_key && \
    ssh-add ./my_key && \
    ssh -o StrictHostKeyChecking=no [email protected] || true && \
    npm install --production && \
    rm ./my_key && \
    rm -rf ~/.ssh/*

ENTRYPOINT ["npm", "run"]

CMD ["start"]

Todos 190 comentarios

Me pregunto si el # 6075 te dará lo que necesitas.

Un contenedor secreto podría hacerlo un poco más seguro, pero todos los puntos mencionados siguen vigentes.

+1 Esta capacidad también me resultaría útil. En particular, al crear contenedores que requieren software de repositorios de git privados, por ejemplo. Preferiría no tener que compartir una clave de repositorio en el contenedor y, en su lugar, me gustaría poder hacer que la "compilación de la ventana acoplable ..." use algún otro método para obtener acceso a las claves SSH desbloqueadas, tal vez a través de un ssh en ejecución -agente.

+1. Estoy empezando a mojarme los pies con Docker y esta fue la primera barrera que choqué. Pasé un tiempo tratando de usar VOLUME para montar el auth sock antes de darme cuenta de que la ventana acoplable no puede / no quiere montar un volumen de host durante una compilación.

No quiero copias de una clave SSH sin contraseña por ahí y la mecánica de copiar una en un contenedor y luego eliminarla durante la compilación se siente mal. Trabajo dentro de EC2 y ni siquiera me siento bien copiando mis claves privadas allí (sin contraseña o no).

Mi caso de uso es la construcción de un proyecto erlang con rebar. Efectivamente, _podría_ clonar el primer repositorio y AGREGARlo a la imagen con un Dockerfile, pero eso no funciona con las dependencias privadas que tiene el proyecto. Supongo que podría simplemente compilar el proyecto en la máquina host y AGREGAR el resultado a la nueva imagen de Docker, pero me gustaría compilarlo en la caja de arena que es Docker.

Aquí hay algunas otras personas que tienen el mismo caso de uso: https://twitter.com/damncabbage/status/453347012184784896

Por favor, abrace SSH_AUTH_SOCK, es muy útil.

Gracias

Editar: Ahora que sé más sobre cómo funciona Docker (capas FS), es imposible hacer lo que describí con respecto a AGREGAR una clave SSH durante una compilación y eliminarla más tarde. La clave seguirá existiendo en algunas de las capas FS.

+1, ¡poder usar SSH_AUTH_SOCK será muy útil!

Utilizo claves SSH para autenticarme con Github, ya sea un repositorio privado o público.

Esto significa que mis comandos git clone ven así: git clone [email protected]:razic/my-repo.git .

Puedo montar por volumen mi directorio host ~/.ssh en mis contenedores durante un docker run y ssh está todo bien. Sin embargo, no puedo montar mi ~/.ssh durante un docker build .

: +1: para el reenvío ssh durante las compilaciones.

Según tengo entendido, esta es una forma incorrecta. La forma correcta es crear una imagen de la ventana acoplable en la máquina de desarrollo y luego copiarla en el servidor de la ventana acoplable.

@SevaUA - no, eso no es correcto. Esta solicitud se debe a una limitación al hacer docker build... . No puede exportar una variable a esta etapa como puede hacerlo cuando hace un docker run ... . El comando de ejecución permite que las variables se exporten al contenedor de la ventana acoplable mientras se ejecuta, mientras que la compilación no lo permite. Esta limitación es parcialmente intencionada en función de cómo funciona Dockerd al crear contenedores. Pero hay formas de evitar esto y el caso de uso que se describe es válido. Entonces, esta solicitud intenta implementar esta capacidad en la compilación, de alguna manera.

Me gusta la idea del n. ° 6697 (tienda secreta / bóveda), y eso podría funcionar para esto una vez que se haya fusionado. Pero si eso no funciona, una alternativa es hacer cosas ssh de proxy transparente de hombre en el medio fuera del demonio de la ventana acoplable, interceptando el tráfico del demonio de la ventana acoplable (no internamente). Alternativamente, todas las solicitudes de git + ssh podrían ser a algún host definido localmente que haga proxy de forma transparente a github o lo que sea en lo que finalmente necesite terminar.

Esa idea ya se ha planteado (ver comentario 2). No resuelve el problema.

+1 para el reenvío ssh durante las compilaciones.

+1 en el reenvío del agente SSH en docker build

+1 para el reenvío ssh durante la compilación para npm install o similar.

¿Alguien ha conseguido que el reenvío ssh funcione durante la ejecución en OSX? He puesto una pregunta aquí: http://stackoverflow.com/questions/27036936/using-ssh-agent-with-docker/27044586?noredirect=1#comment42633776_27044586 parece que no es posible con OSX ...

+1 = (

Simplemente golpee este obstáculo también. Intentar ejecutar npm install apuntó a un repositorio privado. la configuración se parece a:
host -> vagrant -> docker can ssh-agent reenviar host -> vagrant -! docker

+1
Simplemente presione esto mientras intenta averiguar cómo hacer que el agente ssh funcione durante la 'compilación de docker'.

+1 igual que los chicos anteriores. Parece la mejor solución para este problema cuando se necesita acceder a uno o más repositorios privados de git (piense en bundle install y npm install por ejemplo) al crear la imagen de Docker.

Puedo montar el volumen de mi directorio host ~ / .ssh en mis contenedores durante una ejecución de la ventana acoplable y ssh está bien.

@razic ¿Puedes compartir cómo haces que funcione? Porque cuando lo intenté antes, se quejó de "Mal propietario o permisos".

¿A menos que se asegure de que todos los contenedores se ejecuten con un usuario o permisos específicos que le permitan hacer eso?

+1 a SSH_AUTH_SOCK

@tonivdv eche un vistazo al comando docker run en el comentario inicial sobre este problema. Enlaza monta la ruta a la que hace referencia SSH_AUTH_SOCK a /tmp/ssh_auth_sock dentro del contenedor, luego establece SSH_AUTH_SOCK en el contenedor a esa ruta.

@ md5 Supongo que @razic y @tonivdv están hablando de un montaje como este: -v ~/.ssh:/root/.ssh:ro , pero cuando haces esto, los archivos .ssh no son propiedad de root y, por lo tanto, no pasan las comprobaciones de seguridad.

@KyleJamesWalker sí, eso es lo que entiendo de @razic y que fue uno de mis intentos hace algún tiempo, así que cuando leí a @razic pude hacerlo funcionar, me preguntaba cómo :)

@tonivdv También me encantaría saber si es posible, aunque no pude encontrar nada cuando lo intenté por última vez.

+1 Estoy interesado en crear entornos de desarrollo desechables con Docker, pero no puedo hacerlo funcionar. Esto ayudaría mucho en ese sentido.

Para cualquiera que busque una solución temporal, tengo una solución que utilizo en la que las fuerzas brutas hacen las cosas:

https://github.com/atrauzzi/docker-laravel/blob/master/images/php-cli/entrypoint.sh

De ninguna manera es una solución deseable, ya que requiere un script de punto de entrada completo, pero funciona.

@atrauzzi enfoque interesante. Para nuestro entorno de desarrollo, construimos una imagen base y copiamos la clave ssh directamente en ella. Tiene la ventaja de no necesitar proporcionarlo en cada ejecución. Y cada imagen heredada de ese mago por defecto también tiene la clave. Sin embargo, a nuestra manera, obviamente no puede compartirlo públicamente; p

+1 esto sería genial

@tonivdv El contenedor para el que es el script se

@atrauzzi lo entiendo. Su enfoque debe ser adoptado por imágenes de la ventana acoplable que podrían requerir una clave ssh privada. Por ejemplo, una imagen de compositor debe incluir su script de punto de entrada en caso de repositorios privados. Al menos hasta que Docker venga con una solución nativa.

: +1: para reenvío ssh a través de compilación

¡Imprescindible aquí también!

@atrauzzi Actualmente estoy usando otro enfoque que realmente me gusta. Está creando un contenedor de volumen de datos con el material ssh en él. Cuando quiera usar sus claves ssh en otro contenedor, simplemente puedo usarlo con el siguiente comando:

docker run -ti --volumes-from ssh-data ...

De esta manera, no tiene la necesidad de poner un punto de entrada en cada imagen y puede funcionar con todas las imágenes.

Para crear ese contenedor hago lo siguiente

docker run \
  --name ssh-data \
  -v /root/.ssh \
  -v ${USER_PRIVATE_KEY}:/root/.ssh/id_rsa \
  busybox \
  sh -c 'chown -R root:root ~/.ssh && chmod -R 400 ~/.ssh'

Espero que esto pueda ayudar a otros :)

Salud

@tonivdv : tomé mi enfoque porque si alguien tiene que agregar o actualizar la configuración de SSH, debe volver a importarlo. El contenedor específico que estoy usando es uno que se construye para ejecutar comandos únicos, por lo que cada vez que se ejecuta, toma la copia para asegurarse de que esté actualizado.

@atrauzzi Sí, lo entiendo. Dicho esto, depende del usuario mantener correctamente su contenedor de volumen ssh. Incluso puede usar diferentes si es necesario. Y, opcionalmente, se puede generar sobre la marcha con un script. Pero no creo que haya una única solución buena. Todo depende de las necesidades. Solo quería compartir para que otros pudieran elegir qué solución en función de sus necesidades. Espero poder escribir sobre esto en un blog pronto, ¡y también te enviaré tu solución! Salud

No haría un requisito que las personas que ejecutan sus contenedores mantengan un contenedor de solo datos lleno de claves ssh. Parece involucrado.

@atrauzzi Es cierto que el contenedor de volumen debe estar allí, pero a tu manera, el usuario también debe compartir su clave ssh al ejecutar, ¿verdad? Entonces, además de tener la necesidad de un contenedor de volumen ssh, la única diferencia en ambas soluciones desde un punto de vista de ejecución es:

docker run ... --volumes-from ssh-data ... php-cli ...

y

docker run ... -v ~/.ssh:/path/.host-ssh ... php-cli ..

¿derecho? O me estoy perdiendo algo más :)

Pero entiendo completamente por qué lo estás haciendo a tu manera. Sin embargo, si desea utilizar, por ejemplo, una imagen de compositor de otra persona, la forma de volume-from funcionará de inmediato. Al menos evita crear tu propia imagen con el "truco del punto de entrada".

Como dije, ambos son una solución alternativa y ambos tienen pros y contras.

Salud

Sería genial recibir una actualización del equipo de Docker sobre el estado de esta función. Específicamente, la autenticación SSH de docker build .

Esto ya se acerca a 1 año. Algo sorprendente, dada la practicidad de los casos de uso de la vida real para esto. Actualmente, estamos generando imágenes dinámicamente mediante la confirmación de contenedores en ejecución. No podemos tener un Dockerfile en el repositorio de nuestra aplicación. Esto rompe el flujo de prácticamente todo. Realmente no puedo usar mi aplicación con ningún servicio de Docker como Compose o Swarm hasta que esto se resuelva.

Una actualización sería muy apreciada. Por favor y gracias.

/ cc @phemmer

No es que no queramos esta característica ni nada, realmente veo un caso de uso para algo como esto o secretos en la construcción, solo necesitaríamos una propuesta de alguien dispuesto a implementar y luego, si se aprueba, la implementación de la propuesta.
También hablo en mi nombre, no todos los mantenedores.

@jfrazelle

Sé que no nos están ignorando :)

Entonces el estado es:

Es algo que consideraríamos implementar si hay una propuesta aceptada.
y ancho de banda de ingeniería.

¿Te suena esto exacto?

Además, ¿existen actualmente propuestas abiertas que aborden este tema?

El martes 7 de abril de 2015, Jessie Frazelle [email protected] escribió:

No es que no queramos esta función ni nada, realmente veo un uso
caso de algo como esto o secretos en la compilación, solo necesitaríamos un
propuesta de alguien dispuesto a implementar y luego, si se aprueba, la
implementación de la propuesta.
También hablo en mi nombre, no todos los mantenedores.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

Es algo que consideraríamos implementar si hay una propuesta aceptada.
y ancho de banda de ingeniería.

Y no creo que haya propuestas abiertas al respecto.

El martes 7 de abril de 2015 a las 2:36 p. M., Zachary Adam Kaplan <
[email protected]> escribió:

@jfrazelle

Sé que no nos están ignorando :)

Entonces el estado es:

Es algo que consideraríamos implementar si hay una propuesta aceptada.
y ancho de banda de ingeniería.

¿Te suena esto exacto?

Además, ¿existen actualmente propuestas abiertas que aborden este tema?

El martes 7 de abril de 2015, Jessie Frazelle [email protected]
escribió:

No es que no queramos esta función ni nada, realmente veo un uso
caso de algo como esto o secretos en la compilación, solo necesitaríamos un
propuesta de alguien dispuesto a implementar y luego, si se aprueba, la
implementación de la propuesta.
También hablo en mi nombre, no todos los mantenedores.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90738913.

No sé si estoy simplificando demasiado las cosas, pero aquí está mi propuesta:

SSHAGENT: reenviar # valores predeterminados para ignorar

Si se establece, durante la compilación, el socket y las variables de entorno asociadas se conectan al contenedor, donde se pueden usar. Las piezas mecánicas de este ya existen y están funcionando, solo es cuestión de conectarlas en docker build .

No tengo ninguna experiencia trabajando dentro del código base de la ventana acoplable, pero esto es lo suficientemente importante para mí como para considerar asumirlo.

Estupendo. ¿Dónde puedo averiguar cómo enviar una propuesta? Hay un
directriz específica o debería abrir un problema?

El martes 7 de abril de 2015, Jessie Frazelle [email protected] escribió:

Es algo que consideraríamos implementar si se aceptara
propuesta
y ancho de banda de ingeniería.

Y no creo que haya propuestas abiertas al respecto.

El martes 7 de abril de 2015 a las 2:36 p. M., Zachary Adam Kaplan <
[email protected]
<_e i = "18">

@jfrazelle

Sé que no nos están ignorando :)

Entonces el estado es:

Es algo que consideraríamos implementar si se aceptara
propuesta
y ancho de banda de ingeniería.

¿Te suena esto exacto?

Además, ¿existen actualmente propuestas abiertas que aborden este tema?

El martes 7 de abril de 2015, Jessie Frazelle < [email protected]
<_e i = "31" /> escribió:

No es que no queramos esta función ni nada, realmente veo una
usar
caso de algo como esto o secretos en la compilación, solo necesitaríamos un
propuesta de alguien dispuesto a implementar y luego, si se aprueba, la
implementación de la propuesta.
También hablo en mi nombre, no todos los mantenedores.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90738913.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90739596.

Quiero decir como una propuesta de diseño
https://docs.docker.com/project/advanced-contributing/#design -proposal

El martes 7 de abril de 2015 a las 2:39 p.m., Daniel Staudigel [email protected]
escribió:

No sé si estoy simplificando demasiado las cosas, pero aquí está mi propuesta:

SSHAGENT: reenviar # valores predeterminados para ignorar

Si se establece, durante la compilación, el socket y las variables de entorno asociadas son
conectados al contenedor, donde se pueden utilizar. Las piezas mecanicas
de esto ya existen y están funcionando, es solo una cuestión de conectar
ellos en la construcción de Docker.

No tengo ninguna experiencia trabajando dentro del código base de la ventana acoplable, pero esto
es lo suficientemente importante para mí como para considerar asumirlo.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90739803.

Esta es una idea de muy alto nivel, pero ¿qué pasa si en lugar de adjuntar a través de la api remota de Docker, Docker ejecuta un demonio init, con un demonio ssh incluido, dentro del contenedor?

Esto podría usarse para resolver una serie de problemas.

  • Este demonio sería PID 1, y el proceso de contenedor principal sería PID 2. Esto resolvería todos los problemas con PID 1 que ignora las señales y los contenedores no se cierran correctamente. (# 3793)
  • Esto permitiría reenviar limpiamente el agente de claves SSH. (# 6396)
  • Este demonio podría mantener abiertos los espacios de nombres (# 12035)
  • Un TTY sería creado por el demonio (# 11462)
  • ... y probablemente muchos otros problemas que me estoy olvidando.

es posible que desee ver https://github.com/docker/docker/issues/11529 sobre el
primer punto de viñeta

El martes 7 de abril de 2015 a las 2:46 p.m., Patrick Hemmer [email protected]
escribió:

Esta es una idea de muy alto nivel, pero ¿y si en lugar de adjuntar
la api remota de docker, docker ejecutó un demonio init, con un ssh incluido
demonio, dentro del contenedor?

Esto podría usarse para resolver una serie de problemas.

  • Este demonio sería PID 1 y el proceso del contenedor principal sería
    PID 2. Esto resolvería todos los problemas con PID 1 ignorando señales y
    contenedores que no cierran correctamente. (# 3793
    https://github.com/docker/docker/issues/3793)
  • Esto permitiría reenviar limpiamente el agente de claves SSH. (# 6396
    https://github.com/docker/docker/issues/6396)
  • Este demonio podría mantener abiertos los espacios de nombres (# 12035
    https://github.com/docker/docker/issues/12035)
  • El daemon crearía un TTY (# 11462
    https://github.com/docker/docker/issues/11462)
  • ... y probablemente muchos otros problemas que me estoy olvidando.

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90741192.

11529 no tiene ninguna relación con el problema del PID 1.

dispara, copia, pega, ahora tengo que encontrar el otro otra vez

no, es ese, arregla las cosas zombies de PID 1, que es a lo que pensé que te referías, pero independientemente de que solo estuviera publicando, ya que su prueba es todo

@phemmer Parece que tiene la experiencia necesaria para guiarnos en la elaboración de una propuesta inteligente de implementación.

También parece que @dts y yo estamos dispuestos a dedicar tiempo a trabajar en esto.

@phemmer y @dts ¿hay alguna forma posible de que podamos llevar esta discusión a un cliente de chat en tiempo real un poco más para facilitar la comunicación? Estoy disponible a través de Slack, Google Chat / Hangout, IRC y descargaré cualquier otra cosa si es necesario.

@phemmer Parece que tiene la experiencia para guiarnos en la elaboración de una propuesta inteligente de implementación.

Lamentablemente no realmente :-)
Puedo arrojar ideas de diseño, pero solo conozco pequeñas partes del código base de la ventana acoplable. Es probable que este tipo de cambio sea a gran escala.

Ya ha habido algunas propuestas aquí:

@phemmer sugirió

¿Qué pasa si en lugar de adjuntar a través de la api remota de Docker, Docker ejecuta un demonio init, con un demonio ssh incluido, dentro del contenedor?

@dts sugerido

SSHAGENT: reenviar # valores predeterminados para ignorar
Si se establece, durante la compilación, el socket y las variables de entorno asociadas se conectan al contenedor, donde se pueden usar. Las piezas mecánicas de esto ya existen y están funcionando, solo es cuestión de conectarlas en la construcción de la ventana acoplable.

@razic sugirió

Habilite el enlace de volumen para docker build .

Lo que realmente necesitamos en este momento es que alguien acepte uno de ellos para que podamos empezar a trabajar en él.

@jfrazelle ¿ Alguna idea de cómo podemos llegar al siguiente paso? Realmente solo estoy tratando de hacer esto. Está claro que hay mucho interés en esto. Estoy dispuesto a defender la función, verla hasta su finalización.

Puedo estar disponible para una reunión de slack / irc / Gchat / etc., creo que esto facilitará un poco las cosas, al menos para reunir los requisitos y decidir un curso de acción razonable.

@dts sugerido

SSHAGENT: reenviar # valores predeterminados para ignorar

Esta es solo una idea de cómo se consumiría, no se implementaría. El "demonio init / ssh" es una idea de cómo se implementaría. Ambos podrían existir.

@razic sugirió

Habilite el enlace de volumen para la ejecución de la ventana acoplable.

Desafortunadamente, esto no funcionaría. Suponiendo que esto signifique docker build , y no docker run , que ya admite montajes de volumen, el cliente puede ser remoto (boot2docker es un ejemplo destacado). Los enlaces de volumen solo funcionan cuando el cliente está en el mismo host que el demonio de la ventana acoplable.

@razic, por favor vea este enlace sobre la propuesta de diseño ... esas no son propuestas https://docs.docker.com/project/advanced-contributing/#design -proposal

@femmer

No entiendo exactamente por qué esto no puede funcionar. docker-compose funciona con montajes de volumen contra un clúster swarm . Si el archivo / carpeta no está en el sistema host, ejerce el mismo comportamiento que si ejecutara -v con una ruta que no existe.

@jfrazelle Lo tengo.

Si el archivo / carpeta no está en el sistema host, ejerce el mismo comportamiento que si ejecutara -v con una ruta que no existe en una ventana acoplable local.

No estoy seguro de seguir tu punto. ¿Cómo ayuda ese comportamiento con este problema?
Si tengo un agente de clave ssh escuchando en /tmp/ssh-UPg6h0 en mi máquina local, y tengo la ventana acoplable ejecutándose en una máquina remota, y llamo a docker build , ese agente de clave ssh local no es accesible para el demonio de Docker. El montaje de volumen no lo obtendrá y los contenedores docker build no tendrán acceso a la clave ssh.

Desde un nivel alto, veo solo 2 formas de resolver esto:

1. Proxy el socket del agente de clave ssh:

El demonio de la ventana acoplable crea un socket de dominio Unix dentro del contenedor y cada vez que algo se conecta a él, envía esa conexión al cliente que en realidad está ejecutando el comando docker build .

Esto puede ser difícil de implementar ya que puede haber un número arbitrario de conexiones a ese socket de dominio Unix dentro del contenedor. Esto significaría que el demonio y el cliente de la ventana acoplable tienen que usar un proxy para un número arbitrario de conexiones, o que el demonio debe poder hablar el protocolo del agente ssh y multiplexar las solicitudes.

Sin embargo, ahora que la API remota de Docker admite websockets (no lo era en el momento en que se creó este problema), esto podría no ser demasiado difícil.

2. Inicie un demonio SSH real

En lugar de piratear el agente ssh, utilice una conexión ssh real desde el cliente al contenedor. El cliente de la ventana acoplable tendría un cliente ssh incluido o invocaría ssh en el contenedor remoto.
Este sería un cambio de escala mucho mayor, ya que reemplazaría la forma en que se implementa la fijación a los contenedores. Pero también evitaría que Docker tenga que manejar eso y migrar a protocolos estándar.
Esto también tiene el potencial de resolver otros problemas (como se menciona aquí ).

Entonces, en última instancia, un cambio de escala mucho mayor, pero podría ser una solución más adecuada.
Aunque de manera realista, debido a la escala, dudo que esto suceda.

@femmer

No estoy seguro de seguir tu punto. ¿Cómo ayuda ese comportamiento con este problema?

Porque el caso de uso más común para esto son las personas que crean imágenes con dependencias que se alojan en repositorios privados que requieren autenticación SSH.

Construye la imagen en una máquina que tiene una clave SSH. Así de simple.

Si tengo un agente de clave ssh escuchando en / tmp / ssh-UPg6h0 en mi máquina local, y tengo la ventana acoplable ejecutándose en una máquina remota, y llamo a la compilación de la ventana acoplable, ese agente de clave ssh local no es accesible para el demonio de la ventana acoplable.

Sé. ¿A quien le importa? Ejecutaré docker build en una máquina que tenga acceso al socket de autenticación.

Lo que estoy tratando de decir es ... docker-compose permite usar el comando de volumen contra un clúster swarm , independientemente de si el archivo está realmente en el host o no. .

Deberíamos hacer lo mismo para los montajes de volumen en las compilaciones de Docker.

| El archivo está en el sistema | Acción |
| : - | : - |
| Si | Monte |
| No | Ninguno (en realidad, intenta montar pero crea una carpeta vacía si el archivo / carpeta no existe, puede verificar esto ejecutando docker run -v /DOES_NOT_EXIST:/DOES_NOT_EXIST ubuntu ls -la /DOES_NOT_EXIST ) |

Uno de los conceptos detrás de swarm es hacer que el modelo multi-host sea transparente.

Es bueno que estemos pensando en la ventana acoplable remota, pero en realidad no debería importar.

Deberíamos copiar el comportamiento para el montaje de volumen para docker build exactamente de la misma manera que lo hacemos para docker run .

Desde https://github.com/docker/compose/blob/master/SWARM.md :

Lo principal que impide que las aplicaciones de contenedores múltiples funcionen sin problemas en Swarm es hacer que se comuniquen entre sí: habilitar la comunicación privada entre contenedores en diferentes hosts no se ha resuelto de una manera no pirata.

Las redes a largo plazo se están revisando de tal manera que se ajustarán mucho mejor al modelo de múltiples hosts. Por ahora, los contenedores vinculados se programan automáticamente en el mismo host.

@phemmer Creo que la gente probablemente esté pensando en una solución para el problema que describiste. El problema que está describiendo suena como https://github.com/docker/docker/issues/7249, que está separado.

Si adoptamos mi enfoque: solo permitir el montaje del volumen en la compilación de la ventana acoplable (independientemente de si el archivo que está tratando de montar está realmente en el sistema , entonces podemos cerrar este problema y comenzar a trabajar en https://github.com/ docker / docker / issues / 7249, que ampliaría el comportamiento de esta función para trabajar con demonios de docker remotos que no tienen el archivo local.

@ cpuguy83 Antes de crear una propuesta, estaba mirando # 7133 y noté que parece directamente relacionado.

¿Podrías agregar algunas palabras aquí? ¿El # 7133 está realmente relacionado con mi sugerencia para solucionar este problema, que es permitir que docker build soporte volúmenes?

@razic Es en relación con el hecho de que VOLUME /foo realidad crea un volumen y lo monta en el contenedor durante la compilación, lo que generalmente no es deseable.

También diría que una propuesta basada en el uso de bind-mounts para colocar archivos en contenedores de compilación probablemente no funcionará.
Ver # 6697

La ejecución de -v con la compilación de Docker podría tener una ruta de ejecución de código diferente.
En lugar de crear un volumen y montarlo durante la construcción, podemos retener el
comportamiento actual en el que no se hace referencia a los volúmenes de los archivos docker. Y
en su lugar, solo actúa sobre -v cuando se ejecuta usando argumentos para la CLI.

El miércoles 8 de abril de 2015, Brian Goff [email protected] escribió:

@razic https://github.com/razic Es en relación con el hecho de que VOLUME
/ foo en realidad crea un volumen y lo monta en el contenedor durante
build, que generalmente es indeseable.

También diría una propuesta basada en el uso de bind-mounts para obtener archivos en
construir contenedores probablemente no va a volar.
Ver # 6697 https://github.com/docker/docker/pull/6697

-
Responda a este correo electrónico directamente o véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90905722.

@ cpuguy83 Gracias por la aclaración.

6697 Tampoco va a volar porque ya está cerrado y el # 10310 es prácticamente un engaño del # 6697.

+1, acabo de golpear esto hoy mientras intentaba crear una imagen para una aplicación Rails que usa Bower para instalar las dependencias del lado del cliente. Sucede que una de las dependencias apunta a [email protected]:angular/bower-angular-i18n.git y dado que git falla allí, bower falla y la construcción de la imagen también falla.

Me gusta mucho lo que hace vagabundo por cierto. Con una única configuración de forward_agent en Vagrantfile, esto se resuelve para invitados vagabundos. ¿Podría Docker implementar algo como esto?

Además, como nota adicional, esto sucede mientras se construye la imagen. ¿Alguien sabe de alguna solución alternativa existente?

Mi solución fue generar un nuevo par de claves RSA, configurar la clave pub en github (agregar la huella digital) y agregar la clave privada a la imagen de Docker:

ADD keys/docker_rsa /srv/.ssh/id_rsa

Me encantaría evitar esto, pero supongo que es aceptable por ahora. ¡Cualquier otra sugerencia apreciada!

No estoy seguro de quién ha matado a más cachorros. Usted por hacer eso, o Docker por no brindarle una mejor manera hasta ahora.

En cualquier caso, probablemente voy a presentar una propuesta este fin de semana. @ cpuguy83 tiene razón en que la gente al menos está pensando en esto y discutiendo posibles soluciones. Entonces, en este punto, solo se trata de que nos pongamos de acuerdo en algo y de que alguien trabaje en ello. Estoy totalmente dispuesto a trabajar en ello, ya que en realidad es una de mis mayores quejas con Docker actualmente.

@razic Es un caso de uso bastante común, así que gracias por investigar esto también. En cuanto a la solución, funciona. Posiblemente, la clave podría eliminarse de la imagen después de ser utilizada, después de todo, solo se usa para obtener el código de la aplicación de github.

@fullofcaffeine No estoy 100% seguro de cómo funciona Docker internamente, pero creo que, a menos que se haga en un solo comando RUN (lo cual es imposible con su solución alternativa), el historial de la imagen mantiene la clave SSH.

@razic buen punto.

Como solución a esta limitación, hemos estado jugando con la idea de descargar las claves privadas (desde un servidor HTTP local), ejecutar un comando que requiere las claves y luego eliminar las claves.

Dado que hacemos todo esto en un solo RUN , nada se almacena en caché en la imagen. Así es como se ve en el Dockerfile:

RUN ONVAULT npm install --unsafe-perm

Nuestra primera implementación en torno a este concepto está disponible en https://github.com/dockito/vault

El único inconveniente es que requiere que el servidor HTTP se ejecute, por lo que no se crea ningún concentrador Docker.

Déjame saber lo que piensas :)

+1
Me encantaría ver esto implementado, ayudaría a configurar contenedores para el entorno de desarrollo.

+1, solo necesita ssh-agent reenviado con boot2dock

Terminamos haciendo un proceso de 3 pasos para sortear esta limitación:

  1. compile el contenedor de la ventana acoplable sin las dependencias requeridas por SSH, agregando la fuente en el paso final
  2. monte la fuente a través del volumen compartido, más SSH_AUTH_SOCK a través del volumen compartido y ejecute el paso de compilación, escribiendo la salida que requiere ssh (por ejemplo, gemas ruby ​​alojadas en github) de nuevo en el volumen compartido
  3. Vuelva a ejecutar la compilación de la ventana acoplable, que volverá a activar la adición de origen, ya que las gemas ahora se encuentran en el directorio de origen

El resultado es una imagen de la ventana acoplable con dependencias extraídas a través de SSH-auth que nunca tuvo una clave SSH.

Creé un script para habilitar el reenvío del agente ssh para docker run en un entorno boot2docker en OSX con una molestia mínima. Sé que no resuelve el problema de compilación, pero podría ser útil para algunos:

https://gist.github.com/rcoup/53e8dee9f5ea27a51855

¿El agente de claves ssh Forward funciona con servicios como el servicio de contenedor de Amazon EC 2? Me parece que esto requerirá un software específico que puede no estar disponible en todas las plataformas o PaaS que está utilizando para implementar sus contenedores.

Se requiere una solución más genérica que funcione para todos.

Actualmente, estoy usando variables de entorno. Un script bash obtiene la variable de clave privada (y hosts conocidos) y la imprime en los archivos id_rsa y known_hosts. Funciona, pero todavía tengo que evaluar las implicaciones de seguridad de tal solución.

FWIW, he descubierto que un ssh-agent en contenedor y el intercambio de volumen funcionan bien con un mínimo de tonterías:

https://github.com/whilp/ssh-agent

Sin embargo, sería genial tener un soporte de primera clase para esto.

Es importante distinguir qué funciona en _run_ vs _build_. solución @whilp 's funciona de maravilla en _run_ pero no funciona en _build_ porque no se puede acceder a los volúmenes de otra ventana acoplable durante _build_. De ahí por qué este boleto sigue siendo una llaga abierta y dolorosa.

@rvowles sí, estuvo de acuerdo. Reuní algo para generar contenedores a través de una secuencia de llamadas de ejecución / confirmación (es decir, sin Dockerfiles); eso tenía sentido para mi caso de uso particular, pero el soporte generalizado (incluido el tiempo de compilación) para algo como el reenvío de agentes sería muy útil.

¿Se incluyen las direcciones IP para los contenedores en ejecución en / etc / hosts durante la compilación? Si es así, una solución podría ser iniciar un contenedor que sirva las claves y luego enrollarlo durante la compilación.

Es posible que a todos les interese saber que escribí en un blog sobre una forma de usar su agente SSH durante docker build - http://aidanhs.com/blog/post/2015-10-07-dockerfiles-reproducibility- engaño / # _ simplificar_su_experiencia_usar_un_ssh_agent

Solo necesitas comenzar con un solo contenedor. Una vez iniciado, el acceso del agente SSH debería funcionar sin problemas con solo 3 líneas adicionales en su Dockerfile, ya no es necesario exponer sus claves al contenedor.

Algunas advertencias: necesita Docker> = 1.8, y no funcionará en una compilación automatizada de Docker Hub (obviamente). ¡Lea también la nota sobre seguridad! Siéntase libre de plantear problemas en el repositorio de github sshagent al que enlazo en la publicación si tiene algún problema.

También resolví este problema de manera similar a @aidanhs : extrayendo el secreto requerido sobre la subred de la
https://github.com/mdsol/docker-ssh-exec

¿Ha habido algún progreso para hacer esto posible? No puedo enlazar-montar el directorio ~/.ssh del host porque los permisos y la propiedad se estropean.

¿No se podría solucionar esto permitiendo que los montajes de enlace fuercen uid / gid y permisos específicos?

@atrauzzi bind-mounts no puede forzar uid / gid / permissions.
Puede hacer esto a través de FUSE (por ejemplo, bindfs), pero no solo con montajes de enlace normales.

@ cpuguy83 Eso realmente comienza a llevarme por caminos con los que no quiero tener que lidiar. Especialmente cuando estoy usando un host basado en Windows.

¿No hay una opción fácil de usar aquí? Tengo la sensación de que hay un problema aquí que simplemente se aplaza.

@atrauzzi De hecho, no es un problema fácil de resolver en el plazo inmediato (de todos modos, no sin problemas).

+1 este es un gran bloqueador para una aplicación Dockerfile de Node.js que de otra manera sería simple. He trabajado en muchas aplicaciones de Node y rara vez he visto una que no tenga un repositorio privado de Github como dependencia de NPM.

Como solución alternativa , .git en cada uno. En la compilación de Docker, solo se pueden instalar usando el directorio local. Si necesitan ser repositorios git completos por alguna razón, asegúrese de que el archivo .git no esté presente en la compilación de la ventana acoplable y agregue .git/modules/<repo> como <path>/<repo>/.git . Eso asegurará que sean repositorios normales como si fueran clonados.

Gracias por esa sugerencia @jakirkham , pero hemos estado usando npm install trabajo normal

Por ahora, tenemos una solución que funciona pero que es asquerosa. Tenemos:

  • Creó un usuario y equipo de Github que tiene acceso de solo lectura a los repositorios que usamos como dependencias de NPM
  • Envió la clave privada de ese usuario a nuestro repositorio donde tenemos nuestro Dockerfile
  • En el Dockerfile, en lugar de RUN npm install hacemos RUN GIT_SSH='/code/.docker/git_ssh.sh' npm install

Donde git_ssh.sh es un script como este:

#!/bin/sh
ssh -o StrictHostKeyChecking=no -i /code/.docker/deploy_rsa "$@"

Funciona, pero reenviar el agente de claves ssh sería mucho más agradable y mucho menos trabajo de configuración.

: +1:
No puedo creer que esta solicitud de función aún no esté implementada, ya que aquí hay muchos casos de uso en los que las personas requieren acceso desde repositorios privados durante el tiempo de compilación.

Estoy intentando crear contenedores para varios entornos de desarrollo de sistemas integrados, que requieren acceso a repositorios privados. Agregar soporte para claves ssh de host sería una gran característica. Los métodos más populares que vuelan en SO y otras páginas son inseguros y mientras no haya soporte para esta característica, las capas con claves privadas se extenderán.

: +1:

: +1: He estado necesitando esto desde siempre.

Hola @apeace , no sé si lo has visto, pero he comentado anteriormente sobre nuestra solución a este problema.

Es una combinación de un script y un servidor web. ¿Qué opinas de https://github.com/dockito/vault ?

@pirelenito, ¿eso no haría que la clave todavía estuviera disponible dentro de una capa de la compilación? Si ese es el caso, no vale la pena para nosotros agregar Dockito Valut a nuestro proceso de compilación; me parece tan 'jenky' como lo que estamos haciendo ahora. ¡Agradezco la sugerencia!

@apeace el ONVAULT descarga las claves, ejecuta su comando y luego borra las claves inmediatamente. Dado que todo esto sucede en el mismo comando, la capa final no contendrá la clave.

@apeace En Medidata, usamos una pequeña herramienta que construimos llamada docker-ssh-exec . Solo deja el binario docker-ssh-exec en la imagen de compilación resultante, sin secretos. Y solo requiere un cambio de una palabra en Dockerfile , por lo que es muy "de bajo impacto".

Pero si _realmente_ necesita usar una solución de Docker-Native-Only, ahora hay una forma incorporada de hacerlo, como se indica en la publicación del blog de la --build-arg para pasar valores efímeros al proceso de compilación. Debería poder pasar una clave SSH privada como ARG , escribirla en el sistema de archivos, realizar un git checkout , y luego _eliminar_ la clave, todo dentro del alcance de un RUN Directiva docker-ssh-exec ). Esto generará un Dockerfile feo, pero no debería requerir herramientas externas.

Espero que esto ayude.

@benton Hemos encontrado una solución similar. :)

Gracias @pirelenito y @benton , ¡

EDITAR : lo siguiente es _NO_ seguro, de hecho:

Para el registro, así es como verifica un repositorio privado de Github sin dejar su clave SSH en la imagen resultante.

Primero, reemplace user/repo-name en el siguiente Dockerfile con la ruta a su repositorio privado (asegúrese de mantener el prefijo [email protected] para que ssh se use para el pago):

FROM ubuntu:latest

ARG SSH_KEY
ENV MY_REPO [email protected]:user/repo-name.git

RUN apt-get update && apt-get -y install openssh-client git-core &&\
    mkdir -p /root/.ssh && chmod 0700 /root/.ssh && \
    ssh-keyscan github.com >/root/.ssh/known_hosts

RUN echo "$SSH_KEY" >/root/.ssh/id_rsa &&\
    chmod 0600 /root/.ssh/id_rsa &&\
    git clone "${MY_REPO}" &&\
    rm -f /root/.ssh/id_rsa

Luego construye con el comando

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

pasando la ruta correcta a su clave SSH privada.

^ con Docker 1.9

@benton Es posible que desee observar de cerca la salida de docker inspect sshtest y docker history sshtest . Creo que encontrará que los metadatos en la imagen final tienen su secreto incluso si no están disponibles dentro del contexto del contenedor ...

@ljrittle Buen avistamiento. De hecho, la clave está ahí si usa VAR . Supongo que aquí todavía se requiere una solución externa.

Quizás una razón por la que aún no se ha desarrollado una solución nativa es porque existen varias soluciones alternativas. Pero estoy de acuerdo con la mayoría de los demás aquí en que una solución incorporada serviría mejor a los usuarios y se ajustaría a la filosofía de "baterías incluidas" de Docker.

De los documentos ...

Nota: No se recomienda utilizar variables de tiempo de compilación para pasar secretos como claves github, credenciales de usuario, etc.

(https://docs.docker.com/engine/reference/builder/#arg)

No creo que una ruta a un archivo se aplique a esto, la nota trata sobre permitir que la contraseña / token sea visible en el registro de su consola.

No sigo a @jcrombez. El ejemplo fue pasar la clave ssh como una variable a través de ARG . Entonces, se aplica.

En términos de riesgo de seguridad, esto es muy diferente:

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

que esto :

docker build --tag=sshtest --build-arg SSH_KEY="mykeyisthis" .

si alguien encuentra su registro de terminal, las consecuencias no son las mismas.
pero no soy un experto en seguridad, esto aún podría ser peligroso por otras razones que no conozco.

En la línea de comando, supongo.

Sin embargo, como señaló @ljrittle y admitió @benton , cualquier forma en que use --build-arg / ARG se confirmará en la compilación. Por lo tanto, inspeccionarlo revelará información sobre la clave. Ambos abandonan el estado en el contenedor de la ventana acoplable final y ambos sufren la misma vulnerabilidad en ese extremo. Por lo tanto, ¿por qué Docker recomienda no hacer esto?

_ ENCUESTA DE USUARIOS_

_La mejor manera de recibir notificaciones de actualizaciones es usar el botón _Suscribirse_ en esta página._

No utilices los comentarios "+1" o "Yo también tengo esto" sobre los problemas. Nosotros automaticamente
recopile esos comentarios para mantener el hilo corto.

Las personas que se enumeran a continuación han votado a favor de este problema al dejar un comentario +1:

@ fletcher91
@benlemasurier
@dmuso
@probepark
@saada
@ianAndrewClark
@jakirkham
@galindro
@luisguilherme
@akurkin
@allardhoeve
@SevaUA
@sankethkatta
@kouk
@cliffxuan
@ kotlas92
@taion

_ ENCUESTA DE USUARIOS_

_La mejor manera de recibir notificaciones de actualizaciones es usar el botón _Suscribirse_ en esta página._

No utilices los comentarios "+1" o "Yo también tengo esto" sobre los problemas. Nosotros automaticamente
recopile esos comentarios para mantener el hilo corto.

Las personas que se enumeran a continuación han votado a favor de este problema al dejar un comentario +1:

@parknicker
@dursk
@adambiggs

En términos de riesgo de seguridad, esto es muy diferente:

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

aparte de tu historial de bash, son exactamente iguales; hay muchos lugares donde esa información puede terminar.

Por ejemplo, considere que las solicitudes de API se pueden registrar en el servidor;

Aquí hay un registro de demonio por docker build --tag=sshtest --build-arg SSH_KEY="fooobar" .

DEBU[0090] Calling POST /v1.22/build
DEBU[0090] POST /v1.22/build?buildargs=%7B%22SSH_KEY%22%3A%22fooobar%22%7D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&shmsize=0&t=sshtest&ulimits=null
DEBU[0090] [BUILDER] Cache miss: &{[/bin/sh -c #(nop) ARG SSH_KEY]}
DEBU[0090] container mounted via layerStore: /var/lib/docker/aufs/mnt/de3530a82a1a141d77c445959e4780a7e1f36ee65de3bf9e2994611513790b8c
DEBU[0090] container mounted via layerStore: /var/lib/docker/aufs/mnt/de3530a82a1a141d77c445959e4780a7e1f36ee65de3bf9e2994611513790b8c
DEBU[0090] Skipping excluded path: .wh..wh.aufs
DEBU[0090] Skipping excluded path: .wh..wh.orph
DEBU[0090] Applied tar sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef to 91f79150f57d6945351b21c9d5519809e2d1584fd6e29a75349b5f1fe257777e, size: 0
INFO[0090] Layer sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef cleaned up

_ ENCUESTA DE USUARIOS_

_La mejor manera de recibir notificaciones de actualizaciones es usar el botón _Suscribirse_ en esta página._

No utilices los comentarios "+1" o "Yo también tengo esto" sobre los problemas. Nosotros automaticamente
recopile esos comentarios para mantener el hilo corto.

Las personas que se enumeran a continuación han votado a favor de este problema al dejar un comentario +1:

@ cj2

Estoy tratando de poner en contenedor una aplicación simple de rubí / rack. El Gemfile hace referencia a varias gemas privadas. En el momento en que bundle install comienza e intenta acceder a los repositorios privados, empiezo a recibir este error

Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Pude solucionarlo, pero no sin exponer mi clave privada. Eso no servirá. Habilite el reenvío de autenticación SSH.

+1 para el reenvío ssh durante las compilaciones. No puedo usar go get con repositorios privados por eso; (

+1 para habilitar este caso de uso de manera segura

_ ENCUESTA DE USUARIOS_

_La mejor manera de recibir notificaciones de actualizaciones es usar el botón _Suscribirse_ en esta página._

No utilices los comentarios "+1" o "Yo también tengo esto" sobre los problemas. Nosotros automaticamente
recopile esos comentarios para mantener el hilo corto.

Las personas que se enumeran a continuación han votado a favor de este problema al dejar un comentario +1:

@lukad

Con solo leer esta discusión muy interesante, me pregunto si una solución simple podría resolver estos problemas. En lo alto de mi cabeza, estoy pensando, una opción en el Dockerfile para poder excluir / ignorar directorios / archivos internos específicos al tomar instantáneas. ¿Qué tan difícil puede ser?

es decir

EXCLUIR .ssh

Estoy pensando que se aplicaría en todos los pasos que siguen, por lo que si lo colocó después de FROM, podría agregar sus claves tanto como quiera y construir como de costumbre y nunca tener que preocuparse por las claves que terminan accidentalmente en su imagen (concedido es posible que deba agregarlos en cada paso que los requiera, pero no tendría que preocuparse de que terminen en una imagen)

La sugerencia de @benton funciona bien, y el demonio de la ventana acoplable solo registrará la clave id_rsa si está en modo de depuración.

Una forma aún más linda de exponer su clave durante la compilación es:

# Dockerfile
ARG SSH_KEY
RUN eval `ssh-agent -s` > /dev/null \
    && echo "$SSH_KEY" | ssh-add - \
    && git clone [email protected]:private/repository.git

docker build -t my_tag --build-arg SSH_KEY="$(< ~/.ssh/id_rsa)" .

Ja, aunque de hecho está ahí sentado si miras docker inspect my_tag .. así que no estoy seguro de cuál es el valor real de boot-arg, aparte de ser un poco más ordenado que ENV.

Y, si tiene una contraseña en la clave id_rsa, supongo que podría ser un mal humano y hacer:

# Dockerfile
ARG SSH_KEY
ARG SSH_PASS
RUN eval `ssh-agent -s` > /dev/null \
    && echo "echo $SSH_PASS" > /tmp/echo_ps && chmod 700 /tmp/echo_ps \
    && echo "$SSH_KEY" | SSH_ASKPASS=/tmp/echo_ps DISPLAY= ssh-add - \
    && git clone [email protected]:private/repository.git
    && rm /tmp/echo_ps

docker build -t my_tag --build-arg SSH_KEY="$(< ~/.ssh/id_rsa)" --build-arg SSH_PASS=<bad_idea> .

Por supuesto, es difícil racionalizar que sea ni remotamente una buena idea ... pero todos somos humanos, supongo.

Por supuesto, todas las principales razones para hacer esto parecerían ser que las personas realizan "instalación en paquete" o "ir a buscar" en repositorios privados durante una compilación.

Yo diría que solo proporcione sus dependencias y AGREGUE todo el proyecto ... pero, a veces, las cosas deben hacerse ahora.

@SvenDowideit @thaJeztah ¿Existe alguna solución para este problema? Traté de seguir el hilo, pero entre cerrar y abrir otros hilos y muchas opiniones no tengo idea de qué hará el equipo de Docker ni cuándo.

Lo mejor, pero ¿necesita implementación?

La compilación de Docker usa ssh-agent dentro de la compilación para usar como proxy al ssh de su host y luego usar sus claves sin tener que conocerlas.

Para cualquiera que esté aprendiendo sobre el proxy del agente ssh: github al rescate

La idea original de @phemmer .

@yordis No creo que haya una "gran" solución en el hilo que esté disponible de forma gratuita todavía.

Este comentario de docker / docker-py # 980 parece indicar que si copia sus claves ssh en el directorio de claves de su usuario raíz en su sistema host, el demonio usará esas claves. Sin embargo, soy un novato loco en este sentido, por lo que alguien más puede aclararlo.


Ok, pero no el mejor

Pasando la clave con los argumentos de compilación de Docker 1.8.
Advertencias .

Definitivamente una mala idea

Mucha gente también ha recomendado aquí agregar la clave temporalmente al contexto de compilación y luego eliminarla rápidamente. Suena realmente peligroso porque si la clave se infiltra en una de las confirmaciones, cualquiera que use el contenedor puede acceder a esa clave comprobando una confirmación en particular.


¿Por qué esto no ha ido a ninguna parte todavía?

Necesita una propuesta de diseño, este tema es _cah_- _alborotado_ y las ideas son solo vagas por el momento. Los detalles de implementación reales se están perdiendo en una neblina de "¿y si hiciéramos x?" Y +1. Para organizarse y avanzar en esta característica tan necesaria, aquellos que tengan posibles soluciones deben crear un archivo. . .

propuesta de diseño

y luego haga referencia a este problema.

Tengo algunas novedades sobre este tema.

En DockerCon la semana pasada, nos animaron a llevar nuestras preguntas más difíciles al pabellón "Pregunte a los expertos" de Docker, así que fui y tuve una breve charla con un ingeniero inteligente y amigable con el título alentador de Arquitecto de soluciones. Le di un breve resumen de este tema, que espero haber transmitido con precisión, porque me aseguró que esto se puede hacer con _sólo_ docker-compose ! Los detalles de lo que estaba proponiendo involucraban una compilación de varias etapas, tal vez para acumular las dependencias en un contexto diferente al de la compilación final de la aplicación, y parecía involucrar el uso de volúmenes de datos en el momento de la compilación.

Desafortunadamente, no tengo experiencia con docker-compose, por lo que no pude seguir todos los detalles, pero me aseguró que si le escribía con el problema exacto, me respondería con una solución. Así que escribí lo que espero sea un correo electrónico lo suficientemente claro , que incluye una referencia a este problema abierto de GitHub. Y escuché de él esta mañana, con su seguridad de que responderá cuando se le ocurra algo.

Estoy seguro de que está muy ocupado, por lo que no esperaría nada inmediato, pero lo encuentro alentador, en la medida en que ha entendido el problema y está listo para atacarlo solo con el conjunto de herramientas nativo de Docker.

@benton Utilizo la siguiente configuración de docker-compose.yaml para hacer las cosas descritas en este tema:

version: '2'
services:
  serviceName:
     volumes:
      - "${SSH_AUTH_SOCK}:/tmp/ssh-agent"
    environment:
      SSH_AUTH_SOCK: /tmp/ssh-agent

Asegúrese de que ssh-agent se haya iniciado en la máquina host y conozca la clave (puede verificarlo con el comando ssh-add -L).

Tenga en cuenta que es posible que necesite agregar

Host *
  StrictHostKeyChecking no

a .ssh / config del contenedor.

Hola @WoZ! gracias por tu respuesta, parece bastante simple, así que lo intentaré :)

Sin embargo, tengo una pregunta, ¿cómo se puede usar esto con compilaciones automatizadas en Docker Hub? Por lo que ahora, no hay forma de usar un archivo de redacción allí :(

@garcianavalon funciona bien, pero es solo por run , no por build . Todavía no funciona con Docker para Mac, aunque aparentemente está en la lista de tareas pendientes.

Editar: https://github.com/docker/for-mac/issues/410

Se nos ocurrieron 2 soluciones alternativas más para nuestras necesidades específicas:

1) Configure nuestro propio paquete espejo para npm, pypi, etc. detrás de nuestra VPN, de esta manera no necesitamos SSH.

2) Toda la máquina host ya tenemos acceso a repositorios privados, por lo que clonamos / descargamos el paquete privado localmente en la máquina host, ejecutamos la instalación del paquete para descargarlo, luego usamos -v para mapear el volumen a la ventana acoplable y luego compilamos la ventana acoplable.

Actualmente estamos usando la opción 2).

En cuanto a docker run , docker-ssh-agent-forward parece proporcionar una solución elegante y funciona en Docker para Mac / Linux.

Puede ser una buena idea COPIAR el archivo known_hosts del host en lugar de crearlo en el contenedor (menos seguro), ya que ssh-agent no parece reenviar hosts conocidos.

Pero el problema fundamental de extraer dependencias privadas durante un paso de ejecución de la ventana acoplable es omitir la caché de compilación de la ventana acoplable, que puede ser muy importante en términos de tiempo de compilación.

Un enfoque para sortear esta limitación es md5 / fechar sus declaraciones de dependencia de compilación (por ejemplo, package.json ), enviar el resultado a una imagen y reutilizar la misma imagen si el archivo no ha cambiado. El uso del hash en el nombre de la imagen permitirá almacenar en caché varios estados. También tendría que combinarse con el resumen de la imagen preinstalado.

Esto debería ser más robusto que la solución de

Esto debería ser más robusto que la solución de

Mi solución específica no ha funcionado desde 1.9.0; resultó que la función introducida en 1.8.0 en la que confiaba no era intencional y, por lo tanto, se eliminó.

Aunque el principio de mi solución sigue siendo bueno (solo requiere que tenga un servidor DNS fuera de su máquina que a) use su máquina yb) pueda agregar entradas a las ubicaciones apropiadas), realmente no puedo decir con entusiasmo lo recomiendo más.

¡Gracias por la información adicional @aidanhs!

Algunas actualizaciones con respecto a mi solución propuesta: los hashes en realidad no necesitan combinarse, ya que el hash de la imagen base justo después de agregar el archivo de declaración de dependencias simplemente se puede usar. Además, es mejor simplemente montar el archivo known_host como un volumen, ya que ssh-agent solo se puede usar en tiempo de ejecución de todos modos, y es más seguro ya que contiene una lista de todos los hosts a los que se conecta.

Implementé la solución completa para node / npm y se puede encontrar aquí con documentación detallada y ejemplos: https://github.com/iheartradio/docker-node

Por supuesto, los principios pueden extenderse a otros marcos.

El mismo problema aquí, ¿cómo se construye algo, donde ese algo requiere credenciales SSH para verificar y construir una serie de proyectos en el momento de la compilación, dentro de un contenedor docker, sin escribir credenciales en la imagen o en una imagen base?

Trabajamos alrededor de esto con un proceso de construcción de 2 pasos. Se crea una imagen de "compilación" que contiene las dependencias de origen / claves / compilación. Una vez que está construido, se ejecuta para extraer los resultados de la construcción en un archivo tar que luego se agrega a una imagen de "implementación". A continuación, se elimina la imagen de compilación y todo lo que se publica es la imagen de "implementación". Esto tiene un buen efecto secundario de mantener bajos los tamaños de los contenedores / capas.

@ binarytemple-bet365, consulte https://github.com/iheartradio/docker-node para ver un ejemplo de extremo a extremo que hace exactamente eso. Utilizo más de dos pasos, ya que uso un contenedor de servicio ssh, preinstalar (imagen base hasta antes de instalar dependencias privadas), instalar (estado del contenedor después de la instalación en tiempo de ejecución de las dependencias privadas) y post-instalar (agrega comandos que tenía después de la instalación) de dependencias privadas) para optimizar la velocidad y la separación de preocupaciones.

Echa un vistazo a Rocker , es una solución limpia.

@Sodki Seguí tu consejo. Sí, el rocker es una solución limpia y bien pensada. Más es una pena que el equipo de Docker no se limitara a tomar ese proyecto bajo su protección y desaprobar docker build . Gracias.

¿Todavía no hay mejor manera? :(

¿Alguien ha probado esta nueva cosa de calabaza? https://github.com/docker/docker/pull/22641 Podría ser la solución nativa de Docker que estamos buscando. Voy a probarlo ahora e informar para ver cómo va.

Después de más de 2 años, esto aún no se ha solucionado 😞 Por favor, el equipo de Docker haga algo al respecto

Parece que la nueva opción --squash en 1.13 funciona para mí:
http://g.recordit.co/oSuMulfelK.gif

Lo construyo con: docker build -t report-server --squash --build-arg SSH_KEY="$(cat ~/.ssh/github_private_key)" .

Entonces, cuando hago docker history o docker inspect , la clave no se muestra.

Mi Dockerfile se ve así:

FROM node:6.9.2-alpine

ARG SSH_KEY

RUN apk add --update git openssh-client && rm -rf /tmp/* /var/cache/apk/* &&\
  mkdir -p /root/.ssh && chmod 0700 /root/.ssh && \
  ssh-keyscan github.com > /root/.ssh/known_hosts

RUN echo "$SSH_KEY" > /root/.ssh/id_rsa &&\
  chmod 0600 /root/.ssh/id_rsa

COPY package.json .

RUN npm install
RUN rm -f /root/.ssh/id_rsa

# Bundle app source
COPY . .

EXPOSE 3000

CMD ["npm","start"]

@ kienpham2000 , parece que su captura de pantalla todavía contiene las claves. ¿Podría comprobar la salida de docker history con la marca --no-trunc e informar aquí si las claves privadas se muestran o no en la ventana acoplable? ¿historia?

@ryanschwartz tienes razón, el --no-trunc muestra toda la maldita cosa, esto no vuela.

@ kienpham2000
Otra cosa que introdujeron en la versión 1.13 es:

Construye secretos
• habilita los secretos del tiempo de compilación usando —build-secret flag
• crea tmpfs durante la compilación y expone secretos al
contenedores de construcción, que se utilizarán durante la construcción.
https://github.com/docker/docker/pull/28079

¿Quizás esto podría funcionar?

Los secretos de compilación no llegaron a la 1.13, pero con suerte lo harán en la 1.14.

El 15 de diciembre de 2016 a las 9:45 a. M., "Alex" [email protected] escribió:

@ kienpham2000 https://github.com/kienpham2000
Otra cosa que introdujeron en la versión 1.13 es:

Construye secretos
• habilita los secretos del tiempo de compilación usando —build-secret flag
• crea tmpfs durante la compilación y expone secretos al
contenedores de construcción, que se utilizarán durante la construcción.
• # 28079 https://github.com/docker/docker/pull/28079

¿Quizás esto podría funcionar?

-
Estás recibiendo esto porque estás suscrito a este hilo.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/docker/docker/issues/6396#issuecomment-267393020 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/AAdcPDxrctBP2TlCtXen-Y_uY8Y8B09Sks5rIXy2gaJpZM4CD4SM
.

Así que un año después: No, esta es una mala idea. No deberías hacer eso. Hay varias otras soluciones. Por ejemplo, Github puede proporcionar tokens de acceso. Puede usarlos en archivos de configuración / variables de entorno con menos riesgo, ya que puede especificar qué acciones están permitidas para cada token.

La solución es implementar el reenvío SSH. Como lo hace Vagrant, por ejemplo.

¿Alguien puede explicarme por qué es tan complicado implementar eso?

@omarabid : ¿está respondiendo a su propuesta original de usar variables de entorno para pasar claves privadas que se usarán dentro del Dockerfile? No hay duda de que es una mala práctica de seguridad.

En cuanto a su sugerencia de usar tokens de acceso, terminarían almacenados en una capa y puede ser tan peligroso dejarlos tirados como una clave SSH. Incluso si solo tiene acceso de solo lectura, la mayoría de las personas no querrían que otros tuvieran acceso de solo lectura a sus repositorios. Además, sería necesario que se produjeran revocaciones / rotaciones / distribuciones frecuentes; esto es un poco más fácil de manejar para cada desarrollador, etc. que con tokens de acceso "maestros".

La solución de secretos de compilación mencionada en algunos comentarios parece que es un paso en la dirección correcta, pero la capacidad de usar un agente SSH es la mejor. Quizás uno podría usar un agente SSH en combinación con secretos de compilación, no estoy seguro.

Es natural que los desarrolladores / sistemas de CI usen un agente SSH durante las operaciones de git / build. Esto es mucho más seguro que tener una clave privada de texto sin formato y sin contraseña que debe revocarse / reemplazarse en masa en una variedad de sistemas. Además, con los agentes SSH no hay posibilidad de que los datos de la clave privada se comprometan con una imagen. En el peor de los casos, una variable de entorno / SSH_AUTH_SOCK remanente quedará atrás en la imagen.

Obtuve esta última solución sin mostrar el contenido de la clave secreta o sin usar una herramienta acoplable adicional de terceros (con suerte, la bóveda secreta durante el PR construido se fusionará pronto).

Estoy usando aws cli para descargar la clave privada compartida de S3 en el repositorio actual del host. Esta clave está cifrada en reposo mediante KMS. Una vez que se descarga la clave, Dockerfile simplemente COPIA esa clave durante el proceso de compilación y la elimina después, el contenido no se muestra en docker inspect o docker history --no-trunc

Descargue la clave privada de github desde S3 primero a la máquina host:

# build.sh
s3_key="s3://my-company/shared-github-private-key"
aws configure set s3.signature_version s3v4
aws s3 cp $s3_key id_rsa --region us-west-2 && chmod 0600 id_rsa

docker build -t app_name .

Dockerfile tiene este aspecto:

FROM node:6.9.2-alpine

ENV id_rsa /root/.ssh/id_rsa
ENV app_dir /usr/src/app

RUN mkdir -p $app_dir
RUN apk add --update git openssh-client && rm -rf /tmp/* /var/cache/apk/* && mkdir -p /root/.ssh && ssh-keyscan github.com > /root/.ssh/known_hosts

WORKDIR $app_dir

COPY package.json .
COPY id_rsa $id_rsa
RUN npm install && npm install -g gulp && rm -rf $id_rsa

COPY . $app_dir
RUN rm -rf $app_dir/id_rsa

CMD ["start"]

ENTRYPOINT ["npm"]

@ kienpham2000 , ¿por qué esta solución no mantendría la clave en la capa de imagen? Las acciones de copiar y eliminar la clave se realizan en comandos separados, por lo que hay una capa que debería tener la clave.
Nuestro equipo estaba usando la solución suya hasta ayer, pero encontramos una solución mejorada:

  • Generamos una URL de firma previa para acceder a la clave con aws s3 cli, y limitamos el acceso durante unos 5 minutos, guardamos esta URL de firma previa en un archivo en el directorio repo, luego en dockerfile la agregamos a la imagen.
  • En dockerfile tenemos un comando RUN que hace todos estos pasos: use la URL previa para obtener la clave ssh, ejecute npm install y elimine la clave ssh.
    Al hacer esto en un solo comando, la clave ssh no se almacenaría en ninguna capa, pero se almacenará la URL de firma previa, y esto no es un problema porque la URL no será válida después de 5 minutos.

El script de construcción se ve así:

# build.sh
aws s3 presign s3://my_bucket/my_key --expires-in 300 > ./pre_sign_url
docker build -t my-service .

Dockerfile tiene este aspecto:

FROM node

COPY . .

RUN eval "$(ssh-agent -s)" && \
    wget -i ./pre_sign_url -q -O - > ./my_key && \
    chmod 700 ./my_key && \
    ssh-add ./my_key && \
    ssh -o StrictHostKeyChecking=no [email protected] || true && \
    npm install --production && \
    rm ./my_key && \
    rm -rf ~/.ssh/*

ENTRYPOINT ["npm", "run"]

CMD ["start"]

@diegocsandrim gracias por señalar eso, realmente me gusta tu solución, voy a actualizar nuestro material aquí. ¡Gracias por compartir!

Soy un poco nuevo en el hilo, pero fundamentalmente parece que la gente está tratando de resolver un problema mejor resuelto por PKI. No todo el mundo está tratando necesariamente de salvar el mismo problema en el que PKI sería la mejor solución, pero suficientes referencias parecen indicar que podría ser algo que debería considerarse.

Parece molesto, pero fundamentalmente posible

  • crear una autoridad de certificación local
  • tener un proceso para generar un certificado
  • tener un proceso para emitir el certificado
  • tener un proceso para revocar dicho certificado
  • hacer que los demonios ssh usen PKI

Y si la gente siente que esto es factible, entonces por favor créelo y ábralo, después de todo el trabajo debe hacerse bien una vez. No tengo idea de si la compilación de roumen petrov es segura y no anotó ningún código fuente (no he verificado el alquitrán), por lo que no tengo idea de qué tan seguro es.

https://security.stackexchange.com/questions/30396/how-to-set-up-openssh-to-use-x509-pki-for-authentication

https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html

@mehmetcodes : Tener una PKI no resuelve realmente el problema. Para que funcione la autenticación SSH basada en PKI, aún deberá cargar la clave privada en la imagen.

A menos que su autoridad de certificación local emita certificados de muy corta duración (por ejemplo, menos de una hora) y usted revoque el certificado inmediatamente después de una compilación exitosa, esto no es seguro.

Si logra crear un proceso de certificado de corta duración, eso no es muy diferente a simplemente usar una nueva clave SSH que revoca inmediatamente después de que finaliza una compilación.

Oh, es incluso más molesto que eso, pero debo estar en algo o ¿por qué existiría en la naturaleza?

https://blog.cloudflare.com/red-october-cloudflares-open-source-implementation-of-the-two-man-rule/
https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/

No sé, una clave temporal SSH es probablemente mucho mejor para la mayoría de los casos de uso, pero hay algo inquietante en cada recurso, incluido el que sugerí, particularmente en este contexto.

En su lugar, normalmente solo montaría un volumen con la clave, pero eso no ayuda a la necesidad de la solución Docker para Mac / moby.

quien diablos es moby?

@el color blanco
Image of Moby

Llegué tan lejos como esto en MacOS:

bash-3.2$ docker run -t -i -v "$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" python:3.6 ssh-add -l
docker: Error response from daemon: Mounts denied:
The path /var/folders/yb/880w03m501z89p0bx7nsxt580000gn/T//ssh-DcwJrLqQ0Vu1/agent.10466
is not shared from OS X and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> File Sharing.
See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info.
.

/ var / es un alias, con el que Docker parece tener problemas. Pero si prefijo la ruta $ SSH_AUTH_SOCK con /private (es decir, la ruta de alias resuelta), Docker puede leer el archivo, pero obtengo:

bash-3.2$ docker run -t -i -v "/private$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" python:3.6 ssh-add -l
Could not open a connection to your authentication agent.

En este punto, me pregunto qué tan malo es simplemente ...

docker run -v ~/.ssh:/root/.ssh python:3.6 bash

?

docker build  --build-arg ssh_prv_key="$(cat ~/.ssh/id_rsa_no_pass)" --build-arg ssh_pub_key="$(cat ~/.ssh/id_rsa.pub)" --squash .

Y luego dentro del archivo Docker:

ARG ssh_prv_key
ARG ssh_pub_key

# Authorize SSH Host
RUN mkdir -p /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan github.com > /root/.ssh/known_hosts

# Add the keys and set permissions
RUN echo "$ssh_prv_key" > /root/.ssh/id_rsa && \
    echo "$ssh_pub_key" > /root/.ssh/id_rsa.pub && \
    chmod 600 /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/id_rsa.pub

Y no olvides incluir

RUN rm -f /root/.ssh/id_rsa /root/.ssh/id_rsa.pub

como paso final.

El problema aquí es que su clave privada no debe estar protegida con contraseña.

El problema con el comentario anterior es que las claves terminan en las capas ... rm no se eliminará de una capa anterior, ya que cada línea en un archivo de ventana acoplable es una capa ...

¿ docker secret resuelve este problema?
WDYT @thaJeztah

Docker secret no está (todavía) disponible durante la compilación, y solo está disponible en los servicios (por lo que aún no está disponible para docker run )

Sin embargo, al usar compilaciones de múltiples etapas, algo como esto podría funcionar (escribiendo en mi teléfono, así que permítanme vincular una esencia que creé hace un tiempo); https://gist.github.com/thaJeztah/836c4220ec024cf6dd48ffa850f07770

Ya no estoy tan involucrado con Docker, pero, ¿cómo es posible que este problema exista durante tanto tiempo? No estoy tratando de gritar, sino en lugar de comprender cuál es el esfuerzo necesario para solucionar esto porque cuando estaba lidiando con esto, parece un problema muy común para cualquier empresa que extrae paquetes privados como ruby gems de un repositorio privado.

¿ Moby preocupa este problema al

Han pasado casi 3 años 😢

@yordis docker builder estuvo congelado durante uno o dos años. El equipo de Docker declaró que el constructor es lo suficientemente bueno y que enfoca sus esfuerzos en otra parte. Pero esto se ha ido y desde entonces se han realizado dos cambios en el constructor. Construye la etapa de squash y mustli. Así que los secretos del tiempo de construcción pueden estar en camino.

Para el reenvío en tiempo de ejecución de ssh-agent, recomendaría https://github.com/uber-common/docker-ssh-agent-forward

Por qué tiene que ser tan difícil para algo que no parece gran cosa, supongo.

@yord está leyendo la descripción principal de este problema, implementar esto está lejos de ser trivial; Dicho esto, si alguien tiene una propuesta de diseño técnico para esto, no dude en abrir un tema o relaciones públicas para su discusión. También tenga en cuenta que para la parte _build_, se inició un proyecto buildkit para futuras mejoras del constructor; https://github.com/moby/buildkit

@thaJeztah Desearía poder tener las habilidades necesarias, pero no las tengo.

@villlem , ¿conoces alguna hoja de ruta del equipo de Docker?

Los informes semanales para el constructor se pueden encontrar aquí; https://github.com/moby/moby/tree/master/reports/builder Los secretos del tiempo de compilación todavía se enumeran en el informe más reciente, pero podrían necesitar ayuda

Estamos usando la solución de @diegocsandrim pero con un paso de cifrado intermedio para evitar dejar una clave SSH sin cifrar en S3.

Este paso adicional significa que la clave no se puede recuperar de la imagen de Docker (la URL para descargarla caduca después de cinco minutos) y no se puede recuperar de AWS (ya que está encriptada con una contraseña rotativa conocida solo por la imagen de Docker). .

En build.sh:

BUCKET_NAME=my_bucket
KEY_FILE=my_unencrypted_key
openssl rand -base64 -out passfile 64
openssl enc -aes-256-cbc -salt -in $KEY_FILE -kfile passfile | aws s3 cp - s3://$BUCKET_NAME/$(hostname).enc_key
aws s3 presign s3://$BUCKET_NAME/$(hostname).enc_key --expires-in 300 > ./pre_sign_url
docker build -t my_service

Y en el Dockerfile:

COPY . .

RUN eval "$(ssh-agent -s)" && \
    wget -i ./pre_sign_url -q -O - | openssl enc -aes-256-cbc -d -kfile passfile > ./my_key && \
    chmod 700 ./my_key && \
    ssh-add ./my_key && \
    mkdir /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan github.com > /root/.ssh/known_hosts && \
    [commands that require SSH access to Github] && \
    rm ./my_key && \
    rm ./passfile && \
    rm -rf /root/.ssh/

si está utilizando docker run , debe montar su .ssh con --mount type=bind,source="${HOME}/.ssh/",target="/root/.ssh/",readonly . Readonly es la magia, enmascara los permisos normales y ssh básicamente ve los permisos 0600 con los que está contento. También puede jugar con -u root:$(id -u $USER) para que el usuario root en el contenedor escriba cualquier archivo que cree con el mismo grupo que su usuario, por lo que es de esperar que al menos pueda leerlos si no los escribe completamente sin tener que chmod / chown .

Por fin.

Creo que este problema ahora se puede resolver usando solo docker build , usando compilaciones de múltiples etapas .
Solo COPY o ADD la clave SSH u otro secreto donde lo necesite, y utilícelo en RUN declaraciones como desee.

Luego, use una segunda instrucción FROM para iniciar un nuevo sistema de archivos, y COPY --from=builder para importar algún subconjunto de directorios que no incluyen el secreto .

(Todavía no he probado esto, pero si la función funciona como se describe ...)

Las compilaciones de varias etapas de

He verificado la siguiente técnica:

  1. Pase la _ubicación de una clave privada_ como un argumento de compilación, como GITHUB_SSH_KEY , a la primera etapa de una compilación de varias etapas
  2. Use ADD o COPY para escribir la clave donde sea necesaria para la autenticación. Tenga en cuenta que si la ubicación de la clave es una ruta del sistema de archivos local (y no una URL), _no_ debe estar en el archivo .dockerignore , o la directiva COPY no funcionará. Esto tiene implicaciones para la imagen final, como verá en el paso 4 ...
  3. Utilice la clave según sea necesario. En el siguiente ejemplo, la clave se usa para autenticarse en GitHub. Esto también funciona para los repositorios privados de Gemas y bundler de Ruby. Dependiendo de la cantidad de código base que necesite incluir en este punto, puede terminar agregando la clave nuevamente como un efecto secundario de usar COPY . o ADD . .
  4. RETIRE LA LLAVE SI ES NECESARIO . Si la ubicación de la clave es una ruta del sistema de archivos local (y no una URL), entonces es probable que se haya agregado junto con la base de código cuando hizo ADD . o COPY . Este es probablemente _precisamente el directorio_ que es se copiará en la imagen de tiempo de ejecución final, por lo que probablemente también desee incluir una declaración RUN rm -vf ${GITHUB_SSH_KEY} una vez que haya terminado de usar la clave.
  5. Una vez que su aplicación esté completamente integrada en su WORKDIR , comience la segunda etapa de compilación con una nueva declaración FROM , que indique la imagen de tiempo de ejecución deseada. Instale las dependencias de tiempo de ejecución necesarias y luego COPY --from=builder contra WORKDIR de la primera etapa.

Aquí hay un ejemplo Dockerfile que demuestra la técnica anterior. Proporcionar un argumento de compilación GITHUB_SSH_KEY probará la autenticación de GitHub durante la compilación, pero los datos clave _no_ se incluirán en la imagen de tiempo de ejecución final. GITHUB_SSH_KEY puede ser una ruta del sistema de archivos (dentro del directorio de compilación de Docker) o una URL que proporciona los datos de la clave, pero la clave en sí no debe estar encriptada en este ejemplo.

########################################################################
# BUILD STAGE 1 - Start with the same image that will be used at runtime
FROM ubuntu:latest as builder

# ssh is used to test GitHub access
RUN apt-get update && apt-get -y install ssh

# The GITHUB_SSH_KEY Build Argument must be a path or URL
# If it's a path, it MUST be in the docker build dir, and NOT in .dockerignore!
ARG GITHUB_SSH_KEY=/path/to/.ssh/key

  # Set up root user SSH access for GitHub
ADD ${GITHUB_SSH_KEY} /root/.ssh/id_rsa

# Add the full application codebase dir, minus the .dockerignore contents...
# WARNING! - if the GITHUB_SSH_KEY is a file and not a URL, it will be added!
COPY . /app
WORKDIR /app

# Build app dependencies that require SSH access here (bundle install, etc.)
# Test SSH access (this returns false even when successful, but prints results)
RUN ssh -o StrictHostKeyChecking=no -vT [email protected] 2>&1 | grep -i auth

# Finally, remove the $GITHUB_SSH_KEY if it was a file, so it's not in /app!
# It can also be removed from /root/.ssh/id_rsa, but you're probably not going
# to COPY that directory into the runtime image.
RUN rm -vf ${GITHUB_SSH_KEY} /root/.ssh/id*

########################################################################
# BUILD STAGE 2 - copy the compiled app dir into a fresh runtime image
FROM ubuntu:latest as runtime
COPY --from=builder /app /app

_Podría_ ser más seguro pasar los datos clave en el argumento GITHUB_SSH_KEY Build, en lugar de la _ ubicación_ de los datos clave. Esto evitaría la inclusión accidental de los datos clave si se almacenan en un archivo local y luego se agregan con COPY . . Sin embargo, esto requeriría usar echo y la redirección de shell para escribir los datos en el sistema de archivos, lo que podría no funcionar en todas las imágenes base. Utilice la técnica que sea más segura y factible para su conjunto de imágenes base.

@jbiel Otro año, y la solución que encontré es usar algo como Vault.

Aquí hay un enlace con 2 métodos (calabaza y contenedor intermedio descrito anteriormente por @benton)

Solo estoy agregando una nota para decir que ninguno de los enfoques actuales funcionará si tiene una frase de contraseña en la clave ssh que está usando, ya que el agente le pedirá la frase de contraseña cada vez que realice la acción que requiere acceso. No creo que haya una forma de evitar esto sin pasar la frase clave (que no es deseable por varias razones)

Resolviendo.
Cree un script bash (~ / bin / docker-compose o me gusta):

#!/bin/bash

trap 'kill $(jobs -p)' EXIT
socat TCP-LISTEN:56789,reuseaddr,fork UNIX-CLIENT:${SSH_AUTH_SOCK} &

/usr/bin/docker-compose $@

Y en Dockerfile usando socat:

...
ENV SSH_AUTH_SOCK /tmp/auth.sock
...
  && apk add --no-cache socat openssh \
  && /bin/sh -c "socat -v UNIX-LISTEN:${SSH_AUTH_SOCK},unlink-early,mode=777,fork TCP:172.22.1.11:56789 &> /dev/null &" \
  && bundle install \
...
or any other ssh commands will works

Luego ejecuta docker-compose build

@benton, ¿por qué usas RUN rm -vf ${GITHUB_SSH_KEY} /root/.ssh/id* ? ¿No debería ser solo RUN rm -vf /root/.ssh/id* ? O tal vez entendí mal la intención aquí.

@benton Y tampoco es seguro hacerlo:

RUN ssh -o StrictHostKeyChecking=no -vT [email protected] 2>&1

Tienes que comprobar la huella dactilar

Solucioné este problema de esta manera

ARGS USERNAME
ARGS PASSWORD
RUN git config --global url."https://${USERNAME}:${PASSWORD}@github.com".insteadOf "ssh://[email protected]"

luego construye con

docker build --build-arg USERNAME=use --build-arg PASSWORD=pwd. -t service

Pero al principio, su servidor git privado debe admitir el repositorio username:password clone.

Comando @zeayes RUN almacenado en el historial del contenedor. Entonces su contraseña es visible para otros.

Correcto; al usar --build-arg / ARG , esos valores aparecerán en el historial de compilación. Es posible utilizar esta técnica si utiliza compilaciones de varias etapas y confía en el host en el que se compilan las imágenes (es decir, ningún usuario que no sea de confianza tiene acceso al historial de compilación local), y las etapas de compilación intermedias no se envían a un registro.

Por ejemplo, en el siguiente ejemplo, USERNAME y PASSWORD solo aparecerán en el historial de la primera etapa ("constructor"), pero no estarán en el historial de la etapa final;

FROM something AS builder
ARG USERNAME
ARG PASSWORD
RUN something that uses $USERNAME and $PASSWORD

FROM something AS finalstage
COPY --from= builder /the/build-artefacts /usr/bin/something

Si solo la imagen final (producida por "finalstage") se envía a un registro, USERNAME y PASSWORD no estarán en esa imagen.

_Sin embargo_, en el historial de la caché de compilación local, esas variables seguirán estando allí (y almacenadas en el disco como texto sin formato).

El constructor de próxima generación (usando BuildKit ) tendrá más características, también relacionadas con el paso de secretos en tiempo de construcción; está disponible en Docker 18.06 como una característica experimental, pero saldrá de experimental en una versión futura, y se agregarán más características (tendría que verificar si los secretos / credenciales ya son posibles en la versión actual)

@kinnalru @thaJeztah thx, uso compilaciones de múltiples etapas, pero la contraseña se puede ver en el historial del contenedor de caché, ¡gracias!

@zeayes ¡Oh! Veo que hice un error de copiar / pegar; la última etapa no debe usar FROM builder .. . Aquí tienes un ejemplo completo; https://gist.github.com/thaJeztah/af1c1e3da76d7ad6ce2abab891506e50

Este comentario de @kinnalru es la forma correcta de hacer esto https://github.com/moby/moby/issues/6396#issuecomment -348103398

Con este método, Docker nunca maneja sus claves privadas. Y también funciona hoy, sin que se agreguen funciones nuevas.

Me tomó un tiempo darme cuenta, así que aquí hay una explicación más clara y mejorada. Cambié el código de --network=host y localhost , por lo que no necesita saber su dirección IP. ( esencia aquí )

Esto es docker_with_host_ssh.sh , envuelve la ventana acoplable y reenvía SSH_AUTH_SOCK a un puerto en localhost:

#!/usr/bin/env bash

# ensure the processes get killed when we're done
trap 'kill $(jobs -p)' EXIT

# create a connection from port 56789 to the unix socket SSH_AUTH_SOCK (which is used by ssh-agent)
socat TCP-LISTEN:56789,reuseaddr,fork UNIX-CLIENT:${SSH_AUTH_SOCK} &
# Run docker
# Pass it all the command line args ($@)
# set the network to "host" so docker can talk to localhost
docker $@ --network='host'

En el Dockerfile, nos conectamos a través de localhost al ssh-agent de hosts:

FROM python:3-stretch

COPY . /app
WORKDIR /app

RUN mkdir -p /tmp

# install socat and ssh to talk to the host ssh-agent
RUN  apt-get update && apt-get install git socat openssh-client \
  # create variable called SSH_AUTH_SOCK, ssh will use this automatically
  && export SSH_AUTH_SOCK=/tmp/auth.sock \
  # make SSH_AUTH_SOCK useful by connecting it to hosts ssh-agent over localhost:56789
  && /bin/sh -c "socat UNIX-LISTEN:${SSH_AUTH_SOCK},unlink-early,mode=777,fork TCP:localhost:56789 &" \
  # stuff I needed my ssh keys for
  && mkdir -p ~/.ssh \
  && ssh-keyscan gitlab.com > ~/.ssh/known_hosts \
  && pip install -r requirements.txt

Luego puede construir su imagen invocando el script:

$ docker_with_host_ssh.sh build -f ../docker/Dockerfile .

@cowlicks puede estar interesado en esta solicitud de extracción, que agrega soporte para docker build --ssh para reenviar el agente SSH durante la compilación; https://github.com/docker/cli/pull/1419. La sintaxis de Dockerfile todavía no está en las especificaciones oficiales, pero puede usar una directiva syntax=.. en su Dockerfile para usar una interfaz que lo admita (vea el ejemplo / instrucciones en la solicitud de extracción).

Esa solicitud de extracción será parte del próximo lanzamiento 18.09.

Parece que ahora está disponible en la versión 18.09. Dado que este hilo aparece antes de las notas de la versión y la publicación media, realizaré una publicación cruzada aquí.

Notas de lanzamiento:
https://docs.docker.com/develop/develop-images/build_enhancements/#using -ssh-to-access-private-data-in-builds

Publicación mediana:
https://medium.com/@tonistiigi/build -secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

Muy emocionante.

Creo que podemos cerrar esto porque ahora tenemos docker build --ssh

Problema de redacción relacionado aquí: docker / compose # 6865. Funcionalidad para usar Redactar y exponer el socket del agente SSH a los contenedores que se indica que aterrizarán en la próxima versión candidata, 1.25.0-rc3 ( versiones ).

¿Fue útil esta página
0 / 5 - 0 calificaciones