Clone privé git repo avec dockerfile

240

J'ai copié ce code à partir de ce qui semble être divers dockers de travail, voici le mien:

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

Cela me donne l'erreur

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

C'est ma première utilisation de dockerfiles, mais d'après ce que j'ai lu (et tiré des configurations de travail), je ne vois pas pourquoi cela ne fonctionne pas.

Mon id_rsa est dans le même dossier que mon dockerfile et est une copie de ma clé locale qui peut cloner ce dépôt sans problème.

Éditer:

Dans mon dockerfile je peux ajouter:

RUN cat /root/.ssh/id_rsa

Et il imprime la bonne clé, donc je sais qu'il est copié correctement.

J'ai également essayé de faire ce que Noé m'a conseillé et j'ai couru:

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

Malheureusement, cela ne fonctionne pas non plus.

Crooksey
la source

Réponses:

300

Ma clé était protégée par mot de passe, ce qui causait le problème, un fichier de travail est maintenant répertorié ci-dessous (pour aider les futurs googleurs)

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
la source
11
Juste au cas où, voici un lien décrivant comment supprimer la protection par mot de passe de la clé
Thomas
82
Juste pour info, après avoir exécuté RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts, l'image l'enregistrera en tant que couche. Si quelqu'un met la main sur votre image, il peut récupérer la clé ... même si vous supprimez ce fichier dans une couche ultérieure, b / c, il peut revenir à l'étape 7 lorsque vous l'ajoutez.
Bernie Perez
23
Merci pour la réponse utile. Mais pour nous, la construction a échoué de manière aléatoire et après enquête, nous avons remarqué que ssh-keyscanle délai par défaut de 5 secondes était dépassé par bitbucket. ssh-keyscanne signalera même pas d'erreur. Il vaut donc mieux courir RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hostspour être en sécurité.
fluidsonic
5
Quelqu'un pourrait-il expliquer pourquoi la course ssh-keyscanest un problème? Ma compréhension est que cela va simplement extraire la clé publique de Github / Bitbucket. Quelle alternative peut être utilisée pour qu'elle ne se retrouve pas dans une couche?
Pedro
9
@Pedro L'opération keyscan en particulier n'est pas un problème du tout, vous avez clairement raison. Si quelque chose, ces clés publiques hôtes doivent être diffusées autant que possible. Voir sshd (8) pour plus de détails sur le known_hostsfichier. Les gens votent simplement des choses au hasard quand elles semblent assez alarmantes.
TNE
99

Vous devez créer un nouvel ensemble de clés SSH pour cette image Docker, car vous ne voulez probablement pas y incorporer votre propre clé privée. Pour le faire fonctionner, vous devrez ajouter cette clé aux clés de déploiement dans votre référentiel git. Voici la recette complète:

  1. Générez des clés ssh avec ssh-keygen -q -t rsa -N '' -f repo-keylesquelles vous obtiendrez les fichiers repo-key et repo-key.pub.

  2. Ajoutez repo-key.pub à vos clés de déploiement de référentiel.
    Sur GitHub, accédez à [votre référentiel] -> Paramètres -> Déployer les clés

  3. Ajoutez quelque chose comme ça à votre Dockerfile:

    AJOUTER clé de dépôt /
    COURIR \
      chmod 600 / repo-key && \  
      echo "IdentityFile / repo-key" >> / etc / ssh / ssh_config && \  
      echo -e "StrictHostKeyChecking no" >> / etc / ssh / ssh_config && \  
      // vos commandes git clone ici ...
    

Notez que ci-dessus désactive StrictHostKeyChecking, vous n'avez donc pas besoin de .ssh / known_hosts. Bien que j'aime probablement plus la solution avec ssh-keyscan dans l'une des réponses ci-dessus.

Marcin R
la source
6
Attention: dans ma config, echo -e "..." écrit aussi -e dans le fichier. Retirez simplement le drapeau et cela fonctionne bien.
Conchylicultor
Votre réponse a été absolument parfaite pour m'aider à résoudre mon problème. Je vous remercie!
David Pointer du
J'ai toujours le même problème:fatal: Could not read from remote repository.
Alex
1
Merci des millions! Je suis sur le point de vous déclarer l'amour. Vous avez résolu un problème que je luttais depuis des jours!
alexandra
La réponse choisie pour cette question n'est plus une bonne réponse. C'était correct en 2014, mais pour 2020, c'est la bonne réponse.
Bikal Basnet
71

Il n'est pas nécessaire de jouer avec les configurations ssh. Utilisez un fichier de configuration (pas un Dockerfile) qui contient des variables d'environnement et demandez à un script shell de mettre à jour votre fichier Docker au moment de l'exécution. Vous gardez les jetons hors de vos Dockerfiles et vous pouvez cloner sur https (pas besoin de générer ou de passer les clés ssh).

Accédez à Paramètres> Jetons d'accès personnels

  • Générez un jeton d'accès personnel avec la repoportée activée.
  • Clone comme ceci: git clone https://[email protected]/user-or-org/repo

Certains commentateurs ont noté que si vous utilisez un Dockerfile partagé, cela pourrait exposer votre clé d'accès à d'autres personnes sur votre projet. Bien que cela puisse ou non être un problème pour votre cas d'utilisation spécifique, voici quelques façons de gérer cela:

  • Utilisez un script shell pour accepter des arguments qui pourraient contenir votre clé en tant que variable. Remplacez une variable dans votre Dockerfile par sedou similaire, c'est-à-dire en appelant le script avec sh rundocker.sh MYTOKEN=foolequel remplacer https://{{MY_TOKEN}}@github.com/user-or-org/repo. Notez que vous pouvez également utiliser un fichier de configuration (au format .yml ou au format de votre choix) pour faire la même chose mais avec des variables d'environnement.
  • Créez un utilisateur github (et générez un jeton d'accès pour) pour ce projet uniquement
Calvin Froedge
la source
De quel contexte parlez-vous Settings > Applications?
turboladen
1
L'inconvénient de cette approche est que vous stockez les informations d'identification pour un dépôt privé dans le Dockerfile, contrairement à l'approche de @ crooksey qui vous permettrait de référencer une clé qui est stockée séparément d'un Dockerfile. Sans contexte sur la façon dont OP stocke le Dockerfile, nous ne pouvons pas déterminer si cela provoquerait un problème, mais d'après mon expérience personnelle, j'aime stocker mes Dockerfiles dans un VCS et je ne voudrais pas engager quoi que ce soit qui contienne des informations d'identification. Une fois que Docker a implémenté la capacité de passer des variables env pour construire la commande, je conviens que ce serait la solution la plus propre.
Jabbslad
2
@CalvinFroedge par localement, je suppose que vous voulez dire votre hôte? Je ne suis pas au courant d'un moyen d'exposer les variables d'environnement sur l'hôte à un conteneur au moment de la construction, c'est pourquoi nous avons des problèmes ouverts comme celui-ci github.com/docker/docker/issues/6822 . Pouvez-vous clarifier?
Jabbslad
1
Encore plus propre (séparation des préoccupations): un volume lié pour le référentiel cloné + un conteneur dédié uniquement pour la tâche de clonage + un volume lié uniquement avec les clés SSH (ou token, comme vous le suggérez). Voir stackoverflow.com/a/30992047 , peut être combiné avec stackoverflow.com/a/29981990 .
Peterino
9
La question est aussi pour un repo BITBUCKET, pas un repo github.
Michael Draper
25

Une autre option consiste à utiliser une version Docker à plusieurs étapes pour vous assurer que vos clés SSH ne sont pas incluses dans l'image finale.

Comme décrit dans mon article, vous pouvez préparer votre image intermédiaire avec les dépendances requises pour git cloner puis COPYles fichiers requis dans votre image finale.

De plus, si nous avons LABELnos couches intermédiaires, nous pouvons même les supprimer de la machine lorsque vous avez terminé.

# 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

On peut alors construire:

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

Prouvez que nos clés SSH ont disparu:

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

Nettoyez les images intermédiaires de la machine de génération:

docker rmi -f $(docker images -q --filter label=stage=intermediate)
jaker
la source
ARG SSH_PRIVATE_KEY doit être remplacé par ARG SSH_KEY
Joseph Persie
ne pouvons-nous pas simplement supprimer les clés une fois le clonage git terminé?
Broncha
1
Vous pouvez le faire, mais vous devez le faire dans le cadre d'un single RUNafin de ne pas laisser la clé dans un calque d'image précédent. À partir de Docker, 1.13vous pouvez également utiliser l' argument --squash expérimental qui supprimerait la clé SSH dans vos couches d'image finales.
jaker
19

Pour le référentiel bitbucket, générez le mot de passe d'application (paramètres Bitbucket -> Gestion des accès -> Mot de passe d'application, voir l'image) avec un accès en lecture au référentiel et au projet.

menu utilisateur bitbucket

Ensuite, la commande que vous devez utiliser est:

git clone https://username:[email protected]/reponame/projectname.git
Nomce
la source
1
Plus simple :) Je dois admettre que je préférerais une approche basée sur SSH, mais je n'ai pas pu faire fonctionner les fichiers ci-dessus ... les fichiers ne sont pas trouvés, etc.
Janos
Je ne vois pas "Gestion des accès" ... Je suppose que c'est obsolète?
Martin Thoma
1
Travaillé! Clair et simple ... Génial!
Josemy
2
Bien sûr ... Il vous suffit de cliquer sur votre photo de profil dans la barre de gauche, puis sur les paramètres de Bitbucket et vous verrez quelque chose comme ceci: imgur.com/EI33zj3
Josemy
1
Cela a fonctionné pour moi. Cependant, j'ai des sous-modules et je --recursiven'ai pas fonctionné. J'ai dû mettre git clonepour chaque sous-module, ce qui est bien mais aurait été formidable si cela avait fonctionné récursivement.
Zailyn Tamayo
14

Souvent, vous ne voulez pas effectuer git clonede dépôt privé à partir de la génération de docker. Faire le clone là-bas implique de placer les informations d'identification ssh privées à l'intérieur de l'image où elles peuvent être extraites ultérieurement par toute personne ayant accès à votre image.

Au lieu de cela, la pratique courante consiste à cloner le dépôt git depuis l'extérieur de docker dans l'outil CI de votre choix, et simplement COPYles fichiers dans l'image. Cela a un deuxième avantage: la mise en cache du docker. La mise en cache Docker examine la commande en cours d'exécution, les variables d'environnement qu'elle inclut, les fichiers d'entrée, etc., et si elles sont identiques à une génération précédente de la même étape parent, elle réutilise le cache précédent. Avec une git clonecommande, la commande elle-même est identique, donc docker réutilisera le cache même si le dépôt git externe est modifié. Cependant, une COPYcommande examinera les fichiers dans le contexte de génération et pourra voir s'ils sont identiques ou ont été mis à jour et utiliser le cache uniquement lorsque cela est approprié.


Si vous souhaitez ajouter des informations d'identification à votre build, envisagez de le faire avec une build à plusieurs étapes et en ne plaçant ces informations d'identification qu'à un stade précoce qui n'est jamais balisé et poussé à l'extérieur de votre hôte de build. Le résultat ressemble à:

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
...

Plus récemment, BuildKit a testé certaines fonctionnalités expérimentales qui vous permettent de passer une clé ssh en tant que montage qui n'est jamais écrit sur l'image:

# 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

Et vous pouvez construire cela avec:

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

Notez que cela nécessite toujours que votre clé ssh ne soit pas protégée par mot de passe, mais vous pouvez au moins exécuter la génération en une seule étape, en supprimant une commande COPY et en évitant que les informations d'identification ssh ne fassent jamais partie d'une image.


BuildKit a également ajouté une fonctionnalité juste pour ssh qui vous permet d'avoir toujours vos clés ssh protégées par mot de passe, le résultat ressemble à:

# 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

Et vous pouvez construire cela avec:

$ 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 .

Encore une fois, cela est injecté dans la génération sans jamais être écrit dans une couche d'image, ce qui élimine le risque que les informations d'identification ne s'échappent accidentellement.


Pour forcer Docker à exécuter le git clonemême lorsque les lignes précédentes ont été mises en cache, vous pouvez injecter un ARG de génération qui change avec chaque génération pour casser le cache. Cela ressemble à ceci:

# 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

Ensuite, vous injectez cet argument changeant dans la commande de construction du docker:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .
BMitch
la source
Vous proposez d'utiliser git depuis l'extérieur de Docker, mais vous expliquez quand même comment gérer les clés ssh. Quand jugez-vous cela nécessaire / approprié?
JCarlosR
2
@JCarlosR lorsque vous n'avez pas de système externe pour exécuter la construction (par exemple un système CI / CD capable d'exécuter le clone à l'avance). Il peut y avoir des exceptions, mais un clone à l'intérieur d'un Dockerfile est une odeur de code.
BMitch
1

Les solutions ci-dessus n'ont pas fonctionné pour bitbucket. J'ai pensé que cela faisait l'affaire:

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