ssh keys - para - Usando claves SSH dentro del contenedor docker
instalar y configurar docker centos (22)
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
Tengo una aplicación que ejecuta varias cosas divertidas con Git (como ejecutar git clone & git push) y estoy intentando acoplarla.
Sin embargo, tengo un problema en el que necesito poder agregar una clave SSH al contenedor para que lo use el "usuario" del contenedor.
Intenté copiarlo en /root/.ssh/
, cambiando $HOME
, creando un contenedor git ssh, y aún así no tuve 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 de git pull
como git pull
''puede permitir selectivamente que los servidores remotos accedan a su agente ssh local como si se estuviera ejecutando en el servidor''
https://developer.github.com/guides/using-ssh-agent-forwarding/
Ampliando la respuesta de Peter Grainger, pude usar la compilación de varias etapas disponible desde Docker 17.05. La página oficial dice:
Con las compilaciones de varias etapas, usted usa múltiples declaraciones
FROM
en su Dockerfile. Cada instrucciónFROM
puede usar una base diferente, y cada una de ellas comienza una nueva etapa de la construcción. Puede copiar artefactos de forma selectiva de una etapa a otra, dejando atrás todo lo que no desea en la imagen final.
Teniendo esto en cuenta aquí es mi ejemplo de Dockerfile
incluye tres etapas de compilació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"]
.dockerignore
repite el contenido del archivo .gitignore
(impide que se .gitignore
los node_modules
y los directorios dist
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, simplemente especifique un argumento vacío SSH_KEY_PASSPHRASE
.
Así es como funciona:
1). En la primera etapa, solo package.json
, los archivos yarn.lock
y la clave SSH privada se copian en la primera imagen intermedia llamada sources
. Para evitar más mensajes de contraseña de la clave SSH, se agrega automáticamente a ssh-agent
. Finalmente, el comando yarn
instala todas las dependencias requeridas de NPM y clona los 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 directorio dist
de la siguiente imagen intermedia denominada production
. Tenga en cuenta que el código fuente de los node_modules
instalados se copia de la imagen denominada sources
producidas 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/
Aquí solo tenemos el directorio node_modules
desde la primera imagen intermedia, ya no SSH_KEY_PASSPHRASE
argumentos SSH_KEY
y SSH_KEY_PASSPHRASE
. 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á como ezze/geoport:0.6.0
al incluir solo el directorio dist
de la segunda imagen intermedia denominada production
e instalación de 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 se correlacionan con la primera y la segunda etapas de construcción intermedia.
Si tu corres
$ docker history ezze/geoport:0.6.0 --no-trunc
no verá ninguna mención de SSH_KEY
y SSH_KEY_PASSPHRASE
en la imagen final.
De la forma más sencilla, obtenga una cuenta de launchpad y use: ssh-import-id
En un contenedor de ventana acoplable 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 de la ventana acoplable.
En versiones posteriores de la ventana acoplable (17.05) puede usar compilaciones de múltiples etapas . ¿Cuál es la opción más segura ya que las compilaciones anteriores solo pueden ser utilizadas por la compilación subsiguiente y luego se destruyen?
Ver la respuesta a mi pregunta de para más información
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, pip
y npm
para descargar desde un repositorio privado.
La solución que encontré es agregar sus claves usando la bandera --build-arg
. Luego, puede usar el nuevo comando experimental --squash
(agregado 1.13) para combinar las capas de modo que las claves ya no estén disponibles después de eliminarlas. 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 funciones experimentales, puede agregar --squash
al comando de compilación que fusionará las capas, eliminando las claves SSH y ocultándolas del docker history
.
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 utilizar rutas relativas, en relación con el directorio donde se encuentra su Dockerfile. Entonces deberías usar:
ADD id_rsa /root/.ssh/id_rsa
Y ponga el archivo id_rsa en el mismo directorio donde se encuentra su Dockerfile.
Mira esto para más detalles: http://docs.docker.io/reference/builder/#add
Este problema es realmente molesto. Ya que no puedes agregar / copiar ningún archivo fuera del contexto de dockerfile, lo que significa que es imposible simplemente vincular ~ / .ssh / id_rsa en /root/.ssh/id_rsa de la imagen, y cuando definitivamente necesitas una clave para hacer algo como git clone desde un enlace de repositorio privado ..., durante la construcción de la imagen de la ventana acoplable.
De todos modos, encontré una solución para la solución, no tan persuasiva, pero funcionó para mí.
en su archivo docker:
- agrega este archivo como /root/.ssh/id_rsa
- haz lo que quieras, como git clone, compositor ...
- rm /root/.ssh/id_rsa al final
un guión para hacer en una sesión:
- cp su clave a la carpeta que contiene dockerfile
- construcción docker
- rm la clave copiada
Cada vez que tenga que ejecutar un contenedor desde esta imagen con algunos requisitos de ssh, simplemente agregue -v para el comando de ejecución, como:
ventana acoplable ejecutar -v ~ / .ssh / id_rsa: /root/.ssh/id_rsa - comando de imagen de contenedor de nombre
Esta solución no genera una clave privada ni en la fuente del proyecto ni en la imagen de la ventana acoplable construida, por lo que ya no hay problema de seguridad de qué preocuparse.
Estoy tratando de solucionar el problema de otra manera: agregando la clave pública ssh a una imagen. Pero en mis pruebas, descubrí que "docker cp" es para copiar DESDE un contenedor a un host. El elemento 3 en la respuesta de creak parece estar diciendo que puedes usar el docker cp para inyectar archivos en un contenedor. Consulte https://docs.docker.com/engine/reference/commandline/cp/
extracto
Copie los archivos / carpetas desde el 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
Los contenedores Docker deben considerarse como "servicios" propios. Para separar las preocupaciones se deben 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 puede vincularse al servicio que lo necesite.
2) Use un contenedor para ejecutar la tarea de clonación de git, (es decir, solo se trata de clonar) vinculando el contenedor de datos cuando lo ejecute.
3) Lo mismo para la clave ssh: póngalo como un volumen (como se sugirió anteriormente) y vincúlelo al servicio de clonación de git 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 la 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.
Me encontré con el mismo problema de hoy y con una versión modificada poco con publicaciones anteriores, encontré este enfoque más útil para mí
docker run -it -v ~/.ssh/id_rsa:/root/.my-key:ro image /bin/bash
(Tenga en cuenta que el indicador de solo lectura para que el contenedor no ensucie mi clave ssh en ningún caso).
Dentro del contenedor ahora puedo correr:
ssh-agent bash -c "ssh-add ~/.my-key; git clone <gitrepourl> <target>"
Por lo tanto, no obtengo ese Bad owner or permissions on /root/.ssh/..
error que notó @kross
Para inyectar tu clave ssh, dentro de un contenedor, tienes múltiples soluciones:
Usando un Dockerfile con la instrucción
ADD
, puede inyectarlo durante su proceso de construcciónSimplemente haciendo algo como
cat id_rsa | docker run -i <image> sh -c ''cat > /root/.ssh/id_rsa''
cat id_rsa | docker run -i <image> sh -c ''cat > /root/.ssh/id_rsa''
Usando el comando
docker cp
que le permite inyectar archivos mientras se ejecuta un contenedor.
Puede pasar las claves autorizadas a su contenedor usando una carpeta compartida y establecer permisos usando un archivo docker 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 su ejecución de la ventana acoplable contiene algo como lo siguiente para compartir un directorio de autenticación en el host (que contiene las teclas autorizadas) con el contenedor y luego abrir el puerto ssh al que se podrá acceder 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 consultar https://github.com/jpetazzo/nsenter que parece ser otra forma de abrir un shell en un contenedor y ejecutar comandos dentro de un contenedor.
Reconozco a la hora de la fiesta, ¿qué tal esto hará que las claves de su sistema operativo host estén disponibles para la raíz 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 atrás las claves privadas.
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
Tu script podrá realizar un git clone
.
Extra: si desea que los archivos clonados pertenezcan a un usuario específico, debe usar chown
ya que usar otro usuario que no sea root dentro del contenedor hará que git
falle.
Puedes 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 salir del contenedor para que un usuario no root pueda acceder a los archivos fuera del contenedor.
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.
Si está utilizando la ventana acoplable, una opción fácil es reenviar el agente de SSH de esa manera:
something:
container_name: something
volumes:
- $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
environment:
SSH_AUTH_SOCK: /ssh-agent
Si no le importa la seguridad de sus claves SSH, aquí hay muchas respuestas buenas. Si lo haces, la mejor respuesta que encontré fue la de un enlace en un comentario anterior a este comentario de GitHub de diegocsandrim . Para que sea más probable que otros lo vean, y en caso de que el 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 de squash
, 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 unos 5 minutos, guardamos esta URL de pre-firma en un archivo en el directorio de repositorio, luego en el archivo docker lo agregamos a la imagen.
En dockerfile tenemos un comando RUN que realiza todos estos pasos: use la URL de precontrol 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á en ninguna capa, pero la URL de inicio de sesión se almacenará, 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 como:
# 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"]
También puede vincular su directorio .ssh entre el host y el contenedor, no sé si este método tiene implicaciones 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
Recuerda que la ventana acoplable se ejecuta con sudo (a menos que no lo hagas), si este es el caso, estarás usando las teclas raíz ssh.
Tuvimos un problema similar cuando realizamos la instalación de npm en el tiempo de compilación de la ventana acoplable.
Inspirados en la solución de Daniel van Flymen y combinándolos con la reescritura de url de git , encontramos un método un poco más simple para autenticar la instalación de npm desde los repositorios de github privados: usamos touthens 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 direcciones URL deben volver a escribirse 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 la ventana acoplable 1.9, así que la opción --squash aún no está ahí, 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
Una solución es montar las claves ssh del host en la ventana acoplable con las siguientes opciones:
docker run -v /home/<host user>/.ssh:/home/<docker user>/.ssh <image>
Similar a la solución anterior. Pero funciona con un usuario no root. Trabaja perfectamente con github.