Klonuj prywatne repozytorium git za pomocą pliku dockerfile

240

Skopiowałem ten kod z różnych działających dokerów, tutaj jest mój:

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

To daje mi błąd

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

Po raz pierwszy używam plików docker, ale z tego, co przeczytałem (i wziąłem z działających konfiguracji), nie rozumiem, dlaczego to nie działa.

Mój id_rsa znajduje się w tym samym folderze co plik dokera i jest kopią mojego klucza lokalnego, który bez problemu może sklonować to repo.

Edytować:

W moim pliku dokera mogę dodać:

RUN cat /root/.ssh/id_rsa

I drukuje prawidłowy klucz, więc wiem, że został poprawnie skopiowany.

Próbowałem też postępować zgodnie z zaleceniami Noego i pobiegłem:

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

To też niestety nie działa.

Crooksey
źródło

Odpowiedzi:

300

Mój klucz był chroniony hasłem, co było przyczyną problemu, działający plik jest teraz wymieniony poniżej (na pomoc przyszłych pracowników Google)

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
źródło
11
Na wszelki wypadek tutaj znajduje się link opisujący, jak usunąć ochronę hasłem klucza
Thomas
82
Tylko do twojej wiadomości, po uruchomieniu RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts, obraz zapisze to jako warstwę. Jeśli ktoś zdobędzie twój obraz, może odzyskać klucz ... nawet jeśli usuniesz ten plik na późniejszej warstwie, b / c może wrócić do kroku 7 po dodaniu go.
Bernie Perez,
23
Dziękuję za pomocną odpowiedź. Ale dla nas kompilacja nie powiodła się losowo i po badaniu zauważyliśmy, że ssh-keyscandomyślny limit czasu wynosi 5 sekund, który często przekraczał bitbucket. ssh-keyscannawet nie zgłosi błędu. Więc lepiej biegnij, RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hostsżeby być bezpiecznym.
Fluidsonic
5
Czy ktoś mógłby wyjaśnić, dlaczego bieganie ssh-keyscanjest problemem? Rozumiem, że po prostu wyciągnie klucz publiczny z Github / Bitbucket. Jaką alternatywę można zastosować, aby nie skończyła się warstwą?
Pedro
9
@ Pedro W szczególności krok po klawiaturze nie jest żadnym problemem, masz rację. Jeśli tak, te klucze publiczne hosta powinny być rozłożone jak najwięcej. Szczegółowe informacje na temat known_hostspliku znajdują się w sshd (8) . Ludzie opowiadają się za przypadkowymi rzeczami, kiedy brzmią wystarczająco niepokojąco.
tne
99

Powinieneś utworzyć nowy zestaw kluczy SSH dla tego obrazu Docker, ponieważ prawdopodobnie nie chcesz osadzać tam własnego klucza prywatnego. Aby to zadziałało, musisz dodać ten klucz do kluczy wdrażania w repozytorium git. Oto kompletny przepis:

  1. Wygeneruj klucze ssh, za pomocą ssh-keygen -q -t rsa -N '' -f repo-keyktórych otrzymasz pliki repo-key i repo-key.pub.

  2. Dodaj repo-key.pub do kluczy wdrażania repozytorium.
    Na GitHub przejdź do [twoje repozytorium] -> Ustawienia -> Wdróż klucze

  3. Dodaj coś takiego do pliku Docker:

    DODAJ klucz repo /
    BIEGAĆ \
      chmod 600 / repo-key && \  
      echo „IdentityFile / repo-key” >> / etc / ssh / ssh_config && \  
      echo -e "StrictHostKeyChecking no" >> / etc / ssh / ssh_config && \  
      // twoje polecenia klonowania git tutaj ...
    

Zauważ, że powyżej wyłącza StrictHostKeyChecking, więc nie potrzebujesz .ssh / known_hosts. Chociaż prawdopodobnie bardziej podoba mi się rozwiązanie z ssh-keyscan w jednej z powyższych odpowiedzi.

Marcin R.
źródło
6
Ostrzeżenie: w mojej konfiguracji echo -e „...” również zapisuje -e w pliku. Wystarczy usunąć flagę i działa dobrze.
Conchylicultor
Twoja odpowiedź była absolutnie idealna, pomagając mi rozwiązać mój problem. Dziękuję Ci!
David Pointer
Nadal mam ten sam problem:fatal: Could not read from remote repository.
Alex
1
Dziękuję miliony! Jestem na skraju deklarowania wam miłości. Rozwiązałeś problem, z którym walczyłem przez wiele dni!
Alexandra
Odpowiedź wybrana na to pytanie nie jest już dobrą odpowiedzią. W 2014 r. Było to prawidłowe, ale na 2020 r. Jest to poprawna odpowiedź.
Bikal Basnet
70

Nie ma potrzeby bawienia się konfiguracjami ssh. Użyj pliku konfiguracyjnego (nie Dockerfile), który zawiera zmienne środowiskowe, a skrypt powłoki zaktualizuje plik dokera w czasie wykonywania. Trzymasz tokeny poza Dockerfiles i możesz klonować przez https (nie musisz generować ani przekazywać kluczy ssh).

Przejdź do Ustawienia> Osobiste tokeny dostępu

  • Wygeneruj osobisty token dostępu z repowłączonym zakresem.
  • Klonuj tak: git clone https://[email protected]/user-or-org/repo

Niektórzy komentatorzy zauważyli, że jeśli użyjesz udostępnionego pliku Docker, może to ujawnić Twój klucz dostępu innym osobom w twoim projekcie. Chociaż może to dotyczyć konkretnego przypadku użycia, może to dotyczyć następujących sposobów: Oto kilka sposobów rozwiązania tego problemu:

  • Użyj skryptu powłoki, aby zaakceptować argumenty, które mogą zawierać Twój klucz jako zmienną. Zastąp zmienną w swoim pliku Docker plikiem sedpodobnym lub podobnym, tj. Wywołanie skryptu, sh rundocker.sh MYTOKEN=fooktóry by go zastąpił https://{{MY_TOKEN}}@github.com/user-or-org/repo. Pamiętaj, że możesz również użyć pliku konfiguracyjnego (w formacie .yml lub dowolnym innym formacie), aby zrobić to samo, ale ze zmiennymi środowiskowymi.
  • Utwórz użytkownika github (i wygeneruj token dostępu) tylko dla tego projektu
Calvin Froedge
źródło
O jakim kontekście mówisz Settings > Applications?
turboladen
1
Minusem tego podejścia jest to, że przechowujesz dane uwierzytelniające do prywatnego repozytorium w Dockerfile, w przeciwieństwie do podejścia @ crooksey, które pozwala odwoływać się do klucza przechowywanego oddzielnie od Dockerfile. Bez kontekstu, w jaki sposób OP przechowuje plik Docker, nie możemy ustalić, czy to spowodowałoby problem, ale z własnego doświadczenia lubię przechowywać moje pliki Docker w VCS i nie chciałbym zatwierdzać niczego, co zawierałoby poświadczenia. Gdy Docker zaimplementuje możliwość przekazywania zmiennych env do komendy build, zgadzam się, że byłoby to najczystsze rozwiązanie.
Jabbslad
2
@ CalvinFroedge przez lokalnie Zakładam, że masz na myśli swojego gospodarza? Nie znam sposobu ujawnienia zmiennych środowiskowych na hoście w kontenerze podczas kompilacji, dlatego mamy otwarte problemy, takie jak ten github.com/docker/docker/issues/6822 . Czy możesz to wyjaśnić?
Jabbslad
1
Jeszcze czystsze (rozdzielenie obaw): połączony wolumin dla sklonowanego repozytorium + dedykowany kontener tylko do zadania klonowania + połączony wolumin tylko z kluczami SSH (lub tokenem, jak sugerujesz). Zobacz stackoverflow.com/a/30992047 , może być połączony z stackoverflow.com/a/29981990 .
Peterino
9
Pytanie dotyczy także repozytorium BITBUCKET, a nie repozytorium github.
Michael Draper,
25

Inną opcją jest użycie wieloetapowej kompilacji dokera, aby upewnić się, że klucze SSH nie są uwzględnione w ostatecznym obrazie.

Jak opisano w moim poście , możesz przygotować swój obraz pośredni z wymaganymi zależnościami do klonowania, a następnie COPYwymagane pliki do ostatecznego obrazu.

Dodatkowo, jeśli mamy LABELnasze warstwy pośrednie, możemy nawet usunąć je z maszyny po zakończeniu.

# 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

Następnie możemy zbudować:

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

Udowodnij, że klucze SSH zniknęły:

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

Wyczyść obrazy pośrednie z maszyny kompilacji:

docker rmi -f $(docker images -q --filter label=stage=intermediate)
jaker
źródło
ARG SSH_PRIVATE_KEY należy zastąpić ARG SSH_KEY
Joseph Persie
nie możemy po prostu usunąć kluczy po zakończeniu klonowania git?
Broncha,
1
Możesz zrobić, ale musisz to zrobić jako część jednego, RUNaby nie pozostawić klucza na poprzedniej warstwie obrazu. Jako doker 1.13można użyć --squash eksperymentalnego argumentu, który usunąłby klucz SSH również w końcowych warstwach obrazu.
jaker
19

W przypadku repozytorium bitbucket wygeneruj hasło aplikacji (ustawienia Bitbucket -> Zarządzanie dostępem -> Hasło aplikacji, zobacz obraz) z dostępem do odczytu repozytorium i projektu.

menu użytkownika bitbucket

Następnie należy użyć polecenia:

git clone https://username:[email protected]/reponame/projectname.git
Nomka
źródło
1
Najprościej :) Muszę przyznać, że wolę podejście oparte na SSH, ale nie mogłem uzyskać żadnego z powyższych działających ... plików nie znaleziono itp.
Janos
Nie widzę „Zarządzania dostępem”… Myślę, że jest nieaktualny?
Martin Thoma
1
Pracował! Prosty i prosty ... Świetnie!
Josemy
2
Oczywiście ... Wystarczy kliknąć zdjęcie profilowe na lewym pasku, a następnie ustawienia Bitbucket, a zobaczysz coś takiego: imgur.com/EI33zj3
Josemy
1
To zadziałało dla mnie. Mam jednak podmoduły i --recursivenie działałem . Musiałem wstawić git clonedla każdego podmodułu, co jest w porządku, ale byłoby świetnie, gdyby działało rekurencyjnie.
Zailyn Tamayo
14

Często nie chcesz wykonywać git cloneprywatnego repozytorium z kompilacji dokera. Wykonanie tam klonowania polega na umieszczeniu prywatnych poświadczeń ssh wewnątrz obrazu, gdzie mogą je później wyodrębnić dowolne osoby mające dostęp do twojego obrazu.

Zamiast tego powszechną praktyką jest klonowanie repozytorium git spoza dokera w wybranym narzędziu CI i po prostu COPYpliki do obrazu. Ma to drugą zaletę: buforowanie dokerów. Buforowanie dokera sprawdza uruchamiane polecenie, zawarte w nim zmienne środowiskowe, pliki wejściowe itp. Jeśli są identyczne z poprzednią kompilacją z tego samego kroku nadrzędnego, ponownie wykorzystuje poprzednią pamięć podręczną. W git cloneprzypadku polecenia samo polecenie jest identyczne, więc doker ponownie użyje pamięci podręcznej, nawet jeśli zmieni się zewnętrzne repozytorium git. Jednak COPYpolecenie sprawdzi pliki w kontekście kompilacji i zobaczy, czy są one identyczne lub zostały zaktualizowane, i użyje pamięci podręcznej tylko wtedy, gdy jest to właściwe.


Jeśli zamierzasz dodać poświadczenia do swojej kompilacji, rozważ zrobienie tego z kompilacją wieloetapową i umieszczaj te poświadczenia tylko na wczesnym etapie, który nigdy nie jest oznaczany i wypychany poza host kompilacji. Wynik wygląda następująco:

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

Ostatnio BuildKit testuje niektóre eksperymentalne funkcje, które pozwalają przekazać klucz ssh jako mount, który nigdy nie jest zapisywany na obrazie:

# 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

Możesz to zbudować za pomocą:

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

Należy pamiętać, że nadal wymaga to, aby klucz ssh nie był chroniony hasłem, ale można przynajmniej uruchomić kompilację w jednym etapie, usuwając polecenie KOPIUJ i unikając poświadczenia ssh, które nigdy nie będzie częścią obrazu.


BuildKit dodał także funkcję tylko dla ssh, która pozwala nadal mieć chronione hasłem klucze ssh, wynik wygląda następująco:

# 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

Możesz to zbudować za pomocą:

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

Ponownie jest on wstrzykiwany do kompilacji bez zapisywania go w warstwie obrazu, co eliminuje ryzyko przypadkowego wycieku poświadczenia.


Aby zmusić okno dokowane do uruchomienia git clonenawet wtedy, gdy wiersze zostały uprzednio zbuforowane, możesz wstrzyknąć ARG kompilacji, który zmienia się przy każdej kompilacji, aby przerwać bufor. To wygląda jak:

# 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

Następnie wstrzykujesz ten zmieniający się argument w poleceniu kompilacji dokera:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .
BMitch
źródło
Sugerujesz korzystanie z git spoza Dockera, ale i tak wyjaśnisz, jak radzić sobie z kluczami ssh. Kiedy uważasz to za konieczne / właściwe?
JCarlosR
2
@JCarlosR, gdy nie masz zewnętrznego systemu do uruchomienia kompilacji (np. System CI / CD zdolny do wcześniejszego uruchomienia klonu). Mogą istnieć wyjątki, ale klon wewnątrz pliku Docker ma zapach kodu.
BMitch
1

Powyższe rozwiązania nie działały w przypadku bitbucket. Pomyślałem, że to załatwia sprawę:

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