Clonar repositorio privado de git con dockerfile

240

He copiado este código de lo que parecen ser varios dockerfiles de trabajo, aquí está el mío:

FROM ubuntu

MAINTAINER Luke Crooks "[email protected]"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git python-virtualenv

# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN chown -R root:root /root/.ssh

# Create known_hosts
RUN touch /root/.ssh/known_hosts

# Remove host checking
RUN echo "Host bitbucket.org\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config

# Clone the conf files into the docker container
RUN git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf

Esto me da el error

Step 10 : RUN git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf
 ---> Running in 0d244d812a54
Cloning into '/home/docker-conf'...
Warning: Permanently added 'bitbucket.org,131.103.20.167' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
2014/04/30 16:07:28 The command [/bin/sh -c git clone [email protected]:Pumalo/docker-conf.git /home/docker-conf] returned a non-zero code: 128

Esta es la primera vez que uso dockerfiles, pero por lo que he leído (y tomado de las configuraciones de trabajo) no puedo ver por qué esto no funciona.

Mi id_rsa está en la misma carpeta que mi dockerfile y es una copia de mi clave local que puede clonar este repositorio sin problema.

Editar:

En mi dockerfile puedo agregar:

RUN cat /root/.ssh/id_rsa

E imprime la clave correcta, así que sé que se está copiando correctamente.

También intenté hacer lo que Noah me aconsejó y corrí:

RUN echo "Host bitbucket.org\n\tIdentityFile /root/.ssh/id_rsa\n\tStrictHostKeyChecking no" >> /etc/ssh/ssh_config

Esto lamentablemente tampoco funciona.

crooksey
fuente

Respuestas:

300

Mi clave estaba protegida con contraseña, lo que estaba causando el problema, un archivo de trabajo ahora se enumera a continuación (para ayuda de futuros googlers)

FROM ubuntu

MAINTAINER Luke Crooks "[email protected]"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git
# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
ADD id_rsa /root/.ssh/id_rsa

# Create known_hosts
RUN touch /root/.ssh/known_hosts
# Add bitbuckets key
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git
crooksey
fuente
11
Por si acaso, aquí hay un enlace que describe cómo eliminar la protección con contraseña de la clave
Thomas
82
Solo un FYI, después de ejecutar RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts, la imagen lo guardará como una capa. Si alguien obtiene su imagen, puede recuperar la clave ... incluso si elimina ese archivo en una capa posterior, b / c puede volver al Paso 7 cuando lo agregó.
Bernie Perez
23
Gracias por la útil respuesta. Pero para nosotros, la compilación falló al azar y después de la investigación notamos que ssh-keyscantiene un tiempo de espera predeterminado de 5 segundos que Bitbucket a menudo excedió. ssh-keyscanni siquiera informará un error. Así que mejor corre RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hostspara estar a salvo.
fluidsonic
55
¿Alguien podría explicar por qué correr ssh-keyscanes un problema? Tengo entendido que simplemente extraerá la clave pública de Github / Bitbucket. ¿Qué alternativa se puede usar para que no termine en una capa?
Pedro
99
@Pedro El paso de escaneo de teclas en particular no es un problema en absoluto, claramente tienes razón. En todo caso, estas claves públicas de host deben extenderse tanto como sea posible. Consulte sshd (8) para obtener detalles sobre el known_hostsarchivo. La gente simplemente vota cosas al azar cuando suenan lo suficientemente alarmantes.
TNE
99

Debe crear un nuevo conjunto de claves SSH para esa imagen de Docker, ya que probablemente no desee incrustar allí su propia clave privada. Para que funcione, tendrá que agregar esa clave a las claves de implementación en su repositorio git. Aquí está la receta completa:

  1. Genere claves ssh con las ssh-keygen -q -t rsa -N '' -f repo-keyque obtendrá archivos repo-key y repo-key.pub.

  2. Agregue repo-key.pub a las claves de implementación de su repositorio.
    En GitHub, vaya a [su repositorio] -> Configuración -> Implementar claves

  3. Agregue algo como esto a su Dockerfile:

    AGREGAR clave de repositorio /
    CORRER \
      chmod 600 / repo-key && \  
      echo "IdentityFile / repo-key" >> / etc / ssh / ssh_config && \  
      echo -e "StrictHostKeyChecking no" >> / etc / ssh / ssh_config && \  
      // tus comandos de git clone aquí ...
    

Tenga en cuenta que lo anterior desactiva StrictHostKeyChecking, por lo que no necesita .ssh / known_hosts. Aunque probablemente me guste más la solución con ssh-keyscan en una de las respuestas anteriores.

Marcin R
fuente
66
Advertencia: en mi configuración, echo -e "..." también escribe -e dentro del archivo. Simplemente quite la bandera y funciona bien.
Conchylicultor
Su respuesta fue absolutamente perfecta para ayudarme a resolver mi problema. ¡Gracias!
David Pointer
Todavía tengo el mismo problema:fatal: Could not read from remote repository.
Alex
1
¡Gracias millones! Estoy a punto de declararte amor. ¡Resolviste un problema que estuve luchando durante días!
alexandra
La respuesta seleccionada para esta pregunta ya no es una buena respuesta. Fue correcto en 2014, pero para 2020 esta es la respuesta correcta.
Bikal Basnet
71

No hay necesidad de jugar con configuraciones ssh. Use un archivo de configuración (no un Dockerfile) que contenga variables de entorno y haga que un script de shell actualice su archivo docker en tiempo de ejecución. Mantiene los tokens fuera de sus Dockerfiles y puede clonar sobre https (no es necesario generar o pasar claves ssh).

Vaya a Configuración> Tokens de acceso personal

  • Genere un token de acceso personal con el repoalcance habilitado.
  • Clonar así: git clone https://[email protected]/user-or-org/repo

Algunos comentaristas han notado que si usa un Dockerfile compartido, esto podría exponer su clave de acceso a otras personas en su proyecto. Si bien esto puede o no ser una preocupación para su caso de uso específico, aquí hay algunas formas en que puede lidiar con eso:

  • Use un script de shell para aceptar argumentos que puedan contener su clave como variable. Reemplace una variable en su Dockerfile con sedo similar, es decir, llamando al script con el sh rundocker.sh MYTOKEN=fooque reemplazaría https://{{MY_TOKEN}}@github.com/user-or-org/repo. Tenga en cuenta que también puede usar un archivo de configuración (en .yml o el formato que desee) para hacer lo mismo pero con variables de entorno.
  • Cree un usuario github (y genere un token de acceso para) solo para ese proyecto
Calvin Froedge
fuente
¿De qué contexto estás hablando Settings > Applications?
turboladen
1
La desventaja de este enfoque es que está almacenando credenciales para un repositorio privado dentro del Dockerfile en lugar del enfoque de @ crooksey que le permitiría hacer referencia a una clave que se almacena por separado de un Dockerfile. Sin contexto sobre cómo OP está almacenando el Dockerfile, no podemos determinar si esto podría causar un problema, pero por experiencia personal me gusta almacenar mis Dockerfiles dentro de un VCS y no quisiera comprometer nada que contuviera credenciales. Una vez que Docker implemente la capacidad de pasar las variables env para crear el comando, acepto que esta sería la solución más limpia.
Jabbslad
2
@CalvinFroedge por local ¿Asumo que te refieres a tu anfitrión? No conozco una forma de exponer las variables de entorno en el host a un contenedor en el momento de la compilación, por eso tenemos problemas abiertos como este github.com/docker/docker/issues/6822 . Por favor, ¿puedes aclarar?
Jabbslad
1
Incluso más limpio (separación de preocupaciones): un volumen vinculado para el repositorio clonado + un contenedor dedicado solo para la tarea de clonación + un volumen vinculado solo con las claves SSH (o token, como sugiere). Consulte stackoverflow.com/a/30992047 , tal vez combinado con stackoverflow.com/a/29981990 .
Peterino
99
También la pregunta es para un repositorio BITBUCKET, no para un repositorio github.
Michael Draper
25

Otra opción es utilizar una construcción de acoplador de varias etapas para garantizar que sus claves SSH no se incluyan en la imagen final.

Como se describe en mi publicación , puede preparar su imagen intermedia con las dependencias necesarias para git clone y luego COPYlos archivos necesarios en su imagen final.

Además, si tenemos LABELnuestras capas intermedias, incluso podemos eliminarlas de la máquina cuando haya terminado.

# Choose and name our temporary image.
FROM alpine as intermediate
# Add metadata identifying these images as our build containers (this will be useful later!)
LABEL stage=intermediate

# Take an SSH key as a build argument.
ARG SSH_KEY

# Install dependencies required to git clone.
RUN apk update && \
    apk add --update git && \
    apk add --update openssh

# 1. Create the SSH directory.
# 2. Populate the private key file.
# 3. Set the required permissions.
# 4. Add github to our list of known hosts for ssh.
RUN mkdir -p /root/.ssh/ && \
    echo "$SSH_KEY" > /root/.ssh/id_rsa && \
    chmod -R 600 /root/.ssh/ && \
    ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

# Clone a repository (my website in this case)
RUN git clone [email protected]:janakerman/janakerman.git

# Choose the base image for our final image
FROM alpine

# Copy across the files from our `intermediate` container
RUN mkdir files
COPY --from=intermediate /janakerman/README.md /files/README.md

Entonces podemos construir:

MY_KEY=$(cat ~/.ssh/id_rsa)
docker build --build-arg SSH_KEY="$MY_KEY" --tag clone-example .

Prueba que nuestras claves SSH se han ido:

docker run -ti --rm clone-example cat /root/.ssh/id_rsa

Limpie las imágenes intermedias de la máquina de compilación:

docker rmi -f $(docker images -q --filter label=stage=intermediate)
jaker
fuente
ARG SSH_PRIVATE_KEY necesita ser reemplazado por ARG SSH_KEY
Joseph Persie
¿No podemos eliminar las claves una vez que git clone haya terminado?
Broncha
1
Podría hacerlo, pero necesitaría hacerlo como parte de una sola RUNpara no dejar la clave en una capa de imagen anterior. A partir de Docker 1.13, puede usar el argumento --squash experimental que también eliminaría la clave SSH en sus capas de imagen finales.
jaker
19

Para el repositorio de bitbucket, genere la contraseña de la aplicación (configuración de Bitbucket -> Gestión de acceso -> Contraseña de la aplicación, vea la imagen) con acceso de lectura al repositorio y al proyecto.

menú de usuario de bitbucket

Entonces el comando que debes usar es:

git clone https://username:[email protected]/reponame/projectname.git
Nominar
fuente
1
Más simple :) Debo admitir que preferiría un enfoque basado en SSH, pero no pude lograr que ninguno de los anteriores funcionara ... no se encuentran archivos, etc.
Janos
No veo "Gestión de acceso" ... ¿Supongo que está desactualizado?
Martin Thoma
1
¡Trabajó! Llano y simple ... ¡Genial!
Josemy
2
Por supuesto ... Solo tiene que hacer clic en su foto de perfil en la barra izquierda, luego en la configuración de Bitbucket y verá algo como esto: imgur.com/EI33zj3
Josemy
1
Esto funcionó para mí. Sin embargo, tengo submódulos y --recursiveno funcionó. Tuve que poner git clonepara cada submódulo, lo cual está bien, pero habría sido genial si hubiera funcionado recursivamente.
Zailyn Tamayo el
14

A menudo no desea realizar un git clonerepositorio privado desde la compilación de la ventana acoplable. Hacer el clon allí implica colocar las credenciales ssh privadas dentro de la imagen para que luego puedan ser extraídas por cualquier persona con acceso a su imagen.

En cambio, la práctica común es clonar el repositorio git desde fuera de la ventana acoplable en la herramienta de CI que elija, y simplemente COPYlos archivos en la imagen. Esto tiene un segundo beneficio: el almacenamiento en caché de la ventana acoplable. El almacenamiento en caché de Docker analiza el comando que se ejecuta, las variables de entorno que incluye, los archivos de entrada, etc., y si son idénticos a una compilación anterior del mismo paso principal, reutiliza esa caché anterior. Con un git clonecomando, el comando en sí es idéntico, por lo que Docker reutilizará el caché incluso si se cambia el repositorio externo de git. Sin embargo, un COPYcomando mirará los archivos en el contexto de compilación y podrá ver si son idénticos o si se han actualizado, y usará la memoria caché solo cuando sea apropiado.


Si va a agregar credenciales a su compilación, considere hacerlo con una compilación de varias etapas, y solo coloque esas credenciales en una etapa temprana que nunca se etiquete y empuje fuera de su host de compilación. El resultado se ve así:

FROM ubuntu as clone

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git
# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
COPY id_rsa /root/.ssh/id_rsa

# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git

FROM ubuntu as release
LABEL maintainer="Luke Crooks <[email protected]>"

COPY --from=clone /repo /repo
...

Más recientemente, BuildKit ha estado probando algunas características experimentales que le permiten pasar una clave ssh como una montura que nunca se escribe en la imagen:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <[email protected]>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=secret,id=ssh_id,target=/root/.ssh/id_rsa \
    git clone [email protected]:User/repo.git

Y puedes construir eso con:

$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --secret id=ssh_id,src=$(pwd)/id_rsa .

Tenga en cuenta que esto aún requiere que su clave ssh no esté protegida por contraseña, pero al menos puede ejecutar la compilación en una sola etapa, eliminando un comando COPY y evitando que la credencial ssh forme parte de una imagen.


BuildKit también agregó una característica solo para ssh que le permite tener sus claves ssh protegidas con contraseña, el resultado es el siguiente:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <[email protected]>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=ssh \
    git clone [email protected]:User/repo.git

Y puedes construir eso con:

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --ssh default=$SSH_AUTH_SOCK .

Nuevamente, esto se inyecta en la compilación sin escribirse nunca en una capa de imagen, lo que elimina el riesgo de que la credencial se filtre accidentalmente.


Para forzar a Docker a ejecutar git cloneincluso cuando las líneas anteriores se han almacenado en caché, puede inyectar un ARG de compilación que cambia con cada compilación para romper el caché. Eso parece como:

# inject a datestamp arg which is treated as an environment variable and
# will break the cache for the next RUN command
ARG DATE_STAMP
# Clone the conf files into the docker container
RUN git clone [email protected]:User/repo.git

Luego, inyecta ese cambio de arg en el comando de construcción docker:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .
BMitch
fuente
Sugiere usar git desde fuera de Docker, sin embargo, explica cómo manejar las claves ssh de todos modos. ¿Cuándo considera esto necesario / apropiado?
JCarlosR
2
@JCarlosR cuando no tiene un sistema externo en el que ejecutar la compilación (por ejemplo, un sistema CI / CD capaz de ejecutar el clon por adelantado). Puede haber excepciones, pero un clon dentro de un Dockerfile es un olor a código.
BMitch
1

Las soluciones anteriores no funcionaron para bitbucket. Me imaginé que esto funciona:

RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts \
    && eval `ssh-agent` \
    && ssh-add ~/.ssh/[key] \
    && git clone [email protected]:[team]/[repo].git
tvgriek
fuente