Utilisation des clés SSH dans le conteneur Docker

324

J'ai une application qui exécute diverses choses amusantes avec Git (comme exécuter git clone & git push) et j'essaie de la docker.

Je rencontre un problème, cependant, où je dois pouvoir ajouter une clé SSH au conteneur pour que l'utilisateur du conteneur puisse l'utiliser.

J'ai essayé de le copier /root/.ssh/, de le changer $HOME, de créer un wrapper git ssh, et toujours pas de chance.

Voici le Dockerfile pour référence:

#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 exécute les commandes git comme git pull

intensification
la source
3
Quiconque aborde cette question doit penser à la fin du jeu car il est facile de créer un trou de sécurité et de l'oublier ici si vous ne faites pas attention. Lisez toutes les réponses et choisissez judicieusement.
Josh Habdas

Réponses:

144

C'est un problème plus difficile si vous devez utiliser SSH au moment de la construction. Par exemple, si vous utilisez git clone, ou dans mon cas pipet npmpour télécharger à partir d'un référentiel privé.

La solution que j'ai trouvée est d'ajouter vos clés à l'aide du --build-argdrapeau. Ensuite, vous pouvez utiliser la nouvelle --squashcommande expérimentale (ajoutée 1.13) pour fusionner les couches afin que les clés ne soient plus disponibles après leur suppression. Voici ma solution:

Commande Build

$ 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

Mise à jour: si vous utilisez Docker 1.13 et que vous disposez de fonctionnalités expérimentales, vous pouvez ajouter --squashà la commande build qui fusionnera les couches, supprimant les clés SSH et les masquant docker history.

Daniel van Flymen
la source
13
Ce fil de discussion GitHub indiquerait que cette approche n'est toujours pas sécurisée. Voir ce commentaire pour une autre solution similaire.
eczajk
4
Une autre solution au lieu d'écraser est d'ajouter et de supprimer la clé dans la même commande RUN, et entre l'ajout et la suppression, vous l'utilisez pour ce dont vous avez besoin.
Benjamin Hammer Nørgaard
2
Vous pouvez peut-être supprimer les lignes de création du id_rsa.pubfichier car il n'est pas nécessaire.
LCB
1
Au lieu d'écraser, utilisez des constructions d'images à plusieurs étapes .
Richard Kiefer
Si votre clé est protégée par mot de passe, utilisez-la à la $(openssl rsa -in ~/.ssh/id_rsa)place
BroiSatse
89

Il s'avère que lors de l'utilisation d'Ubuntu, le ssh_config n'est pas correct. Vous devez ajouter

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

à votre Dockerfile afin qu'il reconnaisse votre clé ssh.

intensification
la source
2
Vous devez probablement également définir le nom d'utilisateur correct comme ceciRUN echo " Host example.com" >> /root/.ssh/config RUN echo " User <someusername>" >> /root/.ssh/config
monofone
1
Pourquoi quelqu'un copierait-il la clé privée d'une machine hôte vers un conteneur? La commande est OK, mais je ne vois pas de sens à faire ce qui précède ...
Vladimir Djuricic
12
Ce n'est pas sûr! Voir ma solution ci-dessous pour la dernière version 1.13 de Docker. @ebensing
Daniel van Flymen
1
@VladimirDjuricic Cependant, il y a des choses comme les clés de déploiement.
Zelphir Kaltstahl
en fait, vous devez exécuter ssh-keygen -A pour configurer correctement ssh sur le conteneur minimal ubuntu. Ensuite, vous pouvez ajouter des clés pub / priv et démarrer sshd. J'ai cette entrée dans mon dockerfile: 'RUN ssh-keygen -A' comme l'une des étapes.
piotrektt
84

Remarque : n'utilisez cette approche que pour les images qui sont privées et le seront toujours !

La clé ssh reste stockée dans l'image, même si vous supprimez la clé dans une commande de calque après l'avoir ajoutée (voir les commentaires dans cet article ).

Dans mon cas, c'est ok, c'est donc ce que j'utilise:

# 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
yellowcap
la source
91
Cela gardera votre clé dans l'image, ne le faites pas.
CppLearner
12
@CppLearner vous avez raison, cela stocke la clé dans l'image et cela peut être un problème de sécurité dans certains cas. Merci d'avoir souligné cela. Cependant, il existe de nombreuses situations où cela est parfaitement enregistré. Par exemple, pour les images stockées dans un référentiel privé ou les images qui sont créées directement sur un serveur de production en copiant les clés locales de l'image.
yellowcap
2
De plus, si vous installez vos fournisseurs dans le Dockerfile, rien ne vous empêche de supprimer la clé ssh une fois les fournisseurs installés.
SebScoFr
2
@SebScoFr, apparemment, les clés seront stockées dans l'une des couches, même si vous les supprimez dans une commande ultérieure (voir le lien dans la réponse mise à jour). Ainsi, l'image exposera toujours la clé ssh, et la solution ne doit être utilisée que pour des images privées!
yellowcap le
1
@yellowcap pas si vous - écrasez la construction
Anoyz
57

Si vous utilisez Docker Composer, un choix simple consiste à transférer l'agent SSH comme ça:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
Aistis
la source
23
Juste une note que cela ne fonctionne pas pour les hôtes Mac, que ce soit avec docker-machine (via VirtualBox) ou Docker pour Mac (qui utilise xhyve) car les sockets de domaine Unix ne sont pas mandatés.
Joe Shaw
SSH_AUTH_SOCKest une variable qui contient un chemin vers un agent ssh
Aistis
2
plus de détails sur SSH_AUTH_SOCK blog.joncairns.com/2013/12/understanding-ssh-agent-and-ssh-add
JuanPablo
1
ssh-forwarding est désormais également pris en charge sur les hôtes macOS - au lieu de monter le chemin de $SSH_AUTH_SOCK, vous devez monter ce chemin - /run/host-services/ssh-auth.sock.
Jakub Kukul
48

En développant la réponse de Peter Grainger, j'ai pu utiliser la version multi-étapes disponible depuis Docker 17.05. La page officielle indique:

Avec les FROMgénérations à plusieurs étapes, vous utilisez plusieurs instructions dans votre Dockerfile. Chaque FROMinstruction peut utiliser une base différente et chacune d'elles commence une nouvelle étape de la construction. Vous pouvez copier de manière sélective des artefacts d'une étape à une autre, laissant derrière vous tout ce que vous ne voulez pas dans l'image finale.

Garder cela à l'esprit ici est mon exemple d' Dockerfileinclure trois étapes de construction. Il est destiné à créer une image de production de l'application Web 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"]

.dockerignorerépète le contenu du .gitignorefichier (il empêche les répertoires node_modulesrésultants distdu projet d'être copiés):

.idea
dist
node_modules
*.log

Exemple de commande pour construire une image:

$ 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 votre clé SSH privée n'a pas de phrase secrète, spécifiez simplement un SSH_KEY_PASSPHRASEargument vide .

Voilà comment cela fonctionne:

1). Sur la première étape uniquement package.json, les yarn.lockfichiers et la clé SSH privée sont copiés dans la première image intermédiaire nommée sources. Afin d'éviter d'autres invites de phrase secrète de clé SSH, il est automatiquement ajouté à ssh-agent. Enfin, la yarncommande installe toutes les dépendances requises de NPM et clone les référentiels git privés de Bitbucket sur SSH.

2). La deuxième étape construit et réduit le code source de l'application Web et le place dans le distrépertoire de la prochaine image intermédiaire nommée production. Notez que le code source de installé node_modulesest copié à partir de l'image nommée sourcesproduite sur la première étape par cette ligne:

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

Il pourrait également s'agir de la ligne suivante:

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

Nous n'avons ici que le node_modulesrépertoire de la première image intermédiaire, non SSH_KEYet des SSH_KEY_PASSPHRASEarguments. Tout le reste requis pour la construction est copié à partir de notre répertoire de projet.

3). À la troisième étape, nous réduisons la taille de l'image finale qui sera étiquetée ezze/geoport:0.6.0en incluant uniquement le distrépertoire de la deuxième image intermédiaire nommée productionet en installant Node Express pour démarrer un serveur Web.

La liste des images donne une sortie comme celle-ci:

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

où les images non étiquetées correspondent aux première et deuxième étapes de construction intermédiaires.

Si vous courez

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

vous ne verrez aucune mention de SSH_KEYet SSH_KEY_PASSPHRASEdans l'image finale.

ezze
la source
Ancien poste, mais je tiens à souligner que c'est de loin la meilleure façon de le faire avant le 18.09. Le squash est inutile et sujet aux risques. Avec plusieurs étapes, vous savez que vous n'apportez que les artefacts que vous souhaitez. Considérez le squash comme une option de désactivation des fichiers que vous ne voulez pas et plusieurs étapes comme une option d'activation. Cette réponse doit être plus élevée. La cuisson de vos clés ssh dans l'image est une pratique terrible.
mritalien
@ezze Merci beaucoup pour ce message très utile :) L'agent SSH me rend fou, j'ai fait quelque chose de similaire à ce que vous avez fait: je vois correctement dans les journaux de construction de docker Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)mais quand je vérifie dans un autre RUN ou même dans le même RUN commande en faisant un ssh-add -lil me dit que "L'agent n'a pas d'identité". Commencer à arracher mes cheveux, des pensées?
Alex
40

Afin de vous injecter la clé ssh, au sein d'un container, vous avez plusieurs solutions:

  1. En utilisant un Dockerfile avec l' ADDinstruction, vous pouvez l'injecter pendant votre processus de construction

  2. Faire simplement quelque chose comme cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  3. Utilisation de la docker cpcommande qui vous permet d'injecter des fichiers pendant l'exécution d'un conteneur.

creack
la source
2
Donc, pour l'instant, j'ai essayé de le copier dans /root/.ssh/id_rsa mais je reçois toujours des erreurs "Échec de la vérification de la clé de l'hôte. n'utilise pas la clé pour une raison quelconque. Je pense donc qu'il y a autre chose que je dois faire pour dire au système de l'utiliser comme clé ssh? Je ne sais pas exactement comment déboguer celui-ci. (et je sais que cette clé fonctionne car elle s'exécute sans problème de l'hôte)
ebensing
pouvez-vous vous assurer que / etc / ssh / ssh_config cible le fichier de clé correct?
creack
1
Existe-t-il un bon moyen d'inspecter les fichiers du conteneur Docker? Ou devrais-je simplement essayer de copier dans une configuration valide?
ebensing
3
J'ai juste essayé avec l'image 'base', en faisant apt-get install openssh-serveret en mettant ma clé dans /root/.ssh/id_rsa et ça a bien fonctionné. Quelle image utilisez-vous?
creack
si vous avez besoin d'inspecter le fichier d'un conteneur, la meilleure façon serait de valider et d'exécuter l'image résultante avec 'cat'.
creack
15

Une solution multiplateforme consiste à utiliser un montage de liaison pour partager le .sshdossier de l'hôte dans le conteneur:

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

Semblable à l'agent qui transfère cette approche, les clés publiques seront accessibles au conteneur. Un autre avantage est qu'il fonctionne également avec un utilisateur non root et vous permettra de vous connecter à GitHub. Une mise en garde à prendre en compte, cependant, est que tout le contenu (y compris les clés privées) du .sshdossier sera partagé, de sorte que cette approche n'est souhaitable que pour le développement et uniquement pour les images de conteneurs de confiance.

Mohammad Azim
la source
1
cela pourrait fonctionner, mais pas docker buildseulement pendantdocker run
Alexander Mills
3
C'est exactement le point. Vous ne voulez pas mettre vos clés ssh dans un fichier docker.
Mohammad Azim
2
Étant donné que le transfert d'agent SSH ne fonctionne pas en dehors de Linux, cela constitue une bonne solution pour être opérationnel dans un environnement de développement sans trop de tracas.
Josh Habdas
J'exécute Docker à l'aide docker-compose upde mon Windows 10 local. Comment dois-je utiliser votre solution dans ce scénario?
llaaalu
Essentiellement, vous demandez comment mapper le volume dans Docker Composer. Ci-dessus, il y a une réponse à cette question. Spécifiquement pour Windows, cela pourrait aider stackoverflow.com/questions/41334021/…
Mohammad Azim
14

Les conteneurs Docker doivent être considérés comme des «services» qui leur sont propres. Pour séparer les préoccupations, vous devez séparer les fonctionnalités:

1) Les données doivent être dans un conteneur de données: utilisez un volume lié pour cloner le référentiel dans. Ce conteneur de données peut ensuite être lié au service qui en a besoin.

2) Utilisez un conteneur pour exécuter la tâche de clonage git, (c'est-à-dire qu'il ne s'agit que du clonage) reliant le conteneur de données à celui-ci lorsque vous l'exécutez.

3) Même chose pour la clé ssh: mettez-le comme un volume (comme suggéré ci-dessus) et liez-le au service de clonage git lorsque vous en avez besoin

De cette façon, la tâche de clonage et la clé sont éphémères et ne sont actives qu'en cas de besoin.

Maintenant, si votre application elle-même est une interface git, vous voudrez peut-être envisager les API REST github ou bitbucket directement pour faire votre travail: c'est pour cela qu'elles ont été conçues.

MrE
la source
13

Cette ligne est un problème:

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

Lorsque vous spécifiez les fichiers que vous souhaitez copier dans l'image, vous ne pouvez utiliser que des chemins relatifs - par rapport au répertoire où se trouve votre Dockerfile. Vous devriez donc plutôt utiliser:

ADD id_rsa /root/.ssh/id_rsa

Et placez le fichier id_rsa dans le même répertoire que votre Dockerfile.

Consultez ceci pour plus de détails: http://docs.docker.io/reference/builder/#add

Dan Keder
la source
4
C'est également un problème de sécurité car il met une clé privée dans une image qui peut être facilement oubliée.
Mike D
docker cple met simplement dans le conteneur et non l'image, non?
Alexander Mills
13

Nous avons eu un problème similaire lors de l'installation de npm au moment de la construction du docker.

Inspiré de la solution de Daniel van Flymen et la combinant avec la réécriture d'URL git , nous avons trouvé une méthode un peu plus simple pour authentifier l'installation de npm à partir de dépôts github privés - nous avons utilisé des jetons oauth2 au lieu des clés.

Dans notre cas, les dépendances npm ont été spécifiées comme "git + https://github.com/ ..."

Pour l'authentification dans le conteneur, les URL doivent être réécrites pour être adaptées à l'authentification ssh (ssh: //[email protected]/) ou à l'authentification par jeton (https: // $ {GITHUB_TOKEN} @ github.com /)

Commande Build:

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

Malheureusement, je suis sur Docker 1.9, donc l'option --squash n'est pas encore là, il faut éventuellement l'ajouter

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
Markko Paas
la source
11

Transférez le socket d'authentification ssh vers le conteneur:

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

Votre script pourra effectuer un git clone.

Extra: Si vous souhaitez que les fichiers clonés appartiennent à un utilisateur spécifique, vous devez utiliser chowncar l'utilisation d'un autre utilisateur que root dans le conteneur gitéchouera.

Vous pouvez faire cette publication dans l'environnement du conteneur quelques variables supplémentaires:

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

Après avoir cloné, vous devez exécuter chown $OWNER_USER:$OWNER_GROUP -R <source_folder>pour définir la propriété appropriée avant de quitter le conteneur afin que les fichiers soient accessibles par un utilisateur non root en dehors du conteneur.

edupo
la source
1
Dans les versions Docker plus récentes, vous pouvez transmettre -u root:$(id -u $USER)au moins les fichiers appartenant au même groupe principal que votre utilisateur, ce qui devrait les rendre au moins lisibles à moins sudoque quelque chose ne les crée avec des 0600autorisations.
dragon788
@ dragon788 Je pense que vous avez une faute de frappe: -u root:$(id -u $USER)devrait l'être -g.
edupo
Bon appel! Je ne semble pas être en mesure de le réparer depuis un mobile, j'essaierai bientôt sur le bureau.
dragon788
J'ai /tmp/ssh_auth.sock: No such file or directorymaintenant c'est /tmp/ssh-vid8Zzi8UILE/agent.46016sur ma machine hôte
vladkras
@vladkras, l'erreur est assez générique. Cela peut être dû à des autorisations sur l' /tmpintérieur de votre conteneur. Ou une faute de frappe sur la commande docker run. Assurez-vous que l'instruction de liaison est correcte -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock: l'ordre est important et le point-virgule est également important. Veuillez consulter la documentation de Docker pour obtenir de l'aide.
edupo
10

Comme eczajk l'a déjà fait remarquer dans la réponse de Daniel van Flymen, il ne semble pas sûr de retirer les clés et de les utiliser --squash, car elles seront toujours visibles dans l'historique ( docker history --no-trunc).

Au lieu de cela, avec Docker 18.09, vous pouvez désormais utiliser la fonction "build secrets". Dans mon cas, j'ai cloné un dépôt git privé en utilisant la clé SSH de mon hôte avec les éléments suivants dans mon Dockerfile:

# syntax=docker/dockerfile:experimental

[...]

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

[...]

Pour pouvoir l'utiliser, vous devez activer le nouveau backend BuildKit avant de lancer docker build:

export DOCKER_BUILDKIT=1

Et vous devez ajouter le --ssh defaultparamètre à docker build.

Plus d'informations à ce sujet ici: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

frsc
la source
1
Meilleure solution à mon humble avis. J'ai dû faire deux autres choses pour le faire fonctionner: 1) ajouter ma clé privée à ssh-agent avec ssh-add ~/.ssh/id_rsaet 2) ajouter l'hôte git à known_hosts, c'est-à-dire pour bitbucket:RUN ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
Moritz Ringler
Je n'ai pas du tout réussi à faire fonctionner cela. Je reçois toujours des erreurs d'autorisations: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access and the repository exists.cela malgré le passage du --ssh defaultdrapeau dans ma génération de docker et l'utilisation --mount=type=sshde la commande d'exécution où je git clone. Je suis en mesure de cloner le même dépôt sans problème sur la machine de génération. Il échoue simplement dans le conteneur de construction de docker. Je soupçonne que la version mac de Docker ne fait pas passer le client ssh.
PMende
@PMende avez-vous pu comprendre ce problème que vous avez mentionné, car je suis également confronté au même problème.
Sadan A.
@SadanArshad Il s'avère que cette fonctionnalité n'est actuellement prise en charge que si vous exécutez Docker à partir d'une machine Linux. Cela ne fonctionne pas si vous exécutez vos commandes Docker à partir d'un Mac (et probablement de Windows également, bien que je ne puisse pas confirmer).
PMende
Dommage que cela ne fonctionne pas avec docker-compose ... github.com/docker/compose/issues/6440
Alexis Wilke
9

Ce problème est vraiment ennuyeux. Comme vous ne pouvez pas ajouter / copier de fichier en dehors du contexte dockerfile, ce qui signifie qu'il est impossible de simplement lier ~ / .ssh / id_rsa dans /root/.ssh/id_rsa de l'image, et quand vous avez définitivement besoin d'une clé pour faire quelque chose de sshed comme git clone à partir d'un lien de dépôt privé ..., lors de la construction de votre image docker.

Quoi qu'il en soit, j'ai trouvé une solution de contournement, pas si convaincante, mais j'ai travaillé pour moi.

  1. dans votre dockerfile:

    • ajoutez ce fichier sous /root/.ssh/id_rsa
    • faites ce que vous voulez, comme git clone, composer ...
    • rm /root/.ssh/id_rsa à la fin
  2. un script à faire en une seule séance:

    • cp votre clé vers le dossier contenant dockerfile
    • construction de docker
    • rm la clé copiée
  3. chaque fois que vous devez exécuter un conteneur à partir de cette image avec des exigences ssh, ajoutez simplement -v pour la commande run, comme:

    docker run -v ~ / .ssh / id_rsa: /root/.ssh/id_rsa --nom de commande d'image de conteneur

Cette solution n'entraîne aucune clé privée à la fois dans la source de votre projet et dans l'image docker intégrée, donc plus de problème de sécurité à craindre.

ImLeo
la source
1
"Puisque vous ne pouvez pas ajouter / copier de fichier en dehors du contexte du fichier docker", l' avez-vous vu docker cp? Il est utilisé pour «copier des fichiers / dossiers entre un conteneur et votre hôte».
Jonathon Reinhart
@JonathonReinhart, merci de l'avoir signalé. Oui, docker cppourrait faire l'affaire. Cependant, dans cette situation même, j'avais besoin de ssh_key pendant la construction de l'image, et il n'y a pas de conteneur à ce moment ... mettra à jour mon expression peu claire, merci quand même.
ImLeo
9

J'ai rencontré le même problème aujourd'hui et une version légèrement modifiée avec les messages précédents, j'ai trouvé cette approche plus utile pour moi

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

(Notez que le drapeau en lecture seule pour que le conteneur ne gâche pas ma clé ssh dans tous les cas.)

À l'intérieur du conteneur, je peux maintenant exécuter:

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

Je n'ai donc pas cette Bad owner or permissions on /root/.ssh/..erreur qui a été notée par @kross

tojo
la source
Je vous remercie! Ce fut la clé pour le faire fonctionner pour moi: avoir le ssh-agent et ssh-add en une seule commande comme: ssh-agent bash -c "ssh-add...". Je peux ensuite passer ce droit dans Docker Run. Tous les exemples précédents que j'ai trouvés utilisés eval ssh-agent, suivis de ssh-add et je n'ai pas pu trouver un moyen de passer cela evalvia la commande docker run.
ryanman
6

Vous pouvez également lier votre répertoire .ssh entre l'hôte et le conteneur, je ne sais pas si cette méthode a des implications en termes de sécurité mais c'est peut-être la méthode la plus simple. Quelque chose comme ça devrait fonctionner:

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

N'oubliez pas que docker fonctionne avec sudo (sauf si vous ne le faites pas), si tel est le cas, vous utiliserez les clés ssh racine.

Luis Elizondo
la source
L'utilisation de cette méthode fonctionne avec docker 0.11 mais si vous utilisez fig, cela générera une erreur de panique. Je ne sais pas pourquoi
Luis Elizondo
3
Ce serait une méthode préférée, l'astuce serait d'utiliser les clés de mon utilisateur hôte non privilégié comme racine du conteneur. Comme vous le mentionnez, essayez de ne pas le faire lorsque l'utilisateur root hôte cède Bad owner or permissions on /root/.ssh/config.
kross
cela ne peut être utilisé que pendant docker run, mais pas pendant docker build.
ccpizza
3
@ccpizza, je considère cela comme un avantage. Beaucoup de ces réponses laissent des clés privées stockées dans une image; la clé reste stockée même après avoir supprimé la clé dans une commande de calque suivante. En introduisant les clés privées uniquement lors de l'exécution (pas de génération), elles ne peuvent exister que dans le conteneur (pas dans l'image).
Cowlinator
6

À partir de docker API 1.39+(Vérifier la version de l'API avec docker version), la version --sshDocker permet l' option avec un socket d'agent ou des clés pour permettre au moteur Docker de transférer les connexions de l'agent SSH.

Commande Build

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

Dockerfile

# 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 [email protected]:myorg/myproject.git myproject

Plus d'informations:

Edison Arango
la source
1
L'expansion tilde n'a pas fonctionné pour moi; Je suis arrivé: could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory. Utilisez le chemin complet s'il ne fonctionne pas.
slhck
3

Si vous ne vous souciez pas de la sécurité de vos clés SSH, il existe de nombreuses bonnes réponses ici. Si vous le faites, la meilleure réponse que j'ai trouvée provient d'un lien dans un commentaire ci-dessus vers ce commentaire GitHub par diegocsandrim . Pour que les autres soient plus susceptibles de le voir, et juste au cas où le dépôt disparaîtrait, voici une version éditée de cette réponse:

La plupart des solutions finissent ici par laisser la clé privée dans l'image. C'est mauvais, car toute personne ayant accès à l'image a accès à votre clé privée. Comme nous ne savons pas assez sur le comportement desquash , cela peut toujours être le cas même si vous supprimez la clé et écrasez ce calque.

Nous générons une URL de pré-signature pour accéder à la clé avec aws s3 cli, et limitons l'accès pendant environ 5 minutes, nous enregistrons cette URL de pré-signature dans un fichier dans le répertoire repo, puis dans dockerfile nous l'ajoutons à l'image.

Dans dockerfile, nous avons une commande RUN qui effectue toutes ces étapes: utilisez l'URL pré-chant pour obtenir la clé ssh, exécutez npm install et supprimez la clé ssh.

En faisant cela dans une seule commande, la clé ssh ne serait stockée dans aucune couche, mais l'URL de pré-signature sera stockée, et ce n'est pas un problème car l'URL ne sera pas valide après 5 minutes.

Le script de construction ressemble à ceci:

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

Dockerfile ressemble à ceci:

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"]
Sam H.
la source
1
Le problème avec cette solution est que, comme pre_sign_url changera à chaque fois, l'installation de npm ne peut pas être mise en cache même s'il n'y a pas de modification du fichier packages.json. Il est préférable d'obtenir la clé dans le build.sh et de la définir comme un argument de construction afin qu'elle ne change pas à chaque fois
York Yang
3

Un aperçu concis des défis de SSH à l'intérieur des conteneurs Docker est détaillé ici . Pour vous connecter à des télécommandes de confiance à l'intérieur d'un conteneur sans divulguer de secrets, il existe plusieurs façons:

Au-delà de cela, il est également possible d'utiliser un magasin de clés fonctionnant dans un conteneur Docker séparé accessible lors de l'exécution lors de l'utilisation de Compose. L'inconvénient ici est une complexité supplémentaire due à la machinerie requise pour créer et gérer un magasin de clés tel que Vault by HashiCorp .

Pour une utilisation de la clé SSH dans un conteneur Docker autonome, consultez les méthodes liées ci-dessus et considérez les inconvénients de chacune en fonction de vos besoins spécifiques. Si, cependant, vous exécutez à l'intérieur de Compose et que vous souhaitez partager une clé d'une application au moment de l'exécution (reflétant les aspects pratiques de l'OP), essayez ceci:

  • Créez un docker-compose.envfichier et ajoutez-le à votre .gitignorefichier.
  • Mettez à jour votre docker-compose.ymlet ajoutez env_filepour le service nécessitant la clé.
  • Accédez à la clé publique à partir de l'environnement lors de l'exécution de l'application, par exemple process.node.DEPLOYER_RSA_PUBKEYdans le cas d'une application Node.js.

L'approche ci-dessus est idéale pour le développement et les tests et, bien qu'elle puisse satisfaire les exigences de production, en production, il vaut mieux utiliser l'une des autres méthodes identifiées ci-dessus.

Ressources supplémentaires:

Josh Habdas
la source
3

Vous pouvez utiliser la construction en plusieurs étapes pour créer des conteneurs Voici l'approche que vous pouvez adopter: -

Étape 1 Construire une image avec 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

Étape 2: construisez votre conteneur

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

ajoutez l'attribut env dans votre fichier de composition:

   environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

puis passez les arguments du script de construction comme ceci:

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

Et retirez le conteneur intermédiaire pour plus de sécurité. Cela vous aidera à applaudir.

Devesh
la source
2

Un moyen simple et sécurisé pour y parvenir sans enregistrer votre clé dans une couche d'image Docker ou passer par la gymnastique ssh_agent est:

  1. Dans l'une des étapes de votre Dockerfile, créez un .sshrépertoire en ajoutant:

    RUN mkdir -p /root/.ssh

  2. En dessous, cela indique que vous souhaitez monter le répertoire ssh en tant que volume:

    VOLUME [ "/root/.ssh" ]

  3. Assurez-vous que votre conteneur ssh_configsait où trouver les clés publiques en ajoutant cette ligne:

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

  4. Exposez le .sshrépertoire de votre utilisateur local au conteneur lors de l'exécution:

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

    Ou dans votre dockerCompose.ymlajouter ceci sous la clé de volume du service:

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

Votre finale Dockerfiledevrait contenir quelque chose comme:

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" ]
Buchanora
la source
1

J'essaie de résoudre le problème dans l'autre sens: en ajoutant une clé publique ssh à une image. Mais dans mes essais, j'ai découvert que "docker cp" est destiné à la copie D'un conteneur vers un hôte. Le point 3 de la réponse de creak semble dire que vous pouvez utiliser docker cp pour injecter des fichiers dans un conteneur. Voir https://docs.docker.com/engine/reference/commandline/cp/

extrait

Copiez les fichiers / dossiers du système de fichiers d'un conteneur vers le chemin de l'hôte. Les chemins sont relatifs à la racine du système de fichiers.

  Usage: docker cp CONTAINER:PATH HOSTPATH

  Copy files/folders from the PATH to the HOSTPATH
EricGreg
la source
Cette URL semble être rompue maintenant.
slm
Ceci est obsolète ou incorrect. Il peut copier l'une ou l'autre direction, au plus tard le 1.8.2.
Jonathon Reinhart
1

Vous pouvez passer les clés autorisées dans votre conteneur à l'aide d'un dossier partagé et définir des autorisations à l'aide d'un fichier docker comme celui-ci:

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

Et votre docker run contient quelque chose comme ce qui suit pour partager un répertoire d'authentification sur l'hôte (contenant les authorised_keys) avec le conteneur, puis ouvrez le port ssh qui sera accessible via le port 7001 sur l'hôte.

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

Vous voudrez peut-être regarder https://github.com/jpetazzo/nsenter qui semble être une autre façon d'ouvrir un shell sur un conteneur et d'exécuter des commandes dans un conteneur.

Andrew Pate
la source
1

Tard dans la soirée, certes, que diriez-vous de cela qui rendra vos clés de système d'exploitation hôte disponibles pour rooter à l'intérieur du conteneur, à la volée:

docker run -v ~/.ssh:/mnt -it my_image /bin/bash -c "ln -s /mnt /root/.ssh; ssh [email protected]"

Je ne suis pas en faveur de l'utilisation de Dockerfile pour installer des clés car les itérations de votre conteneur peuvent laisser des clés privées derrière.

Jepper
la source
0

Vous pouvez utiliser des secrets pour gérer toutes les données sensibles dont un conteneur a besoin au moment de l'exécution mais vous ne voulez pas les stocker dans l'image ou dans le contrôle de code source, telles que:

  • Noms d'utilisateur et mots de passe
  • Certificats et clés TLS
  • Clés SSH
  • Autres données importantes telles que le nom d'une base de données ou d'un serveur interne
  • Chaînes génériques ou contenu binaire (jusqu'à 500 Ko)

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

J'essayais de comprendre comment ajouter des clés de signature à un conteneur à utiliser pendant l'exécution (pas de génération) et suis tombé sur cette question. Les secrets de Docker semblent être la solution pour mon cas d'utilisation, et puisque personne ne l'a encore mentionné, je vais l'ajouter.

Travis Britz
la source
0

Dans mon cas, j'ai eu un problème avec nodejs et 'npm i' à partir d'un référentiel distant. J'ai corrigé l'ajout de l'utilisateur 'node' au conteneur nodejs et 700 à ~ / .ssh dans le conteneur.

Dockerfile:

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

après cela, il a commencé à travailler

Дмитрий Урбанович
la source
-1

Manière la plus simple, obtenez un compte de tableau de bord et utilisez: ssh-import-id

Sam Saffron
la source
8
La question portait sur les clés privées. ssh-import-idil semble qu'il importe uniquement les clés publiques.
cddr
-1

Dans un conteneur Docker en cours d'exécution, vous pouvez émettre ssh-keygen avec l'option docker -i (interactive). Cela transmettra les invites du conteneur pour créer la clé à l'intérieur du conteneur Docker.

Jerome Anthony
la source
1
Et maintenant quoi? Vous ne pouvez rien faire après cela, car vous n'êtes pas autorisé à le faire.
Jonathon Reinhart
-1

Pour debian / root / authorized_keys:

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
StanislavKo
la source