Skip to main content


Segurança


A segurança em ambientes Docker é crucial para garantir que os contêineres e as aplicações que eles hospedam estejam protegidos contra vulnerabilidades e ameaças. Como o Docker cria ambientes isolados para aplicativos, ele oferece um nível básico de segurança. No entanto, essa isolação não é infalível, e a falta de boas práticas pode expor o ambiente a riscos como contêineres maliciosos, violações de rede e acessos não autorizados.



Executar Docker com usuário não root


O daemon do Docker se liga a um soquete Unix, não a uma porta TCP. Por padrão, é o usuário root que possui o soquete Unix, e outros usuários só podem acessá-lo usando sudo (O daemon Docker sempre é executado como usuário root).


Por padrão, os contêineres Docker são executados com privilégios de superusuário (root) dentro e fora do contêiner. Isso significa que o processo dentro do contêiner é executado com permissões elevadas, independentemente do usuário que o iniciou no ambiente Docker host. O motivo para isso é que, no nível do sistema operacional, um contêiner Docker é simplesmente um processo comum no sistema hospedeiro. Todo processo em um sistema operacional tem um "dono", e o "dono" do processo do contêiner é o usuário do sistema hospedeiro que executou o comando docker run.


Para ilustrar, se o comando docker run for executado por um usuário com privilégios de root, o processo dentro do contêiner também será executado como root, herdando assim todas as permissões associadas. No entanto, se o docker run for executado por um usuário não root, o correto seria dizer que o usuário root dentro do container não terá privilégios de root né ? Sim e não, o processo dentro do contêiner ainda será executado como root em algumas situações.


Se você está criando um grupo chamado docker e colocando todos os usuários que devam usar o docker dentro desse grupo, o usuário root dentro do container vai ter privilégios elevados porque o grupo docker concede privilégios de root aos usuários dentro do grupo. Isso significa que, mesmo que o usuário que iniciou o contêiner não tenha privilégios de root no sistema host, o processo dentro do contêiner ainda terá esses privilégios de root, devido à associação com o grupo docker.


Essa abordagem tem implicações importantes em termos de segurança, pois um processo dentro de um contêiner com privilégios de root pode potencialmente realizar operações de alto impacto no sistema hospedeiro, como instalação de software, modificação de arquivos críticos do sistema e acesso a recursos sensíveis.


Mas entenda que, embora o usuário que executa o docker run tenha influência sobre o usuário padrão dentro do container, o usuário root dentro do container não tem acesso direto ao sistema de arquivos ou recursos do host. Isso se deve ao isolamento fornecido pelos containers Docker, que implementam namespaces de processos, rede e sistema de arquivos. Para que ele possa ter acesso, como já foi dito, a imagem teria que estar infectada com algum malware.


Para evitar esse tipo de coisa é crucial utilizar imagens confiáveis de fontes oficiais e manter os containers atualizados para reduzir o risco de infecções por malware.


Existem quatro abordagens que podemos seguir para deixar a execução dos containers um pouco mais segura, do melhor método para o menos indicado (pelo menos se usado sem nenhum outro método):


  1. Utilização do Docker em modo rootless;
  2. Usar o recurso user-namespace;
  3. Usa a opção USER dentro do Dockerfile;
  4. Usar o grupo Docker;

A planilha abaixo representa as vantagens e desvantagens de cada método descrito acima:

MétodoVantagensDesvantagens
Modo RootlessMaior segurança, os daemon e containers são executados como usuários não root.Nem todas as funcionalidades do Docker disponíveis, como a utilização de volumes anônimos e a configuração de redes complexas. A implementação e o gerenciamento do modo Rootless podem exigir mais conhecimento técnico e familiaridade com namespaces de usuários do Linux, o que pode ser um obstáculo para usuários menos experientes. Nem todas as ferramentas e workflows Docker são compatíveis com o modo Rootless. Isso pode exigir a adaptação de ferramentas ou a busca por alternativas compatíveis, o que pode gerar trabalho adicional.
User NamespaceMapeamento do usuário root para um específico no host.Requer conhecimento de namespaces de usuários, daemon do Docker com privilégios de root. Apesar de oferecer isolamento granular, o próprio daemon do Docker ainda é executado com privilégios de root, o que pode representar um risco de segurança se houver vulnerabilidades no daemon.
Opção USER no DockerfileLimitação de privilégios do processo principal, redução da superfície de ataque.Usuário root dentro do container ainda existe com privilégios administrativos, isolamento menos granular.
Grupo Docker- Não recomendado: riscos de segurança e baixa segurança.- Não recomendado: evitar para aumentar a segurança.


Docker daemon por grupo


Esse método é útil quando você não quer executar os comandos docker com sudo, para isso, crie um grupo Unix chamado docker e adicione usuários a ele. Quando o daemon Docker é iniciado, ele cria um soquete Unix acessível aos membros do grupo docker. Em algumas distribuições Linux, o sistema cria automaticamente este grupo ao instalar o Docker Engine usando um gerenciador de pacotes. Nesse caso, não há necessidade de criar o grupo manualmente.


Colocando usuário no grupo docker:

Terminal
# Verifique se o grupo existe, se não existir, nada será retornado:
╼ $ sudo getent group docker
docker:x:999:

### Caso não exista, crie o grupo:
╼ $ sudo groupadd docker

# Adicione os usuários dentro do grupo docker:
╼ $ sudo gpasswd -a username docker
Adding user username to group docker

# Agora reinicie o daemon do docker:
╼ $ sudo systemctl restart docker

# Verifique se funcionou:
╼ $ id
uid=1000(username) gid=1000(username) groups=1000(username)

## Não vemos o grupo docker aqui, então devemos reiniciar o sistema!

# Caso não possa reiniciar o sistema agora, use o comando abaixo
# para ativar as alterações nos grupos (se deslogar perderá a ação realizada):
╼ $ newgrp docker

# Quando puder reiniciar, faça:
╼ $ sudo reboot

# Verifique se funcionou:
╼ $ docker run hello-world

Hello from Docker!


Docker daemon attack surface


O daemon do Docker apresenta uma superfície significativa de ataque devido aos seus privilégios de root, a menos que o modo Rootless seja utilizado. Em primeiro lugar, apenas usuários confiáveis devem ter permissão para controlar seu daemon Docker.


O Docker permite compartilhar um diretório entre o host do Docker e um contêiner convidado; e permite que você faça isso sem limitar os direitos de acesso do contêiner. Isso significa que você pode iniciar um contêiner onde o diretório /host é o diretório / do seu host; e o contêiner pode alterar seu sistema de arquivos host sem qualquer restrição.


Isso é semelhante ao modo como os sistemas de virtualização permitem o compartilhamento de recursos do sistema de arquivos. Nada impede que você compartilhe seu sistema de arquivos raiz.


Isso tem uma forte implicação de segurança: por exemplo, se você instrumentar o Docker a partir de um servidor web para provisionar contêineres por meio de uma API, deverá ser ainda mais cuidadoso do que o normal com a verificação de parâmetros, para garantir que um usuário mal-intencionado não possa passar parâmetros criados causando danos ao Docker para criar contêineres arbitrários.


Por esse motivo, o endpoint da API REST (usado pela CLI do Docker para se comunicar com o daemon do Docker) mudou no Docker 0.5.2 e agora usa um soquete UNIX em vez de um soquete TCP vinculado a 127.0.0.1. Você pode então usar verificações de permissão tradicionais do UNIX para limitar o acesso ao soquete de controle.


Mesmo que você coloque um firewall para limitar o acesso ao endpoint da API REST do Docker de outros hosts na rede, o endpoint ainda poderá ser acessível a partir de contêineres e poderá facilmente resultar na escalada de privilégios. Portanto, é obrigatório proteger os endpoints da API com HTTPS e certificados. Também é recomendável garantir que ele seja acessível apenas por uma rede confiável ou VPN (o padrão é estar desativado).


O daemon também é potencialmente vulnerável a outras entradas, como carregamento de imagem de qualquer disco com docker load ou da rede com docker pull. A partir do Docker 1.3.2, as imagens agora são extraídas em um subprocesso chroot em plataformas Linux/Unix, sendo o primeiro passo em um esforço mais amplo em direção à separação de privilégios. A partir do Docker 1.10.0, todas as imagens são armazenadas e acessadas pelos checksums criptográficos de seu conteúdo, limitando a possibilidade de um invasor causar uma colisão com uma imagem existente.


Finalmente, se você executar o Docker em um servidor, é recomendado executar exclusivamente o Docker no servidor e mover todos os outros serviços para dentro de contêineres controlados pelo Docker. Você ainda pode ter outros serviços rodando no host Docker, mas minimize o máximo possível.



Docker daemon com modo Rootless


O modo (rootless) no Docker permite executar o daemon do Docker e os contêineres como um usuário não root para mitigar possíveis vulnerabilidades no daemon e no tempo de execução do contêiner. Esse modo não requer privilégios de root, mesmo durante a instalação do daemon do Docker, desde que os pré-requisitos sejam atendidos.


O modo rootless executa o daemon do Docker e os contêineres dentro de um espaço de nomes de usuário (user namespace). Isso é muito semelhante ao modo userns-remap (veremos mais abaixo), exceto que, com o modo userns-remap, o próprio daemon está sendo executado com privilégios de root, enquanto que no modo rootless, tanto o daemon quanto o contêiner estão sendo executados sem privilégios de root.


O modo rootless não usa binários com bits SETUID ou capacidades de arquivo, exceto newuidmap e newgidmap, que são necessários para permitir que vários UID/GID sejam usados no espaço de nomes de usuário.


Para usar esse método, é necessário atender a certos requisitos:

  • Você deve instalar o newuidmap e o newgidmap no host. Esses comandos são fornecidos pelo pacote uidmap na maioria das distribuições.

  • Os arquivos /etc/subuid e /etc/subgid devem conter pelo menos 65.536 UIDs/GIDs subordinados para o usuário.


Para ver como implantar esse método, veja a documentação oficial.



Docker daemon com User-Namespaces


Os Linux namespaces fornece isolamento para a execução de processos, limitando o acesso deles aos recursos do sistema sem que o processo em execução esteja ciente das limitações. A melhor maneira de prevenir ataques de escalonamento de privilégios de dentro de um contêiner é configurar as aplicações do seu contêiner para serem executadas como usuários não privilegiados.


Para contêineres cujos processos devem ser executados como usuário root dentro do contêiner, você pode remapear esse usuário para um usuário menos privilegiado no host Docker. O usuário mapeado recebe uma faixa de UIDs que funcionam dentro do namespace como UIDs normais de 0 a 65536, mas não têm privilégios na própria máquina host.


Ou seja, ao utilizar o user-namespaces, o usuário root dentro do container é mapeado para um usuário não root na máquina host Docker, reforçando a segurança através do isolamento de privilégios.


Pré-requisitos

Para usar esse método, é necessário atender a certos requisitos:


  • Requisito 1
    Para usar namespaces de usuário no Docker, é necessário associar faixas de IDs de usuário (UIDs) e IDs de grupo (GIDs) a um usuário existente. Essas faixas de IDs são responsáveis por mapear os usuários e grupos dentro do contêiner para usuários e grupos no host Docker. Mesmo que essa associação seja um detalhe de implementação, é importante que exista.

    Se você preferir não usar um usuário existente, o Docker pode criar um para você. No entanto, se você optar por usar um usuário existente, é necessário garantir que ele já esteja definido no sistema, o que geralmente é feito através de entradas correspondentes nos arquivos /etc/passwd e /etc/group.

    Além disso, é importante notar que o usuário associado às faixas de UID e GID é o proprietário dos diretórios de armazenamento namespace localizados em /var/lib/docker/. Isso significa que ele terá permissões sobre esses diretórios.

  • Requisito 2
    No host, o remapeamento de namespaces vai ser controlado por dois arquivos: /etc/subuid e /etc/subgid. Esses arquivos geralmente são gerenciados automaticamente quando você adiciona ou remove usuários ou grupos, mas em algumas distribuições como RHEL e CentOS 7.3, pode ser necessário gerenciá-los manualmente.

    Cada arquivo contém três campos: o nome de usuário ou ID do usuário, seguido por um UID ou GID inicial (que é tratado como UID ou GID 0 dentro do namespace) e o número máximo de UIDs ou GIDs disponíveis para o usuário. Por exemplo, considerando a seguinte entrada:

    vagrant:100000:65536

    Isso significa que os processos com namespaces de usuário iniciados pelo usuário vagrant são de propriedade do UID do host 100000 (que parece ser o UID 0 dentro do namespace) até 165535 (100000 + 65536 - 1). Esses intervalos não devem se sobrepor para garantir que os processos com namespaces não possam acessar os namespaces uns dos outros.

    Depois de adicionar seu usuário, verifique se há uma entrada para o usuário em /etc/subuid e /etc/subgid. Se não houver, será necessário adicioná-lo, tomando cuidado para evitar sobreposições. Veja o exemplo abaixo após adicionar um novo usuário:

    /etc/subuid
    vagrant:100000:65536
    fulano:165536:65536

    /etc/subgid
    vagrant:100000:65536
    fulano:165536:65536
  • Requisito 3
    Se houver algum local no host do Docker onde o usuário não privilegiado precise gravar, ajuste as permissões desses locais conforme necessário. Isso também é verdadeiro se você quiser usar o usuário dockremap criado automaticamente pelo Docker, mas não puder modificar as permissões até depois de configurar e reiniciar o Docker.

  • Requisito 4
    Habilitar userns-remap efetivamente mascara as camadas existentes de imagens e contêineres, bem como outros objetos do Docker dentro de /var/lib/docker/. Isso ocorre porque o Docker precisa ajustar a propriedade desses recursos e, na verdade, armazená-los em um subdiretório dentro de /var/lib/docker/. É melhor habilitar esse recurso em uma nova instalação do Docker em vez de uma existente.

    Da mesma forma, se você desativar userns-remap, não poderá acessar nenhum dos recursos criados enquanto estiver habilitado.


Habilitando o userns-remap

Existem duas forma de habilitar o userns-remap:


Você pode iniciar o dockerd com a flag --userns-remap, para isso é necessário modificar o .service em sistemas que usam o SystemD. Ou configurar o daemon do Docker usando o arquivo de configuração daemon.json, sendo este o método mais recomendado.


/etc/docker/daemon.json
{
"userns-remap": "testuser:testuser"
}

Para usar o usuário dockremap e fazer com que o Docker o crie para você, defina o valor como default em vez de testuser.



Dockerfile com a opção USER


Por padrão, a maioria dos contêineres Docker é executada com o usuário root, o que pode trazer riscos significativos de segurança, especialmente em ambientes de produção. Contudo, algumas tarefas específicas durante o processo de build e deploy podem exigir permissões de root para serem concluídas sem erros.


Após realizar essas tarefas que exigem privilégios elevados, é uma boa prática criar explicitamente um usuário não root e conceder a ele o nível mínimo de acesso necessário para executar o aplicativo. Para isso, utilize ferramentas como chmod e chown para ajustar as permissões de arquivos e diretórios.


Antes das diretivas ENTRYPOINT ou CMD, adicione a instrução USER para garantir que o aplicativo seja executado como um usuário não root. Isso protege o ambiente de execução, restringindo o que pode ser acessado pelo contêiner.


Para ver como implementar, acesse aqui.



Qual opção usar?


Vamos usar o princípio do menor privilégio que é uma abordagem fundamental e deve ser levada em conta ao trabalharmos com containers. O princípio do menor privilégio se resume a conceder apenas os privilégios necessários para uma determinada tarefa, processo ou usuário. Para mais detalhes leia aqui.


Para uma melhor prática no uso dos containers, eu recomendo criar um usuário e um grupo específicos para cada aplicação que o container vai executar (basicamente um usuário por container), após isso, deve-se fazer uso da opção USER no dockerfile ou user no docker-compose. A criação dos usuários é feita usando o comando useradd, já a criação de grupo é feita usando o comando groupadd no Linux (da para usar apenas useradd para criar tanto o usuário quanto o grupo).


É fundamental garantir que apenas as permissões necessárias sejam concedidas a esses usuários e grupos criados. Se você usar os usuários que já existem no container, como no caso de container de banco de dados, não precisa se preocupar em criar o usuário.


A criação do usuário dentro do container vai depender do container que está sendo inicializado. Por exemplo, se estiver executando um container com o MySQL, você configuraria o Dockerfile ou Docker-compose para usar o usuário do MySQL para executar o serviço dentro do container (normalmente é o usuário com UID 999 e com GID 999). Da mesma forma, para um container com MongoDB, você usaria o usuário dedicado ao MongoDB (normalmente é o usuário com UID 999 e com GID 999).


Agora, se estiver executando uma aplicação em NodeJS, Java, Python, ou qualquer outra linguagem, você pode fazer a criação do usuário dentro do container.


Abaixo segue um exemplo de como seria a configuração para container com banco de dados. Já temos um exemplo de como seria usando dockerfile com a opção USER quando se deve criar o usuário.

docker-compose.yaml
mongodb:
image: docker.io/mongo:4.4.25
command: mongod --nojournal --storageEngine wiredTiger
restart: unless-stopped
user: "999:999"
volumes:
- ../../data/mongodb:/data/db

mysql:
image: docker.io/mysql:8.1.0
command: >
mysqld
--character-set-server=utf8mb3
--collation-server=utf8mb3_general_ci
--binlog-expire-logs-seconds=259200
restart: unless-stopped
user: "999:999"
volumes:
- ../../data/mysql:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: "SENHA"

Isso ajuda a limitar os privilégios do serviço apenas ao que é necessário para sua execução, reduzindo assim a superfície de ataque e potenciais riscos de segurança.


A abordagem descrita acima é eficaz e granular, pois restringe os privilégios ao mínimo necessário para a execução da aplicação. Ainda recomendo liberar o uso do docker com sudo para um maior controle de quais usuários podem usar o docker; lembrando que deve ser liberado o sudo apenas para executar os comandos docker e nada mais. Ainda é possível usar o grupo do docker para isso, mas não terá os registros de logs dos comandos executados.


A opção do rootless é uma opção viável, mas ela tem suas limitações e pode não oferecer a mesma granularidade de controle de privilégios.


Caso o usuário deva ser criado via docker-compose, não será possível, mas podemos adotar uma abordagem simples. Crie o script abaixo:

init.sh
#!/bin/bash

# Cria um grupo e um usuário dentro do container
useradd -r myuser

# Executa o comando principal do container (no caso do Node.js, você pode iniciar sua aplicação Node.js aqui)
exec "$@"

Agora no docker file, adicione o script como command e logo em seguida os comandos necessário para que o container tenha uma razão/propósito contínuo de existir:

docker-compose.yaml
version: '3'

services:
node_app:
image: node:14
volumes:
- ./init.sh:/usr/local/bin/init.sh
command: /usr/local/bin/init.sh npm start


Capabilities


No Linux, Capabilities são mecanismos de segurança que permite um controle mais granular das permissões de um processo. Ao invés de simplesmente permitir ou negar acesso a recursos do sistema, as capabilities oferecem um conjunto mais refinado de permissões que podem ser concedidas ou negadas individualmente a um processo. Isso melhora a segurança, reduzindo o risco de abuso de privilégios caso um processo seja comprometido.


Os containers Docker não recebem acesso irrestrito de root no host, mesmo quando o processo dentro do container está rodando como root. Por padrão, o Docker remove muitas capabilities sensíveis para proteger o host de ações perigosas feitas por processos no container. Algumas capabilities críticas, como CAP_SYS_ADMIN e CAP_NET_RAW, são removidas para evitar abuso.


Você pode modificar as capabilities de um container com as opções:

  • --cap-add: Adiciona uma capability específica ao container.
  • --cap-drop: Remove uma capability específica.

Abaixo podemos ver um exemplo de como usar. Estamos adicionando a capability CAP_NET_ADMIN (gerenciar interfaces de rede) e removendo a capability CAP_NET_RAW (uso de sockets brutos).

Terminal
╼ $ sudo docker run --cap-add=NET_ADMIN --cap-drop=NET_RAW nginx


Seccomp security profiles for Docker


Os Seccomp Security Profiles no Docker são arquivos de configuração que definem as syscalls (chamadas de sistema) permitidas ou bloqueadas para os containers. Eles ajudam a controlar as ações que os processos dentro do container podem executar no kernel do host, oferecendo uma camada adicional de segurança.


Esses perfis utilizam o Seccomp (Secure Computing Mode), uma funcionalidade do kernel Linux, para limitar as interações de syscalls. Isso reduz a superfície de ataque no sistema operacional, tornando os containers mais seguros contra exploits que possam comprometer o host.


Por padrão, o Docker aplica um perfil Seccomp default a todos os containers, a menos que um perfil personalizado seja especificado. O perfil padrão permite as syscalls mais comuns usadas pela maioria das aplicações, bloqueando chamadas de sistema consideradas perigosas.


Com as Seccomp personalizadas, podemos definir perfis para atender às necessidades de segurança específicas de uma aplicação. Isso permite ajustar o nível de restrição, permitindo ou bloqueando syscalls com base no comportamento esperado do container. Exemplo de Uso de Perfis Seccomp no Docker:

custom-seccomp.json
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": ["read", "write", "exit", "exit_group"],
"action": "SCMP_ACT_ALLOW"
},
{
"names": ["execve"],
"action": "SCMP_ACT_ALLOW"
}
]
}

O defaultAction: SCMP_ACT_ERRNO bloqueia qualquer syscall não listada explicitamente. Já SCMP_ACT_ALLOW, permite syscalls necessárias, como leitura/escrita e execução de programas. Agora basta iniciar um container usando o perfil Seccomp personalizado:


Terminal
╼ $ sudo docker run --security-opt seccomp=custom-seccomp.json ubuntu:latest


Docker Content Trust - DCT


O Docker Content Trust (DCT) é uma funcionalidade do Docker que assegura a integridade e autenticidade das imagens de container. Ele utiliza assinaturas digitais para garantir que as imagens utilizadas no processo de build ou execução sejam provenientes de fontes confiáveis e não tenham sido alteradas.


Com o DCT habilitado, o Docker só permite a execução ou pull de imagens que estejam devidamente assinadas. Isso protege contra o uso de imagens maliciosas ou adulteradas, aumentando a segurança do ambiente de execução. O DCT é baseado no Notary, uma tecnologia da CNCF (Cloud Native Computing Foundation), que implementa o protocolo TUF (The Update Framework). Esse protocolo gerencia as assinaturas digitais e os metadados das imagens.


O DCT pode ser usado por qualquer pessoa que utilize o Docker, mas ele depende da existência de um registry para armazenar as assinaturas e os metadados das imagens. Por padrão, ele funciona com o Docker Hub ou qualquer outro registry que suporte o Notary, que é a tecnologia subjacente ao DCT.


Para ativar o DCT, defina a variável de ambiente DOCKER_CONTENT_TRUST como 1:

Terminal
╼ $ export DOCKER_CONTENT_TRUST=1

Quando ativado o docker pull, docker run e docker build só funcionarão para imagens assinadas. As imagens sem assinatura ou invalidadas serão rejeitadas.



Como Assinar Imagens com Docker Content Trust


O Docker cria automaticamente as chaves de assinatura ao fazer o push de uma imagem pela primeira vez. Durante o processo, o Docker solicita uma senha para proteger a chave de root.

Terminal
╼ $ sudo docker push <imagem>:<tag>

Antes de baixar ou executar uma imagem, o Docker verifica a assinatura com os metadados armazenados no servidor Notary. Ao fazer o build da imagem, podemos forçar assinatura, para isso, adicione a flag --sign ao construir imagens:

Terminal
╼ $ sudo docker build --sign -t <imagem>:<tag> .

Se você já tem a imagem e quer assinar, faça:

Terminal
╼ $ sudo docker trust sign <imagem>:<tag>


Trivy


O Trivy é uma ferramenta de scanner de vulnerabilidades para contêineres e sistemas de imagens de contêineres. Ele é usado para detectar vulnerabilidades conhecidas em imagens Docker, imagens OCI (Open Container Initiative) e sistemas de arquivos locais.

Terminal
# Baixe o arquivo binário:
wget -P /usr/src/ https://github.com/aquasecurity/trivy/releases/download/v0.50.1/trivy_0.50.1_Linux-64bit.tar.gz

# Extraia o binário movendo ele para outro diretório:
tar -xf /usr/src/trivy_0.50.1_Linux-64bit.tar.gz -C /usr/local/bin/

# Com a instalação feita, garantiremos que está tudo certo verificando a versão:
trivy version
Version: 0.50.1

Para usar o Trivy a imagem já deve estar buildada (já tem que ter a imagem pronta para uso). Vamos construir uma:

dockerfile
FROM node:latest

RUN adduser fulano

USER fulano

ENV LAST_NAME=ciclano

RUN export LAST_NAME

RUN mkdir /tmp/users && echo "Docker Build" > /tmp/users/users.txt

CMD cat /tmp/users/users.txt

Agora vamos fazer o build da imagem:

Terminal
docker build -t test-build -f dockerfile .
[+] Building 58.4s (8/8) FINISHED docker:default
=> [internal] load build definition from dockerfile 0.0s
=> => transferring dockerfile: 232B 0.0s
=> [internal] load metadata for docker.io/library/node:latest 4.8s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/node:latest@sha256:b9ccc4aca32eebf124e0ca0fd573dacffba2b9236987a1d4d2625ce3c162ecc8 52.3s
=> => resolve docker.io/library/node:latest@sha256:b9ccc4aca32eebf124e0ca0fd573dacffba2b9236987a1d4d2625ce3c162ecc8 0.0s
=> => sha256:c3978d05bc68452fec21b7e4e76399380f4e7505d7f9f034c5981678732f6e96 7.34kB / 7.34kB 0.0s
=> => sha256:71215d55680cf0ab2dcc0e1dd65ed76414e3fb0c294249b5b9319a8fa7c398e4 49.55MB / 49.55MB 10.2s
=> => sha256:3cb8f9c23302e175d87a827f0a1c376bd59b1f6949bd3bc24ab8da0d669cdfa0 24.05MB / 24.05MB 10.5s
=> => sha256:b9ccc4aca32eebf124e0ca0fd573dacffba2b9236987a1d4d2625ce3c162ecc8 1.21kB / 1.21kB 0.0s
=> => sha256:5f899db30843f8330d5a40d1acb26bb00e93a9f21bff253f31c20562fa264767 64.14MB / 64.14MB 29.4s
=> => sha256:ca75f977b1c9e9a2cc5480efe5b7df07ce38373316e30b91eeadddb6a025b8a8 2.00kB / 2.00kB 0.0s
=> => extracting sha256:71215d55680cf0ab2dcc0e1dd65ed76414e3fb0c294249b5b9319a8fa7c398e4 1.1s
=> => sha256:567db630df8d441ffe43e050ede26996c87e3b33c99f79d4fba0bf6b7ffa0213 211.14MB / 211.14MB 46.3s
=> => sha256:f4ac4e9f5ffb96287f2ff537a9cf450fc883facf1276832aac2360270cb0af2b 3.37kB / 3.37kB 10.7s
=> => sha256:375735fcaa7ab4b06a8024c6f4c7a7c809f60d45fb0b37b2969db6ffaf68d5a9 49.72MB / 49.72MB 27.0s
=> => extracting sha256:3cb8f9c23302e175d87a827f0a1c376bd59b1f6949bd3bc24ab8da0d669cdfa0 0.4s
=> => sha256:c12db77023cdbf9c549ddbe6de3ca1c22511ca898d103c91ff5552d09adecc79 2.23MB / 2.23MB 28.0s
=> => sha256:ac50344c1606288c28b458e45a6220b5a18711af76ef6f32247d86c59bc6cce1 450B / 450B 28.3s
=> => extracting sha256:5f899db30843f8330d5a40d1acb26bb00e93a9f21bff253f31c20562fa264767 1.5s
=> => extracting sha256:567db630df8d441ffe43e050ede26996c87e3b33c99f79d4fba0bf6b7ffa0213 3.9s
=> => extracting sha256:f4ac4e9f5ffb96287f2ff537a9cf450fc883facf1276832aac2360270cb0af2b 0.0s
=> => extracting sha256:375735fcaa7ab4b06a8024c6f4c7a7c809f60d45fb0b37b2969db6ffaf68d5a9 1.6s
=> => extracting sha256:c12db77023cdbf9c549ddbe6de3ca1c22511ca898d103c91ff5552d09adecc79 0.0s
=> => extracting sha256:ac50344c1606288c28b458e45a6220b5a18711af76ef6f32247d86c59bc6cce1 0.0s
=> [2/4] RUN adduser fulano 0.6s
=> [3/4] RUN export LAST_NAME 0.2s
=> [4/4] RUN mkdir /tmp/users && echo "Docker Build" > /tmp/users/users.txt 0.2s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:7e8a9189d6a292eaae3d002d9d5809685b2121ee0a5af464ed59ad083bdc241a 0.0s
=> => naming to docker.io/library/test-build 0.0s

Como no exemplo colocamos a tag test-build:latest. Podemos executar o comando trivy image com o nome da imagem para iniciar a análise.

Terminal
trivy image test-build:latest

Caso você queira ver somente a saída de um nível específico, adicione a flag --severity e escolha um ou mais níveis citados. Exemplo: --severity CRITICAL,HIGH.


O comando acima é usado para realizar uma varredura na imagem de contêiner usando a ferramenta Trivy. Esta varredura irá analisar a imagem em busca de vulnerabilidades conhecidas e gerar um relatório sobre essas vulnerabilidades. Por padrão, o Trivy classifica as vulnerabilidades em cinco níveis de severidade:

SeveridadeDescrição
UnknownSeveridade desconhecida, não determinada ou definida
LowBaixa severidade, menos crítica ou explorável
MediumSeveridade moderada, riscos moderados para segurança
HighAlta severidade, risco significativo para segurança
CriticalSeveridade crítica, risco extremamente alto

Essa ferramenta gera um link na coluna Title apontando para uma página que fornecerá mais detalhes a respeito da vulnerabilidade. Basta clicar no link azul que ele redirecionará você para a página automaticamente. Escolher imagens de contêiner com bases mais enxutas é uma abordagem eficaz para reduzir as vulnerabilidades e melhorar a segurança do seu ambiente de contêineres.