Moby: Encaminha o agente de chave ssh para o contêiner

Criado em 13 jun. 2014  ·  190Comentários  ·  Fonte: moby/moby

Seria bom ser capaz de encaminhar um agente de chave ssh para um contêiner durante um run ou build .
Freqüentemente, precisamos construir o código-fonte que existe em um repositório privado onde o acesso é controlado pela chave ssh.

Adicionar o arquivo de chave ao contêiner é uma má ideia, pois:

  1. Você acabou de perder o controle de sua chave SSH
  2. Sua chave pode precisar ser desbloqueada por meio de senha
  3. Sua chave pode não estar em um arquivo e só pode ser acessada por meio do agente de chave.

Você poderia fazer algo como:

# docker run -t -i -v "$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" fedora ssh-add -l
2048 82:58:b6:82:c8:89:da:45:ea:9a:1a:13:9c:c3:f9:52 phemmer<strong i="15">@whistler</strong> (RSA)

Mas:

  1. Isso só funciona para docker run , não build .
  2. Isso só funciona se o docker daemon estiver sendo executado no mesmo host que o cliente.

A solução ideal é fazer com que o cliente encaminhe o soquete do agente principal da mesma forma que ssh pode.
No entanto, a dificuldade nisso é que isso exigiria chamadas de construção e anexação de API remotas para dar suporte ao proxy de um número arbitrário de fluxos de soquete. Apenas fazer um único fluxo bidirecional não seria suficiente, pois o agente de chave ssh é um soquete de domínio unix e pode ter várias conexões simultâneas.

aresecurity exintermediate kinfeature

Comentários muito úteis

@ kienpham2000 , por que essa solução não manteria a chave na camada da imagem? As ações de copiar e remover a chave estão sendo feitas em comandos separados, portanto existe uma camada que deve ter a chave.
Nossa equipe estava usando a sua solução até ontem, mas encontramos uma solução melhorada:

  • Geramos uma URL de pré-assinatura para acessar a chave com 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 seguida, no dockerfile, adicionamos à imagem.
  • No dockerfile, temos um comando RUN que executa todas essas etapas: use a URL de pré-inscrição para obter a chave ssh, execute npm install e remova a chave ssh.
    Fazendo isso em um único comando, a chave ssh não seria armazenada em nenhuma camada, mas a URL de pré-assinatura seria 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 se parece com isto:

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

Todos 190 comentários

Eu me pergunto se # 6075 vai te dar o que você precisa

Um contêiner secreto pode torná-lo um pouco mais seguro, mas todos os pontos mencionados permanecem válidos.

1 Eu também consideraria esse recurso útil. Em particular, ao construir contêineres que requerem software de repositórios git privados, por exemplo. Prefiro não ter que compartilhar uma chave repo no contêiner e, em vez disso, gostaria de poder fazer com que o "docker build ..." use algum outro método para obter acesso às chaves SSH desbloqueadas, talvez por meio de um ssh em execução -agente.

+1. Estou apenas começando a molhar os pés com o Docker e esta foi a primeira barreira que bati. Passei um tempo tentando usar VOLUME para montar a meia de autenticação antes de perceber que o docker não pode / não monta um volume de host durante uma compilação.

Não quero cópias de uma chave SSH sem senha e a mecânica de copiá-la para um contêiner e, em seguida, excluí-la durante a construção parece incorreta. Eu trabalho dentro do EC2 e nem mesmo me sinto bem em copiar minhas chaves privadas lá (sem senha ou não).

Meu caso de uso é construir um projeto erlang com vergalhão. Com certeza, eu _pude_ clonar o primeiro repo e ADICIONÁ-lo à imagem com um Dockerfile, mas isso não funciona com dependências privadas que o projeto tem. Acho que poderia apenas construir o projeto na máquina host e ADICIONAR o resultado à nova imagem do Docker, mas gostaria de construí-lo na caixa de areia que é o Docker.

Aqui estão algumas outras pessoas que têm o mesmo caso de uso: https://twitter.com/damncabbage/status/453347012184784896

Por favor, abrace SSH_AUTH_SOCK, é muito útil.

Obrigado

Edit: Agora que sei mais sobre como o Docker funciona (camadas FS), é impossível fazer o que descrevi em relação a ADICIONAR uma chave SSH durante uma compilação e excluí-la mais tarde. A chave ainda existirá em algumas das camadas FS.

+1, poder usar SSH_AUTH_SOCK será muito útil!

Eu uso chaves SSH para autenticar com o Github, seja um repositório privado ou público.

Isso significa que meus git clone comandos se parecem com: git clone [email protected]:razic/my-repo.git .

Posso montar o volume do diretório do host ~/.ssh em meus contêineres durante um docker run e ssh está tudo certo. No entanto, não posso montar meu ~/.ssh durante um docker build .

: +1: para encaminhamento de ssh durante as compilações.

Pelo que entendi, este é o caminho errado. O caminho certo é criar uma imagem docker na máquina dev e, em seguida, copiá-la para o servidor docker.

@SevaUA - não, isso não é correto. Este pedido é devido a uma limitação ao fazer docker build... . Você não pode exportar uma variável para este estágio como faria ao fazer docker run ... . O comando run permite que as variáveis ​​sejam exportadas para o contêiner docker durante a execução, ao passo que a construção não permite isso. Essa limitação é parcialmente intencional com base em como o dockerd funciona ao construir contêineres. Mas existem maneiras de contornar isso e o caso de uso descrito é válido. Portanto, esta solicitação está tentando implementar esse recurso na construção, de alguma forma.

Eu gosto da ideia de # 6697 (armazenamento secreto / cofre), e isso pode funcionar para isso, uma vez que seja mesclado. Mas se isso não funcionar, uma alternativa é fazer coisas de ssh de proxy transparente man-in-the-middle fora do daemon do docker, interceptando o tráfego do daemon do docker (não internamente). Alternativamente, todas as solicitações git + ssh podem ser para algum host definido localmente que faça proxy de forma transparente para o github ou o que você precisar no final das contas.

Essa ideia já foi levantada (ver comentário 2). Isso não resolve o problema.

+1 para encaminhamento de ssh durante as compilações.

+1 no encaminhamento do agente SSH em docker build

+1 para o encaminhamento de ssh durante a compilação para npm install ou similar.

Alguém tem o encaminhamento de ssh funcionando durante a execução no OSX? Eu coloquei uma pergunta aqui: http://stackoverflow.com/questions/27036936/using-ssh-agent-with-docker/27044586?noredirect=1#comment42633776_27044586 parece que não é possível com OSX ...

+1 = (

Apenas acerte este obstáculo também. Tentando executar npm install apontado para um repositório privado. a configuração se parece com:
host -> vagrant -> docker pode ssh-agent encaminhar host -> vagrant -! docker

+1
Basta clicar nisto enquanto tenta descobrir como fazer o agente ssh funcionar durante a 'compilação do docker'.

1 mesmo que os caras anteriores. Parece a melhor solução para esse problema quando precisar acessar um ou mais repositórios git privados (pense em bundle install e npm install por exemplo) ao construir a imagem Docker.

Posso montar o volume do meu diretório host ~ / .ssh em meus contêineres durante uma execução do docker e o ssh está tudo certo.

@razic Você pode compartilhar como você faz isso funcionar? Porque quando eu tentei isso antes, ele reclamei sobre "Proprietário ou permissões ruins"

A menos que você certifique-se de que todos os contêineres sejam executados com um usuário ou permissões específicas que permitem que você faça isso.

+1 para SSH_AUTH_SOCK

@tonivdv dê uma olhada no comando docker run no comentário inicial sobre este problema. O bind monta o caminho referido por SSH_AUTH_SOCK a /tmp/ssh_auth_sock dentro do contêiner e, em seguida, define SSH_AUTH_SOCK no contêiner para esse caminho.

@ md5 Presumo que @razic e @tonivdv estejam falando sobre montagem assim: -v ~/.ssh:/root/.ssh:ro , mas quando você faz isso, os arquivos .ssh não são propriedade do root e, portanto, falham nas verificações de segurança.

@KyleJamesWalker sim, isso é o que eu entendo do @razic e que foi uma das minhas tentativas há algum tempo atrás, então quando li que o @razic foi capaz de fazer funcionar, fiquei me perguntando como :)

@tonivdv Eu também adoraria saber se é possível, mas não consegui encontrar nada quando tentei pela última vez.

1 Estou interessado em construir ambientes de desenvolvimento descartáveis ​​usando Docker, mas não consigo fazer isso funcionar. Isso ajudaria muito nesse aspecto.

Para quem procura uma solução temporária, tenho uma solução que utilizo para forças brutas em:

https://github.com/atrauzzi/docker-laravel/blob/master/images/php-cli/entrypoint.sh

Não é de forma alguma uma solução desejável, pois requer um script de ponto de entrada inteiro, mas funciona.

abordagem interessante @atrauzzi . Para nosso dev env, construímos uma imagem base e copiamos a chave ssh diretamente nela. Tem a vantagem de não ser necessário fornecê-lo a cada corrida. E cada imagem herdada daquele mago por padrão também tem a chave. No entanto, do nosso jeito, você não pode compartilhá-lo publicamente, obviamente; p

+1 isso seria ótimo

@tonivdv O contêiner para o qual o script se destina é feito e destruído com frequência, pois é apenas um host para ferramentas CLI. É claro que você está livre para fazer a operação apenas uma vez. Mas se alguém alterar suas configurações e executar novamente um comando por meio do contêiner, terá que ser uma nova cópia a cada vez.

@atrauzzi eu entendo. Sua abordagem deve ser adotada por imagens docker que podem exigir uma chave ssh privada. Por exemplo, uma imagem do compositor deve incluir o script do seu entrypoint no caso de repositórios privados. Pelo menos até que o docker venha com uma solução nativa.

: +1: para encaminhamento de ssh via build

Deve ter aqui também!

@atrauzzi Atualmente , estou usando outra abordagem da qual gosto muito. É fazer um contêiner de volume de dados com o material ssh nele. Quando você quiser usar suas chaves ssh em outro contêiner, posso simplesmente usar isso com o seguinte comando:

docker run -ti --volumes-from ssh-data ...

Desta forma, você não precisa colocar um ponto de entrada em cada imagem e pode funcionar com todas as imagens.

Para criar esse contêiner, eu faço o seguinte

docker run \
  --name ssh-data \
  -v /root/.ssh \
  -v ${USER_PRIVATE_KEY}:/root/.ssh/id_rsa \
  busybox \
  sh -c 'chown -R root:root ~/.ssh && chmod -R 400 ~/.ssh'

Espero que isso possa ajudar outras pessoas :)

Felicidades

@tonivdv - Eu

@atrauzzi Sim, eu entendo. Dito isso, cabe ao usuário manter seu contêiner de volume ssh corretamente. Ele pode até usar diferentes, se necessário. E, opcionalmente, pode ser gerado instantaneamente com um script. Mas não acho que haja uma única boa solução. Tudo depende das necessidades. Queria apenas compartilhar para que outros pudessem escolher a solução com base em suas necessidades. Espero postar em um blog sobre isso em breve, e encaminharei a sua solução também! Felicidades

Eu não tornaria obrigatório que as pessoas que executam seus contêineres mantenham um contêiner somente de dados cheio de chaves SSH. Parece envolvido.

@atrauzzi É verdade que o contêiner de volume deve estar lá, mas do seu jeito o usuário deve compartilhar a chave ssh ao rodar também, certo? Portanto, além de ter a necessidade de um contêiner de volume ssh, a única diferença em ambas as soluções do ponto de vista de execução é:

docker run ... --volumes-from ssh-data ... php-cli ...

e

docker run ... -v ~/.ssh:/path/.host-ssh ... php-cli ..

direito? Ou estou perdendo outra coisa :)

Mas eu entendo completamente porque você está fazendo do seu jeito. No entanto, se você quiser usar, por exemplo, uma imagem do compositor de outra pessoa, o modo de produção dos volumes funcionará imediatamente. Pelo menos evita criar sua própria imagem com o "hack do entrypoint".

Como eu disse, ambos são uma solução alternativa e têm prós e contras.

Felicidades

Seria muito bom receber uma atualização da equipe do Docker sobre o status desse recurso. Especificamente, autenticação SSH de docker build .

Já está se aproximando de 1 ano. Um tanto surpreendente, dada a praticidade dos casos de uso da vida real para isso. Atualmente, estamos gerando imagens dinamicamente ao comprometer contêineres em execução. Não podemos ter um Dockerfile no repositório de nosso aplicativo. Isso quebra o fluxo de praticamente tudo. Não posso realmente usar meu aplicativo com nenhum serviço Docker, como Compose ou Swarm, até que isso seja resolvido.

Uma atualização seria muito apreciada. Por favor e obrigado.

/ cc @phemmer

Não é que não queiramos esse recurso ou algo assim, eu realmente vejo um caso de uso para algo assim ou segredos na construção, só precisaríamos de uma proposta de alguém disposto a implementar e então se aprovada a implementação da proposta.
Também falo em nome de mim mesmo, nem de todos os mantenedores.

@jfrazelle

Eu sei que vocês não estão nos ignorando :)

Portanto, o status é:

É algo que consideramos implementar se houver uma proposta aceita
e largura de banda de engenharia.

Isso soa correto para você?

Além disso, há atualmente alguma proposta aberta que trate desse problema?

Na terça-feira, 7 de abril de 2015, Jessie Frazelle [email protected] escreveu:

Não é que não queiramos esse recurso ou algo assim, eu realmente vejo uma utilidade
caso para algo como este ou segredos na construção, precisaríamos apenas de um
proposta de alguém disposto a implementar e então se aprovado o
implementação da proposta.
Também falo em nome de mim mesmo, nem de todos os mantenedores.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

É algo que consideramos implementar se houver uma proposta aceita
e largura de banda de engenharia.

sim

E não creio que haja propostas abertas para isso.

Na terça, 7 de abril de 2015 às 14h36, Zachary Adam Kaplan <
notificaçõ[email protected]> escreveu:

@jfrazelle

Eu sei que vocês não estão nos ignorando :)

Portanto, o status é:

É algo que consideramos implementar se houver uma proposta aceita
e largura de banda de engenharia.

Isso soa correto para você?

Além disso, há atualmente alguma proposta aberta que trate desse problema?

Na terça-feira, 7 de abril de 2015, Jessie Frazelle [email protected]
escreveu:

Não é que não queiramos esse recurso ou algo assim, eu realmente vejo uma utilidade
caso para algo como este ou segredos na construção, precisaríamos apenas de um
proposta de alguém disposto a implementar e então se aprovado o
implementação da proposta.
Também falo em nome de mim mesmo, nem de todos os mantenedores.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90738913.

Não sei se estou simplificando demais as coisas, mas aqui está minha proposta:

SSHAGENT: encaminhar # padrões para ignorar

Se definido, durante a construção, o soquete e as variáveis ​​de ambiente associadas são conectados ao contêiner, onde podem ser usados. As peças mecânicas deste já existem e estão funcionando, é só uma questão de conectá-las em docker build .

Não tenho nenhuma experiência de trabalho dentro da base de código do docker, mas isso é importante o suficiente para mim que consideraria aceitá-lo.

Excelente. Onde posso descobrir como enviar uma proposta? Tem alguma
diretriz específica ou devo apenas abrir um problema?

Na terça-feira, 7 de abril de 2015, Jessie Frazelle [email protected] escreveu:

É algo que consideramos implementar se houver um
proposta
e largura de banda de engenharia.

sim

E não creio que haja propostas abertas para isso.

Na terça, 7 de abril de 2015 às 14h36, Zachary Adam Kaplan <
notificaçõ[email protected]
<_e i = "18">

@jfrazelle

Eu sei que vocês não estão nos ignorando :)

Portanto, o status é:

É algo que consideramos implementar se houver um
proposta
e largura de banda de engenharia.

Isso soa correto para você?

Além disso, há atualmente alguma proposta aberta que trate desse problema?

Na terça-feira, 7 de abril de 2015, Jessie Frazelle < notificaçõ[email protected]
<_e i = "31" /> escreveu:

Não é que não queremos esse recurso ou algo assim, eu realmente vejo um
usar
caso para algo como este ou segredos na construção, precisaríamos apenas de um
proposta de alguém disposto a implementar e então se aprovado o
implementação da proposta.
Também falo em nome de mim mesmo, nem de todos os mantenedores.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90737847.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90738913.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90739596.

Quero dizer, como uma proposta de design
https://docs.docker.com/project/advanced-contributing/#design -proposal

Na terça, 7 de abril de 2015 às 14h39, Daniel Staudigel [email protected]
escreveu:

Não sei se estou simplificando demais as coisas, mas aqui está minha proposta:

SSHAGENT: encaminhar # padrões para ignorar

Se definido, durante a construção, o soquete e as variáveis ​​de ambiente associadas são
conectado ao recipiente, onde podem ser usados. As peças mecânicas
disso já existem e estão funcionando, é só uma questão de conectar
-los na versão docker.

Eu não tenho nenhuma experiência de trabalho dentro da base de código do docker, mas este
é importante o suficiente para mim que eu consideraria aceitá-lo.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90739803.

Esta é uma ideia de alto nível, mas e se em vez de anexar por meio da API remota do docker, o docker executasse um daemon init, com um daemon ssh empacotado, dentro do contêiner?

Isso pode ser usado para resolver vários problemas.

  • Esse daemon seria o PID 1 e o processo do contêiner principal seria o PID 2. Isso resolveria todos os problemas com o PID 1 ignorando os sinais e os contêineres não desligando corretamente. (# 3793)
  • Isso permitiria o encaminhamento limpo do agente de chave SSH. (# 6396)
  • Este daemon pode manter os namespaces abertos (# 12035)
  • Um TTY seria criado pelo daemon (# 11462)
  • ... e provavelmente várias outras questões que estou esquecendo.

você pode querer ver https://github.com/docker/docker/issues/11529 sobre o
primeiro ponto

Na terça, 7 de abril de 2015 às 14h46, Patrick Hemmer [email protected]
escreveu:

Esta é uma ideia de alto nível, mas e se, em vez de anexar por
a API remota do docker, o docker executou um daemon init, com um ssh empacotado
daemon, dentro do contêiner?

Isso pode ser usado para resolver vários problemas.

  • Este daemon seria o PID 1, e o processo do contêiner principal seria
    PID 2. Isso resolveria todos os problemas com PID 1 ignorando sinais e
    contêineres não fechando corretamente. (# 3793
    https://github.com/docker/docker/issues/3793)
  • Isso permitiria o encaminhamento limpo do agente de chave SSH. (# 6396
    https://github.com/docker/docker/issues/6396)
  • Este daemon pode manter os namespaces abertos (# 12035
    https://github.com/docker/docker/issues/12035)
  • Um TTY seria criado pelo daemon (# 11462
    https://github.com/docker/docker/issues/11462)
  • ... e provavelmente várias outras questões que estou esquecendo.

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90741192.

11529 não tem nenhuma relação com o problema do PID 1.

atire, copie e cole, agora eu tenho que encontrar o outro novamente

não, é aquele, ele corrige as coisas de zumbis PID 1 que é o que eu pensei que você estava se referindo, mas independentemente disso eu estava apenas postando porque o teste é tudo

@phemmer Parece que você tem o conhecimento necessário para nos orientar na elaboração de uma proposta inteligente de implementação.

Também se parece com @dts e estamos dispostos a dedicar um tempo trabalhando nisso.

@phemmer e @dts há alguma maneira possível de trazermos essa discussão para um cliente de bate-papo um pouco mais em tempo real para facilitar a comunicação? Estou disponível através do Slack, Google Chat / Hangout, IRC e farei o download de qualquer outra coisa, se necessário.

@phemmer Parece que você tem experiência para nos orientar na elaboração de uma proposta inteligente de implementação

Infelizmente, não realmente :-)
Posso lançar ideias de design, mas conheço apenas pequenas partes da base de código do docker. É provável que esse tipo de mudança seja em grande escala.

Já houve algumas propostas aqui:

@phemmer sugerido

e se, em vez de anexar por meio da API remota do docker, o docker executasse um daemon init, com um daemon ssh empacotado, dentro do contêiner?

@dts sugerido

SSHAGENT: encaminhar # padrões para ignorar
Se definido, durante a construção, o soquete e as variáveis ​​de ambiente associadas são conectados ao contêiner, onde podem ser usados. As peças mecânicas disso já existem e estão funcionando, é só uma questão de conectá-las no docker build.

@razic sugerido

Habilite a vinculação de volume para docker build .

O que realmente precisamos neste ponto é que alguém aceite um deles para que possamos começar a trabalhar nele.

@jfrazelle Alguma ideia de como podemos ir para a próxima etapa? Na verdade, estou apenas tentando fazer isso. É claro que há muito interesse nisso. Estou disposto a defender o recurso, acompanhando-o até a conclusão.

Posso estar disponível para uma reunião slack / irc / Gchat / etc, acho que isso vai tornar as coisas um pouco mais fáceis, pelo menos para reunir requisitos e decidir sobre um curso de ação razoável.

@dts sugerido

SSHAGENT: encaminhar # padrões para ignorar

Esta é apenas uma ideia de como seria consumido, não implementado. O "init / ssh daemon" é uma ideia de como seria implementado. Os dois poderiam existir.

@razic sugerido

Ative a vinculação de volume para a execução do docker.

Infelizmente, isso não funcionaria. Assumindo que isso significa docker build , e não docker run , que já suporta montagens de volume, o cliente pode ser remoto (boot2docker é um exemplo proeminente). O vínculo de volume só funciona quando o cliente está no mesmo host que o docker daemon.

@razic consulte este link sobre a proposta de design ... essas não são propostas https://docs.docker.com/project/advanced-contributing/#design -proposal

@phemmer

Não consigo entender exatamente por que isso não funciona. docker-compose trabalha com montagens de volume em um cluster swarm . Se o arquivo / pasta não estiver no sistema host, ele terá o mesmo comportamento como se você executasse -v com um caminho que não existe.

@jfrazelle Entendi.

Se o arquivo / pasta não estiver no sistema host, ele exercerá o mesmo comportamento como se você executasse -v com um caminho que não existe em uma janela de encaixe local.

Não tenho certeza se entendi seu ponto. Como esse comportamento ajuda nesse problema?
Se eu tiver um agente de chave ssh ouvindo em /tmp/ssh-UPg6h0 em minha máquina local e o docker estiver em execução em uma máquina remota e ligar para docker build , esse agente de chave ssh local não está acessível ao daemon docker. A montagem do volume não irá obtê-lo, e os contêineres docker build não terão acesso à chave ssh.

De um alto nível, vejo apenas 2 maneiras de resolver isso:

1. Proxy o soquete do agente de chave ssh:

O docker daemon cria um soquete de domínio Unix dentro do contêiner e sempre que algo se conecta a ele, ele faz o proxy dessa conexão de volta para o cliente que está realmente executando o comando docker build .

Isso pode ser difícil de implementar, pois pode haver um número arbitrário de conexões com esse soquete de domínio Unix dentro do contêiner. Isso significaria que o docker daemon e o cliente precisam fazer o proxy de um número arbitrário de conexões, ou o daemon precisa ser capaz de falar o protocolo do agente ssh e multiplexar as solicitações.

No entanto, agora que a API docker remote suporta websockets (não era na época em que este problema foi criado), isso pode não ser muito difícil.

2. Inicie um daemon SSH real

Em vez de hackear o agente ssh, use uma conexão ssh real do cliente para o contêiner. O cliente docker teria um cliente ssh empacotado ou invocaria ssh no contêiner remoto.
Esta seria uma mudança em escala muito maior, pois substituiria a maneira como a fixação aos contêineres é implementada. Mas também evitaria que o docker tivesse que lidar com isso e migrasse para os protocolos padrão.
Isso também tem o potencial de resolver outros problemas (conforme mencionado aqui ).

Portanto, em última análise, uma mudança em escala muito maior, mas pode ser uma solução mais adequada.
Embora realisticamente, por causa da escala, eu duvido que isso aconteça.

@phemmer

Não tenho certeza se entendi seu ponto. Como esse comportamento ajuda nesse problema?

Porque o caso de uso mais comum para isso são pessoas construindo imagens com dependências hospedadas em repositórios privados que requerem autenticação SSH.

Você constrói a imagem em uma máquina que possui uma chave SSH. Que simples.

Se eu tiver um agente de chave ssh ouvindo em / tmp / ssh-UPg6h0 em minha máquina local e o docker estiver em execução em uma máquina remota e chamar o docker build, esse agente de chave ssh local não estará acessível ao daemon do docker.

Eu sei. Quem se importa? Estarei executando docker build em uma máquina que tem acesso ao socket de autenticação.

O que estou tentando dizer é ... docker-compose permite que você use o comando de volume contra um cluster swarm , independentemente de o arquivo estar realmente no host ou não! .

Devemos fazer a mesma coisa para montagens de volume em compilações docker.

| O arquivo está no sistema | Ação |
| : - | : - |
| Sim | Monte |
| Não Nenhum (na verdade, ele tenta montar, mas cria uma pasta vazia se o arquivo / pasta não existir, você pode verificar isso executando docker run -v /DOES_NOT_EXIST:/DOES_NOT_EXIST ubuntu ls -la /DOES_NOT_EXIST ) |

Um dos conceitos por trás de swarm é tornar o modelo de vários hosts transparente.

É bom que estejamos pensando no docker remoto, mas isso realmente não deveria importar.

Devemos apenas copiar o comportamento de montagem de volume para docker build da mesma maneira que fazemos para docker run .

Em https://github.com/docker/compose/blob/master/SWARM.md :

A principal coisa que impede os aplicativos de vários contêineres de funcionarem perfeitamente no Swarm é fazer com que eles falem uns com os outros: permitir a comunicação privada entre contêineres em hosts diferentes não foi resolvido de uma forma não hacky.

A longo prazo, a rede está sendo revisada de modo que se encaixe muito melhor no modelo de vários hosts. Por enquanto, os containers vinculados são programados automaticamente no mesmo host.

@phemmer Acho que as pessoas provavelmente estão pensando em uma solução para o problema que você descreveu. O problema que você está descrevendo parece https://github.com/docker/docker/issues/7249, que é separado.

Se seguirmos minha abordagem: apenas permitir a montagem de volume no docker build (independentemente de se o arquivo que você está tentando montar está realmente no sistema , então podemos fechar este problema. E começar a trabalhar em https://github.com/ docker / docker / issues / 7249 que estenderia o comportamento desse recurso para trabalhar com daemons docker remotos que não têm o arquivo local.

@ cpuguy83 Antes de criar uma proposta, estava olhando para o # 7133 e percebi que parece diretamente relacionado.

Você poderia apenas adicionar algumas palavras aqui? O # 7133 está realmente relacionado à minha sugestão para corrigir esse problema, que é permitir que docker build ofereça suporte a volumes.

@razic É em relação ao fato de que VOLUME /foo realmente cria um volume e o monta no contêiner durante a construção, o que geralmente é indesejável.

Eu também diria que uma proposta baseada no uso de montagens de ligação para colocar arquivos em contêineres de construção provavelmente não vai dar certo.
Veja # 6697

Executar -v com docker build pode ter um caminho de execução de código diferente.
Em vez de criar um volume e montá-lo durante a construção, podemos manter o
comportamento atual de que os volumes nos dockerfiles não são referenciados. E
em vez disso, age apenas em -v ao executar usando argumentos para a CLI.

Na quarta-feira, 8 de abril de 2015, Brian Goff [email protected] escreveu:

@razic https://github.com/razic É em relação ao fato de VOLUME
/ foo na verdade cria um volume e o monta no contêiner durante
construir, o que geralmente é indesejável.

Eu também diria uma proposta baseada no uso de montagens de ligação para colocar arquivos em
construir contêineres provavelmente não vai dar certo.
Consulte # 6697 https://github.com/docker/docker/pull/6697

-
Responda a este e-mail diretamente ou visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment -90905722.

@ cpuguy83 Obrigado pelo esclarecimento.

6697 Também não vai voar porque já está fechado e o # 10310 é praticamente um idiota do # 6697.

+1, acabei de fazer isso hoje ao tentar construir uma imagem para um aplicativo Rails que usa o Bower para instalar as dependências do cliente. Acontece que uma das dependências aponta para [email protected]:angular/bower-angular-i18n.git e, como o git falha aí, o bower falha e a construção da imagem também.

Eu realmente gosto do que o vagabundo faz. Com uma única configuração forward_agent no Vagrantfile, isso é resolvido para convidados vagrant. O Docker poderia implementar algo assim?

Além disso, como uma observação adicional, isso está acontecendo durante a construção da imagem. Alguém sabe de alguma solução alternativa existente?

Minha solução alternativa foi gerar um novo par de chaves RSA, configurar a chave pub no github (adicionar a impressão digital) e adicionar a chave privada à imagem Docker:

ADD keys/docker_rsa /srv/.ssh/id_rsa

Adoraria evitar isso, mas acho que é aceitável por enquanto. Quaisquer outras sugestões apreciadas!

Não tenho certeza de quem matou mais filhotes. Você por fazer isso ou o Docker por não fornecer uma maneira melhor ainda.

Em qualquer caso, vou apresentar uma proposta provavelmente neste fim de semana. @ cpuguy83 está certo ao dizer que as pessoas estão pelo menos pensando sobre isso e discutindo possíveis soluções. Então, neste ponto, é só uma questão de concordarmos em algo e conseguirmos que alguém trabalhe nisso. Estou totalmente empenhado em trabalhar nisso, pois, na verdade, é uma das minhas maiores queixas com o Docker atualmente.

@razic É um caso de uso bastante comum, então obrigado por investigar isso também. Quanto à solução alternativa, funciona. Possivelmente a chave poderia ser removida da imagem após ser usada, afinal, ela só é usada para obter o código da aplicação do github.

@fullofcaffeine Não tenho 100% de certeza de como o Docker funciona internamente, mas acho que, a menos que seja feito em um único comando RUN (o que é impossível com sua solução alternativa), o histórico da imagem mantém a chave SSH.

@razic bom ponto.

Como uma solução alternativa para essa limitação, estamos brincando com a ideia de baixar as chaves privadas (de um servidor HTTP local), executando um comando que requer as chaves e depois excluindo as chaves.

Como fazemos tudo isso em um único RUN , nada é armazenado em cache na imagem. É assim que fica no Dockerfile:

RUN ONVAULT npm install --unsafe-perm

Nossa primeira implementação em torno desse conceito está disponível em https://github.com/dockito/vault

A única desvantagem é exigir que o servidor HTTP esteja em execução, portanto, nenhum hub Docker é construído.

Diz-me o que pensas :)

+1
adoraria ver isso implementado, ajudaria a configurar contêineres para o ambiente de desenvolvimento

+1, só preciso encaminhar o agente ssh com boot2dock

Acabamos fazendo um processo de 3 etapas para contornar essa limitação:

  1. construir docker container sem dependências exigidas por SSH, adicionando a fonte na etapa final
  2. monte a fonte via volume compartilhado, mais SSH_AUTH_SOCK via volume compartilhado e execute a etapa de compilação, gravando a saída que requer ssh (digamos, github hospedado ruby ​​gems) de volta no volume compartilhado
  3. re-execute o docker build, que irá disparar novamente a adição do código-fonte, uma vez que as gemas agora estão no diretório de origem

O resultado é uma imagem docker com dependências extraídas por meio de autenticação SSH que nunca teve uma chave SSH.

Eu criei um script para habilitar o encaminhamento do agente ssh para docker run em um ambiente boot2docker no OSX com o mínimo de aborrecimento. Sei que não resolve o problema de compilação, mas pode ser útil para alguns:

https://gist.github.com/rcoup/53e8dee9f5ea27a51855

O agente de chave ssh Forward funciona com serviços como o serviço Amazon EC 2 Container? Parece-me que isso exigirá um software específico que pode não estar disponível em todas as plataformas ou PaaS que você está usando para implantar seus contêineres.

É necessária uma solução mais genérica e funcional para todos.

Atualmente, estou usando variáveis ​​de ambiente. Um script bash obtém a variável de chave privada (e hosts conhecidos) e a imprime nos arquivos id_rsa e known_hosts. Funciona, mas ainda não avaliei as implicações de segurança dessa solução.

FWIW, descobri que um agente ssh em contêiner e compartilhamento de volume funcionam bem com o mínimo de idiotice:

https://github.com/whilp/ssh-agent

Seria ótimo ter suporte de primeira classe para isso, no entanto.

É importante distinguir o que funciona em _run_ vs _build_. A solução de @whilp funciona maravilhosamente em _run_, mas não funciona em _build_ porque você não pode acessar outros volumes do docker durante _build_. Daí por que este tíquete ainda é uma ferida aberta e dolorida.

@rvowles sim, concordou. Eu coloquei algo junto para gerar contêineres por meio de uma sequência de chamadas run / commit (ou seja, sem Dockerfiles); isso fazia sentido para meu caso de uso específico, mas o suporte generalizado (incluindo tempo de construção) para algo como encaminhamento de agente seria muito útil.

Os IPs para a execução de contêineres estão incluídos em / etc / hosts durante a compilação? Em caso afirmativo, uma solução pode ser iniciar um contêiner que servia as chaves e, em seguida, enrolar para ele durante a construção.

Todos vocês podem se interessar em saber que escrevi sobre uma maneira de usar seu agente SSH durante docker build - http://aidanhs.com/blog/post/2015-10-07-dockerfiles-reproducibility- trapaça / # _ streamlining_your_experience_using_an_ssh_agent

Você só precisa iniciar um único contêiner. Uma vez iniciado, o acesso do agente SSH deve funcionar perfeitamente com apenas 3 linhas adicionais em seu Dockerfile - não há mais necessidade de expor suas chaves para o contêiner.

Algumas advertências: você precisa do Docker> = 1.8, e ele não funcionará em uma compilação automatizada do Docker Hub (obviamente). Leia também a nota sobre segurança! Sinta-se à vontade para levantar questões no repositório github sshagent que eu linkado na postagem se você tiver qualquer problema.

Também resolvi esse problema de maneira semelhante a @aidanhs - puxando o segredo necessário sobre a sub-rede docker local e removendo-o antes que o instantâneo do sistema de arquivos ocorra. Um contêiner em execução serve ao segredo, que é descoberto pelo cliente usando UDP de transmissão.
https://github.com/mdsol/docker-ssh-exec

Houve algum progresso para tornar isso possível? Não consigo montar o bind-mount do diretório ~/.ssh do host porque as permissões e a propriedade ficam confusas.

Isso não seria solucionável permitindo que as montagens de ligação forcem uid / gid e permissões específicas?

@atrauzzi bind-mounts não pode forçar uid / gid / permissions.
Pode fazer isso via FUSE (por exemplo, bindfs), mas não apenas com montagens bind normais.

@ cpuguy83 Isso realmente começa a me levar por caminhos que não quero ter que enfrentar. Especialmente quando estou usando um host baseado no Windows.

Não há uma opção amigável aqui? Tenho a sensação de que há um problema aqui que está apenas sendo adiado.

@atrauzzi Na verdade, não é um problema fácil de resolver imediatamente (pelo menos não perfeitamente).

+1, este é um grande bloqueador para um Dockerfile de aplicativo Node.js simples. Já trabalhei em muitos aplicativos Node e raramente vi um que não tivesse um repositório Github privado como uma dependência NPM.

Como uma solução alternativa, @apeace , você pode tentar adicioná-los como submódulo (s) git ao seu repositório git. Dessa forma, eles estão no contexto e você pode apenas adicioná-los durante a construção e se quiser realmente limpar, exclua ou ignore o arquivo .git em cada um. Na versão docker, eles podem ser instalados apenas usando o diretório local. Se eles precisarem ser repositórios git completos por algum motivo, certifique-se de que o arquivo .git não esteja presente na compilação do docker e adicione .git/modules/<repo> como <path>/<repo>/.git . Isso garantirá que sejam repositórios normais como se tivessem sido clonados.

Obrigado por essa sugestão, @jakirkham , mas temos npm install .

Por enquanto, temos uma solução que funciona, mas é nojenta. Nós temos:

  • Criou um usuário e equipe do Github que tem acesso somente leitura aos repositórios que usamos como dependências do NPM
  • Confirmou a chave privada desse usuário em nosso repositório, onde temos nosso Dockerfile
  • No Dockerfile, em vez de RUN npm install , fazemos RUN GIT_SSH='/code/.docker/git_ssh.sh' npm install

Onde git_ssh.sh é um script como este:

#!/bin/sh
ssh -o StrictHostKeyChecking=no -i /code/.docker/deploy_rsa "$@"

Funciona, mas encaminhar o agente de chave ssh seria muito melhor e muito menos trabalho de configuração!

: +1:
Não posso acreditar que essa solicitação de recurso ainda não foi implementada, pois existem muitos casos de uso em que as pessoas precisam de acesso de repositórios privados durante o tempo de construção.

Estou tentando construir contêineres para vários ambientes de desenvolvimento de sistema incorporado, que requerem acesso a repositórios privados. Adicionar suporte para chaves ssh de host seria um ótimo recurso. Os métodos mais populares que voam em SO e outras páginas são inseguros e, enquanto não houver suporte para este recurso, camadas com chaves privadas se espalharão.

: +1:

: +1: Tenho precisado disso há muito tempo.

Olá @apeace , não sei se você viu, mas comentei anteriormente sobre nossa solução alternativa para esse problema.

É uma combinação de um script e um servidor web. O que você acha https://github.com/dockito/vault ?

@pirelenito isso não faria com que a chave ainda estivesse disponível em uma camada da construção? Se for esse o caso, não vale a pena adicionar Dockito Valut ao nosso processo de construção - parece tão 'jenky' para mim quanto o que estamos fazendo agora. Agradeço a sugestão!

@apeace o ONVAULT baixa as chaves, executa o seu comando e apaga imediatamente as chaves. Como tudo isso acontece no mesmo comando, a camada final não conterá a chave.

@apeace Na Medidata, estamos usando uma ferramenta minúscula que criamos chamada docker-ssh-exec . Ele deixa apenas o binário docker-ssh-exec na imagem de compilação resultante - sem segredos. E isso requer apenas uma mudança de uma palavra para Dockerfile , portanto, é uma "pegada pequena".

Mas se você _realmente_ precisar usar uma solução apenas nativa do docker, agora existe uma maneira integrada de fazer isso, conforme observado no blog da --build-arg para passar valores efêmeros para o processo de compilação. Você deve ser capaz de passar uma chave SSH privada como ARG , gravá-la no sistema de arquivos, executar git checkout e, em seguida, _excluir_ a chave, tudo dentro do escopo de RUN Diretiva docker-ssh-exec faz). Isso resultará em Dockerfile feios, mas não deve exigir ferramentas externas.

Espero que isto ajude.

@benton Nós encontramos uma solução semelhante. :)

Obrigado @pirelenito e @benton , vou verificar todas as suas sugestões!

EDITAR : o seguinte _NÃO_ é seguro, na verdade:

Para registro, veja como você verifica um repositório privado do Github sem deixar sua chave SSH na imagem resultante.

Primeiro, substitua user/repo-name no seguinte Dockerfile pelo caminho para seu repo privado (certifique-se de manter o prefixo [email protected] para que ssh seja usado para checkout):

FROM ubuntu:latest

ARG SSH_KEY
ENV MY_REPO [email protected]:user/repo-name.git

RUN apt-get update && apt-get -y install openssh-client git-core &&\
    mkdir -p /root/.ssh && chmod 0700 /root/.ssh && \
    ssh-keyscan github.com >/root/.ssh/known_hosts

RUN echo "$SSH_KEY" >/root/.ssh/id_rsa &&\
    chmod 0600 /root/.ssh/id_rsa &&\
    git clone "${MY_REPO}" &&\
    rm -f /root/.ssh/id_rsa

Em seguida, construa com o comando

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

passando o caminho correto para sua chave SSH privada.

^ com Docker 1.9

@benton Você pode querer olhar de perto a saída de docker inspect sshtest e docker history sshtest . Acho que você descobrirá que os metadados na imagem final contêm seu segredo, mesmo que não estejam disponíveis no próprio contexto do contêiner ...

@ljrittle Good spotting. A chave está realmente lá se você usar um VAR . Acho que uma solução alternativa externa ainda é necessária aqui.

Talvez uma razão pela qual uma solução nativa ainda não foi desenvolvida seja porque várias soluções alternativas _existem_ em vigor. Mas eu concordo com a maioria dos outros aqui que uma solução integrada serviria melhor aos usuários e se encaixaria na filosofia de "baterias incluídas" do Docker.

Dos documentos ...

Observação: não é recomendado usar variáveis ​​de tempo de compilação para passar segredos como chaves do github, credenciais de usuário etc.

(https://docs.docker.com/engine/reference/builder/#arg)

Não acho que um caminho para um arquivo se aplique a isso, a nota é sobre deixar uma senha / token totalmente visível no log do console.

Eu não sigo @jcrombez. O exemplo foi passar a chave ssh como uma variável via ARG . Então, ele se aplica.

Em termos de risco de segurança, isso é muito diferente:

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

do que este:

docker build --tag=sshtest --build-arg SSH_KEY="mykeyisthis" .

se alguém encontrar o log do seu terminal, as consequências não são as mesmas.
mas não sou um especialista em segurança, isso ainda pode ser perigoso por alguns outros motivos dos quais não tenho conhecimento.

Na linha de comando, suponho.

No entanto, como @ljrittle apontou e @benton admitiu, qualquer maneira que você usar --build-arg / ARG será comprometida na construção. Portanto, inspecioná-lo revelará informações sobre a chave. Ambos saem do estado no contêiner docker final e ambos sofrem a mesma vulnerabilidade nessa extremidade. Portanto, por que docker não recomenda fazer isso.

_USER POLL_

_A melhor maneira de ser notificado sobre atualizações é usar o botão _Subscribe_ nesta página._

Não use comentários "+1" ou "Eu também tenho" nas questões. Nós automaticamente
colete esses comentários para manter o tópico curto.

As pessoas listadas abaixo votaram a favor deste problema, deixando um comentário de +1:

@ fletcher91
@benlemasurier
@dmuso
@probepark
@saada
@ianAndrewClark
@jakirkham
@galindro
@luisguilherme
@akurkin
@allardhoeve
@SevaUA
@sankethkatta
@kouk
@cliffxuan
@ kotlas92
@taion

_USER POLL_

_A melhor maneira de ser notificado sobre atualizações é usar o botão _Subscribe_ nesta página._

Não use comentários "+1" ou "Eu também tenho" nas questões. Nós automaticamente
colete esses comentários para manter o tópico curto.

As pessoas listadas abaixo votaram a favor deste problema, deixando um comentário de +1:

@parknicker
@dursk
@adambiggs

Em termos de risco de segurança, isso é muito diferente:

docker build --tag=sshtest --build-arg SSH_KEY="$(cat ~/.ssh/path-to-private.key)" .

além de sua história do bash, eles são exatamente os mesmos; há muitos lugares onde essa informação pode acabar.

Por exemplo, considere que as solicitações de API podem ser registradas no servidor;

Aqui está um log daemon para docker build --tag=sshtest --build-arg SSH_KEY="fooobar" .

DEBU[0090] Calling POST /v1.22/build
DEBU[0090] POST /v1.22/build?buildargs=%7B%22SSH_KEY%22%3A%22fooobar%22%7D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&memory=0&memswap=0&rm=1&shmsize=0&t=sshtest&ulimits=null
DEBU[0090] [BUILDER] Cache miss: &{[/bin/sh -c #(nop) ARG SSH_KEY]}
DEBU[0090] container mounted via layerStore: /var/lib/docker/aufs/mnt/de3530a82a1a141d77c445959e4780a7e1f36ee65de3bf9e2994611513790b8c
DEBU[0090] container mounted via layerStore: /var/lib/docker/aufs/mnt/de3530a82a1a141d77c445959e4780a7e1f36ee65de3bf9e2994611513790b8c
DEBU[0090] Skipping excluded path: .wh..wh.aufs
DEBU[0090] Skipping excluded path: .wh..wh.orph
DEBU[0090] Applied tar sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef to 91f79150f57d6945351b21c9d5519809e2d1584fd6e29a75349b5f1fe257777e, size: 0
INFO[0090] Layer sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef cleaned up

_USER POLL_

_A melhor maneira de ser notificado sobre atualizações é usar o botão _Subscribe_ nesta página._

Não use comentários "+1" ou "Eu também tenho" nas questões. Nós automaticamente
colete esses comentários para manter o tópico curto.

As pessoas listadas abaixo votaram a favor deste problema, deixando um comentário de +1:

@ cj2

Estou tentando criar um contêiner de um aplicativo simples de rubi / rack. O Gemfile faz referência a várias joias privadas. No momento em que bundle install começa e tenta acessar os repositórios privados, eu começo a receber este erro

Host key verification failed.
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Consegui contornar isso, mas não sem expor minha chave privada. Isso não vai dar certo. Ative o encaminhamento de autenticação ssh.

+1 para encaminhamento de ssh durante as compilações. Não é possível usar go get com repositórios privados por causa disso; (

+1 para habilitar este caso de uso de maneira segura

_USER POLL_

_A melhor maneira de ser notificado sobre atualizações é usar o botão _Subscribe_ nesta página._

Não use comentários "+1" ou "Eu também tenho" nas questões. Nós automaticamente
colete esses comentários para manter o tópico curto.

As pessoas listadas abaixo votaram a favor deste problema, deixando um comentário de +1:

@lukad

Apenas lendo esta discussão muito interessante, estou me perguntando se uma solução simples pode resolver esses problemas. No topo da minha cabeça, eu estou pensando, uma opção no Dockerfile para apenas ser capaz de excluir / ignorar diretórios / arquivos internos específicos ao tirar instantâneos. Quão difícil isso poderia ser?

ie

EXCLUIR .ssh

Estou pensando que se aplicaria a todas as etapas a seguir, então se você colocou depois de FROM, então você poderia adicionar suas chaves o quanto quiser e construir normalmente e nunca precisa se preocupar com as chaves acidentalmente acabando em sua imagem (concedido você pode precisar adicioná-los a cada etapa que os requer, mas você não precisa se preocupar com eles acabando em uma imagem)

A sugestão de @benton funciona bem, e o docker daemon só registrará a chave id_rsa se estiver no modo de depuração.

Uma maneira ainda mais fofa de expor sua chave durante a compilação é:

# Dockerfile
ARG SSH_KEY
RUN eval `ssh-agent -s` > /dev/null \
    && echo "$SSH_KEY" | ssh-add - \
    && git clone [email protected]:private/repository.git

docker build -t my_tag --build-arg SSH_KEY="$(< ~/.ssh/id_rsa)" .

Ha, embora esteja realmente lá se você olhar para docker inspect my_tag .. então não tenho certeza de qual é o valor real de boot-arg, além de ser um pouco mais organizado que ENV.

E, se você tiver uma senha na chave id_rsa, acho que você pode ser um mau humano e fazer:

# Dockerfile
ARG SSH_KEY
ARG SSH_PASS
RUN eval `ssh-agent -s` > /dev/null \
    && echo "echo $SSH_PASS" > /tmp/echo_ps && chmod 700 /tmp/echo_ps \
    && echo "$SSH_KEY" | SSH_ASKPASS=/tmp/echo_ps DISPLAY= ssh-add - \
    && git clone [email protected]:private/repository.git
    && rm /tmp/echo_ps

docker build -t my_tag --build-arg SSH_KEY="$(< ~/.ssh/id_rsa)" --build-arg SSH_PASS=<bad_idea> .

É claro que é difícil racionalizar que é mesmo remotamente uma boa ideia ... mas somos todos humanos, suponho.

Concedido, todos os maiores motivos para fazer isso parecem ser para as pessoas fazendo "bundle install" ou "go get" em repositórios privados durante uma compilação.

Eu diria apenas vender suas dependências e ADICIONAR todo o projeto ... mas, às vezes, as coisas precisam ser feitas agora.

@SvenDowideit @thaJeztah Existe alguma solução para este problema? Tentei seguir o thread, mas entre fechar e abrir outros threads e muitas opiniões, não tenho ideia do que a equipe do Docker fará ou quando.

O melhor, mas precisa de implementação?

A compilação do Docker usa o agente ssh dentro da compilação para proxy para o ssh do seu host e, em seguida, usa suas chaves sem precisar conhecê-las!

Para qualquer um que acabou de aprender sobre proxy ssh-agent: github para o resgate

ideia original de @phemmer .

@yordis Não acho que haja uma solução "ótima" no tópico que ainda esteja disponível gratuitamente.

Este comentário de docker / docker-py # 980 parece indicar que se você copiar suas chaves ssh para o diretório de chaves do usuário root em seu sistema host, o daemon usará essas chaves. No entanto, sou um novato louco a este respeito, então alguém pode ser capaz de esclarecer.


Ok mas não o melhor

Passando a chave com argumentos de compilação do docker 1.8.
Advertências .

Definitivamente uma má ideia

Muitas pessoas também recomendaram adicionar a chave temporariamente ao contexto de construção e removê-la rapidamente. Parece muito perigoso porque se a chave entrar em um dos commits, qualquer um que usar o container pode acessar aquela chave checando um commit em particular.


Por que isso ainda não foi a lugar nenhum?

É necessária uma proposta de design, esta questão é _cah_- _luttered_ e as ideias são apenas vagas no momento. Os detalhes reais da implementação estão sendo perdidos em uma névoa de "e se fizéssemos x" e + 1s. Para se organizar e avançar neste recurso tão necessário, aqueles que têm soluções possíveis devem criar um. . .

Proposta de projeto

e, em seguida, referencie esse problema.

Tenho algumas novidades sobre este assunto.

Na DockerCon, na semana passada, fomos incentivados a trazer nossas perguntas mais difíceis para o pavilhão "Ask the Experts" do Docker, então fui e conversei brevemente com um engenheiro inteligente e amigável com o título encorajador de Arquiteto de Soluções. Dei a ele um breve resumo deste problema, que espero ter transmitido com precisão, porque ele me garantiu que isso pode ser feito com _apenas_ docker-compose ! Os detalhes do que ele estava propondo envolviam uma construção de vários estágios - talvez para acumular as dependências em um contexto diferente do que a versão final do aplicativo - e parecia envolver o uso de volumes de dados no momento da construção.

Infelizmente, não tenho experiência com docker-compose, então não pude acompanhar todos os detalhes, mas ele me garantiu que se eu escrevesse para ele com o problema exato, ele responderia com uma solução. Então, escrevi o que espero ser um e-mail claro o suficiente , que inclui uma referência a este problema aberto do GitHub. E eu ouvi de volta dele esta manhã, com sua garantia de que ele responderá quando ele vier com alguma coisa.

Tenho certeza de que ele está muito ocupado, então não esperaria nada imediato, mas acho isso encorajador, na medida em que ele entendeu o problema e está pronto para atacá-lo apenas com o conjunto de ferramentas nativo do docker.

@benton Eu uso a seguinte configuração de docker-compose.yaml para fazer as coisas descritas neste tópico:

version: '2'
services:
  serviceName:
     volumes:
      - "${SSH_AUTH_SOCK}:/tmp/ssh-agent"
    environment:
      SSH_AUTH_SOCK: /tmp/ssh-agent

Certifique-se de que o ssh-agent tenha iniciado na máquina host e saiba sobre a chave (você pode verificá-lo com o comando ssh-add -L).

Observe que você pode precisar adicionar

Host *
  StrictHostKeyChecking no

para .ssh / config do contêiner.

Olá @WoZ! obrigado pela sua resposta, parece bastante simples, então vou tentar :)

Eu tenho uma pergunta, porém, como você pode usar isso com compilações automatizadas no hub do docker? Até onde eu sei, não há como usar um arquivo de composição aqui :(

@garcianavalon funciona bem, mas é apenas para run , não build . Ainda não está funcionando com o Docker para Mac, embora esteja aparentemente na lista de tarefas.

Editar: https://github.com/docker/for-mac/issues/410

Criamos mais 2 soluções alternativas para nossas necessidades específicas:

1) Configure nosso próprio espelho de pacote para npm, pypi, etc. atrás de nossa VPN, desta forma não precisamos de SSH.

2) Já temos acesso a repositórios privados em todas as máquinas host, portanto, clonamos / baixamos o pacote privado localmente na máquina host, executamos a instalação do pacote para baixá-lo e, em seguida, usamos -v para mapear o volume para o docker e, em seguida, construímos o docker.

No momento, estamos usando a opção 2).

Até docker run , docker-ssh-agent-forward parece fornecer uma solução elegante e funciona em Docker para Mac / Linux.

Ainda pode ser uma boa ideia COPIAR o arquivo known_hosts do host em vez de criá-lo no contêiner (menos seguro), visto que o ssh-agent não parece encaminhar hosts conhecidos.

Mas o problema fundamental em extrair dependências privadas durante uma etapa de execução do docker é ignorar o cache de compilação do docker, o que pode ser muito significativo em termos de tempo de compilação.

Uma abordagem para contornar esta limitação é md5 / date suas declarações de dependência de construção (por exemplo, package.json ), enviar o resultado para uma imagem e reutilizar a mesma imagem se o arquivo não tiver mudado. Usar o hash no nome da imagem permitirá o armazenamento em cache de vários estados. Teria de ser combinado com o resumo da imagem de pré-instalação também.

Isso deve ser mais robusto do que a solução da @aidanhs para construir servidores, embora eu ainda tenha que testá-lo em escala.

Isso deve ser mais robusto do que a solução da @aidanhs para construir servidores, embora eu ainda tenha que testá-lo em escala.

Minha solução específica não funcionou desde 1.9.0 - descobri que o recurso introduzido no 1.8.0, no qual eu estava contando, não era intencional e por isso foi removido.

Embora o princípio da minha solução permaneça bom (requer apenas que você tenha um servidor DNS fora de sua máquina que a) sua máquina use eb) você seja capaz de adicionar entradas em locais apropriados), não posso dizer que estou entusiasmado recomendo mais.

Obrigado pela informação extra @aidanhs!

Algumas atualizações em relação à minha solução proposta: os hashes não precisam realmente ser combinados como o hash da imagem base logo após adicionar o arquivo de declaração de dependências, simplesmente podem ser usados. Além disso, é melhor simplesmente montar o arquivo known_host como um volume, já que o ssh-agent só pode ser usado em tempo de execução - e mais seguro porque contém uma lista de todos os hosts aos quais você se conecta.

Implementei a solução completa para node / npm e ela pode ser encontrada aqui com documentação detalhada e exemplos: https://github.com/iheartradio/docker-node

Claro, os princípios podem ser estendidos para outras estruturas.

O mesmo problema aqui, como alguém constrói algo, onde esse algo requer credenciais SSH a fim de verificar e construir uma série de projetos em tempo de construção, dentro de um contêiner docker, sem gravar credenciais na imagem ou imagem de base.

Nós contornamos isso tendo um processo de construção de 2 etapas. Uma imagem "build" contendo as dependências source / keys / build é criada. Depois de compilado, ele é executado para extrair os resultados da compilação em um tarfile que mais tarde é adicionado a uma imagem de "implantação". A imagem de construção é então removida e tudo o que é publicado é a imagem de "implantação". Isso tem um bom efeito colateral de manter o tamanho do contêiner / camada baixo.

@ binarytemple-bet365 consulte https://github.com/iheartradio/docker-node para um exemplo de ponta a ponta fazendo exatamente isso. Eu uso mais de duas etapas, pois uso um contêiner de serviço ssh, pré-instalo (imagem base até antes de instalar dependências privadas), instalo (estado do contêiner após a instalação em tempo de execução de dependências privadas) e pós-instalação (adiciona comandos que você tinha após a instalação de dependências privadas) para otimizar a velocidade e separação de interesses.

Confira Rocker , é uma solução limpa.

@Sodki Segui seu conselho. Sim, o rocker é uma solução limpa e bem pensada. É uma pena que a equipe do docker não tenha simplesmente assumido o controle desse projeto e descontinuado docker build . Obrigada.

Ainda não há maneira melhor? :(

Alguém já experimentou essa nova coisa de squash? https://github.com/docker/docker/pull/22641 Pode ser a solução nativa do docker que estamos procurando. Vou tentar agora e relatar para ver como funciona.

Depois de mais de 2 anos, isso ainda não está corrigido 😞 Por favor, a equipe do Docker faça algo a respeito

Parece que a nova opção --squash em 1.13 funciona para mim:
http://g.recordit.co/oSuMulfelK.gif

Eu o construo com: docker build -t report-server --squash --build-arg SSH_KEY="$(cat ~/.ssh/github_private_key)" .

Portanto, quando faço docker history ou docker inspect , a chave não aparece.

Meu Dockerfile se parece com isto:

FROM node:6.9.2-alpine

ARG SSH_KEY

RUN apk add --update git openssh-client && rm -rf /tmp/* /var/cache/apk/* &&\
  mkdir -p /root/.ssh && chmod 0700 /root/.ssh && \
  ssh-keyscan github.com > /root/.ssh/known_hosts

RUN echo "$SSH_KEY" > /root/.ssh/id_rsa &&\
  chmod 0600 /root/.ssh/id_rsa

COPY package.json .

RUN npm install
RUN rm -f /root/.ssh/id_rsa

# Bundle app source
COPY . .

EXPOSE 3000

CMD ["npm","start"]

@ kienpham2000 , sua captura de tela parece que ainda contém as chaves - você poderia verificar a saída de docker history com a sinalização --no-trunc e relatar aqui se as chaves privadas são ou não exibidas no docker história?

@ryanschwartz você está certo, o --no-trunc mostra a coisa toda, isso não funciona.

@ kienpham2000
Outra coisa que eles introduziram na versão 1.13 é:

Crie segredos
• habilita segredos de tempo de construção usando - sinalizador de segredo de construção
• cria tmpfs durante a compilação e expõe segredos para o
contêineres de construção, para serem usados ​​durante a construção.
https://github.com/docker/docker/pull/28079

Talvez isso pudesse funcionar?

Os segredos de compilação não chegaram ao 1.13, mas espero que o façam no 1.14.

Em 15 de dezembro de 2016, às 9h45, "Alex" [email protected] escreveu:

@ kienpham2000 https://github.com/kienpham2000
Outra coisa que eles introduziram na versão 1.13 é:

Crie segredos
• habilita segredos de tempo de construção usando - sinalizador de segredo de construção
• cria tmpfs durante a compilação e expõe segredos para o
contêineres de construção, para serem usados ​​durante a construção.
• # 28079 https://github.com/docker/docker/pull/28079

Talvez isso pudesse funcionar?

-
Você está recebendo isto porque está inscrito neste tópico.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/docker/docker/issues/6396#issuecomment-267393020 ou mudo
o segmento
https://github.com/notifications/unsubscribe-auth/AAdcPDxrctBP2TlCtXen-Y_uY8Y8B09Sks5rIXy2gaJpZM4CD4SM
.

Então, um ano depois: Não, isso é uma má ideia. Você não deveria fazer isso. Existem várias outras soluções. Por exemplo, o Github pode fornecer tokens de acesso. Você pode usá-los em arquivos de configuração / variáveis ​​de ambiente com menos risco, pois pode especificar quais ações são permitidas para cada token.

A solução é implementar o encaminhamento SSH. Como o Vagrant faz, por exemplo.

Alguém pode me explicar porque é tão complicado implementar isso?

@omarabid - você está respondendo à sua proposta original de usar variáveis ​​de ambiente para passar chaves privadas a serem usadas no Dockerfile? Não há dúvida de que essa é uma prática de segurança ruim.

Quanto à sua sugestão de usar tokens de acesso, eles acabariam armazenados em uma camada e podem ser tão perigosos de serem deixados por aí quanto uma chave SSH. Mesmo que ele tenha acesso somente leitura, a maioria das pessoas não gostaria que outras pessoas tivessem acesso somente leitura a seus repositórios. Além disso, a revogação / rotação / distribuição frequente precisaria ocorrer; isso é um pouco mais fácil de lidar para cada desenvolvedor, etc., em vez de tokens de acesso "mestre".

A solução de segredos de compilação mencionada alguns comentários atrás parece ser um passo na direção certa, mas a capacidade de usar um agente SSH é melhor. Talvez alguém pudesse usar um agente SSH em combinação com segredos de compilação, não tenho certeza.

É natural que os desenvolvedores / sistemas de CI usem um agente SSH durante as operações git / build. Isso é muito mais seguro do que ter uma chave privada de texto simples, sem senha, que deve ser revogada / substituída em massa em uma variedade de sistemas. Além disso, com os agentes SSH, não há possibilidade de os dados da chave privada serem confirmados em uma imagem. Na pior das hipóteses, uma variável de ambiente / remanescente SSH_AUTH_SOCK será deixada para trás na imagem.

Obtive esta solução alternativa mais recente sem mostrar o conteúdo da chave secreta ou usar a ferramenta docker extra de terceiros (espero que o cofre secreto durante o PR criado seja mesclado em breve).

Estou usando o aws cli para baixar a chave privada compartilhada do S3 para o repositório atual do host. Esta chave é criptografada em repouso usando KMS. Assim que a chave for baixada, o Dockerfile irá apenas COPIAR essa chave durante o processo de compilação e removê-la depois, o conteúdo não aparece em docker inspect ou docker history --no-trunc

Baixe a chave privada github do S3 primeiro para a máquina host:

# build.sh
s3_key="s3://my-company/shared-github-private-key"
aws configure set s3.signature_version s3v4
aws s3 cp $s3_key id_rsa --region us-west-2 && chmod 0600 id_rsa

docker build -t app_name .

O Dockerfile se parece com isto:

FROM node:6.9.2-alpine

ENV id_rsa /root/.ssh/id_rsa
ENV app_dir /usr/src/app

RUN mkdir -p $app_dir
RUN apk add --update git openssh-client && rm -rf /tmp/* /var/cache/apk/* && mkdir -p /root/.ssh && ssh-keyscan github.com > /root/.ssh/known_hosts

WORKDIR $app_dir

COPY package.json .
COPY id_rsa $id_rsa
RUN npm install && npm install -g gulp && rm -rf $id_rsa

COPY . $app_dir
RUN rm -rf $app_dir/id_rsa

CMD ["start"]

ENTRYPOINT ["npm"]

@ kienpham2000 , por que essa solução não manteria a chave na camada da imagem? As ações de copiar e remover a chave estão sendo feitas em comandos separados, portanto existe uma camada que deve ter a chave.
Nossa equipe estava usando a sua solução até ontem, mas encontramos uma solução melhorada:

  • Geramos uma URL de pré-assinatura para acessar a chave com 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 seguida, no dockerfile, adicionamos à imagem.
  • No dockerfile, temos um comando RUN que executa todas essas etapas: use a URL de pré-inscrição para obter a chave ssh, execute npm install e remova a chave ssh.
    Fazendo isso em um único comando, a chave ssh não seria armazenada em nenhuma camada, mas a URL de pré-assinatura seria 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 se parece com isto:

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

@diegocsandrim obrigado por apontar isso, gostei muito da sua solução, vou atualizar nosso material aqui. Obrigado por compartilhar!

Eu sou um pouco novo no tópico, mas fundamentalmente parece que as pessoas estão tentando resolver um problema melhor resolvido por PKI. Nem todo mundo está necessariamente tentando salvar o mesmo problema em que PKI seria a melhor solução, mas referências suficientes parecem indicar que pode ser algo que deve ser considerado.

Parece irritante, mas fundamentalmente possível

  • criar uma autoridade de certificação local
  • tem um processo para gerar um certificado
  • tem um processo para emitir o certificado
  • ter um processo para revogar o referido certificado
  • fazer daemons ssh usar PKI

E se as pessoas acharem que isso é viável, por favor, crie-o e abra o código-fonte, afinal o trabalho precisa ser feito bem uma vez. Não tenho ideia se a compilação de roumen petrov é segura e não anotei nenhum código-fonte (não verifiquei o tar), então não tenho ideia de quão segura é.

https://security.stackexchange.com/questions/30396/how-to-set-up-openssh-to-use-x509-pki-for-authentication

https://jamielinux.com/docs/openssl-certificate-authority/create-the-root-pair.html

@mehmetcodes : Ter uma PKI não resolve realmente o problema. Para que a autenticação SSH baseada em PKI funcione, você ainda precisará carregar a chave privada para a imagem.

A menos que sua autoridade de certificação local emita certificados de curta duração (por exemplo, menos de uma hora) e revogue o certificado imediatamente após uma construção bem-sucedida, isso não é seguro.

Se você conseguir criar um processo de certificado de curta duração, isso não será muito diferente do que apenas usar uma nova chave SSH que você revoga imediatamente após o término da compilação.

Oh, é ainda mais irritante do que isso, mas devo estar certa de alguma coisa ou por que ela existiria na selva?

https://blog.cloudflare.com/red-october-cloudflares-open-source-implementation-of-the-two-man-rule/
https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/

Não sei, uma chave temporária SSH é provavelmente muito melhor para a maioria dos casos de uso, mas há algo preocupante sobre cada recurso, incluindo o que sugeri, especialmente neste contexto.

Em vez disso, você normalmente apenas montaria um volume com a tecla, mas isso não elimina a necessidade do docker para solução Mac / moby.

quem diabos é moby?

@cor branca
Image of Moby

Eu cheguei a este ponto no MacOS:

bash-3.2$ docker run -t -i -v "$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" python:3.6 ssh-add -l
docker: Error response from daemon: Mounts denied:
The path /var/folders/yb/880w03m501z89p0bx7nsxt580000gn/T//ssh-DcwJrLqQ0Vu1/agent.10466
is not shared from OS X and is not known to Docker.
You can configure shared paths from Docker -> Preferences... -> File Sharing.
See https://docs.docker.com/docker-for-mac/osxfs/#namespaces for more info.
.

/ var / é um alias, com o qual o Docker parece ter dificuldade. Mas se eu prefixo o caminho $ SSH_AUTH_SOCK com /private (ou seja, o caminho do alias resolvido), o Docker pode ler o arquivo, mas eu obtenho:

bash-3.2$ docker run -t -i -v "/private$SSH_AUTH_SOCK:/tmp/ssh_auth_sock" -e "SSH_AUTH_SOCK=/tmp/ssh_auth_sock" python:3.6 ssh-add -l
Could not open a connection to your authentication agent.

Neste ponto, estou me perguntando o quão ruim é apenas ...

docker run -v ~/.ssh:/root/.ssh python:3.6 bash

?

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

E, em seguida, dentro do arquivo Docker:

ARG ssh_prv_key
ARG ssh_pub_key

# 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

E não se esqueça de incluir

RUN rm -f /root/.ssh/id_rsa /root/.ssh/id_rsa.pub

como a etapa final.

O problema aqui é que sua chave privada não deve ser protegida por senha.

O problema com o comentário anterior é que as chaves acabam nas camadas ... rm não exclui de uma camada anterior, pois cada linha em um arquivo docker é uma camada.

docker secret resolve este problema?
WDYT @thaJeztah

docker secret não está (ainda) disponível durante a compilação e apenas disponível em serviços (portanto, ainda não para docker run )

Ao usar compilações de vários estágios, algo como isso pode funcionar (digitando no meu telefone, então deixe-me vincular uma essência que criei há algum tempo); https://gist.github.com/thaJeztah/836c4220ec024cf6dd48ffa850f07770

Não estou mais tão envolvido com o Docker, mas, como é possível que esse problema exista há tanto tempo. Não estou tentando gritar, mas sim entender qual é o esforço necessário para consertar isso porque, quando eu estava lidando com isso, parecia um problema muito comum para qualquer empresa que puxa pacotes privados como ruby gems de um repo privado.

O Moby preocupa com este problema? Por que tem que ser tão difícil para algo que não parece grande coisa, eu acho.

Já se passaram quase 3 anos 😢

@yordis docker builder ficou congelado por um ou dois anos. A equipe do Docker afirmou que o builder é bom o suficiente e que eles concentram seus esforços em outro lugar. Mas isso acabou e houve duas mudanças no construtor desde então. Construções de estágio de squash e mustli. Portanto, os segredos do buildtime podem estar a caminho.

Para encaminhamento em tempo de execução do agente ssh, eu recomendaria https://github.com/uber-common/docker-ssh-agent-forward

Por que tem que ser tão difícil para algo que não parece grande coisa, eu acho.

@yord está lendo a descrição principal deste problema, implementá-lo está longe de ser trivial; Posto isto, se alguém tiver uma proposta de desenho técnico para isso, fique à vontade para abrir um fascículo ou RP para discussão. Observe também que para a parte _build_, um projeto buildkit foi iniciado para melhorias futuras para o construtor; https://github.com/moby/buildkit

@thaJeztah Eu gostaria de ter as habilidades necessárias, mas não tenho.

@villlem , você conhece algum roteiro da equipe do Docker?

Os relatórios semanais do construtor podem ser encontrados aqui; https://github.com/moby/moby/tree/master/reports/builder segredos de tempo de construção ainda estão listados no relatório mais recente, mas poderia usar a ajuda

Estamos usando a solução @diegocsandrim , mas com uma etapa de criptografia intermediária para evitar deixar uma chave SSH não criptografada no S3.

Essa etapa extra significa que a chave não pode ser recuperada da imagem do Docker (o URL para fazer o download expira após cinco minutos) e não pode ser recuperada do AWS (pois é criptografada com uma senha rotativa conhecida apenas pela imagem do docker) .

Em build.sh:

BUCKET_NAME=my_bucket
KEY_FILE=my_unencrypted_key
openssl rand -base64 -out passfile 64
openssl enc -aes-256-cbc -salt -in $KEY_FILE -kfile passfile | aws s3 cp - s3://$BUCKET_NAME/$(hostname).enc_key
aws s3 presign s3://$BUCKET_NAME/$(hostname).enc_key --expires-in 300 > ./pre_sign_url
docker build -t my_service

E no Dockerfile:

COPY . .

RUN eval "$(ssh-agent -s)" && \
    wget -i ./pre_sign_url -q -O - | openssl enc -aes-256-cbc -d -kfile passfile > ./my_key && \
    chmod 700 ./my_key && \
    ssh-add ./my_key && \
    mkdir /root/.ssh && \
    chmod 0700 /root/.ssh && \
    ssh-keyscan github.com > /root/.ssh/known_hosts && \
    [commands that require SSH access to Github] && \
    rm ./my_key && \
    rm ./passfile && \
    rm -rf /root/.ssh/

se você estiver usando docker run você deve montar seu .ssh com --mount type=bind,source="${HOME}/.ssh/",target="/root/.ssh/",readonly . O readonly é a mágica, ele mascara as permissões normais e o ssh basicamente vê 0600 permissões com as quais está satisfeito. Você também pode brincar com -u root:$(id -u $USER) para que o usuário root no contêiner escreva quaisquer arquivos que ele criar com o mesmo grupo de seu usuário, então espero que você possa pelo menos lê-los, se não escrevê-los totalmente, sem ter que chmod / chown .

Finalmente.

Acredito que este problema agora pode ser resolvido usando apenas docker build , usando compilações de vários estágios .
Apenas COPY ou ADD a chave SSH ou outro segredo onde quer que você precise, e use-o em RUN instruções como quiser.

Em seguida, use uma segunda instrução FROM para iniciar um novo sistema de arquivos e COPY --from=builder para importar algum subconjunto de diretórios que não incluem o segredo .

(Na verdade, ainda não tentei isso, mas se o recurso funcionar conforme descrito ...)

@benton multi-stage builds funcionam conforme descrito, nós o usamos. É de longe a melhor opção para muitos problemas diferentes, incluindo este.

Eu verifiquei a seguinte técnica:

  1. Passe a _localização de uma chave privada_ como um argumento de construção, como GITHUB_SSH_KEY , para o primeiro estágio de uma construção de vários estágios
  2. Use ADD ou COPY para escrever a chave onde quer que seja necessária para autenticação. Observe que se a localização da chave for um caminho do sistema de arquivos local (e não um URL), _não_ deve estar no arquivo .dockerignore ou a diretiva COPY não funcionará. Isso tem implicações para a imagem final, como você verá na etapa 4 ...
  3. Use a chave conforme necessário. No exemplo abaixo, a chave é usada para autenticação no GitHub. Isso também funciona para os repositórios Ruby bundler e Gem privados. Dependendo de quanto da base de código você precisa incluir neste ponto, você pode acabar adicionando a chave novamente como um efeito colateral do uso de COPY . ou ADD . .
  4. REMOVA A CHAVE SE NECESSÁRIO . Se a localização da chave for um caminho do sistema de arquivos local (e não um URL), é provável que tenha sido adicionado ao lado da base de código quando você fez ADD . ou COPY . Este é provavelmente _precisamente o diretório_ que será copiado para a imagem final do tempo de execução, então você provavelmente também deseja incluir uma instrução RUN rm -vf ${GITHUB_SSH_KEY} quando terminar de usar a chave.
  5. Depois que seu aplicativo estiver completamente integrado em WORKDIR , inicie o segundo estágio de compilação com uma nova instrução FROM , indicando a imagem de tempo de execução desejada. Instale todas as dependências de tempo de execução necessárias e, em seguida, COPY --from=builder contra WORKDIR do primeiro estágio.

Aqui está um exemplo Dockerfile que demonstra a técnica acima. Fornecer um argumento de construção GITHUB_SSH_KEY testará a autenticação do GitHub durante a construção, mas os dados-chave _não_ serão incluídos na imagem final do tempo de execução. O GITHUB_SSH_KEY pode ser um caminho do sistema de arquivos (dentro do diretório de compilação do Docker) ou um URL que fornece os dados da chave, mas a própria chave não deve ser criptografada neste exemplo.

########################################################################
# BUILD STAGE 1 - Start with the same image that will be used at runtime
FROM ubuntu:latest as builder

# ssh is used to test GitHub access
RUN apt-get update && apt-get -y install ssh

# The GITHUB_SSH_KEY Build Argument must be a path or URL
# If it's a path, it MUST be in the docker build dir, and NOT in .dockerignore!
ARG GITHUB_SSH_KEY=/path/to/.ssh/key

  # Set up root user SSH access for GitHub
ADD ${GITHUB_SSH_KEY} /root/.ssh/id_rsa

# Add the full application codebase dir, minus the .dockerignore contents...
# WARNING! - if the GITHUB_SSH_KEY is a file and not a URL, it will be added!
COPY . /app
WORKDIR /app

# Build app dependencies that require SSH access here (bundle install, etc.)
# Test SSH access (this returns false even when successful, but prints results)
RUN ssh -o StrictHostKeyChecking=no -vT [email protected] 2>&1 | grep -i auth

# Finally, remove the $GITHUB_SSH_KEY if it was a file, so it's not in /app!
# It can also be removed from /root/.ssh/id_rsa, but you're probably not going
# to COPY that directory into the runtime image.
RUN rm -vf ${GITHUB_SSH_KEY} /root/.ssh/id*

########################################################################
# BUILD STAGE 2 - copy the compiled app dir into a fresh runtime image
FROM ubuntu:latest as runtime
COPY --from=builder /app /app

Pode ser _poderia_ ser mais seguro passar os próprios dados-chave no argumento de construção GITHUB_SSH_KEY , em vez de _localização_ dos dados-chave. Isso evitaria a inclusão acidental dos dados da chave se eles estiverem armazenados em um arquivo local e, em seguida, adicionados com COPY . . No entanto, isso exigiria o uso de echo e redirecionamento de shell para gravar os dados no sistema de arquivos, o que pode não funcionar em todas as imagens de base. Use a técnica mais segura e viável para seu conjunto de imagens de base.

@jbiel Mais um ano, e a solução que encontrei é usar algo como o Vault.

Aqui está um link com 2 métodos (squash e container intermediário descritos anteriormente por @benton)

Estou apenas adicionando uma observação para dizer que nenhuma das abordagens atuais funcionará se você tiver uma senha longa na chave ssh que está usando, pois o agente solicitará a senha sempre que você executar a ação que requer acesso. Não acho que haja uma maneira de contornar isso sem passar a frase-chave (o que é indesejável por uma série de razões)

Resolvendo.
Crie um script bash (~ / bin / docker-compose ou similar):

#!/bin/bash

trap 'kill $(jobs -p)' EXIT
socat TCP-LISTEN:56789,reuseaddr,fork UNIX-CLIENT:${SSH_AUTH_SOCK} &

/usr/bin/docker-compose $@

E no Dockerfile usando socat:

...
ENV SSH_AUTH_SOCK /tmp/auth.sock
...
  && apk add --no-cache socat openssh \
  && /bin/sh -c "socat -v UNIX-LISTEN:${SSH_AUTH_SOCK},unlink-early,mode=777,fork TCP:172.22.1.11:56789 &> /dev/null &" \
  && bundle install \
...
or any other ssh commands will works

Em seguida, execute docker-compose build

@benton, por que você usa RUN rm -vf ${GITHUB_SSH_KEY} /root/.ssh/id* ? Não deveria ser apenas RUN rm -vf /root/.ssh/id* ? Ou talvez eu tenha entendido mal a intenção aqui.

@benton E também não é seguro fazer:

RUN ssh -o StrictHostKeyChecking=no -vT [email protected] 2>&1

Você tem que verificar a impressão digital

Eu resolvi este problema desta forma

ARGS USERNAME
ARGS PASSWORD
RUN git config --global url."https://${USERNAME}:${PASSWORD}@github.com".insteadOf "ssh://[email protected]"

então construa com

docker build --build-arg USERNAME=use --build-arg PASSWORD=pwd. -t service

Mas, a princípio, seu servidor git privado deve suportar username:password clone repo.

@zeayes Comando RUN armazenado no histórico do contêiner. Portanto, sua senha fica visível para os outros.

Correto; ao usar --build-arg / ARG , esses valores aparecerão no histórico de construção. É _é_ possível usar esta técnica se você usar compilações de vários estágios _e_ confiar no host no qual as imagens são compiladas (ou seja, nenhum usuário não confiável tem acesso ao histórico de compilação local), _e_ estágios de compilação intermediários não são enviados para um registro.

Por exemplo, no exemplo a seguir, USERNAME e PASSWORD só ocorrerão no histórico para o primeiro estágio ("construtor"), mas não estarão no histórico para o estágio final;

FROM something AS builder
ARG USERNAME
ARG PASSWORD
RUN something that uses $USERNAME and $PASSWORD

FROM something AS finalstage
COPY --from= builder /the/build-artefacts /usr/bin/something

Se apenas a imagem final (produzida por "estágio final") for enviada para um registro, USERNAME e PASSWORD não estarão nessa imagem.

_Contudo_, no histórico do cache de construção local, essas variáveis ​​ainda estarão lá (e armazenadas no disco em texto simples).

O construtor de próxima geração (usando BuildKit ) terá mais recursos, também relacionados à passagem de segredos de tempo de construção; está disponível no Docker 18.06 como um recurso experimental, mas sairá do experimental em uma versão futura e mais recursos serão adicionados (eu teria que verificar se os segredos / credenciais já são possíveis na versão atual)

@kinnalru @thaJeztah thx, eu uso compilações de vários estágios, mas a senha pode ser vista no histórico do contêiner do cache, thx!

@zeayes Oh! Vejo que cometi um erro ao copiar / colar; a última etapa não deve usar FROM builder .. . Aqui está um exemplo completo; https://gist.github.com/thaJeztah/af1c1e3da76d7ad6ce2abab891506e50

Este comentário de @kinnalru é a maneira certa de fazer isso https://github.com/moby/moby/issues/6396#issuecomment -348103398

Com esse método, o docker nunca controla suas chaves privadas. E também funciona hoje, sem nenhum novo recurso adicionado.

Levei um tempo para descobrir, então aqui está uma explicação mais clara e aprimorada. Mudei o código --network=host e localhost , então você não precisa saber seu endereço IP. ( essência aqui )

Este é docker_with_host_ssh.sh , ele envolve o docker e encaminha SSH_AUTH_SOCK para uma porta no localhost:

#!/usr/bin/env bash

# ensure the processes get killed when we're done
trap 'kill $(jobs -p)' EXIT

# create a connection from port 56789 to the unix socket SSH_AUTH_SOCK (which is used by ssh-agent)
socat TCP-LISTEN:56789,reuseaddr,fork UNIX-CLIENT:${SSH_AUTH_SOCK} &
# Run docker
# Pass it all the command line args ($@)
# set the network to "host" so docker can talk to localhost
docker $@ --network='host'

No Dockerfile, conectamos por localhost ao host ssh-agent:

FROM python:3-stretch

COPY . /app
WORKDIR /app

RUN mkdir -p /tmp

# install socat and ssh to talk to the host ssh-agent
RUN  apt-get update && apt-get install git socat openssh-client \
  # create variable called SSH_AUTH_SOCK, ssh will use this automatically
  && export SSH_AUTH_SOCK=/tmp/auth.sock \
  # make SSH_AUTH_SOCK useful by connecting it to hosts ssh-agent over localhost:56789
  && /bin/sh -c "socat UNIX-LISTEN:${SSH_AUTH_SOCK},unlink-early,mode=777,fork TCP:localhost:56789 &" \
  # stuff I needed my ssh keys for
  && mkdir -p ~/.ssh \
  && ssh-keyscan gitlab.com > ~/.ssh/known_hosts \
  && pip install -r requirements.txt

Em seguida, você pode construir sua imagem invocando o script:

$ docker_with_host_ssh.sh build -f ../docker/Dockerfile .

@cowlicks, você pode estar interessado nesta solicitação pull, que adiciona suporte para docker build --ssh para encaminhar o agente SSH durante a compilação; https://github.com/docker/cli/pull/1419. A sintaxe do Dockerfile ainda não está nas especificações oficiais, mas você pode usar uma diretiva syntax=.. em seu Dockerfile para usar um front-end que a suporte (consulte o exemplo / instruções na solicitação de pull).

Essa solicitação de pull fará parte da próxima versão 18.09.

Parece que agora está disponível na versão 18.09. Uma vez que este tópico surge antes das notas de lançamento e postagem média, vou postar aqui.

Notas de versão:
https://docs.docker.com/develop/develop-images/build_enhancements/#using -ssh-to-access-private-data-in-builds

Postagem média:
https://medium.com/@tonistiigi/build -secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066

Muito exitante.

Acho que podemos fechar isso porque temos docker build --ssh agora

Problema de composição relacionado aqui: docker / compose # 6865. Funcionalidade para usar o Compose e expor o soquete do agente SSH aos contêineres que serão lançados no próximo release candidate, 1.25.0-rc3 ( releases ).

Esta página foi útil?
0 / 5 - 0 avaliações