Usando chaves SSH dentro do contêiner de janela de encaixe


324

Eu tenho um aplicativo que executa várias coisas divertidas com o Git (como executar o git clone e git push) e estou tentando encaixá-lo.

Estou enfrentando um problema, no qual preciso adicionar uma chave SSH ao contêiner para o usuário 'contêiner' usar.

Tentei copiá-lo /root/.ssh/, mudar $HOME, criar um invólucro git ssh, e ainda sem sorte.

Aqui está o Dockerfile para referência:

#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 executa os comandos git como git pull


3
Qualquer pessoa que se aproxime dessa pergunta deve pensar no final do jogo, pois é fácil criar uma falha de segurança e esquecê-la aqui, se você não for cuidadoso. Leia todas as respostas e escolha sabiamente.
Josh Habdas 17/09/19

Respostas:


144

É um problema mais difícil se você precisar usar o SSH no momento da construção. Por exemplo, se você estiver usando git clone, ou no meu caso, pipe npmbaixar de um repositório particular.

A solução que encontrei é adicionar suas chaves usando a --build-argbandeira. Em seguida, você pode usar o novo --squashcomando experimental (adicionado 1.13) para mesclar as camadas para que as chaves não fiquem mais disponíveis após a remoção. Aqui está a minha solução:

Comando 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

Atualização: se você estiver usando o Docker 1.13 e tiver recursos experimentais, poderá anexar --squashao comando build que mesclará as camadas, removendo as chaves SSH e ocultando-as docker history.


13
Esse encadeamento de problemas do GitHub indicaria que essa abordagem ainda não é segura. Veja este comentário para outra solução semelhante.
eczajk

4
Outra solução, em vez de esmagar, é adicionar e remover a chave no mesmo comando RUN e, entre adicionar e remover, você a usa para o que precisa.
Benjamin Hammer Nørgaard

2
Talvez você possa remover as linhas para criar o id_rsa.pubarquivo, pois não é necessário.
LCB 9/11


Se a sua chave é protegido por senha, utilize $(openssl rsa -in ~/.ssh/id_rsa)vez
BroiSatse

89

Acontece que ao usar o Ubuntu, o ssh_config não está correto. Você precisa adicionar

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

ao seu Dockerfile para que ele reconheça sua chave ssh.


2
Você provavelmente também precisa definir o nome de usuário correto como esteRUN echo " Host example.com" >> /root/.ssh/config RUN echo " User <someusername>" >> /root/.ssh/config
monofone

1
Por que alguém copiaria a chave privada de uma máquina host para um contêiner. Comando é OK, mas não vejo sentido em fazer do acima mencionado ...
Vladimir Djuricic

12
Isso não é seguro! Veja minha solução abaixo para a versão 1.13 mais recente do Docker. @ebensing
Daniel van Flymen

1
@VladimirDjuricic Existem coisas como chaves de implantação.
Zelphir Kaltstahl

na verdade, você precisa executar o ssh-keygen -A para configurar o ssh corretamente no contêiner mínimo do ubuntu. Em seguida, você pode adicionar chaves pub / priv e iniciar o sshd. Eu tenho esta entrada no meu dockerfile: 'RUN ssh-keygen -A' como uma das etapas.
Piotrektt 19/07/19

84

Nota : use esta abordagem apenas para imagens privadas e sempre serão !

A chave ssh permanece armazenada na imagem, mesmo se você remover a chave em um comando de camada depois de adicioná-la (consulte os comentários nesta postagem ).

No meu caso, está tudo bem, então é isso que estou usando:

# 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
Isso manterá sua chave na imagem, não faça isso.
precisa saber é o seguinte

12
@CppLearner, você está certo, isso armazena a chave na imagem e isso pode ser um problema de segurança em alguns casos. Obrigado por destacar isso. No entanto, existem muitas situações em que isso é perfeitamente salvo. Por exemplo, para imagens armazenadas em um repositório privado ou imagens criadas diretamente em um servidor de produção, copiando as chaves locais para a imagem.
yellowcap

2
Além disso, se você instalar seus fornecedores no Dockerfile, nada o impedirá de remover a chave ssh após a instalação dos fornecedores.
SebScoFr

2
@SebScoFr, aparentemente as chaves serão armazenadas em uma das camadas, mesmo se você as remover em um comando posterior (consulte o link na resposta atualizada). Portanto, a imagem sempre expõe a chave ssh, e a solução deve ser usada apenas para imagens privadas!
yellowcap

1
@yellowcap not if you --squash the build #
187 Anoyz

57

Se você estiver usando o docker composer, uma escolha fácil é encaminhar o agente SSH assim:

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

23
Apenas observe que isso não funciona para hosts Mac, seja usando docker-machine (via VirtualBox) ou Docker for Mac (que usa xhyve), porque os soquetes de domínio unix não estão em proxy.
21816 Joe Shaw

SSH_AUTH_SOCKé uma variável, que contém um caminho para um ssh-agente
Aistis


1
Agora, o ssh-forwarding também é suportado nos hosts do macOS - em vez de montar o caminho $SSH_AUTH_SOCK, você deve montá-lo - /run/host-services/ssh-auth.sock.
Jakub Kukul 22/03

47

Expandindo a resposta de Peter Grainger, eu pude usar a compilação de vários estágios disponível desde o Docker 17.05. Página oficial afirma:

Com compilações de vários estágios, você usa várias FROMinstruções no Dockerfile. Cada FROMinstrução pode usar uma base diferente e cada uma delas inicia uma nova etapa da construção. Você pode copiar artefatos seletivamente de um estágio para outro, deixando para trás tudo o que não deseja na imagem final.

Mantendo isso em mente aqui é o meu exemplo de Dockerfileinclusão de três estágios de construção. Ele foi criado para criar uma imagem de produção do aplicativo 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"]

.dockerignorerepete o conteúdo do .gitignorearquivo (impede node_modulesque os distdiretórios resultantes do projeto sejam copiados):

.idea
dist
node_modules
*.log

Exemplo de comando para criar uma imagem:

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

Se sua chave SSH privada não tiver uma senha, basta especificar o SSH_KEY_PASSPHRASEargumento vazio .

É assim que funciona:

1) Somente no primeiro estágio package.json, os yarn.lockarquivos e a chave SSH privada são copiados para a primeira imagem intermediária denominada sources. Para evitar mais solicitações de senha de chave SSH, ela é automaticamente adicionada ssh-agent. Finalmente, o yarncomando instala todas as dependências necessárias do NPM e clona os repositórios git privados do Bitbucket sobre SSH.

2) O segundo estágio cria e reduz o código fonte do aplicativo Web e o coloca no distdiretório da próxima imagem intermediária denominada production. Observe que o código fonte do instalado node_modulesé copiado da imagem nomeada sourcesproduzida no primeiro estágio por esta linha:

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

Provavelmente também poderia ser a seguinte linha:

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

Temos apenas o node_modulesdiretório da primeira imagem intermediária aqui, não SSH_KEYe SSH_KEY_PASSPHRASEmais argumentos. Todo o restante necessário para a construção é copiado do diretório do projeto.

3) No terceiro estágio, reduzimos o tamanho da imagem final que será marcada, ezze/geoport:0.6.0incluindo apenas o distdiretório da segunda imagem intermediária denominada productione instalando o Node Express para iniciar um servidor da web.

A listagem de imagens fornece uma saída como esta:

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

onde imagens sem etiqueta correspondem aos primeiro e segundo estágios de construção intermediários.

Se você correr

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

você não verá nenhuma menção de SSH_KEYe SSH_KEY_PASSPHRASEna imagem final.


Post antigo, mas quero enfatizar que essa é de longe a melhor maneira de fazê-lo antes das 18.09. Squash é desnecessário e propenso a riscos. Com o estágio múltiplo, você sabe que está apenas trazendo os artefatos que deseja. Pense no squash como opt-out dos arquivos que você não deseja e em vários estágios como opt-in. Essa resposta precisa ser maior. Assar as teclas ssh na imagem é uma prática terrível.
Mritalian

@ezze Muito obrigado por este post muito útil :) O agente SSH está me deixando louco, fiz algo parecido com o que você fez: eu vejo corretamente nos logs de construção do docker, Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)mas quando eu verifico outro RUN ou mesmo no mesmo RUN comando ao fazer um ssh-add -l, diz-me que "O agente não tem identidades". Começando a arrancar meus cabelos, algum pensamento?
Alex

40

Para injetar sua chave ssh, em um contêiner, você tem várias soluções:

  1. Usando um Dockerfile com a ADDinstrução, você pode injetá-lo durante o processo de compilação

  2. Simplesmente fazendo algo como cat id_rsa | docker run -i <image> sh -c 'cat > /root/.ssh/id_rsa'

  3. Usando o docker cpcomando que permite injetar arquivos enquanto um contêiner está em execução.


2
Então, a partir de agora, tentei copiá-lo para /root/.ssh/id_rsa, mas ainda recebi "Falha na verificação da chave do host. Fatal: a extremidade remota desligou inesperadamente" erros do Git, o que tenho certeza que significa não está usando a chave por qualquer motivo. Então, estou pensando que há outra coisa que preciso fazer para dizer ao sistema para usá-lo como chave ssh? Não sei exatamente como depurar este. (e eu sei que isso funciona chave porque ele é executado sem problema a partir do host)
ebensing

você pode garantir que o / etc / ssh / ssh_config direcione o arquivo de chave correto?
creack 8/08/13

1
Existe uma boa maneira de inspecionar os arquivos do contêiner de docker? Ou devo apenas tentar copiar em uma configuração válida?
ebensing

3
Eu apenas tentei com a imagem 'base', fazendo apt-get install openssh-servere colocando minha chave em /root/.ssh/id_rsa e funcionou bem. Qual imagem você está usando?
creack

se você precisar inspecionar o arquivo de um contêiner, a melhor maneira seria confirmar e executar a imagem resultante com 'cat'.
creack

15

Uma solução de plataforma cruzada é usar uma montagem de ligação para compartilhar a .sshpasta do host no contêiner:

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

Semelhante ao encaminhamento do agente, essa abordagem tornará as chaves públicas acessíveis ao contêiner. Uma vantagem adicional é que ele também funciona com um usuário não root e o conectará ao GitHub. Uma ressalva a considerar, no entanto, é que todo o conteúdo (incluindo chaves privadas) da .sshpasta será compartilhado, portanto essa abordagem é apenas desejável para o desenvolvimento e apenas para imagens de contêineres confiáveis.


1
isso pode funcionar, mas não docker buildapenas durantedocker run
Alexander Mills

3
Esse é exatamente o ponto. Você não deseja colocar suas chaves ssh dentro de um arquivo docker.
Mohammad Azim

2
Dado que o encaminhamento de agente SSH não funciona fora do Linux, isso é uma boa solução para a instalação e a execução em um ambiente de desenvolvimento sem muito barulho.
Josh Habdas 26/09/19

Estou executando o Docker docker-compose upno Windows 10. local. Como devo usar sua solução nesse cenário?
llaaalu 30/09/19

Essencialmente, você está perguntando como mapear o volume na composição do Docker. Acima, há uma resposta para responder a isso. Especificamente para o Windows, isso pode ajudar a stackoverflow.com/questions/41334021/…
Mohammad Azim

14

Os contêineres do Docker devem ser vistos como 'serviços' próprios. Para separar preocupações, você deve separar as funcionalidades:

1) Os dados devem estar em um contêiner de dados: use um volume vinculado para clonar o repositório. Esse contêiner de dados pode ser vinculado ao serviço que precisa dele.

2) Use um contêiner para executar a tarefa de clonagem git (ou seja, é apenas o trabalho que está clonando) vinculando o contêiner de dados a ele quando você o executar.

3) O mesmo para a chave ssh: coloque um volume (como sugerido acima) e vincule-o ao serviço de clone do git quando você precisar

Dessa forma, a tarefa de clonagem e a chave são efêmeras e ativas apenas quando necessário.

Agora, se o aplicativo em si for uma interface git, convém considerar as APIs REST do github ou bitbucket diretamente para fazer seu trabalho: é para isso que elas foram projetadas.


13

Esta linha é um problema:

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

Ao especificar os arquivos que você deseja copiar para a imagem, você só pode usar caminhos relativos - em relação ao diretório em que está o Dockerfile. Então você deve usar:

ADD id_rsa /root/.ssh/id_rsa

E coloque o arquivo id_rsa no mesmo diretório em que está o seu Dockerfile.

Verifique isso para obter mais detalhes: http://docs.docker.io/reference/builder/#add


4
Isso também é um problema de segurança porque coloca uma chave privada em uma imagem que pode ser facilmente esquecida.
Mike D

docker cpapenas coloca no container e não na imagem, certo?
Alexander Mills

13

Tivemos um problema semelhante ao fazer a instalação do npm no tempo de construção do docker.

Inspirados na solução de Daniel van Flymen e combinando-a com a reescrita de git url , descobrimos um método um pouco mais simples para autenticar a instalação do npm a partir de repositórios particulares do github - usamos tokens oauth2 em vez das chaves.

No nosso caso, as dependências do npm foram especificadas como "git + https://github.com/ ..."

Para autenticação no contêiner, os URLs precisam ser reescritos para serem adequados para autenticação ssh (ssh: //git@github.com/) ou autenticação de token (https: // $ {GITHUB_TOKEN} @ github.com /)

Comando Build:

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

Infelizmente, estou no docker 1.9, então a opção --squash ainda não está lá, eventualmente ela precisa ser adicionada

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

11

Encaminhe o soquete de autenticação ssh para o contêiner:

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

Seu script poderá executar a git clone.

Extra: se você deseja que os arquivos clonados pertençam a um usuário específico, é necessário usar, chownpois o uso de outro usuário que não seja root dentro do contêiner fará com que gitfalhe.

Você pode fazer esta publicação no ambiente do contêiner algumas variáveis ​​adicionais:

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

Depois de clonar, você deve executar chown $OWNER_USER:$OWNER_GROUP -R <source_folder>para definir a propriedade adequada antes de sair do contêiner, para que os arquivos sejam acessíveis por um usuário não raiz fora do contêiner.


1
Nas versões mais recentes do Docker, você pode passar -u root:$(id -u $USER)para pelo menos os arquivos pertencentes ao mesmo grupo principal que o usuário, o que deve tornar todos eles pelo menos legíveis, a menos sudoque algo os esteja criando com 0600permissões.
dragon788

@ dragon788 Eu acho que você tem um erro de digitação: -u root:$(id -u $USER)deveria ser -g.
edupo

Boa decisão! Parece que não consigo corrigi-lo a partir do celular, tentarei no desktop em breve.
dragon788

Eu tenho /tmp/ssh_auth.sock: No such file or directoryagora está /tmp/ssh-vid8Zzi8UILE/agent.46016na minha máquina host
vladkras

@vladkras o erro é bastante genérico. Pode ser causado devido a permissões /tmpdentro de seu contêiner. Ou um erro de digitação no comando docker run. Verifique se a instrução de ligação está correta -v $SSH_AUTH_SOCK:/tmp/ssh_auth.sock: Ordem é importante e ponto-e-vírgula também é importante. Verifique a documentação do docker para obter mais ajuda.
edupo

10

Como o eczajk já comentou na resposta de Daniel van Flymen, não parece seguro remover as chaves e usá-las --squash, pois elas ainda serão visíveis na história ( docker history --no-trunc).

Em vez disso, com o Docker 18.09, agora você pode usar o recurso "construir segredos". No meu caso, clonei um repositório Git privado usando a chave SSH dos meus hosts com o seguinte no meu Dockerfile:

# syntax=docker/dockerfile:experimental

[...]

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

[...]

Para poder usar isso, é necessário ativar o novo back-end BuildKit antes da execução docker build:

export DOCKER_BUILDKIT=1

E você precisa adicionar o --ssh defaultparâmetro para docker build.

Mais informações sobre isso aqui: https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066


1
Melhor solução IMHO. Eu tive que fazer mais duas coisas para fazê-lo funcionar: 1) Adicionar a minha chave privada para ssh-agente com ssh-add ~/.ssh/id_rsae 2) Adicionar o anfitrião git para known_hosts, ou seja, para bitbucket:RUN ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts
Moritz Ringler

Não consegui fazer isso funcionar. Ainda estou recebendo erros de permissão: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access and the repository exists.apesar de passar a --ssh defaultbandeira na minha janela de encaixe e usar --mount=type=ssho comando run em que eu git clone. Sou capaz de clonar o mesmo repositório sem problemas na máquina de compilação. Simplesmente falha no contêiner de construção da janela de encaixe. Eu suspeito que a versão para mac do Docker não esteja realmente transmitindo o cliente ssh.
PMende

@PMende você conseguiu descobrir esse problema mencionado porque também estou enfrentando o mesmo.
Sadan A.

@SadanArshad Parece que atualmente esta funcionalidade é suportada apenas se você estiver executando o Docker a partir de uma máquina Linux. Não funciona se você estiver executando os comandos do Docker em um Mac (e provavelmente no Windows também, embora eu não possa confirmar).
PMende

Pena que não funciona com o docker-compose ... github.com/docker/compose/issues/6440
Alexis Wilke

9

Esta questão é realmente irritante. Como você não pode adicionar / copiar nenhum arquivo fora do contexto do dockerfile, isso significa que é impossível vincular ~ / .ssh / id_rsa ao /root/.ssh/id_rsa da imagem e quando você definitivamente precisa de uma chave para executar alguma coisa de sshed como o git clone de um link de repo privado ..., durante a construção da sua imagem do docker.

Enfim, encontrei uma solução para a solução alternativa, não tão convincente, mas funcionou para mim.

  1. no seu arquivo docker:

    • adicione este arquivo como /root/.ssh/id_rsa
    • faça o que quiser, como git clone, compositor ...
    • rm /root/.ssh/id_rsa no final
  2. um script para fazer em uma sessão:

    • cp sua chave para a pasta que contém o dockerfile
    • docker build
    • rm a chave copiada
  3. sempre que você precisar executar um contêiner a partir desta imagem com alguns requisitos ssh, basta adicionar -v para o comando run, como:

    docker execute -v ~ / .ssh / id_rsa: /root/.ssh/id_rsa --name comando imagem de contêiner

Essa solução não resulta em nenhuma chave privada na imagem do docker e na imagem do docker, portanto, não há mais problema de segurança com o que se preocupar.


1
"Como você não pode adicionar / copiar nenhum arquivo fora do contexto do dockerfile," Você viu docker cp? É usado para "Copiar arquivos / pastas entre um contêiner e seu host".
Jonathon Reinhart

@ JonathonReinhart, obrigado por apontar isso. Sim, docker cppoderia fazer o truque. No entanto, nessa mesma situação, eu precisava da ssh_key durante a criação da imagem, e não há nenhum contêiner naquele momento ... atualizará minha expressão pouco clara, obrigado de qualquer maneira.
ImLeo

9

Encontrei o mesmo problema hoje e uma versão modificada com posts anteriores achei essa abordagem mais útil para mim

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

(Observe que o sinalizador somente leitura para que o contêiner não mexa na minha chave ssh em nenhum caso.)

Agora, dentro do contêiner, posso executar:

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

Portanto, não recebo o Bad owner or permissions on /root/.ssh/..erro que foi observado por @kross


Obrigado! Esta foi a chave para fazê-lo funcionar para mim: ter o ssh-agent e ssh-add em um único comando como: ssh-agent bash -c "ssh-add...". Posso então passar isso direto para a janela de encaixe. Todos os exemplos anteriores que encontrei foram utilizados eval ssh-agent, seguidos por ssh-add e não consegui descobrir uma maneira de passar isso evalpelo comando docker run.
Ryanman


6

Você também pode vincular seu diretório .ssh entre o host e o contêiner. Não sei se esse método tem implicações de segurança, mas pode ser o método mais fácil. Algo assim deve funcionar:

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

Lembre-se de que a janela de encaixe é executada com o sudo (a menos que você não faça isso), se esse for o caso, você usará as teclas ssh raiz.


O uso desse método funciona com o docker 0.11, mas se você usar o fig, ocorrerá um erro de pânico. Não sei por que
Luis Elizondo

3
Esse seria um método preferido, o truque seria usar as chaves do meu usuário host não privilegiado como raiz do contêiner. Como você mencionou, tentar fazê-lo não como o usuário root do host produz Bad owner or permissions on /root/.ssh/config.
quer

isso só pode ser usado durante docker run, mas não durante docker build.
Ccpizza #

3
@ccpizza, vejo isso como uma vantagem. Muitas dessas respostas deixam chaves privadas armazenadas em uma imagem; a chave permanece armazenada mesmo depois de removida a chave em um comando de camada subsequente. Ao introduzir as chaves privadas apenas durante a execução (não compilar), elas podem existir apenas no contêiner (não na imagem).
cowlinator

6

A partir de docker API 1.39+(Verificar versão da API com docker version) docker build permite a --sshopção com um soquete ou chaves de agente para permitir que o Docker Engine encaminhe as conexões do agente SSH.

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

Mais informações:


1
A expansão til não funcionou para mim; Eu tenho: could not parse ssh: [default=~/.ssh/id_rsa]: stat ~/.ssh/id_rsa: no such file or directory. Use o caminho completo se não funcionar.
slhck 24/01

3

Se você não se importa com a segurança de suas chaves SSH, há muitas boas respostas aqui. Em caso afirmativo, a melhor resposta que encontrei foi de um link no comentário acima para este comentário do GitHub por diegocsandrim . Para que outros tenham maior probabilidade de vê-lo, e no caso de esse repositório desaparecer, aqui está uma versão editada dessa resposta:

A maioria das soluções aqui acaba deixando a chave privada na imagem. Isso é ruim, pois qualquer pessoa com acesso à imagem tem acesso à sua chave privada. Como não sabemos o suficiente sobre o comportamento desquash , isso ainda pode ser o caso, mesmo se você excluir a chave e esmagar essa camada.

Geramos uma URL de pré-assinatura para acessar a chave com o aws s3 cli e limitamos o acesso por cerca de 5 minutos, salvamos essa URL de pré-assinatura em um arquivo no diretório repo e, em dockerfile, a adicionamos à imagem.

No dockerfile, temos um comando RUN que executa todas estas etapas: use a URL de pré-gravação para obter a chave ssh, execute o npm install e remova a chave ssh.

Ao fazer isso em um único comando, a chave ssh não seria armazenada em nenhuma camada, mas a URL de pré-assinatura será armazenada, e isso não é um problema, porque a URL não será válida após 5 minutos.

O script de construção se parece com:

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

O Dockerfile fica assim:

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
O problema com esta solução é que, como o pre_sign_url muda sempre, a instalação do npm não pode ser armazenada em cache, mesmo que não haja alteração no arquivo packages.json. É melhor para obter a chave na build.sh e defini-lo como um argumento de compilação para que ele não vai mudar a cada vez
Iorque Yang


3

Uma visão geral concisa dos desafios do SSH nos contêineres do Docker é detalhada aqui . Para conectar-se a controles remotos confiáveis ​​a partir de um contêiner sem vazar segredos, existem algumas maneiras:

Além desses, há também a possibilidade de usar um armazenamento de chaves em execução em um contêiner de docker separado, acessível em tempo de execução ao usar o Compose. A desvantagem aqui é a complexidade adicional devido ao mecanismo necessário para criar e gerenciar um keystore, como o Vault da HashiCorp .

Para uso da chave SSH em um contêiner do Docker independente, consulte os métodos vinculados acima e considere as desvantagens de cada um, dependendo de suas necessidades específicas. Se, no entanto, você estiver executando o Compose e quiser compartilhar uma chave para um aplicativo em tempo de execução (refletindo os aspectos práticos do OP), tente o seguinte:

  • Crie um docker-compose.envarquivo e adicione-o ao seu .gitignorearquivo.
  • Atualize docker-compose.ymle adicione o env_fileserviço que requer a chave.
  • Acesse a chave pública do ambiente no tempo de execução do aplicativo, por exemplo, process.node.DEPLOYER_RSA_PUBKEYno caso de um aplicativo Node.js.

A abordagem acima é ideal para desenvolvimento e teste e, embora possa atender aos requisitos de produção, na produção é melhor usar um dos outros métodos identificados acima.

Recursos adicionais:


3

Você pode usar a construção de vários estágios para construir contêineres É a abordagem que você pode seguir: -

Estágio 1: construindo uma imagem com 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

Etapa 2: construa seu contêiner

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

adicione o atributo env no seu arquivo de composição:

   environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

depois passe argumentos do script de construção como este:

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

E remova o contêiner intermediário por segurança. Isso irá ajudá-lo a aplausos.


2

Uma maneira simples e segura de conseguir isso sem salvar sua chave em uma camada de imagem do Docker ou passar pela ginástica ssh_agent é:

  1. Como uma das etapas no seu Dockerfile, crie um .sshdiretório adicionando:

    RUN mkdir -p /root/.ssh

  2. Abaixo disso, indique que você deseja montar o diretório ssh como um volume:

    VOLUME [ "/root/.ssh" ]

  3. Verifique se o contêiner ssh_configsabe onde encontrar as chaves públicas adicionando esta linha:

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

  4. Exponha o .sshdiretório do usuário local ao contêiner em tempo de execução:

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

    Ou dockerCompose.ymladicione-o na chave de volume do serviço:

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

Sua final Dockerfiledeve conter algo como:

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

Estou tentando resolver o problema de outra maneira: adicionando a chave ssh pública a uma imagem. Mas, em meus testes, descobri que "docker cp" é para copiar de um contêiner para um host. O item 3 da resposta por creak parece estar dizendo que você pode usar o docker cp para injetar arquivos em um contêiner. Consulte https://docs.docker.com/engine/reference/commandline/cp/

excerto

Copie arquivos / pastas do sistema de arquivos de um contêiner para o caminho do host. Os caminhos são relativos à raiz do sistema de arquivos.

  Usage: docker cp CONTAINER:PATH HOSTPATH

  Copy files/folders from the PATH to the HOSTPATH

Este URL parece estar quebrado agora.
Slm 31/07

Isso é obsoleto ou incorreto. Pode copiar qualquer direção, a partir de 1.8.2.
Jonathon Reinhart

1

Você pode passar as chaves autorizadas para o contêiner usando uma pasta compartilhada e definir permissões usando um arquivo docker como este:

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

E sua execução do docker contém algo como o seguinte para compartilhar um diretório de autenticação no host (segurando as teclas authorised_keys) com o contêiner e abrir a porta ssh que poderá ser acessada através da porta 7001 no host.

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

Você pode consultar https://github.com/jpetazzo/nsenter, que parece ser outra maneira de abrir um shell em um contêiner e executar comandos dentro de um contêiner.


1

É tardio para a parte, que tal isso, que disponibilizará as chaves do sistema operacional do host para fazer root dentro do contêiner, em tempo real:

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

Não sou a favor de usar o Dockerfile para instalar chaves, pois as iterações do seu contêiner podem deixar as chaves privadas para trás.


0

Você pode usar segredos para gerenciar quaisquer dados confidenciais que um contêiner precisa em tempo de execução, mas não deseja armazenar na imagem ou no controle de origem, como:

  • Nomes de usuário e senhas
  • Certificados e chaves TLS
  • Chaves SSH
  • Outros dados importantes, como o nome de um banco de dados ou servidor interno
  • Sequências genéricas ou conteúdo binário (tamanho de até 500 kb)

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

Eu estava tentando descobrir como adicionar chaves de assinatura a um contêiner para usar durante o tempo de execução (não compilar) e me deparei com essa pergunta. Os segredos do Docker parecem ser a solução para o meu caso de uso e, como ninguém o mencionou ainda, eu o adicionarei.


0

No meu caso, tive um problema com o nodejs e o 'npm i' de um repositório remoto. Corrigi-o adicionado usuário 'node' ao container nodejs e 700 ao ~ / .ssh no container.

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

depois disso começou a funcionar


-1

De maneira mais simples, obtenha uma conta da barra de ativação e use: ssh-import-id


8
A questão era sobre chaves privadas. ssh-import-idparece que apenas importa chaves públicas.
Cdd #

-1

Em um contêiner de docker em execução, você pode emitir ssh-keygen com a opção docker -i (interativa). Isso encaminhará as solicitações do contêiner para criar a chave dentro do contêiner do Docker.


1
E depois o que? Você não pode fazer nada depois disso, porque não tem permissão para fazê-lo.
Jonathon Reinhart

-1

Para debian / root / allowed_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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.