Clonar repositório git privado com dockerfile


240

Copiei esse código do que parece ser vários arquivos docker de trabalho, aqui está o meu:

FROM ubuntu

MAINTAINER Luke Crooks "luke@pumalo.org"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git python-virtualenv

# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
ADD id_rsa /root/.ssh/id_rsa
RUN chmod 700 /root/.ssh/id_rsa
RUN chown -R root:root /root/.ssh

# Create known_hosts
RUN touch /root/.ssh/known_hosts

# Remove host checking
RUN echo "Host bitbucket.org\n\tStrictHostKeyChecking no\n" >> /root/.ssh/config

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf

Isso me dá o erro

Step 10 : RUN git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf
 ---> Running in 0d244d812a54
Cloning into '/home/docker-conf'...
Warning: Permanently added 'bitbucket.org,131.103.20.167' (RSA) to the list of known hosts.
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
2014/04/30 16:07:28 The command [/bin/sh -c git clone git@bitbucket.org:Pumalo/docker-conf.git /home/docker-conf] returned a non-zero code: 128

É a primeira vez que uso dockerfiles, mas pelo que li (e extraí das configurações de trabalho) não consigo ver por que isso não funciona.

Meu id_rsa está na mesma pasta que meu dockerfile e é uma cópia da minha chave local que pode clonar este repositório sem problemas.

Editar:

No meu dockerfile, posso adicionar:

RUN cat /root/.ssh/id_rsa

E ela imprime a chave correta, para que eu saiba que está sendo copiada corretamente.

Também tentei fazer o que Noé recomendou e corri:

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

Infelizmente, isso também não funciona.

Respostas:


300

Minha chave foi protegida por senha, causando o problema. Agora, um arquivo de trabalho está listado abaixo (para obter ajuda de futuros googlers)

FROM ubuntu

MAINTAINER Luke Crooks "luke@pumalo.org"

# Update aptitude with new repo
RUN apt-get update

# Install software 
RUN apt-get install -y git
# Make ssh dir
RUN mkdir /root/.ssh/

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
ADD id_rsa /root/.ssh/id_rsa

# Create known_hosts
RUN touch /root/.ssh/known_hosts
# Add bitbuckets key
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

11
Apenas no caso, aqui é uma ligação que descreve como remover a proteção de senha da chave
Thomas

82
Apenas um FYI, depois de executar RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts, a imagem salvará isso como uma camada. Se alguém obtiver sua imagem em espera, ela poderá recuperar a chave ... mesmo se você excluir esse arquivo em uma camada posterior, porque poderá voltar à Etapa 7 quando a adicionar.
Bernie Perez

23
Obrigado pela resposta útil. Mas, para nós, a construção falhou aleatoriamente e, após investigação, notamos que ssh-keyscano tempo limite padrão é de 5 segundos, que o bitbucket geralmente excede. ssh-keyscannem relatará um erro. Então é melhor correr RUN ssh-keyscan -T 60 bitbucket.org >> /root/.ssh/known_hostspara estar seguro.
fluidsonic 26/02

5
Alguém poderia explicar por que correr ssh-keyscané um problema? Meu entendimento é que ele simplesmente puxará a chave pública do Github / Bitbucket. Que alternativa pode ser usada para não acabar em uma camada?
Pedro

9
@Pedro A etapa de digitalização de chaves em particular não é um problema, você está claramente certo. Se alguma coisa, essas chaves públicas do host devem ser espalhadas o máximo possível. Veja sshd (8) para detalhes sobre o known_hostsarquivo. As pessoas apenas votam aleatoriamente quando soam alarmantes o suficiente.
tne

99

Você deve criar um novo conjunto de chaves SSH para essa imagem do Docker, pois provavelmente não deseja incorporar sua própria chave privada. Para fazê-lo funcionar, você precisará adicionar essa chave às chaves de implantação no seu repositório git. Aqui está a receita completa:

  1. Gere chaves ssh com as ssh-keygen -q -t rsa -N '' -f repo-keyquais você fornecerá os arquivos repo-key e repo-key.pub.

  2. Adicione repo-key.pub às chaves de implantação do repositório.
    No GitHub, vá para [seu repositório] -> Configurações -> Implementar chaves

  3. Adicione algo assim ao seu Dockerfile:

    ADICIONAR repo-key /
    CORRE \
      chmod 600 / repo-key && \  
      echo "IdentityFile / repo-key" >> / etc / ssh / ssh_config && \  
      echo -e "StrictHostKeyChecking no" >> / etc / ssh / ssh_config && \  
      // seu git clone comanda aqui ...
    

Observe que acima desativa o StrictHostKeyChecking, assim você não precisa de .ssh / known_hosts. Embora eu provavelmente goste mais da solução com o ssh-keyscan em uma das respostas acima.


6
Aviso: na minha configuração, echo -e "..." também escreve -e dentro do arquivo. Basta remover a bandeira e ela funciona bem.
Conchylicultor

Sua resposta foi absolutamente perfeita para me ajudar a resolver meu problema. Obrigado!
David Pointer

Eu ainda tenho o mesmo problema:fatal: Could not read from remote repository.
Alex

1
Obrigado milhões! Estou prestes a declarar amor por você. Você resolveu um problema que eu estava lutando há dias!
Alexandra

A resposta selecionada para esta pergunta não é mais uma boa resposta. Estava correto em 2014, mas para 2020 esta é a resposta correta.
Bikal Basnet

70

Não é necessário mexer nas configurações ssh. Use um arquivo de configuração (não um arquivo Docker) que contenha variáveis ​​de ambiente e faça com que um script de shell atualize seu arquivo docker em tempo de execução. Você mantém os tokens fora dos arquivos do Docker e pode clonar por https (não é necessário gerar ou passar chaves ssh).

Vá para Configurações> Tokens de acesso pessoal

  • Gere um token de acesso pessoal com o repoescopo ativado.
  • Clone assim: git clone https://MY_TOKEN@github.com/user-or-org/repo

Alguns comentadores observaram que, se você usar um Dockerfile compartilhado, isso poderá expor sua chave de acesso a outras pessoas em seu projeto. Embora isso possa ou não ser uma preocupação para o seu caso de uso específico, aqui estão algumas maneiras de lidar com isso:

  • Use um script de shell para aceitar argumentos que possam conter sua chave como uma variável. Substitua uma variável no seu Dockerfile por sedou similar, ou seja, chamando o script pelo sh rundocker.sh MYTOKEN=fooqual a substituição seria ativada https://{{MY_TOKEN}}@github.com/user-or-org/repo. Observe que você também pode usar um arquivo de configuração (em .yml ou em qualquer formato que desejar) para fazer a mesma coisa, mas com variáveis ​​de ambiente.
  • Crie um usuário do github (e gere um token de acesso) apenas para esse projeto

De que contexto você está falando Settings > Applications?
turboladen

1
A desvantagem dessa abordagem é que você está armazenando credenciais para um repositório particular dentro do Dockerfile, em oposição à abordagem do @ crooksey, que permitiria fazer referência a uma chave armazenada separadamente de um Dockerfile. Sem o contexto de como o OP está armazenando o Dockerfile, não podemos determinar se isso causaria um problema, mas por experiência pessoal, gosto de armazenar meus Dockerfiles em um VCS e não gostaria de confirmar nada que contenha credenciais. Depois que o Docker implementa a capacidade de passar variáveis ​​env para construir o comando, concordo que essa seria a solução mais limpa.
Jabbslad 12/15/15

2
@CalvinFroedge por localmente Presumo que você esteja se referindo ao seu host? Não conheço uma maneira de expor variáveis ​​de ambiente no host para um contêiner no momento da compilação, e é por isso que temos problemas abertos como este github.com/docker/docker/issues/6822 . Por favor, você pode esclarecer?
Jabbslad 13/05

1
Ainda mais limpo (separação de preocupações): um volume vinculado para o repositório clonado + um contêiner dedicado apenas para a tarefa de clonagem + um volume vinculado apenas com as chaves SSH (ou token, como você sugere). Consulte stackoverflow.com/a/30992047 , talvez combinado com stackoverflow.com/a/29981990 .
Peterino 14/12

9
Também a pergunta é para um repositório BITBUCKET, não para um repositório do Github.
Michael Draper

25

Outra opção é usar uma janela de encaixe de vários estágios para garantir que suas chaves SSH não sejam incluídas na imagem final.

Conforme descrito no meu post, você pode preparar sua imagem intermediária com as dependências necessárias para o git clone e, em seguida, COPYos arquivos necessários na sua imagem final.

Além disso, se tivermos LABELnossas camadas intermediárias, podemos excluí-las da máquina quando terminar.

# Choose and name our temporary image.
FROM alpine as intermediate
# Add metadata identifying these images as our build containers (this will be useful later!)
LABEL stage=intermediate

# Take an SSH key as a build argument.
ARG SSH_KEY

# Install dependencies required to git clone.
RUN apk update && \
    apk add --update git && \
    apk add --update openssh

# 1. Create the SSH directory.
# 2. Populate the private key file.
# 3. Set the required permissions.
# 4. Add github to our list of known hosts for ssh.
RUN mkdir -p /root/.ssh/ && \
    echo "$SSH_KEY" > /root/.ssh/id_rsa && \
    chmod -R 600 /root/.ssh/ && \
    ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts

# Clone a repository (my website in this case)
RUN git clone git@github.com:janakerman/janakerman.git

# Choose the base image for our final image
FROM alpine

# Copy across the files from our `intermediate` container
RUN mkdir files
COPY --from=intermediate /janakerman/README.md /files/README.md

Podemos então construir:

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

Prove que nossas chaves SSH se foram:

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

Limpe imagens intermediárias da máquina de construção:

docker rmi -f $(docker images -q --filter label=stage=intermediate)

ARG SSH_PRIVATE_KEY precisa ser substituído por ARG SSH_KEY
Joseph Persie

não podemos simplesmente excluir as chaves quando o clone do git estiver pronto?
Broncha 17/06/19

1
Você poderia, mas precisaria fazê-lo como parte de um único, RUNpara não deixar a chave na camada de imagem anterior. Na janela de encaixe, 1.13você pode usar o argumento --squash experimental que também removeria a chave SSH nas camadas finais da imagem.
Jaker

19

Para o repositório de bitbucket, gere a Senha do aplicativo (Configurações de Bitbucket -> Gerenciamento de acesso -> Senha do aplicativo, veja a imagem) com acesso de leitura ao repositório e projeto.

menu do usuário bitbucket

Em seguida, o comando que você deve usar é:

git clone https://username:generated_password@bitbucket.org/reponame/projectname.git

1
Mais simples :) Devo admitir que prefiro uma abordagem baseada em SSH, mas não consegui fazer nenhum dos trabalhos acima ... arquivos não foram encontrados etc.
Janos

Não vejo "Gerenciamento de acesso" ... acho que está desatualizado?
Martin Thoma

1
Trabalhou! Puro e simples ... Ótimo!
217 Josemy

2
Claro ... Você só precisa clicar na foto do seu perfil na barra esquerda, depois nas configurações do Bitbucket e verá algo assim: imgur.com/EI33zj3
Josemy

1
Isso funcionou para mim. No entanto, tenho submódulos e --recursivenão funcionou. Eu tive que colocar git clonepara cada submódulo, o que é bom, mas teria sido ótimo se tivesse funcionado recursivamente.
Zailyn Tamayo

13

Geralmente, você não deseja executar um git clonerepo particular de dentro da construção da janela de encaixe. Fazer o clone lá envolve colocar as credenciais ssh privadas dentro da imagem, para que possam ser extraídas posteriormente por qualquer pessoa com acesso à sua imagem.

Em vez disso, a prática comum é clonar o repositório git de fora da janela de encaixe na sua ferramenta de CI preferida e simplesmente COPYos arquivos na imagem. Isso tem um segundo benefício: cache do docker. O armazenamento em cache do Docker examina o comando que está sendo executado, as variáveis ​​de ambiente que ele inclui, os arquivos de entrada etc., e se eles são idênticos a uma compilação anterior da mesma etapa pai, reutilizam esse cache anterior. Com um git clonecomando, o próprio comando é idêntico; portanto, o docker reutilizará o cache, mesmo que o repositório git externo seja alterado. No entanto, um COPYcomando examinará os arquivos no contexto de construção e poderá ver se eles são idênticos ou foram atualizados e usará o cache somente quando for apropriado.


Se você deseja adicionar credenciais à sua compilação, considere fazê-lo com uma compilação de vários estágios e apenas coloque essas credenciais em um estágio inicial que nunca seja marcado e enviado para fora do host da compilação. O resultado se parece com:

FROM ubuntu as clone

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git
# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Copy over private key, and set permissions
# Warning! Anyone who gets their hands on this image will be able
# to retrieve this private key file from the corresponding image layer
COPY id_rsa /root/.ssh/id_rsa

# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

FROM ubuntu as release
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

COPY --from=clone /repo /repo
...

Mais recentemente, o BuildKit testou alguns recursos experimentais que permitem passar uma chave ssh como uma montagem que nunca é gravada na imagem:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=secret,id=ssh_id,target=/root/.ssh/id_rsa \
    git clone git@bitbucket.org:User/repo.git

E você pode criar isso com:

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

Observe que isso ainda exige que sua chave ssh não seja protegida por senha, mas você pode pelo menos executar a compilação em um único estágio, removendo um comando COPY e evitando que a credencial ssh faça parte de uma imagem.


O BuildKit também adicionou um recurso apenas para ssh, que permite que você ainda tenha suas chaves ssh protegidas por senha; o resultado é o seguinte:

# syntax=docker/dockerfile:experimental
FROM ubuntu as clone
LABEL maintainer="Luke Crooks <luke@pumalo.org>"

# Update aptitude with new repo
RUN apt-get update \
 && apt-get install -y git

# Make ssh dir
# Create known_hosts
# Add bitbuckets key
RUN mkdir /root/.ssh/ \
 && touch /root/.ssh/known_hosts \
 && ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

# Clone the conf files into the docker container
RUN --mount=type=ssh \
    git clone git@bitbucket.org:User/repo.git

E você pode criar isso com:

$ eval $(ssh-agent)
$ ssh-add ~/.ssh/id_rsa
(Input your passphrase here)
$ DOCKER_BUILDKIT=1 docker build -t your_image_name \
  --ssh default=$SSH_AUTH_SOCK .

Novamente, isso é injetado na compilação sem nunca ser gravado em uma camada de imagem, eliminando o risco de a credencial vazar acidentalmente.


Para forçar o docker a executar o git clonemesmo quando as linhas anteriores foram armazenadas em cache, você pode injetar um ARG de compilação que muda a cada compilação para interromper o cache. Isso se parece com:

# inject a datestamp arg which is treated as an environment variable and
# will break the cache for the next RUN command
ARG DATE_STAMP
# Clone the conf files into the docker container
RUN git clone git@bitbucket.org:User/repo.git

Em seguida, você injeta a alteração do argumento no comando docker build:

date_stamp=$(date +%Y%m%d-%H%M%S)
docker build --build-arg DATE_STAMP=$date_stamp .

Você sugere usar o git de fora do Docker, mas explica como lidar com as chaves ssh de qualquer maneira. Quando você considera isso necessário / apropriado?
precisa saber é o seguinte

1
@JCarlosR quando você não possui um sistema externo para executar a compilação (por exemplo, um sistema de CI / CD capaz de executar o clone antecipadamente). Pode haver exceções, mas um clone dentro de um Dockerfile é um cheiro de código.
BMitch 21/01

1

As soluções acima não funcionaram para o bitbucket. Achei que isso funciona:

RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts \
    && eval `ssh-agent` \
    && ssh-add ~/.ssh/[key] \
    && git clone git@bitbucket.org:[team]/[repo].git
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.