10 práticas recomendadas para proteger imagens do Docker. Parte 2

Uma tradução do artigo foi preparada especificamente para os alunos do curso Linux Security .


Leia a primeira parte


5. Não deixe dados confidenciais nas imagens do Docker


Às vezes, ao criar um aplicativo dentro de uma imagem do Docker, você precisa de dados confidenciais como uma chave SSH privada para extrair código de um repositório privado ou tokens para instalar pacotes fechados. Se você copiá-los para um contêiner intermediário do Docker, eles serão armazenados em cache na camada à qual foram adicionados, mesmo se você os excluir posteriormente. Esses tokens e chaves devem ser armazenados fora do Dockerfile .

Use compilações de vários estágios


Usando o suporte do Docker para compilações de vários estágios, manipule segredos na camada intermediária da imagem, que é excluída posteriormente para que nenhum dado sensível atinja a compilação final. Use o código a seguir para adicionar dados secretos ao middleware:

 FROM: ubuntu as intermediate WORKDIR /app COPY secret/key /tmp/ RUN scp -i /tmp/key build@acme/files . FROM ubuntu WORKDIR /app COPY --from=intermediate /app . 

Usar comandos do Docker Secrets


Use a função alfa no Docker para gerenciar dados confidenciais para montar arquivos confidenciais sem armazená-los em cache:

 # syntax = docker/dockerfile:1.0-experimental FROM alpine # shows secret from default secret location RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre # shows secret from custom secret location RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar 

Você pode aprender mais sobre o gerenciamento de dados confidenciais no site do Docker.

Cuidado com cópias recursivas


Você também deve prestar atenção na cópia de arquivos para a imagem criada. Por exemplo, o comando a seguir copia recursivamente toda a pasta de contexto do assembly para uma imagem do Docker, o que também pode resultar na cópia de arquivos confidenciais:

 COPY . . 

Se houver arquivos confidenciais em sua pasta, exclua-os ou use .dockerignore para ignorá-los:

 private.key appsettings.json 

6. Use etiquetas fixas para imunidade


Cada imagem do Docker pode ter várias tags que representam variações das mesmas imagens. A tag mais comum é a latest , representando a versão mais recente de uma imagem. As tags de imagem não são imutáveis ​​e um autor de imagem pode publicar a mesma tag várias vezes.

Isso significa que a imagem base do seu arquivo Docker pode mudar entre as compilações. Isso pode levar a um comportamento inesperado devido a alterações feitas na imagem base.

Existem várias maneiras de corrigir esse problema:

  • Prefira a tag mais específica disponível. Se a imagem tiver várias tags, como :8 e :8.0.1 ou mesmo :8.0.1-alpine , prefira a última, pois é o link mais específico para a imagem. Evite usar as tags mais comuns, como as mais recentes. Ao fixar uma tag específica, lembre-se de que ela pode ser excluída.
  • Para resolver o problema de uma tag de imagem específica se tornar inacessível e se tornar um limite de exibição de anúncios para grupos que dependem dela, considere iniciar um espelho local dessa imagem no registro ou na conta que está sob seu próprio controle. É importante levar em conta os custos de manutenção necessários para essa abordagem, pois isso significa que você precisa manter o registro. É uma boa prática replicar a imagem que você deseja usar em seu registro para garantir que a imagem usada não esteja sendo alterada.
  • Seja extremamente específico! Em vez de puxar a tag, puxe a imagem usando um link SHA256 específico para a imagem do Docker, o que garante que você obtenha a mesma imagem para cada solicitação. No entanto, observe que o uso de um link SHA256 pode ter o seguinte risco - se a imagem mudar, o hash pode não funcionar mais.

7. Use COPY em vez de ADICIONAR


O Docker fornece dois comandos para copiar arquivos do host para a imagem do Docker quando ele é criado: COPY e ADD . Os comandos são de natureza semelhante, mas diferem em sua funcionalidade:

  • COPIAR - copia recursivamente arquivos locais, indicando os arquivos ou diretórios de origem e destino. Com COPY, você deve declarar locais.
  • ADD - copia recursivamente os arquivos locais, cria implicitamente um diretório de destino, se não existir, e aceita arquivos como URLs locais ou remotos como fonte, que ele estende ou carrega, respectivamente, no diretório de destino.
    Embora as diferenças entre ADD e COPY não sejam tão fundamentais, elas são importantes. Esteja ciente deles para evitar possíveis problemas de segurança:
  • Quando URLs remotas são usadas para baixar dados diretamente para o local original, isso pode levar a ataques do broker que modificam o conteúdo do arquivo baixado. Além disso, a origem e a autenticidade dos URLs remotos devem ser verificadas. Ao usar COPY, a origem dos arquivos a serem baixados de URLs remotas deve ser declarada em uma conexão TLS segura e sua origem também deve ser verificada.
  • Notas sobre o espaço e as camadas das imagens: o uso de COPY permite separar a adição do arquivo dos locais remotos e descompactá-lo em diferentes camadas, o que otimiza o cache das imagens. Se forem necessários arquivos remotos, combine todos eles em um comando RUN, que posteriormente baixa, extrai e elimina, otimizando a operação de camada única em várias camadas que seriam necessárias usando o ADD.
  • Quando arquivos locais são usados, o ADD os extrai automaticamente para o diretório de destino. Embora isso possa ser aceitável, ele aumenta o risco de obter bombas zip e vulnerabilidades de Zip Slip , que podem ser iniciadas automaticamente.

8. Use tags de metadados


Os rótulos de imagem fornecem metadados para as imagens que você cria. Isso facilita para os usuários descobrir como usar a imagem. A tag mais comum é "mantenedor", que indica o endereço de email e o nome da pessoa que suporta esta imagem. Adicione metadados usando o seguinte comando LABEL :

 LABEL maintainer="me@acme.com" 

Além dos contatos do mantenedor, adicione quaisquer metadados importantes para você. Esses metadados podem conter: um hash de confirmação, um link para o assembly apropriado, status de qualidade (todos os testes foram aprovados?), Código-fonte, um link para o local do arquivo SECURITY.TXT etc.

É uma boa prática oferecer suporte ao arquivo SECURITY.TXT (RFC5785), que aponta para a política de Divulgação Responsável do esquema de etiquetas do Docker ao adicionar novos, por exemplo:

 LABEL securitytxt="https://www.example.com/.well-known/security.txt" 

Veja mais informações sobre etiquetas para imagens do Docker:

https://label-schema.org/rc1/

9. Use montagem de vários estágios para imagens pequenas e seguras


Quando você cria um aplicativo usando o Dockerfile , são criados muitos artefatos necessários apenas no momento da construção. Podem ser ferramentas de desenvolvimento e bibliotecas necessárias para compilação ou dependências necessárias para executar testes de unidade, arquivos temporários, segredos etc.

O armazenamento desses artefatos em uma imagem básica que pode ser usada na produção leva a um aumento no tamanho da imagem do Docker, o que pode afetar bastante o tempo necessário para fazer o download e também aumentar a superfície de ataque, como resultado do qual mais pacotes serão instalados. O mesmo vale para a imagem do Docker que você está usando - pode ser necessária uma imagem específica do Docker para criar, mas não para executar o código do aplicativo.

Golang é um ótimo exemplo. Para criar um aplicativo Golang, você precisa de um compilador Go. O compilador cria um arquivo executável que é executado em qualquer sistema operacional, sem dependências, incluindo imagens limpas.

Essa é uma boa razão pela qual o Docker tem a capacidade de criar etapas. Essa função permite usar várias imagens temporárias durante o processo de montagem, salvando apenas a última imagem junto com as informações que você copiou nela. Então você tem duas imagens:

  • A primeira imagem é um tamanho muito grande, juntamente com muitas dependências usadas para criar o aplicativo e executar os testes.
  • A segunda imagem é muito clara em termos de tamanho e número de bibliotecas, contendo apenas cópias de artefatos necessários para executar o aplicativo em produção.

10. Use o linter


Use o linter para evitar erros comuns e estabelecer práticas recomendadas que os engenheiros podem seguir automaticamente.

Um desses linter é o hadolint . Ele analisa o Dockerfile e emite um aviso sobre qualquer erro que não esteja em conformidade com suas recomendações.



O Hadolint se torna ainda mais poderoso quando usado em um ambiente de desenvolvimento integrado (IDE). Por exemplo, ao usar o hadolint como uma extensão VSCode, erros de limpeza aparecem durante a entrada. Isso ajuda a escrever os melhores arquivos docker mais rapidamente.

Saiba mais sobre como proteger suas imagens do Docker.

Source: https://habr.com/ru/post/pt482044/


All Articles