Segredos seguros ao criar no Docker Compose

Uma tradução do artigo foi preparada antes do início do curso Python Web Developer .




Ao criar uma imagem do Docker, você pode precisar de segredos, como uma senha para um repositório de pacotes particulares. Você não deseja que esse segredo acabe na imagem, pois quem tiver acesso à imagem terá acesso ao seu repositório privado.
Nota : Se você pensar em "Por que não usar apenas variáveis ​​de ambiente?", Que são usadas para segredos em tempo de execução ao criar uma imagem. Este artigo se concentra na criação de segredos usados ​​ao criar uma imagem usando um arquivo Docker.
As versões mais recentes do Docker mantêm segredos usando o serviço BuildKit experimental e, no Docker Compose 1.25 e posterior, você já pode criar imagens usando o BuildKit. Infelizmente, em março de 2020, a capacidade de trabalhar com segurança com segredos do Compose ainda está em desenvolvimento .

Então o que fazer agora?

No artigo de hoje, mostrarei como você pode usar o mesmo Dockerfile para criar com segurança imagens de segredos sem perder os benefícios do desenvolvimento rápido usando o Docker Compose.

Duas opções para usar seu arquivo docker


É muito conveniente usar o mesmo Dockerfile para produção e desenvolvimento local com o Docker Compose. Geralmente você usa o Dockerfile junto com a função de compilação do Compose:

version: "3.7"
services:
  yourapp:
    build:
      context: "."	

Então você pode fazer:

$ docker-compose up

Com este comando, você pode (re) montar a imagem e depois executá-la.
Para uso na produção, você coleta a imagem e a envia com push :

$ docker build -t myimage .
$ docker push myimage

E enquanto tudo está indo bem. Mas e se você precisar de uma construção secreta?

Primeira tentativa (insegura)


Suponha que você tenha um script que precise de uma construção secreta, por exemplo, para baixar um pacote Python de um repositório privado do DevPI . Por uma questão de simplicidade, derivaremos simplesmente o segredo com a ajuda use-secret.shde mostrar que o temos.

#!/bin/bash
set -euo pipefail

echo "Secret is: $THEPASSWORD"

Você pode simplesmente transmitir o segredo usando os argumentos de construção do Docker, pois eles são suportados em todos os lugares, inclusive no Docker Compose.
Nota : Indo além do escopo de nossa discussão, quero dizer que o uso de arquivos do Docker neste artigo não é a melhor prática; no entanto, a complexidade excessiva pode interferir na transmissão do significado principal do artigo.
Portanto, se você deseja executar seu aplicativo Python em produção com o Docker, aqui estão duas boas maneiras de fazer isso:


FROM python:3.8-slim-buster
# Using ARG for build secrets is INSECURE!
ARG THEPASSWORD
COPY use_secret.sh .
RUN ./use_secret.sh

Podemos escrever docker-compose.yml, que será transmitido em segredo:

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Para o trabalho local, você pode executar ou criar uma imagem usando o Redigir:

$ docker-compose build | grep Secret
Secret is: s3kr!t

E está tudo bem.

E também podemos montar a imagem usando o Docker, em preparação para movê-la para o registro de imagens:

$ docker build -t myimage --build-arg THEPASSWORD=s3krit . | grep Secret
Secret is: s3krit

Fazer isso é inseguro: nunca faça isso . Se decidirmos olhar as camadas da imagem, veremos o segredo nela!

$ docker history myimage
IMAGE               CREATED              CREATED BY                                      SIZE
c224231ec30b        47 seconds ago       |1 THEPASSWORD=s3krit /bin/sh -c ./use_secre…   0B
6aef62acf0db        48 seconds ago       /bin/sh -c #(nop) COPY file:7aa28bbe6595e0d5…   62B
f88b19ca8e65        About a minute ago   /bin/sh -c #(nop)  ARG THEPASSWORD              0B
...

Quem obtiver acesso a esta imagem reconhecerá sua senha. O que pode ser feito, então?

Segredos do BuildKit (solução parcial)


O BuildKit é uma solução nova (e ainda experimental) para a criação de imagens do Docker, que, entre outras coisas, adiciona suporte para o uso seguro de segredos durante a montagem . O Docker Compose tem suporte ao BuildKit desde a v1.25.

Mas há um problema: o Docker Compose ainda não suporta a funcionalidade de segredos do BuildKit. Agora, o trabalho está em andamento , mas em março de 2020, não há soluções prontas, para não mencionar uma versão estável.

Portanto, vamos combinar essas duas abordagens:

  • O Docker Compose continuará usando argumentos de construção para passar segredos;
  • Para uma imagem de produção criada usando o docker build, usamos o BuildKit para transmitir segredos.

Dessa forma, podemos usar o mesmo Dockerfile para trabalhar localmente e na produção.
O BuildKit trabalha com segredos da seguinte maneira: o arquivo com segredos é montado em um diretório temporário enquanto o comando RUN é executado, por exemplo, em /var/secrets/thepassword. Como ele é montado durante a execução do comando RUN, não será adicionado à imagem final.

Modificaremos o arquivo use_secret.shpara verificar se existe um arquivo temporário. Se existir, ele usa suas configurações de variável de ambiente $THEPASSWORD. Se o arquivo não existir, retornaremos à variável de ambiente. Ou seja, ele $THEPASSWORDpode ser instalado usando o BuildKit ou argumentos de construção:

#!/bin/bash
set -euo pipefail
if [ -f /run/secrets/thepassword ]; then
   export THEPASSWORD=$(cat /run/secrets/thepassword)
fi

echo "Secret is: $THEPASSWORD"

Em seguida, modificaremos o Dockerfile para adicionar o BuildKit e montar o segredo:

# syntax = docker/dockerfile:1.0-experimental
FROM python:3.8-slim-buster
# Only use the build arg for local development:
ARG THEPASSWORD
COPY use_secret.sh .
# Mount the secret to /run/secrets:
RUN --mount=type=secret,id=thepassword ./use_secret.sh

docker-compose.ymlNós não alteramos o arquivo :

version: "3.7"
services:
  yourapp:
    build:
      context: "."
      args:
        THEPASSWORD: "s3kr!t"

Agora você precisa definir duas variáveis ​​de ambiente, uma das quais informará ao Docker que você deve usar o BuildKit, a segunda que o Compose precisará usar a versão CLI do Docker e, portanto, o BuildKit. Também escreveremos o segredo do arquivo:

$ export DOCKER_BUILDKIT=1
$ export COMPOSE_DOCKER_CLI_BUILD=1
$ echo 's3krit' > /tmp/mypassword

Com o Compose, usamos os argumentos de construção:

$ docker-compose build --progress=plain \
    --no-cache 2>&1 | grep Secret
#12 0.347 Secret is: s3kr!t

Observe que é --no-cachenecessário entender que a imagem será realmente reconstruída se você executar todas as opções acima. Na vida real, esse parâmetro pode ser omitido. 2>&1redirecionar stderrpara stdoutpara a operação correta grep.

Quando estamos prontos para desenvolver a produção, usamos o docker build com a funcionalidade de segredos do BuildKit:

$ docker build --no-cache -t myimage \
    --secret id=thepassword,src=/tmp/mypassword \
    --progress=plain . 2>&1 | grep Secret
#12 0.359 Secret is: s3krit

É seguro?


Vamos garantir que o segredo não seja visível:

$ docker history myimage
IMAGE               CREATED             CREATED BY                                      SIZE
a77f3c32b723        25 seconds ago      RUN |1 THEPASSWORD= /bin/sh -c ./use_secret.…   0B
<missing>           25 seconds ago      COPY use_secret.sh . # buildkit                 160B
...

Viva! Passamos o segredo para o mesmo Dockerfile usando o Compose e docker build, no último caso, não revelamos o segredo da montagem.



Saiba mais sobre o curso.



All Articles