
Usando o Dockerfile, sempre foi difícil acessar recursos privados. Simplesmente não havia uma boa solução. Não é bom usar variáveis de ambiente ou simplesmente excluir arquivos secretos após o uso: eles permanecem nos metadados da imagem. Às vezes, os usuários faziam truques: eles criavam montagens de vários estágios; no entanto, era preciso tomar muito cuidado para que não houvesse valores secretos no estágio final e os arquivos secretos eram armazenados no cache do conjunto local até o recorte.
A equipe de criação do Docker em 18 de setembro inclui muitas atualizações. A principal característica é que uma versão completamente nova da implementação do lado do servidor apareceu; ela é oferecida como parte do projeto Moby BuildKit. O aplicativo do servidor BuildKit adquiriu novos recursos, incluindo suporte para segredos de construção do Dockerfile.
Usando segredos
Primeiro de tudo, você precisa habilitar o lado do servidor BuildKit. O BuildKit na versão 18.09
é uma função de seleção que pode ser ativada usando a variável de ambiente DOCKER_BUILDKIT=1
antes de iniciar a docker build
. Na próxima versão, está planejado tornar o BuildKit parte do servidor por padrão.
export DOCKER_BUILDKIT=1
A implementação de segredos de construção é baseada em dois novos recursos do BuildKit. Uma delas é a capacidade de usar uma interface de usuário carregada de imagens no registro; a segunda é a capacidade de usar pontos de montagem nos comandos RUN
para o Dockerfile. Para usar a função de implementação com suporte a segredos (em vez da padrão), defina a imagem do vinculador usando a diretiva de sintaxe na primeira linha do Dockerfile - indicando a imagem do contêiner que você deseja usar. Até o momento, os segredos no canal estável de Dockerfiles externos não estão disponíveis: você precisará de uma das versões no canal experimental, por exemplo, docker/dockerfile:experimental
ou docker/dockerfile/1.0.0-experimental
.
# syntax=docker/dockerfile:1.0.0-experimental
Se você, como autor do Dockerfile, souber que o comando RUN
instalado no Dockerfile exige um valor secreto, use o rótulo --mount
, indicando qual segredo o comando precisa e onde montá-lo. O rótulo --mount
aceita uma estrutura separada por vírgula como em --mount
para docker run
.
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key command-to-run
Esse rótulo indica que, durante a operação, o comando tem acesso ao arquivo secreto no caminho /run/secrets/mysite.key
. O segredo está disponível apenas para a equipe com a etiqueta de montagem e não para outras partes da montagem. Os dados neste arquivo são baixados do armazenamento secreto com base no identificador especificado "mysite.key". A interface da linha de comandos do Docker atualmente suporta a divulgação de segredos de arquivos de clientes locais usando a marca --secret
.
docker build --secret id=mysite.key,src=path/to/mysite.key .
Como descrito acima, os segredos são definidos por padrão em /run/secrets
, no entanto, você pode especificar qualquer caminho usando a tecla "target". Se "target" for especificado, mas "id" não for, então "id" por padrão se tornará o nome base do caminho de destino.
Não é necessário limitar-se a um segredo. Você pode usar qualquer número deles, indicando diferentes identificadores.
Se o autor do Dockerfile indicar que a instrução RUN
pode usar o segredo e o usuário que está chamando o assembly não o fornecer, o segredo será ignorado e nenhum arquivo será instalado no caminho especificado. Se essa situação for indesejável, use a tecla "requerida": isso indicará que, sem um valor, a montagem falhará.
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN --mount=type=secret,id=mysite.key,required <command-to-run>
Implementação
O arquivo secreto é instalado automaticamente apenas em um sistema de arquivos tmpfs separado para evitar vazamentos na imagem final ou no próximo comando e, portanto, não é armazenado no cache de construção local.
Os valores secretos também são excluídos dos cálculos do cache de construção, para que o cache de metadados não possa ser usado.
Ssh
Na maioria das vezes, eles provavelmente tentam acessar repositórios privados por meio do protocolo SSH. Sim, você pode usar elementos secretos para revelar a chave privada SSH para o assembly, mas existe uma solução melhor. O protocolo SSH usa criptografia de chave pública e, graças a esse design, você não precisa divulgar sua chave privada a ninguém. Por exemplo, se você usa vários computadores com SSH, não precisa transferir sua chave - basta fornecer uma conexão através do protocolo ssh-A
.
Adicionamos um recurso semelhante na docker build
, onde você pode usar o rótulo --ssh
para direcionar uma conexão ou chave do agente SSH existente ao vinculador. Em vez de transmitir informações importantes, o Docker simplesmente informa ao vinculador que elas estão disponíveis. Se o vinculador precisar acessar o servidor remoto via SSH, ele entrará em contato com o cliente e solicitará a confirmação da solicitação específica necessária para a conexão. A chave em si não sai do programa cliente e, após a conclusão do programa que exigia acesso, nenhum dado permanece do vinculador para reconectar a conexão remota.
O acesso à transferência de arquivos via protocolo SSH é concedido apenas aos comandos no Dockerfile que solicitam acesso diretamente ao SSH, especificando o bloco type=ssh
. Outros comandos não possuem dados no agente SSH disponível.
Também vale a pena notar outro aspecto do SSH - o uso do modelo de segurança TOFU. Ao conectar-se ao servidor SSH pela primeira vez, ele solicitará informações sobre o host desconhecido, porque não possui uma chave pública disponível localmente para este servidor e, portanto, não pode verificar se a chave pública fornecida pela parte remota é válida para este endereço.
Ao montar com o Dockerfile, a correção dessa solicitação não pode ser verificada e, portanto, a chave pública do servidor já deve existir no contêiner que tenta usar o SSH. Existem várias maneiras de obter essa chave pública. Por exemplo, a imagem base a fornecerá ou você a copiará do contexto de construção. Se você deseja uma solução mais simples, execute o programa ssh–keyscan
como parte do assembly - ele carregará a chave pública atual do host.
Para solicitar acesso SSH ao comando RUN
no Dockerfile, você deve especificar um bloco do tipo "ssh". Em seguida, durante o processo, um soquete será instalado com acesso somente leitura ao agente SSH. Isso também definirá a variável de ambiente SSH_AUTH_SOCK
para que os programas que usam o protocolo SSH usem automaticamente esse soquete.
# syntax=docker/dockerfile:experimental FROM alpine # install ssh client and git RUN apk add --no-cache openssh-client git # download public key for github.com RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts # clone our private repository RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject
No lado do cliente do Docker, use o rótulo --ssh
indicar que o encaminhamento de SSH é permitido para este assembly.
docker build --ssh default .
O rótulo aceita um par de valores de chave que determina o local do soquete do agente SSH local ou das chaves privadas. Se você quiser usar o valor default=$SSH_AUTH_SOCK
, poderá deixar o caminho do soquete vazio.
No bloco Dockerfile, você também pode usar a chave id para separar os vários servidores no mesmo assembly. Por exemplo, o acesso a vários repositórios no Dockerfile pode ser obtido com diferentes chaves de implantação. Nesse caso, no Dockerfile você usará:
… RUN --mount=type=ssh,id=projecta git clone projecta … RUN --mount=type=ssh,id=projectb git clone projectb …
e expanda os dados do cliente com o docker build --ssh projecta=./projecta.pem --ssh projectb=./projectb.pem
. Observe que, mesmo se você especificar as chaves reais, apenas a conexão do agente será enviada ao vinculador, não o conteúdo real dessas chaves privadas.
Com isso, a revisão dos novos recursos de construção de segredos no Docker 18.09 é concluída. Espero que os novos recursos ajudem a aproveitar melhor os recursos do Dockerfile nos projetos e forneçam um nível mais alto de segurança para a linha de montagem.