Uso de claves SSH dentro del contenedor acoplable

324

Tengo una aplicación que ejecuta varias cosas divertidas con Git (como ejecutar git clone y git push) y estoy tratando de acoplarlo.

Sin embargo, me encuentro con un problema en el que necesito poder agregar una clave SSH al contenedor para que lo use el 'usuario' del contenedor.

Traté de copiarlo /root/.ssh/, cambiando$HOME , crear un git ssh wrapper, y aún así no suerte.

Aquí está el Dockerfile para referencia:

#DOCKER-VERSION 0.3.4                                                           

from  ubuntu:12.04                                                              

RUN  apt-get update                                                             
RUN  apt-get install python-software-properties python g++ make git-core openssh-server -y
RUN  add-apt-repository ppa:chris-lea/node.js                                   
RUN  echo "deb http://archive.ubuntu.com/ubuntu precise universe" >> /etc/apt/sources.list
RUN  apt-get update                                                             
RUN  apt-get install nodejs -y                                                  

ADD . /src                                                                       
ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa                             
RUN   cd /src; npm install                                                      

EXPOSE  808:808                                                                 

CMD   [ "node", "/src/app.js"]

app.js ejecuta los comandos git como git pull

ebensing
fuente
3
Cualquiera que se acerque a esta pregunta debería pensar en el final del juego, ya que es fácil crear un agujero de seguridad y olvidarse de él aquí si no tienes cuidado. Lea todas las respuestas y elija sabiamente.
Josh Habdas

Respuestas:

144

Es un problema más difícil si necesita usar SSH en el momento de la compilación. Por ejemplo, si está utilizando git clone, o en mi caso pipy npmpara descargar desde un repositorio privado.

La solución que encontré es agregar tus claves usando la --build-argbandera. Luego puede usar el nuevo --squashcomando experimental (agregado 1.13) para fusionar las capas para que las claves ya no estén disponibles después de la eliminación. Aquí está mi solución:

Comando de compilación

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

Dockerfile

FROM python:3.6-slim

ARG ssh_prv_key
ARG ssh_pub_key

RUN apt-get update && \
    apt-get install -y \
        git \
        openssh-server \
        libmysqlclient-dev

# 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

# Avoid cache purge by adding requirements first
ADD ./requirements.txt /app/requirements.txt

WORKDIR /app/

RUN pip install -r requirements.txt

# Remove SSH keys
RUN rm -rf /root/.ssh/

# Add the rest of the files
ADD . .

CMD python manage.py runserver

Actualización: si está utilizando Docker 1.13 y tiene características experimentales, puede agregar --squashel comando de compilación que fusionará las capas, eliminará las claves SSH y las ocultará docker history.

Daniel van Flymen
fuente
13
Este hilo de problema de GitHub indicaría que este enfoque todavía no es seguro. Vea este comentario para otra solución similar.
eczajk
44
Otra solución en lugar de aplastar es agregar y quitar la clave en el mismo comando EJECUTAR, y entre agregar y quitar la usas para lo que la necesitas.
Benjamin Hammer Nørgaard el
2
Tal vez pueda eliminar las líneas para crear el id_rsa.pubarchivo, ya que no es necesario.
LCB
1
En lugar de aplastar, utilice compilaciones de imágenes de varias etapas .
Richard Kiefer el
Si su clave está protegida con contraseña, use $(openssl rsa -in ~/.ssh/id_rsa)en su lugar
BroiSatse
89

Resulta que cuando se usa Ubuntu, el ssh_config no es correcto. Necesitas agregar

RUN  echo "    IdentityFile ~/.ssh/id_rsa" >> /etc/ssh/ssh_config

a su Dockerfile para que reconozca su clave ssh.

ebensing
fuente
2
Probablemente también necesite configurar el nombre de usuario correcto de esta maneraRUN echo " Host example.com" >> /root/.ssh/config RUN echo " User <someusername>" >> /root/.ssh/config
monofone
1
¿Por qué alguien copiaría la clave privada de una máquina host a un contenedor? El comando está bien, pero no veo sentido hacer lo mencionado anteriormente ...
Vladimir Djuricic
12
¡Esto no es seguro! Vea mi solución a continuación para obtener la última versión 1.13 de Docker. @ebensing
Daniel van Flymen
1
@VladimirDjuricic Sin embargo, hay cosas como claves de implementación.
Zelphir Kaltstahl el
en realidad necesitas ejecutar ssh-keygen -A para configurar ssh correctamente en ubuntu minimal container. Luego puede agregar claves pub / priv e iniciar sshd. Tengo esta entrada en mi dockerfile: 'EJECUTAR ssh-keygen -A' como uno de los pasos.
piotrektt
84

Nota : ¡solo use este enfoque para imágenes que son privadas y siempre lo serán !

La clave ssh permanece almacenada dentro de la imagen, incluso si elimina la clave en un comando de capa después de agregarla (vea los comentarios en esta publicación ).

En mi caso, esto está bien, así que esto es lo que estoy usando:

# Setup for ssh onto github
RUN mkdir -p /root/.ssh
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN echo "Host github.com\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config
tapa amarilla
fuente
9191
Esto mantendrá su clave en la imagen, no lo haga.
CppLearner
12
@CppLearner tiene razón, esto almacena la clave en la imagen, y eso podría ser un problema de seguridad en algunos casos. Gracias por resaltar eso. Sin embargo, hay muchas situaciones en las que esto se guarda perfectamente. Por ejemplo, para imágenes que se almacenan en un repositorio privado, o imágenes que se crean directamente en un servidor de producción copiando las claves locales a la imagen.
yellowcap
2
Además, si instala sus proveedores dentro del Dockerfile, no hay nada que le impida eliminar la clave ssh una vez que los proveedores estén instalados.
SebScoFr
2
@SebScoFr, aparentemente las claves se almacenarán en una de las capas, incluso si las elimina en un comando posterior (consulte el enlace en la respuesta actualizada). Entonces, la imagen siempre expondrá la clave ssh, ¡y la solución solo debe usarse para imágenes privadas!
yellowcap
1
@yellowcap no si usted - aplasta la construcción
Anoyz
57

Si está utilizando docker compose, una opción fácil es reenviar el agente SSH así:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
Aistis
fuente
23
Solo una nota de que esto no funciona para hosts Mac, ya sea usando docker-machine (a través de VirtualBox) o Docker for Mac (que usa xhyve) porque los sockets de dominio de Unix no están representados.
Joe Shaw
SSH_AUTH_SOCKes una variable que contiene una ruta a un agente ssh
Aistis
2
más detalles sobre SSH_AUTH_SOCK blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add
JuanPablo
1
ssh-forwarding ahora también es compatible con hosts macOS, en lugar de montar la ruta de $SSH_AUTH_SOCK, debe montar esta ruta /run/host-services/ssh-auth.sock.
Jakub Kukul
48

Ampliando la respuesta de Peter Grainger Pude usar la construcción en varias etapas disponible desde Docker 17.05. La página oficial dice:

Con compilaciones de varias etapas, utiliza múltiples FROMdeclaraciones en su Dockerfile. Cada FROMinstrucción puede usar una base diferente, y cada uno de ellos comienza una nueva etapa de la construcción. Puede copiar selectivamente artefactos de una etapa a otra, dejando todo lo que no desea en la imagen final.

Tener esto en cuenta aquí es mi ejemplo de Dockerfileincluir tres etapas de construcción. Está destinado a crear una imagen de producción de la aplicación web del cliente.

# Stage 1: get sources from npm and git over ssh
FROM node:carbon AS sources
ARG SSH_KEY
ARG SSH_KEY_PASSPHRASE
RUN mkdir -p /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan bitbucket.org > /root/.ssh/known_hosts && \
    echo "${SSH_KEY}" > /root/.ssh/id_rsa && \
    chmod 600 /root/.ssh/id_rsa
WORKDIR /app/
COPY package*.json yarn.lock /app/
RUN eval `ssh-agent -s` && \
    printf "${SSH_KEY_PASSPHRASE}\n" | ssh-add $HOME/.ssh/id_rsa && \
    yarn --pure-lockfile --mutex file --network-concurrency 1 && \
    rm -rf /root/.ssh/

# Stage 2: build minified production code
FROM node:carbon AS production
WORKDIR /app/
COPY --from=sources /app/ /app/
COPY . /app/
RUN yarn build:prod

# Stage 3: include only built production files and host them with Node Express server
FROM node:carbon
WORKDIR /app/
RUN yarn add express
COPY --from=production /app/dist/ /app/dist/
COPY server.js /app/
EXPOSE 33330
CMD ["node", "server.js"]

.dockerignorerepite el contenido del .gitignorearchivo (evita node_modulesy distse copian los directorios resultantes del proyecto):

.idea
dist
node_modules
*.log

Ejemplo de comando para construir una imagen:

$ docker build -t ezze/geoport:0.6.0 \
  --build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" \
  --build-arg SSH_KEY_PASSPHRASE="my_super_secret" \
  ./

Si su clave SSH privada no tiene una frase de contraseña, especifique un SSH_KEY_PASSPHRASEargumento vacío .

Así es como funciona:

1) Solo en la primera etapapackage.json , los yarn.lockarchivos y la clave SSH privada se copian en la primera imagen intermedia nombrada sources. Para evitar más mensajes de frase clave de SSH, se agrega automáticamente a ssh-agent. Finalmente, el yarncomando instala todas las dependencias requeridas de NPM y clona repositorios privados de git de Bitbucket sobre SSH.

2) La segunda etapa construye y minimiza el código fuente de la aplicación web y lo coloca en el distdirectorio de la siguiente imagen intermedia nombrada production. Tenga en cuenta que el código fuente de instaladonode_modules se copia de la imagen nombrada sourcesproducida en la primera etapa por esta línea:

COPY --from=sources /app/ /app/

Probablemente también podría ser la siguiente línea:

COPY --from=sources /app/node_modules/ /app/node_modules/

Sólo tenemos node_modules directorio de la primera imagen intermedia, no SSH_KEYy SSH_KEY_PASSPHRASEargumentos. Todo el resto requerido para la compilación se copia de nuestro directorio de proyectos.

3) En la tercera etapa, reducimos el tamaño de la imagen final que se etiquetará ezze/geoport:0.6.0al incluir solodist directorio de la segunda imagen intermedia nombrada productione instalar Node Express para iniciar un servidor web.

Listado de imágenes da una salida como esta:

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ezze/geoport        0.6.0               8e8809c4e996        3 hours ago         717MB
<none>              <none>              1f6518644324        3 hours ago         1.1GB
<none>              <none>              fa00f1182917        4 hours ago         1.63GB
node                carbon              b87c2ad8344d        4 weeks ago         676MB

donde las imágenes no etiquetadas corresponden a la primera y la segunda etapa de construcción intermedia.

Si tu corres

$ docker history ezze/geoport:0.6.0 --no-trunc

no verá ninguna mención de SSH_KEYy SSH_KEY_PASSPHRASEen la imagen final.

ezze
fuente
Publicación anterior, pero quiero enfatizar que esta es, con mucho, la mejor manera de hacerlo antes del 18.09. La calabaza es innecesaria y propensa al riesgo. Con etapas múltiples, sabe que solo está trayendo los artefactos que desea. Piense en squash como una opción de exclusión de los archivos que no desea y en varias etapas como opción de inclusión. Esta respuesta debe ser mayor. Hornear las teclas ssh en la imagen es una práctica terrible.
mritalian
@ezze Muchas gracias por esta publicación tan útil :) SSH-agent me está volviendo loco, hice algo similar a lo que hiciste: veo correctamente en los registros de compilación de la ventana acoplable, Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)pero cuando registro otro RUN o incluso en el mismo RUN al hacer un comando ssh-add -lme dice que "El agente no tiene identidades". Empezando a arrancarme el pelo, ¿alguna idea?
Alex
40

Para inyectar su clave ssh, dentro de un contenedor, tiene múltiples soluciones:

  1. Usando un Dockerfile con las ADDinstrucciones, puede inyectarlo durante su proceso de compilación

  2. Simplemente haciendo algo como cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  3. Usando el docker cpcomando que le permite inyectar archivos mientras se está ejecutando un contenedor.

crujir
fuente
2
Por lo tanto, a partir de ahora, he intentado copiarlo en /root/.ssh/id_rsa pero sigo recibiendo errores de "Verificación de clave de host. Fatal: el extremo remoto colgó inesperadamente" de Git, que estoy bastante seguro de que significa que no está usando la llave por cualquier razón. Entonces, ¿estoy pensando que hay algo más que debo hacer para decirle al sistema que lo use ya que es la clave ssh? No estoy seguro exactamente cómo depurar este. (y sé que esta clave funciona porque se ejecuta sin problemas desde el host)
partir del
¿puede asegurarse de que / etc / ssh / ssh_config apunte al archivo de clave correcto?
chirrido
1
¿Hay una buena manera de inspeccionar los archivos del contenedor acoplable? ¿O debería intentar copiar en una configuración válida?
ebensing
3
Solo intenté con la imagen 'base', haciendo apt-get install openssh-servery poniendo mi clave en /root/.ssh/id_rsa y funcionó bien. ¿Qué imagen estás usando?
chirrido
Si necesita inspeccionar el archivo de un contenedor, la mejor manera sería confirmar y ejecutar la imagen resultante con 'cat'.
creack
15

Una solución multiplataforma es usar un montaje de enlace para compartir la .sshcarpeta del host con el contenedor:

docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>

Similar al reenvío de agentes, este enfoque hará que las claves públicas sean accesibles para el contenedor. Una ventaja adicional es que también funciona con un usuario no root y lo conectará a GitHub. Sin embargo, una advertencia a tener en cuenta es que todos los contenidos (incluidas las claves privadas) de la .sshcarpeta se compartirán, por lo que este enfoque solo es deseable para el desarrollo y solo para imágenes de contenedor confiables.

Mohammad Azim
fuente
1
esto podría funcionar, pero no docker buildsolo durantedocker run
Alexander Mills
3
Ese es exactamente el punto. No desea poner sus claves ssh dentro de un archivo acoplable.
Mohammad Azim
2
Dado que el reenvío de agentes SSH no funciona fuera de Linux, esta es una buena solución para ponerse en marcha en un entorno de desarrollo sin mucho alboroto.
Josh Habdas
Estoy ejecutando Docker docker-compose upen mi Windows 10. local ¿Cómo debo usar su solución en ese escenario?
llaaalu
Básicamente, está preguntando cómo asignar el volumen en la composición de Docker. Arriba hay una respuesta que responde a esto. Específicamente para Windows, esto podría ayudar a stackoverflow.com/questions/41334021/…
Mohammad Azim
14

Los contenedores Docker deben verse como "servicios" propios. Para separar las preocupaciones, debe separar las funcionalidades:

1) Los datos deben estar en un contenedor de datos: use un volumen vinculado para clonar el repositorio. Ese contenedor de datos se puede vincular al servicio que lo necesita.

2) Use un contenedor para ejecutar la tarea de clonación git (es decir, su único trabajo es la clonación) vinculando el contenedor de datos cuando la ejecute.

3) Lo mismo para la clave ssh: póngalo como un volumen (como se sugirió anteriormente) y vincúlelo al servicio git clone cuando lo necesite

De esa manera, tanto la tarea de clonación como la clave son efímeras y solo están activas cuando es necesario.

Ahora, si su aplicación en sí es una interfaz git, es posible que desee considerar las API REST de github o bitbucket directamente para hacer su trabajo: para eso están diseñadas.

MrE
fuente
13

Esta línea es un problema:

ADD ../../home/ubuntu/.ssh/id_rsa /root/.ssh/id_rsa

Al especificar los archivos que desea copiar en la imagen, solo puede usar rutas relativas, relativas al directorio donde está su Dockerfile. Entonces deberías usar:

ADD id_rsa /root/.ssh/id_rsa

Y coloque el archivo id_rsa en el mismo directorio donde está su Dockerfile.

Mira esto para más detalles: http://docs.docker.io/reference/builder/#add

Dan Keder
fuente
44
Este también es un problema de seguridad porque pone una clave privada en una imagen que se puede olvidar fácilmente.
Mike D
docker cpsolo lo pone en el contenedor y no en la imagen, ¿verdad?
Alexander Mills el
13

Tuvimos un problema similar al hacer la instalación de npm en el tiempo de compilación de Docker.

Inspirado en la solución de Daniel van Flymen y combinándola con git url rewrite , encontramos un método un poco más simple para autenticar la instalación de npm desde repositorios privados de github: utilizamos tokens oauth2 en lugar de las claves.

En nuestro caso, las dependencias npm se especificaron como "git + https://github.com/ ..."

Para la autenticación en el contenedor, las URL deben reescribirse para que sean adecuadas para la autenticación ssh (ssh: //[email protected]/) o la autenticación de token (https: // $ {GITHUB_TOKEN} @ github.com /)

Comando de compilación:

docker build -t sometag --build-arg GITHUB_TOKEN=$GITHUB_TOKEN . 

Desafortunadamente, estoy en Docker 1.9, por lo que la opción de squash aún no está disponible, eventualmente debe agregarse

Dockerfile:

FROM node:5.10.0

ARG GITHUB_TOKEN

#Install dependencies
COPY package.json ./

# add rewrite rule to authenticate github user
RUN git config --global url."https://${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"

RUN npm install

# remove the secret token from the git config file, remember to use --squash option for docker build, when it becomes available in docker 1.13
RUN git config --global --unset url."https://${GITHUB_TOKEN}@github.com/".insteadOf

# Expose the ports that the app uses
EXPOSE 8000

#Copy server and client code
COPY server /server 
COPY clients /clients
Markko Paas
fuente
11

Reenvíe el socket de autenticación ssh al contenedor:

docker run --rm -ti \
        -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock \
        -e SSH_AUTH_SOCK=/tmp/ssh_auth.sock \
        -w /src \
        my_image

Su guión podrá realizar a git clone.

Extra: si desea que los archivos clonados pertenezcan a un usuario específico, debe usarlos, chownya que usar otro usuario que no sea root dentro del contenedor hará que gitfalle.

Puede hacer esto publicando en el entorno del contenedor algunas variables adicionales:

docker run ...
        -e OWNER_USER=$(id -u) \
        -e OWNER_GROUP=$(id -g) \
        ...

Después de clonar, debe ejecutar chown $OWNER_USER:$OWNER_GROUP -R <source_folder>para establecer la propiedad adecuada antes de abandonar el contenedor para que un usuario no root pueda acceder a los archivos fuera del contenedor.

edupo
fuente
1
En las versiones más recientes de Docker, puede pasar -u root:$(id -u $USER)para tener al menos los archivos propiedad del mismo grupo primario que su usuario, lo que debería hacer que todos sean al menos legibles, a sudomenos que algo los esté creando con 0600permisos.
dragon788
@ dragon788 Creo que tienes un error tipográfico: -u root:$(id -u $USER)debería serlo -g.
edupo
¡Buena llamada! Parece que no puedo solucionarlo desde el móvil, lo intentaré en el escritorio pronto.
dragon788
Ahora tengo /tmp/ssh_auth.sock: No such file or directoryque está /tmp/ssh-vid8Zzi8UILE/agent.46016en mi máquina host
vladkras
@vladkras el error es bastante genérico. Podría ser causado debido a los permisos /tmpdentro de su contenedor. O un error tipográfico en el comando Docker Run. Asegúrese de que la declaración de enlace sea correcta -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock: el orden es importante y el punto y coma también es importante. Consulte la documentación de la ventana acoplable para obtener más ayuda.
edupo
10

Como ya comentó eczajk en la respuesta de Daniel van Flymen, no parece seguro quitar las llaves y usarlas --squash, ya que aún serán visibles en el historial ( docker history --no-trunc).

En cambio, con Docker 18.09, ahora puede usar la función "construir secretos". En mi caso, cloné un repositorio privado de git usando la clave SSH de mi host con lo siguiente en mi Dockerfile:

# syntax=docker/dockerfile:experimental

[...]

RUN --mount=type=ssh git clone [...]

[...]

Para poder usar esto, debe habilitar el nuevo backend BuildKit antes de ejecutar docker build :

export DOCKER_BUILDKIT=1

Y necesitas agregar el --ssh default parámetro a docker build.

Más información sobre esto aquí: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

frsc
fuente
1
La mejor solución en mi humilde opinión. Tuve que hacer dos cosas más para que funcione: 1) agregar mi clave privada a ssh-agent with ssh-add ~/.ssh/id_rsay 2) agregar el host git a known_hosts, es decir, para bitbucket:RUN ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
Moritz Ringler
No he podido hacer que esto funcione en absoluto. Todavía recibo errores de permisos: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access and the repository exists.esto a pesar de pasar la --ssh defaultbandera en mi Docker Build y usar --mount=type=sshel comando de ejecución donde yo git clone. Puedo clonar el mismo repositorio sin problemas en la máquina de compilación. Simplemente falla en el contenedor de compilación de la ventana acoplable. Sospecho que la versión mac de Docker no está pasando el cliente ssh.
PMende
@PMende, ¿pudiste resolver este problema que mencionaste porque yo también estoy enfrentando lo mismo?
Sadan A.
@SadanArshad Resulta que esta funcionalidad actualmente solo es compatible si está ejecutando Docker desde una máquina Linux. No funciona si está ejecutando sus comandos de Docker desde una Mac (y probablemente también de Windows, aunque no puedo confirmarlo).
PMende
Lástima que no funcione con Docker-compose ... github.com/docker/compose/issues/6440
Alexis Wilke
9

Este problema es realmente molesto. Dado que no puede agregar / copiar ningún archivo fuera del contexto de dockerfile, lo que significa que es imposible vincular ~ / .ssh / id_rsa en /root/.ssh/id_rsa de la imagen, y cuando definitivamente necesita una clave para hacer algo como git clone desde un enlace de repositorio privado ..., durante la construcción de su imagen acoplable.

De todos modos, encontré una solución alternativa, no tan convincente, pero funcionó para mí.

  1. en su dockerfile:

    • agregue este archivo como /root/.ssh/id_rsa
    • haz lo que quieras, como git clone, compositor ...
    • rm /root/.ssh/id_rsa al final
  2. Un guión para hacer en una sesión:

    • cp su clave para la carpeta que contiene dockerfile
    • Docker Build
    • rm la clave copiada
  3. cada vez que tenga que ejecutar un contenedor desde esta imagen con algunos requisitos ssh, simplemente agregue -v para el comando de ejecución, como:

    docker run -v ~ / .ssh / id_rsa: /root/.ssh/id_rsa --name comando de imagen de contenedor

Esta solución da como resultado que no haya una clave privada tanto en la fuente del proyecto como en la imagen incorporada del acoplador, por lo que ya no debe preocuparse por ningún problema de seguridad.

ImLeo
fuente
1
"Dado que no puede agregar / copiar ningún archivo fuera del contexto de dockerfile," ¿Lo ha visto docker cp? Se utiliza para "Copiar archivos / carpetas entre un contenedor y su host".
Jonathon Reinhart
@JonathonReinhart, gracias por señalarlo. Sí, docker cppodría hacer el truco. Sin embargo, en esta misma situación, necesitaba el ssh_key durante la construcción de la imagen, y no hay ningún contenedor en ese momento ... actualizará mi expresión poco clara, gracias de todos modos.
ImLeo
9

Me encontré con el mismo problema hoy y la versión un poco modificada con publicaciones anteriores me pareció más útil para mí.

docker run -it -v ~/.ssh/id_rsa:/root/.my-key:ro image /bin/bash

(Tenga en cuenta que solo marca para que el contenedor no ensucie mi clave ssh en ningún caso).

Dentro del contenedor ahora puedo ejecutar:

ssh-agent bash -c "ssh-add ~/.my-key; git clone <gitrepourl> <target>"

Así que no recibo ese Bad owner or permissions on /root/.ssh/..error que notó @kross

tojo
fuente
¡Gracias! Esta fue la clave para conseguir que funcione para mí: tener el ssh-agent y ssh-add en un solo comando como: ssh-agent bash -c "ssh-add...". Entonces puedo pasar eso directamente a Docker Run. Todos los ejemplos anteriores que encontré utilizados eval ssh-agent, seguidos de ssh-add y no pude encontrar una manera de pasar eso a evaltravés del comando docker run.
ryanman
6

También puede vincular su directorio .ssh entre el host y el contenedor, no sé si este método tiene alguna implicación de seguridad, pero puede ser el método más fácil. Algo como esto debería funcionar:

$ sudo docker run -it -v /root/.ssh:/root/.ssh someimage bash

Recuerde que Docker se ejecuta con sudo (a menos que no lo haga), si este es el caso, usará las claves ssh raíz.

Luis Elizondo
fuente
El uso de este método funciona con Docker 0.11, pero si usa Fig, arrojará un error de pánico. No sé por qué
Luis Elizondo
3
Este sería un método preferido, el truco sería utilizar las claves de mi usuario host no privilegiado como raíz del contenedor. Como mencionas, tratar de hacerlo no como rinde el usuario raíz del host Bad owner or permissions on /root/.ssh/config.
Kross
esto solo se puede usar durante docker run, pero no durante docker build.
ccpizza
3
@ccpizza, lo veo como una ventaja. Muchas de estas respuestas dejan claves privadas almacenadas en una imagen; la clave permanece almacenada incluso después de eliminar la clave en un comando de capa posterior. Al introducir las claves privadas solo durante la ejecución (no compilación), solo pueden existir en el contenedor (no en la imagen).
cowlinator
6

A partir de docker API 1.39+(Verifique la versión de API con docker version), --sshDocker Build permite la opción con un socket de agente o claves para permitir que Docker Engine reenvíe las conexiones de agente SSH.

Comando de construcción

export DOCKER_BUILDKIT=1
docker build --ssh default=~/.ssh/id_rsa .

Dockerfile

# syntax=docker/dockerfile:experimental
FROM python:3.7

# Install ssh client (if required)
RUN apt-get update -qq
RUN apt-get install openssh-client -y

# Download public key for github.com
RUN --mount=type=ssh mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts

# Clone private repository
RUN --mount=type=ssh git clone [email protected]:myorg/myproject.git myproject

Más información:

Edison Arango
fuente
1
La expansión tilde no funcionó para mí; Tengo: could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory. Use la ruta completa si no funciona.
slhck
3

Si no le importa la seguridad de sus claves SSH, aquí hay muchas buenas respuestas. Si lo hace, la mejor respuesta que encontré fue de un enlace en un comentario anterior a este comentario de GitHub por diegocsandrim . Para que otros tengan más probabilidades de verlo, y en caso de que ese repositorio desaparezca, aquí hay una versión editada de esa respuesta:

La mayoría de las soluciones aquí terminan dejando la clave privada en la imagen. Esto es malo, ya que cualquier persona con acceso a la imagen tiene acceso a su clave privada. Como no sabemos lo suficiente sobre el comportamiento desquash , este puede ser el caso incluso si elimina la clave y aplasta esa capa.

Generamos una URL de pre-firma para acceder a la clave con aws s3 cli, y limitamos el acceso durante aproximadamente 5 minutos, guardamos esta URL de pre-firma en un archivo en el directorio repo, luego en dockerfile la agregamos a la imagen.

En dockerfile tenemos un comando EJECUTAR que realiza todos estos pasos: use la URL previa al canto 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 la URL de pre-firma se almacenará, y esto no es un problema porque la URL no será válida después de 5 minutos.

El script de compilació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 se ve así:

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"]
Sam H.
fuente
1
El problema con esta solución es que debido a que pre_sign_url cambiará cada vez, la instalación de npm no se puede almacenar en caché, incluso si no hay cambios en el archivo packages.json. Es mejor obtener la clave en build.sh y configurarla como argumento de construcción para que no cambie todo el tiempo
York Yang
3

Aquí se detalla una descripción concisa de los desafíos de SSH dentro de los contenedores Docker . Para conectarse a controles remotos confiables desde un contenedor sin filtrar secretos, hay algunas maneras:

Más allá de estos, también existe la posibilidad de usar un almacén de claves que se ejecuta en un contenedor acoplado separado accesible en tiempo de ejecución cuando se usa Compose. El inconveniente aquí es la complejidad adicional debido a la maquinaria requerida para crear y administrar un almacén de claves como Vault by HashiCorp .

Para el uso de la clave SSH en un contenedor Docker independiente, consulte los métodos vinculados anteriormente y considere los inconvenientes de cada uno según sus necesidades específicas. Sin embargo, si está ejecutando dentro de Compose y desea compartir una clave para una aplicación en tiempo de ejecución (que refleja los aspectos prácticos del OP) intente esto:

  • Cree un docker-compose.envarchivo y agréguelo a su .gitignorearchivo.
  • Actualice su docker-compose.ymly agregue env_filepara el servicio que requiere la clave.
  • Acceda a la clave pública desde el entorno en el tiempo de ejecución de la aplicación, por ejemplo, process.node.DEPLOYER_RSA_PUBKEYen el caso de una aplicación Node.js.

El enfoque anterior es ideal para el desarrollo y las pruebas y, si bien podría satisfacer los requisitos de producción, en la producción es mejor usar uno de los otros métodos identificados anteriormente.

Recursos adicionales:

Josh Habdas
fuente
3

Puede usar la compilación de varias etapas para compilar contenedores. Este es el enfoque que puede tomar:

Etapa 1 construyendo una imagen con ssh

FROM ubuntu as sshImage
LABEL stage=sshImage
ARG SSH_PRIVATE_KEY
WORKDIR /root/temp

RUN apt-get update && \
    apt-get install -y git npm 

RUN mkdir /root/.ssh/ &&\
    echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa &&\
    chmod 600 /root/.ssh/id_rsa &&\
    touch /root/.ssh/known_hosts &&\
    ssh-keyscan github.com >> /root/.ssh/known_hosts

COPY package*.json ./

RUN npm install

RUN cp -R node_modules prod_node_modules

Etapa 2: construye tu contenedor

FROM node:10-alpine

RUN mkdir -p /usr/app

WORKDIR /usr/app

COPY ./ ./

COPY --from=sshImage /root/temp/prod_node_modules ./node_modules

EXPOSE 3006

CMD ["npm", "run", "dev"] 

agregue el atributo env en su archivo de redacción:

   environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

luego pasa los argumentos del script de construcción de esta manera:

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"

Y retire el contenedor intermedio por seguridad. Esto te ayudará a aplaudir.

Devesh
fuente
2

Una forma simple y segura de lograr esto sin guardar su clave en una capa de imagen de Docker o pasar por la gimnasia ssh_agent es:

  1. Como uno de los pasos en su Dockerfile, cree un .sshdirectorio agregando:

    RUN mkdir -p /root/.ssh

  2. A continuación, eso indica que le gustaría montar el directorio ssh como un volumen:

    VOLUME [ "/root/.ssh" ]

  3. Asegúrese de que su contenedor ssh_configsepa dónde encontrar las claves públicas agregando esta línea:

    RUN echo " IdentityFile /root/.ssh/id_rsa" >> /etc/ssh/ssh_config

  4. Exponga el .sshdirectorio del usuario local al contenedor en tiempo de ejecución:

    docker run -v ~/.ssh:/root/.ssh -it image_name

    O dockerCompose.ymlagregue esto debajo de la tecla de volumen del servicio:

    - "~/.ssh:/root/.ssh"

Su final Dockerfiledebe contener algo como:

FROM node:6.9.1

RUN mkdir -p /root/.ssh
RUN  echo "    IdentityFile /root/.ssh/id_rsa" >> /etc/ssh/ssh_config

VOLUME [ "/root/.ssh" ]

EXPOSE 3000

CMD [ "launch" ]
Buchanora
fuente
1

Estoy tratando de resolver el problema de otra manera: agregando clave ssh pública a una imagen. Pero en mis pruebas, descubrí que "docker cp" es para copiar DE un contenedor a un host. El ítem 3 en la respuesta de crujido parece estar diciendo que puede usar docker cp para inyectar archivos en un contenedor. Ver https://docs.docker.com/engine/reference/commandline/cp/

extracto

Copie archivos / carpetas del sistema de archivos de un contenedor a la ruta del host. Las rutas son relativas a la raíz del sistema de archivos.

  Usage: docker cp CONTAINER:PATH HOSTPATH

  Copy files/folders from the PATH to the HOSTPATH
EricGreg
fuente
Esta URL parece estar rota ahora.
slm
Esto es obsoleto o incorrecto. Puede copiar cualquier dirección, a más tardar 1.8.2.
Jonathon Reinhart
1

Puede pasar las claves autorizadas a su contenedor utilizando una carpeta compartida y establecer permisos utilizando un archivo acoplable como este:

FROM ubuntu:16.04
RUN apt-get install -y openssh-server
RUN mkdir /var/run/sshd
EXPOSE 22
RUN cp /root/auth/id_rsa.pub /root/.ssh/authorized_keys
RUN rm -f /root/auth
RUN chmod 700 /root/.ssh
RUN chmod 400 /root/.ssh/authorized_keys
RUN chown root. /root/.ssh/authorized_keys
CMD /usr/sbin/sshd -D

Y la ejecución de la ventana acoplable contiene algo como lo siguiente para compartir un directorio de autenticación en el host (que contiene las claves autorizadas) con el contenedor y luego abrir el puerto ssh que será accesible a través del puerto 7001 en el host.

-d -v /home/thatsme/dockerfiles/auth:/root/auth -–publish=127.0.0.1:7001:22

Es posible que desee ver https://github.com/jpetazzo/nsenter, que parece ser otra forma de abrir un shell en un contenedor y ejecutar comandos dentro de un contenedor.

Andrew Paté
fuente
1

Tarde para la fiesta, sin duda, ¿qué tal esto que hará que las claves de su sistema operativo host estén disponibles para rootear dentro del contenedor, sobre la marcha:

docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh [email protected]"

No estoy a favor de usar Dockerfile para instalar claves, ya que las iteraciones de su contenedor pueden dejar claves privadas.

Jepper
fuente
0

Puede usar secretos para administrar cualquier información confidencial que un contenedor necesite en tiempo de ejecución, pero no desea almacenarla en la imagen o en el control de origen, como:

  • Nombres de usuario y contraseñas
  • Certificados y claves TLS
  • Claves SSH
  • Otros datos importantes, como el nombre de una base de datos o un servidor interno
  • Cadenas genéricas o contenido binario (hasta 500 kb de tamaño)

https://docs.docker.com/engine/swarm/secrets/

Estaba tratando de descubrir cómo agregar claves de firma a un contenedor para usar durante el tiempo de ejecución (no compilar) y me encontré con esta pregunta. Los secretos de Docker parecen ser la solución para mi caso de uso, y como todavía nadie lo ha mencionado, lo agregaré.

Travis Britz
fuente
0

En mi caso tuve un problema con nodejs y 'npm i' desde un repositorio remoto. Lo arreglé, agregó el usuario 'node' al contenedor de nodejs y 700 a ~ / .ssh en el contenedor.

Dockerfile:

USER node #added the part
COPY run.sh /usr/local/bin/
CMD ["run.sh"]

run.sh:

#!/bin/bash
chmod 700 -R ~/.ssh/; #added the part

docker-compose.yml:

nodejs:
      build: ./nodejs/10/
      container_name: nodejs
      restart: always
      ports:
        - "3000:3000"
      volumes:
        - ../www/:/var/www/html/:delegated
        - ./ssh:/home/node/.ssh #added the part
      links:
        - mailhog
      networks:
        - work-network

después de eso comenzó a funcionar

Дмитрий Урбанович
fuente
-1

De la manera más simple, obtenga una cuenta de launchpad y use: ssh-import-id

Sam Azafrán
fuente
8
La pregunta era sobre las claves privadas. ssh-import-idparece que solo importa claves públicas.
cddr
-1

En un contenedor Docker en ejecución, puede emitir ssh-keygen con la opción docker -i (interactiva). Esto reenviará las indicaciones del contenedor para crear la clave dentro del contenedor acoplable.

Jerome Anthony
fuente
1
¿Y entonces que? No puedes hacer nada después de esto, porque no tienes permiso para hacerlo.
Jonathon Reinhart
-1

Para debian / root / Authorized_keys:

RUN set -x && apt-get install -y openssh-server

RUN mkdir /var/run/sshd
RUN mkdir -p /root/.ssh
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN  echo "ssh-rsa AAAA....yP3w== rsa-key-project01" >> /root/.ssh/authorized_keys
RUN chmod -R go= /root/.ssh
StanislavKo
fuente