Używanie kluczy SSH w kontenerze dokera


324

Mam aplikację, która wykonuje różne zabawne rzeczy za pomocą Git (np. Uruchamianie git clone i git push) i próbuję to dokować.

Mam problem, ale muszę dodać klucz SSH do kontenera, aby mógł go użyć „użytkownik”.

Próbowałem go skopiować /root/.ssh/, zmienić $HOME, utworzyć git ssh i wciąż nie mam szczęścia.

Oto plik Docker w celach informacyjnych:

#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 uruchamia polecenia git jak git pull


3
Każdy, kto podejdzie do tego pytania, powinien pomyśleć o końcowej grze, ponieważ łatwo jest stworzyć lukę bezpieczeństwa i zapomnieć o tym tutaj, jeśli nie jesteś ostrożny. Przeczytaj wszystkie odpowiedzi i wybierz mądrze.
Josh Habdas

Odpowiedzi:


144

Jest to trudniejszy problem, jeśli musisz korzystać z SSH podczas kompilacji. Na przykład, jeśli używasz git clone, lub w moim przypadku pipi npmdo pobrania z prywatnego repozytorium.

Rozwiązaniem, które znalazłem, jest dodanie kluczy za pomocą --build-argflagi. Następnie możesz użyć nowego --squashpolecenia eksperymentalnego (dodano 1.13) do scalenia warstw, aby klucze nie były już dostępne po usunięciu. Oto moje rozwiązanie:

Kompilacja polecenia

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

Plik Docker

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

Aktualizacja: Jeśli korzystasz z Docker 1.13 i masz eksperymentalne funkcje, możesz dołączyć --squashdo komendy build, która scali warstwy, usuwa klucze SSH i ukrywa je docker history.


13
Wątek wydania GitHub wskazywałby, że to podejście nadal nie jest bezpieczne. Zobacz ten komentarz dla innego podobnego rozwiązania.
eczajk

4
Innym rozwiązaniem zamiast zgniatania jest dodawanie i usuwanie klucza w tym samym poleceniu RUN, a pomiędzy dodawaniem i usuwaniem używasz go do tego, czego potrzebujesz.
Benjamin Hammer Nørgaard

2
Być może możesz usunąć wiersze tworzenia id_rsa.pubpliku, ponieważ nie jest to wymagane.
LCB,

1
Zamiast wyciskania użyj wielostopniowych kompilacji obrazu .
Richard Kiefer

Jeśli klucz jest chroniony hasłem, użyj $(openssl rsa -in ~/.ssh/id_rsa)zamiast niego
BroiSatse

89

Okazuje się, że podczas korzystania z Ubuntu ssh_config jest niepoprawny. Musisz dodać

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

do pliku Docker, aby rozpoznać twój klucz ssh.


2
Prawdopodobnie musisz również ustawić poprawną nazwę użytkownika w ten sposóbRUN echo " Host example.com" >> /root/.ssh/config RUN echo " User <someusername>" >> /root/.ssh/config
monofone

1
Dlaczego ktoś miałby kopiować klucz prywatny z komputera hosta do kontenera. Polecenie jest w porządku, ale nie widzę sensu w robieniu wyżej wymienionych ...
Vladimir Djuricic

12
To nie jest bezpieczne! Zobacz moje rozwiązanie poniżej dla najnowszej wersji Docker 1.13. @ebensing
Daniel van Flymen

1
@VladimirDjuricic Istnieją jednak takie klucze, jak klucze wdrażania.
Zelphir Kaltstahl

tak naprawdę musisz uruchomić ssh-keygen -A, aby poprawnie ustawić ssh na minimalnym kontenerze ubuntu. Następnie możesz dodać klucze pub / priv i uruchomić sshd. Mam ten wpis w moim pliku docker: „RUN ssh-keygen -A” jako jeden z kroków.
piotrektt

84

Uwaga : używaj tego podejścia tylko do zdjęć, które są prywatne i zawsze będą !

Klucz ssh pozostaje przechowywany w obrazie, nawet jeśli usuniesz klucz w poleceniu warstwy po dodaniu go (zobacz komentarze w tym poście ).

W moim przypadku jest to w porządku, więc używam tego:

# 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

91
Pozwoli to zachować klucz na obrazie, nie rób tego.
CppLearner,

12
@CppLearner masz rację, to przechowuje klucz na obrazie, aw niektórych przypadkach może to stanowić problem bezpieczeństwa. Dzięki za podkreślenie tego. Istnieje jednak wiele sytuacji, w których jest to całkowicie bezpieczne. Na przykład dla obrazów przechowywanych w prywatnym repozytorium lub obrazów zbudowanych bezpośrednio na serwerze produkcyjnym kopiującym klucze lokalne do obrazu.
yellowcap

2
Ponadto, jeśli zainstalujesz swoich dostawców w Dockerfile, nic nie powstrzyma cię przed usunięciem klucza ssh po zainstalowaniu dostawców.
SebScoFr

2
@SebScoFr, najwyraźniej klucze będą przechowywane w jednej z warstw, nawet jeśli usuniesz je w późniejszym poleceniu (patrz link w zaktualizowanej odpowiedzi). Obraz zawsze będzie odsłaniał klucz ssh, a rozwiązania należy używać tylko do prywatnych zdjęć!
yellowcap

1
@yellowcap nie, jeśli
rozbijesz wersję

56

Jeśli używasz komponowania dokowania , łatwym wyborem jest przekazanie agenta SSH w ten sposób:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent

23
Tylko uwaga, że ​​nie działa to na hostach Mac, niezależnie od tego, czy używasz docker-machine (przez VirtualBox), czy Docker na Mac (który używa xhyve), ponieważ gniazda domeny unix nie są proxy.
Joe Shaw,

SSH_AUTH_SOCKjest zmienną, która zawiera ścieżkę do agenta ssh
Aistis

2
więcej szczegółów na temat SSH_AUTH_SOCK blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add
JuanPablo

1
Przekazywanie ssh jest teraz obsługiwane także na hostach macOS - zamiast montować ścieżkę $SSH_AUTH_SOCK, musisz zamontować tę ścieżkę - /run/host-services/ssh-auth.sock.
Jakub Kukul

47

Rozszerzając odpowiedź Petera Graingera Byłem w stanie korzystać z wersji wieloetapowej dostępnej od Dockera 17.05. Oficjalna strona zawiera:

W kompilacjach wieloetapowych używasz wielu FROMinstrukcji w swoim pliku Docker. Każda FROMinstrukcja może korzystać z innej bazy i każda z nich rozpoczyna nowy etap kompilacji. Możesz selektywnie kopiować artefakty z jednego etapu na drugi, pozostawiając za sobą wszystko, czego nie chcesz na ostatecznym obrazie.

Mając to na uwadze, mój przykład Dockerfileobejmuje trzy etapy budowy. Ma on na celu stworzenie produkcyjnego obrazu aplikacji WWW klienta.

# 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"]

.dockerignorepowtarza zawartość .gitignorepliku (zapobiega kopiowaniu node_modulesi wynikowym distkatalogom projektu):

.idea
dist
node_modules
*.log

Przykład polecenia, aby zbudować obraz:

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

Jeśli twój prywatny klucz SSH nie ma hasła, podaj pusty SSH_KEY_PASSPHRASEargument.

Tak to działa:

1). Tylko na pierwszym etapie package.json, yarn.lockpliki i prywatny klucz SSH są kopiowane do pierwszej pośredniej obrazu nazwie sources. Aby uniknąć dalszych monitów o hasło SSH, jest ono automatycznie dodawane do ssh-agent. Wreszcie yarnpolecenie instaluje wszystkie wymagane zależności z NPM i klonuje prywatne repozytoria git z Bitbucket przez SSH.

2). Drugi etap buduje i minimalizuje kod źródłowy aplikacji internetowej i umieszcza go w distkatalogu następnego obrazu pośredniego o nazwie production. Zauważ, że zainstalowany kod źródłowy node_modulesjest kopiowany z obrazu o nazwie sourceswyprodukowanej w pierwszym etapie przez ten wiersz:

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

Prawdopodobnie może to być również następująca linia:

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

Mamy tylko node_moduleskatalog z pierwszej pośredniej obrazu tutaj, no SSH_KEYi SSH_KEY_PASSPHRASEjuż argumenty. Cała reszta wymagana do kompilacji jest kopiowana z naszego katalogu projektu.

3). W trzecim etapie zmniejszamy rozmiar końcowego obrazu, który zostanie oznaczony jako ezze/geoport:0.6.0, włączając tylko distkatalog z drugiego obrazu pośredniego o nazwie productioni instalując Node Express do uruchomienia serwera WWW.

Wyświetlanie listy obrazów daje takie dane wyjściowe:

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

gdzie nieoznaczone obrazy odpowiadają pierwszemu i drugiemu pośredniemu etapowi kompilacji.

Jeśli uciekniesz

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

nie będzie widać żadnych wzmianek SSH_KEYi SSH_KEY_PASSPHRASEw końcowym obrazie.


Stary post, ale chcę podkreślić, że jest to zdecydowanie najlepszy sposób na zrobienie tego przed 18.09. Squash jest niepotrzebny i narażony na ryzyko. Dzięki wielostopniowemu wieszowi, że przynosisz tylko żądane artefakty. Pomyśl o squashu jako rezygnacji z niepotrzebnych plików, a wielostopniowej jako opt-in. Ta odpowiedź musi być wyższa. Pieczenie kluczy ssh na obrazie to straszna praktyka.
mritalian

@ezze Dziękuję bardzo za ten bardzo przydatny post :) Agent SSH doprowadza mnie do szaleństwa, zrobiłem coś podobnego do tego, co zrobiliście: poprawnie widzę w dziennikach kompilacji dokera, Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)ale kiedy sprawdzam inny RUN lub nawet w tym samym RUN wykonanie polecenia ssh-add -lpowoduje, że „Agent nie ma tożsamości”. Zaczynam ściągać włosy, jakieś myśli?
Alex

40

Aby wstrzyknąć ci klucz ssh, w kontenerze masz wiele rozwiązań:

  1. Używając pliku Docker z ADDinstrukcją, możesz wstrzyknąć go podczas procesu kompilacji

  2. Po prostu robienie czegoś takiego cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  3. Korzystanie z docker cppolecenia, które pozwala wstrzykiwać pliki podczas działania kontenera.


2
Tak więc, jak na razie, próbowałem skopiować go do /root/.ssh/id_rsa, ale nadal otrzymuję komunikat „Błąd weryfikacji klucza hosta nie powiódł się. Śmiertelnie: nieoczekiwanie rozłączył się” Zdalne zakończenie z Git, co jestem pewien, że to oznacza nie używa klucza z jakiegokolwiek powodu. Więc myślę, że jest coś jeszcze, co muszę zrobić, aby powiedzieć systemowi, aby używał go jako klucza ssh? Nie jestem pewien, jak dokładnie debugować ten. (i wiem, że ten klucz działa, ponieważ działa bez problemu z hosta)
ebensing

czy możesz się upewnić, że plik / etc / ssh / ssh_config jest ustawiony na poprawny plik klucza?
creack

1
Czy istnieje dobry sposób na sprawdzenie plików kontenera dokera? A może powinienem po prostu spróbować skopiować w prawidłowej konfiguracji?
ebensing

3
Właśnie próbowałem z obrazem „base”, robiąc apt-get install openssh-serveri wkładając mój klucz do /root/.ssh/id_rsa i działało dobrze. Jakiego obrazu używasz?
creack

jeśli chcesz sprawdzić plik kontenera, najlepszym sposobem byłoby zatwierdzenie i uruchomienie wynikowego obrazu za pomocą „cat”.
creack

15

Jednym z rozwiązań wieloplatformowych jest użycie montowania wiązania w celu udostępnienia .sshfolderu hosta w kontenerze:

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

Takie podejście, podobnie jak przekazywanie agentów, sprawi, że klucze publiczne będą dostępne dla kontenera. Dodatkową zaletą jest to, że działa również z użytkownikiem innym niż root i zapewni ci połączenie z GitHub. Jednym zastrzeżeniem, które należy wziąć pod uwagę, jest to, że cała zawartość (w tym klucze prywatne) z .sshfolderu będą udostępniane, więc takie podejście jest pożądane tylko w przypadku programowania i tylko w przypadku zaufanych obrazów kontenerów.


1
to może zadziałać, ale nie docker buildtylko podczasdocker run
Alexander Mills

3
Właśnie o to chodzi. Nie chcesz umieszczać kluczy ssh w pliku dokera.
Mohammad Azim

2
Biorąc pod uwagę, że przekazywanie agentów SSH nie działa poza Linuksem, jest to dobre rozwiązanie do uruchomienia w środowisku programistycznym bez większego zamieszania.
Josh Habdas

Korzystam z dokera przy użyciu docker-compose upw moim lokalnym systemie Windows 10. Jak powinienem użyć twojego rozwiązania w tym scenariuszu?
llaaalu,

Zasadniczo pytasz, jak mapować głośność w komponowaniu dokera. Powyżej znajduje się odpowiedź na to pytanie. W szczególności dla systemu Windows może to pomóc stackoverflow.com/questions/41334021/…
Mohammad Azim,

14

Kontenery dokowe należy postrzegać jako własne „usługi”. Aby rozdzielić obawy, należy oddzielić funkcje:

1) Dane powinny znajdować się w kontenerze danych: użyj połączonego woluminu, aby sklonować repozytorium. Ten kontener danych można następnie połączyć z potrzebującą go usługą.

2) Użyj kontenera, aby uruchomić zadanie klonowania git (tj. To tylko zadanie klonowania), łącząc z nim kontener danych podczas jego uruchamiania.

3) To samo dla klucza ssh: włóż to wolumin (jak zasugerowano powyżej) i połącz go z usługą klonowania git, gdy go potrzebujesz

W ten sposób zarówno zadanie klonowania, jak i klucz są efemeryczne i aktywne tylko w razie potrzeby.

Teraz, jeśli twoja aplikacja jest interfejsem git, możesz rozważyć zastosowanie interfejsów API REST github lub bitbucket bezpośrednio do wykonania swojej pracy: do tego właśnie zostały zaprojektowane.


13

Ta linia stanowi problem:

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

Określając pliki, które chcesz skopiować do obrazu, możesz używać tylko ścieżek względnych - względem katalogu, w którym znajduje się plik Docker. Zamiast tego powinieneś użyć:

ADD id_rsa /root/.ssh/id_rsa

I umieść plik id_rsa w tym samym katalogu, w którym znajduje się plik Docker.

Sprawdź to, aby uzyskać więcej informacji: http://docs.docker.io/reference/builder/#add


4
Jest to również problem z bezpieczeństwem, ponieważ umieszcza klucz prywatny w obrazie, który można łatwo zapomnieć.
Mike D

docker cppo prostu umieszcza go w pojemniku, a nie na zdjęciu, prawda?
Alexander Mills,

13

Mieliśmy podobny problem podczas instalacji npm w czasie kompilacji dokera.

Zainspirowani rozwiązaniem Daniela van Flymena i połączeniem go z przepisem git url , znaleźliśmy nieco prostszą metodę uwierzytelniania instalacji npm z prywatnych repozytoriów github - zamiast kluczy użyliśmy tokenów oauth2.

W naszym przypadku zależności npm określono jako „git + https://github.com/ ...”

W celu uwierzytelnienia w kontenerze adresy URL muszą zostać przepisane, aby były odpowiednie do uwierzytelnienia ssh (ssh: //git@github.com/) lub uwierzytelnienia tokena (https: // $ {GITHUB_TOKEN} @ github.com /)

Komenda kompilacji:

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

Niestety korzystam z Dockera 1.9, więc opcja -squash jeszcze nie istnieje, w końcu trzeba ją dodać

Plik Docker:

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

11

Przekaż gniazdo uwierzytelniania ssh do kontenera:

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

Twój skrypt będzie mógł wykonać git clone.

Dodatkowo: Jeśli chcesz, aby sklonowane pliki należały do ​​określonego użytkownika, musisz go użyć, chownponieważ użycie innego użytkownika niż root w kontenerze zakończy się gitniepowodzeniem.

Możesz zrobić to publikowanie w środowisku kontenera kilka dodatkowych zmiennych:

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

Po sklonowaniu należy wykonać, chown $OWNER_USER:$OWNER_GROUP -R <source_folder>aby ustawić właściwą własność przed opuszczeniem kontenera, aby pliki były dostępne dla użytkownika innego niż root poza kontenerem.


1
W nowszych wersjach Dockera możesz przekazać -u root:$(id -u $USER)przynajmniej pliki należące do tej samej grupy podstawowej, co użytkownik, co powinno uczynić je przynajmniej czytelnymi, sudochyba że coś tworzy je z 0600uprawnieniami.
dragon788,

@ dragon788 Myślę, że masz literówkę: -u root:$(id -u $USER)powinno być -g.
edupo

Dobra decyzja! Wydaje się, że nie jestem w stanie naprawić tego z telefonu komórkowego, wkrótce wypróbuję na komputerze.
dragon788,

Mam /tmp/ssh_auth.sock: No such file or directorygo teraz /tmp/ssh-vid8Zzi8UILE/agent.46016na mojej maszynie
hoście

@vladkras błąd jest dość ogólny. Może to być spowodowane pozwoleniami na dostęp /tmpdo twojego kontenera. Lub literówka w poleceniu uruchomienia dokera. Upewnij się, że instrukcja bind jest poprawna -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock: kolejność jest ważna, a średnik jest również ważny. Aby uzyskać dalszą pomoc, sprawdź dokumentację dokera .
edupo

10

Jak skomentował już eczajk w odpowiedzi Daniela van Flymena, nie wydaje się bezpieczne usuwanie kluczy i ich używanie --squash, ponieważ nadal będą widoczne w historii ( docker history --no-trunc).

Zamiast tego w Docker 18.09 możesz teraz korzystać z funkcji „buduj sekrety”. W moim przypadku sklonowałem prywatne repozytorium git przy użyciu mojego klucza SSH hosta z następującym plikiem w pliku Docker:

# syntax=docker/dockerfile:experimental

[...]

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

[...]

Aby móc z tego skorzystać, musisz włączyć nowy backend BuildKit przed uruchomieniem docker build:

export DOCKER_BUILDKIT=1

I musisz dodać --ssh defaultparametr do docker build.

Więcej informacji na ten temat tutaj: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066


1
Najlepsze rozwiązanie IMHO. Musiałem zrobić jeszcze dwie rzeczy, aby to zadziałało: 1) dodaj mój prywatny klucz do ssh-agent za pomocą ssh-add ~/.ssh/id_rsai 2) dodaj hosta git do znanych_hostów, tj. Dla bitbucket:RUN ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
Moritz Ringler

W ogóle nie udało mi się tego uruchomić. Nadal dostaję błędy uprawnień: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access and the repository exists.To pomimo przekazania --ssh defaultflagi w mojej kompilacji dokera i użycia --mount=type=sshw poleceniu uruchomienia tam, gdzie ja git clone. Jestem w stanie sklonować to samo repo bez problemu na komputerze kompilacji. Po prostu zawodzi w kontenerze kompilatora dokerów. Podejrzewam, że wersja Mac Dockera tak naprawdę nie przekazuje klienta ssh.
PMende

@PMende, czy byłeś w stanie rozwiązać ten problem, o którym wspomniałeś, ponieważ ja też mam do czynienia z tym samym.
Sadan A.,

@SadanArshad Okazuje się, że ta funkcja jest obecnie obsługiwana tylko wtedy, gdy uruchamiasz Docker z komputera z systemem Linux. Nie działa, jeśli uruchamiasz polecenia Docker na komputerze Mac (i prawdopodobnie także w systemie Windows, choć nie mogę tego potwierdzić).
PMende,

Szkoda, że ​​nie działa z docker
Alexis Wilke

9

Ten problem jest naprawdę denerwujący. Ponieważ nie można dodawać / kopiować żadnego pliku poza kontekstem pliku dokującego, co oznacza, że ​​nie można po prostu połączyć ~ / .ssh / id_rsa z katalogiem /root/.ssh/id_rsa obrazu, a kiedy zdecydowanie potrzebujesz klucza do zrobienia czegoś. jak klon git z prywatnego linku repo ... podczas budowania obrazu dokera.

W każdym razie znalazłem rozwiązanie tego obejścia, nie przekonujące, ale działało dla mnie.

  1. w twoim pliku dokera:

    • dodaj ten plik jako /root/.ssh/id_rsa
    • rób co chcesz, np. klon git, kompozytor ...
    • rm /root/.ssh/id_rsa na końcu
  2. scenariusz do zrobienia w jednym zdjęciu:

    • cp klucz do folderu zawierającego plik dockerfile
    • kompilacja dokera
    • skopiowany klucz
  3. za każdym razem, gdy musisz uruchomić kontener z tego obrazu z pewnymi wymaganiami ssh, po prostu dodaj -v dla polecenia run, na przykład:

    Uruchom okno dokowane -v ~ / .ssh / id_rsa: /root/.ssh/id_rsa - nazwa polecenia obraz kontenera

Dzięki temu rozwiązaniu nie ma klucza prywatnego zarówno w źródle projektu, jak i w wbudowanym obrazie dokera, więc nie trzeba się już martwić o bezpieczeństwo.


1
„Ponieważ nie można dodawać / kopiować żadnego pliku poza kontekstem pliku dokowanego” , Widziałeś docker cp? Służy do „Kopiowania plików / folderów między kontenerem a hostem”.
Jonathon Reinhart

@JonathonReinhart, dzięki za zwrócenie na to uwagi. Tak, docker cpmoże załatwić sprawę. Jednak w tej sytuacji potrzebowałem ssh_key podczas budowania obrazu i nie ma w tym czasie żadnego kontenera ... dzięki temu zaktualizuję moje niejasne wyrażenie.
ImLeo,

9

Natrafiłem dzisiaj na ten sam problem i nieco zmodyfikowana wersja z poprzednimi postami uznałem to podejście za bardziej przydatne dla mnie

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

(Pamiętaj, że flaga tylko do odczytu, więc kontener w żadnym wypadku nie zepsuje mojego klucza ssh).

Wewnątrz kontenera mogę teraz uruchomić:

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

Więc nie dostaję Bad owner or permissions on /root/.ssh/..błędu, który zauważył @kross


Dziękuję Ci! To był klucz do dostać pracy dla mnie: o ssh-agent i ssh-add w jednym poleceniem: ssh-agent bash -c "ssh-add...". Następnie mogę przekazać to prawo do uruchomienia dokera. Użyłem wszystkich poprzednich przykładów eval ssh-agent, a następnie ssh-add i nie mogłem znaleźć sposobu, aby przekazać to evalza pomocą polecenia uruchomienia dokera.
ryanman


6

Możesz także połączyć swój katalog .ssh między hostem a kontenerem, nie wiem czy ta metoda ma wpływ na bezpieczeństwo, ale może to być najłatwiejsza metoda. Coś takiego powinno działać:

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

Pamiętaj, że okno dokowane działa z sudo (chyba że tego nie robisz), w takim przypadku będziesz używać kluczy root ssh.


Ta metoda działa z dokerem 0.11, ale jeśli użyjesz rys., Spowoduje to wystąpienie błędu paniki. Nie wiem dlaczego
Luis Elizondo,

3
Byłaby to preferowana metoda, sztuczka polegałaby na użyciu kluczy mojego nieuprzywilejowanego użytkownika hosta jako katalogu głównego kontenera. Jak wspomniałeś, próba zrobienia tego nie tak, jak daje to użytkownik root Bad owner or permissions on /root/.ssh/config.
kross

można tego użyć tylko podczas docker run, ale nie podczas docker build.
ccpizza

3
@ccpizza, uważam to za zaletę. Wiele z tych odpowiedzi pozostawia prywatne klucze przechowywane na obrazie; klucz pozostaje przechowywany nawet po usunięciu klucza w kolejnej komendzie warstwy. Po wprowadzeniu kluczy prywatnych tylko podczas uruchamiania (nie kompilacji) mogą one istnieć tylko w kontenerze (nie na obrazie).
cowlinator

6

Począwszy od docker API 1.39+(Sprawdź wersję interfejsu API za pomocą docker version) kompilacji --sshdokera umożliwia opcję z gniazdem agenta lub kluczami, aby umożliwić silnikowi Docker przekazywanie połączeń agenta SSH.

Kompilacja poleceń

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

Plik Docker

# 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 git@github.com:myorg/myproject.git myproject

Więcej informacji:


1
Rozszerzenie tyldy nie działało dla mnie; Mam: could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory. Użyj pełnej ścieżki, jeśli to nie działa.
slhck

3

Jeśli nie dbasz o bezpieczeństwo swoich kluczy SSH, znajdziesz tutaj wiele dobrych odpowiedzi. Jeśli to zrobisz, najlepszą odpowiedzią, jaką znalazłem, był link w komentarzu powyżej do tego komentarza GitHub autorstwa diegocsandrim . Aby inni mogli to zobaczyć i na wypadek, gdyby repozytorium kiedykolwiek zniknęło, oto zredagowana wersja tej odpowiedzi:

Większość rozwiązań tutaj pozostawia klucz prywatny na obrazie. Jest to złe, ponieważ każdy, kto ma dostęp do obrazu, ma dostęp do twojego klucza prywatnego. Ponieważ nie wiemy wystarczająco dużo o zachowaniu się squash, nadal może tak być, nawet jeśli usuniesz klucz i zmiażdżysz tę warstwę.

Generujemy adres URL przed podpisaniem, aby uzyskać dostęp do klucza za pomocą aws s3 cli, i ograniczamy dostęp przez około 5 minut, zapisujemy ten adres URL przed podpisaniem w pliku w katalogu repo, a następnie w pliku dokera dodajemy go do obrazu.

W pliku dockerfile mamy polecenie RUN, które wykonuje wszystkie następujące kroki: użyj wstępnego sing URL, aby uzyskać klucz ssh, uruchom instalację npm i usuń klucz ssh.

Wykonując to w jednym poleceniu, klucz ssh nie będzie przechowywany w żadnej warstwie, ale adres URL przed podpisaniem zostanie zapisany i nie stanowi to problemu, ponieważ adres URL nie będzie ważny po 5 minutach.

Skrypt kompilacji wygląda następująco:

# build.sh
aws s3 presign s3://my_bucket/my_key --expires-in 300 > ./pre_sign_url
docker build -t my-service .

Plik Docker wygląda następująco:

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 git@github.com || true && \
    npm install --production && \
    rm ./my_key && \
    rm -rf ~/.ssh/*

ENTRYPOINT ["npm", "run"]

CMD ["start"]

1
Problem z tym rozwiązaniem polega na tym, że ponieważ pre_sign_url zmienia się za każdym razem, instalacja npm nie może być buforowana, nawet jeśli nie ma zmian w pliku packages.json. Lepiej jest zdobyć klucz w build.sh i ustawić go jako argument kompilacji, aby nie zmieniał się za każdym razem
York Yang


3

Zwięzły przegląd wyzwań związanych z SSH wewnątrz kontenerów Docker znajduje się tutaj . Aby połączyć się z zaufanymi pilotami z poziomu kontenera bez ujawniania tajemnic, istnieje kilka sposobów:

Poza tym istnieje również możliwość korzystania z magazynu kluczy działającego w osobnym kontenerze dokowanym, dostępnym w czasie wykonywania podczas korzystania z funkcji Utwórz. Wadą tego rozwiązania jest dodatkowa złożoność związana z maszyną niezbędną do utworzenia magazynu kluczy i zarządzania nim, takiego jak Vault firmy HashiCorp .

W przypadku użycia klucza SSH w autonomicznym kontenerze Docker zapoznaj się z powyższymi metodami i rozważ ich wady w zależności od konkretnych potrzeb. Jeśli jednak uruchamiasz się w trybie tworzenia i chcesz udostępnić klucz do aplikacji w czasie wykonywania (odzwierciedlający praktyczne funkcje PO), spróbuj tego:

  • Utwórz docker-compose.envplik i dodaj go do swojego .gitignorepliku.
  • Zaktualizuj docker-compose.ymli dodaj env_filedo usługi wymagającej klucza.
  • Uzyskaj dostęp do klucza publicznego ze środowiska w czasie wykonywania aplikacji, np. process.node.DEPLOYER_RSA_PUBKEYW przypadku aplikacji Node.js.

Powyższe podejście jest idealne do opracowywania i testowania i chociaż może spełniać wymagania produkcyjne, w produkcji lepiej jest użyć jednej z innych metod określonych powyżej.

Dodatkowe zasoby:


3

Do budowania kontenerów można użyć kompilacji wieloetapowej. Możesz zastosować następujące podejście:

Etap 1 budowanie obrazu za pomocą 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

Etap 2: zbuduj swój kontener

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"] 

dodaj atrybut env do pliku tworzenia:

   environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

następnie przekaż argumenty ze skryptu budowania w następujący sposób:

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

I usuń pośredni pojemnik dla bezpieczeństwa. Pomoże Ci to wiwatować.


2

Prostym i bezpiecznym sposobem na osiągnięcie tego bez zapisywania klucza w warstwie obrazu Docker lub przechodzenia przez gimnastykę ssh_agent jest:

  1. Jako jeden z poniższych kroków Dockerfileutwórz .sshkatalog, dodając:

    RUN mkdir -p /root/.ssh

  2. Poniżej zaznaczono, że chcesz zamontować katalog ssh jako wolumin:

    VOLUME [ "/root/.ssh" ]

  3. Upewnij się, że Twój kontener ssh_configwie, gdzie znaleźć klucze publiczne, dodając ten wiersz:

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

  4. Pokaż .sshkatalog użytkownika lokalnego w kontenerze w czasie wykonywania:

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

    Lub dockerCompose.ymldodaj to pod kluczem głośności usługi:

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

Twój finał Dockerfilepowinien zawierać coś takiego:

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" ]

1

Próbuję rozwiązać problem w inny sposób: dodając publiczny klucz ssh do obrazu. Ale podczas moich prób odkryłem, że „docker cp” służy do kopiowania z kontenera na host. Punkt 3 w odpowiedzi skrzypienia wydaje się mówić, że możesz użyć dokera cp do wstrzyknięcia plików do kontenera. Zobacz https://docs.docker.com/engine/reference/commandline/cp/

fragment

Skopiuj pliki / foldery z systemu plików kontenera na ścieżkę hosta. Ścieżki są względne w stosunku do katalogu głównego systemu plików.

  Usage: docker cp CONTAINER:PATH HOSTPATH

  Copy files/folders from the PATH to the HOSTPATH

Wygląda na to, że ten adres URL jest teraz uszkodzony.
slm

To jest przestarzałe lub niepoprawne. Może kopiować w dowolnym kierunku, najpóźniej 1.8.2.
Jonathon Reinhart

1

Możesz przekazać autoryzowane klucze do swojego kontenera za pomocą folderu współdzielonego i ustawić uprawnienia za pomocą pliku dokera w następujący sposób:

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

A twoje uruchomienie dokera zawiera coś takiego jak poniższe, aby udostępnić katalog auth na hoście (trzymając klucze autoryzowane) z kontenerem, a następnie otworzyć port ssh, który będzie dostępny przez port 7001 na hoście.

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

Możesz spojrzeć na https://github.com/jpetazzo/nsenter, który wydaje się być innym sposobem na otwarcie powłoki na kontenerze i wykonywanie poleceń w kontenerze.


1

Późno na imprezę, co powiesz na to, co sprawi, że klucze systemu operacyjnego hosta będą dostępne do rootowania wewnątrz kontenera w locie:

docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh user@10.20.30.40"

Nie jestem zwolennikiem używania Dockerfile do instalowania kluczy, ponieważ iteracje twojego kontenera mogą pozostawić klucze prywatne.


0

Możesz używać sekretów do zarządzania wszelkimi wrażliwymi danymi, których potrzebuje kontener w czasie wykonywania, ale nie chcesz przechowywać na obrazie lub w kontroli źródła, takich jak:

  • Nazwy użytkowników i hasła
  • Certyfikaty i klucze TLS
  • Klucze SSH
  • Inne ważne dane, takie jak nazwa bazy danych lub serwera wewnętrznego
  • Ogólne ciągi lub zawartość binarna (rozmiar do 500 kb)

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

Próbowałem wymyślić, jak dodać klucze podpisu do kontenera, które będą używane w czasie wykonywania (nie kompilacji) i natknąłem się na to pytanie. Sekrety dokerów wydają się być rozwiązaniem mojego przypadku użycia, a ponieważ nikt jeszcze o tym nie wspomniał, dodam je.


0

W moim przypadku miałem problem z nodejs i „npm i” ze zdalnego repozytorium. Naprawiłem dodawanie użytkownika „node” do kontenera nodejs i 700 do ~ / .ssh w kontenerze.

Plik Docker:

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

potem zaczęło działać


-1

Najprostszy sposób, załóż konto startera i użyj: ssh-import-id


8
Pytanie dotyczyło kluczy prywatnych. ssh-import-idwygląda na to, że importuje tylko klucze publiczne.
cddr

-1

W działającym kontenerze dokera możesz wydać ssh-keygen za pomocą opcji dokera -i (interaktywnej). Spowoduje to przekazanie monitów kontenera o utworzenie klucza w kontenerze dokera.


1
I co wtedy? Po tym nie możesz nic zrobić, ponieważ nie masz na to pozwolenia.
Jonathon Reinhart

-1

W przypadku kluczy debian / root / autoryzowanych_kluczy:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.