21 min de leitura · Guia técnico
Checklist de segurança do Docker é um conjunto de verificações obrigatórias que devem ser aplicadas antes de colocar qualquer ambiente containerizado em produção. Ignorar essas etapas expõe o host, a rede e os dados da aplicação a vulnerabilidades exploráveis remotamente. Para aplicar o checklist completo, siga estes passos:
- Audite e reduza as imagens base, removendo pacotes desnecessários
- Configure usuários não-root nos Dockerfiles com a instrução USER
- Escaneie imagens com Trivy ou Docker Scout antes do deploy
- Isole redes de containers com bridges personalizadas
- Gerencie segredos com Docker secrets, nunca com variáveis de ambiente
- Ative o modo rootless do Docker e aplique políticas de recursos (CPU/memória)
Pré-requisitos para aplicar o checklist de segurança do Docker
- Sistema operacional: Debian 12 (Bookworm) ou Rocky Linux 9 com acesso root ou sudo
- Docker Engine: versão 24.x ou superior instalada e em execução
- Docker Compose: versão 2.x (plugin oficial, não o binário legado)
- Trivy: ferramenta de escaneamento de vulnerabilidades (instalação coberta abaixo)
- Acesso SSH: ao servidor VPS ou dedicado onde os containers serão executados
- Permissão para editar Dockerfiles e arquivos de composição do projeto
- Conhecimento básico de linha de comando Linux e conceitos de containers
Checklist de segurança do Docker: imagens e Dockerfile
O ponto de partida de qualquer ambiente Docker seguro é a qualidade das imagens utilizadas. Imagens infladas com pacotes desnecessários ampliam a superfície de ataque e dificultam auditorias. Prefira imagens base minimalistas como alpine, debian:slim ou distroless do Google.
Ao construir sua própria imagem, siga estas práticas no Dockerfile:
FROM debian:12-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR /app
COPY --chown=appuser:appuser . .
USER appuser
CMD ["./minha-aplicacao"]
Pontos críticos neste Dockerfile:
- FROM debian:12-slim: imagem base enxuta, sem ferramentas de debug desnecessárias
- --no-install-recommends: evita instalação de pacotes sugeridos que não são necessários
- rm -rf /var/lib/apt/lists/*: limpa o cache do apt, reduzindo o tamanho da camada
- USER appuser: o processo principal roda sem privilégios de root
- COPY --chown: arquivos da aplicação pertencem ao usuário não-root
Além disso, nunca copie arquivos .env, chaves SSH ou certificados privados para dentro da imagem. Use o arquivo .dockerignore para excluir esses itens:
.env
.env.*
*.pem
*.key
.git
node_modules
__pycache__
Verifique também se nenhuma camada intermediária do build expõe segredos. Use docker history nome-da-imagem para inspecionar cada camada e confirmar que credenciais não foram incluídas acidentalmente.
Escaneamento de vulnerabilidades com Trivy antes do deploy
Antes de qualquer deploy em produção, o escaneamento de CVEs nas imagens é uma etapa inegociável do processo de segurança de containers. O Trivy é a ferramenta mais adotada para essa finalidade por sua facilidade de uso e base de dados atualizada.
Para instalar o Trivy no Debian 12:
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | \
gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] \
https://aquasecurity.github.io/trivy-repo/deb generic main" | \
sudo tee /etc/apt/sources.list.d/trivy.list
sudo apt-get update && sudo apt-get install -y trivy
Para escanear uma imagem local ou do registry:
trivy image --severity HIGH,CRITICAL nome-da-imagem:tag
Output esperado (exemplo parcial):
nome-da-imagem:tag (debian 12.5)
================================
Total: 3 (HIGH: 2, CRITICAL: 1)
┌──────────────┬────────────────┬──────────┬──────────────────────────┐
│ Library │ Vulnerability │ Severity │ Title │
├──────────────┼────────────────┼──────────┼──────────────────────────┤
│ libssl3 │ CVE-2024-XXXX │ CRITICAL │ OpenSSL: buffer overflow │
│ zlib1g │ CVE-2023-XXXX │ HIGH │ zlib: heap overflow │
└──────────────┴────────────────┴──────────┴──────────────────────────┘
Para integrar o Trivy em pipelines de CI/CD e bloquear deploys automaticamente quando vulnerabilidades críticas forem encontradas, use a flag --exit-code 1:
trivy image --exit-code 1 --severity CRITICAL nome-da-imagem:tag
Se o comando retornar código de saída 1, o pipeline é interrompido antes do deploy. Essa prática elimina a janela de exposição entre a descoberta de uma CVE e a atualização da imagem em produção.
Além do Trivy, o Docker Scout (integrado ao Docker Desktop e à CLI) oferece análise de dependências e recomendações de atualização diretamente no fluxo de trabalho:
docker scout cves nome-da-imagem:tag
Isolamento de rede e controle de portas expostas
O isolamento de rede entre containers é um dos pilares do hardening de ambientes Docker. Por padrão, todos os containers conectados à rede bridge padrão do Docker podem se comunicar entre si, o que representa um risco em ambientes multi-serviço.
Crie redes bridge personalizadas para cada grupo de serviços que precisam se comunicar:
docker network create --driver bridge rede-backend
docker network create --driver bridge rede-frontend
No docker-compose.yml, defina redes explicitamente:
version: "3.9"
services:
app:
image: minha-app:1.0
networks:
- rede-frontend
- rede-backend
banco:
image: postgres:16-alpine
networks:
- rede-backend
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
nginx:
image: nginx:1.26-alpine
ports:
- "127.0.0.1:8080:80"
networks:
- rede-frontend
networks:
rede-frontend:
rede-backend:
secrets:
db_password:
file: ./secrets/db_password.txt
Pontos críticos nesta configuração:
- Redes separadas: o container
nginxnão tem acesso direto ao banco de dados - 127.0.0.1:8080:80: a porta 80 do Nginx é exposta apenas na interface loopback do host, não publicamente
- secrets: a senha do banco é gerenciada via Docker secrets, não como variável de ambiente
Para containers que não precisam de nenhuma conectividade de rede, use --network=none:
docker run --network=none --rm nome-da-imagem tarefa-isolada
Verifique regularmente quais portas estão expostas no host com:
docker ps --format "table {{.Names}}\t{{.Ports}}"
Controle de recursos, capabilities e políticas de segurança
Limitar os recursos que um container pode consumir é essencial para prevenir ataques de negação de serviço (DoS) internos e garantir a estabilidade do host. Use as flags --memory e --cpus ou defina limites no Compose:
services:
app:
image: minha-app:1.0
deploy:
resources:
limits:
cpus: "0.50"
memory: 256M
reservations:
cpus: "0.25"
memory: 128M
Além dos recursos, o Docker herda todas as Linux capabilities padrão para os containers, muitas das quais não são necessárias para a maioria das aplicações. Remova todas e adicione apenas as necessárias:
docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--security-opt no-new-privileges:true \
--read-only \
--tmpfs /tmp \
nome-da-imagem
Explicação das flags:
- --cap-drop ALL: remove todas as capabilities Linux do container
- --cap-add NET_BIND_SERVICE: adiciona apenas a capability necessária para bind em portas abaixo de 1024
- --security-opt no-new-privileges:true: impede que processos dentro do container adquiram novos privilégios via setuid/setgid
- --read-only: monta o sistema de arquivos do container como somente leitura
- --tmpfs /tmp: fornece um diretório temporário em memória para escrita
Para ambientes que exigem conformidade mais rigorosa, considere integrar perfis AppArmor ou seccomp ao runtime do container. O Docker já aplica um perfil seccomp padrão, mas perfis customizados permitem restringir chamadas de sistema específicas da aplicação.
Se você está configurando um servidor Linux para hospedar múltiplos serviços em containers, consulte também as Dicas de Otimização de Servidores Linux para ajustar parâmetros do kernel que impactam diretamente o desempenho e a segurança dos containers.
Gerenciamento de segredos e variáveis sensíveis
O gerenciamento inadequado de credenciais é uma das causas mais comuns de comprometimento em ambientes Docker. Variáveis de ambiente definidas com -e ou no bloco environment do Compose ficam visíveis via docker inspect e podem aparecer em logs de orquestradores como Kubernetes ou Swarm.
Atenção: nunca armazene senhas, tokens de API ou chaves privadas diretamente em Dockerfiles, arquivos docker-compose.yml versionados no Git ou como variáveis de ambiente passadas na linha de comando.
Para usar Docker secrets no modo Swarm:
echo "minha_senha_segura" | docker secret create db_password -
Para verificar os secrets criados:
docker secret ls
Output esperado:
ID NAME DRIVER CREATED UPDATED
abc123def456ghi789jkl012 db_password 2 minutes ago 2 minutes ago
Dentro do container, o secret fica disponível como arquivo em /run/secrets/db_password, legível apenas pelo processo da aplicação. Configure sua aplicação para ler credenciais a partir de arquivos, não de variáveis de ambiente.
Para ambientes sem Swarm, alternativas válidas incluem:
- HashiCorp Vault: solução robusta para gerenciamento de segredos em produção
- Arquivos .env fora do repositório: carregados via
--env-filecom permissões restritas (chmod 600) - Variáveis de ambiente do sistema operacional host: injetadas no Compose via
${VARIAVEL}sem hardcode
Verifique periodicamente se algum secret foi exposto acidentalmente em imagens já publicadas:
docker history --no-trunc nome-da-imagem | grep -i -E "password|secret|key|token"
Modo rootless do Docker e hardening do daemon
O modo rootless do Docker é uma das melhorias de segurança mais significativas disponíveis atualmente, permitindo executar o daemon e os containers inteiramente sem privilégios de root no host. Isso reduz drasticamente o impacto de uma eventual fuga de container.
Para instalar as dependências e configurar o modo rootless no Debian 12:
sudo apt-get install -y uidmap dbus-user-session
dockerd-rootless-setuptool.sh install
Após a instalação, configure as variáveis de ambiente para o usuário atual:
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
export PATH=/usr/bin:$PATH
Adicione essas linhas ao ~/.bashrc ou ~/.profile para persistência. Para iniciar o daemon rootless automaticamente:
systemctl --user enable docker
systemctl --user start docker
loginctl enable-linger $(whoami)
Além do modo rootless, aplique hardening ao arquivo de configuração do daemon Docker em /etc/docker/daemon.json:
{
"icc": false,
"no-new-privileges": true,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"userns-remap": "default",
"live-restore": true
}
Explicação das opções:
- icc: false: desativa a comunicação inter-container na rede bridge padrão
- no-new-privileges: true: aplica a restrição globalmente a todos os containers
- userns-remap: default: ativa o mapeamento de user namespaces, isolando UIDs do container do host
- live-restore: true: mantém containers rodando durante reinicializações do daemon
Após editar o arquivo, reinicie o daemon:
sudo systemctl restart docker
Para entender melhor como um VPS Linux funciona como base para ambientes Docker, consulte o artigo Compreendendo o Servidor VPS: O que é e Como Funciona!.
Auditoria, logs e monitoramento contínuo
A segurança de containers não termina no deploy. O monitoramento contínuo e a auditoria de eventos são componentes essenciais de uma postura de segurança madura. Configure o Docker para enviar logs a um sistema centralizado e monitore eventos em tempo real.
Para visualizar eventos do daemon Docker em tempo real:
docker events --filter type=container --filter event=die
Para auditar containers em execução e verificar configurações de segurança, use o Docker Bench for Security, um script oficial baseado no CIS Docker Benchmark:
docker run --rm --net host --pid host --userns host --cap-add audit_control \
-e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
-v /etc:/etc:ro \
-v /usr/bin/containerd:/usr/bin/containerd:ro \
-v /usr/bin/runc:/usr/bin/runc:ro \
-v /usr/lib/systemd:/usr/lib/systemd:ro \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--label docker_bench_security \
docker/docker-bench-security
O script gera um relatório com itens classificados como [PASS], [WARN] e [INFO], cobrindo configurações do host, do daemon, das imagens e dos containers em execução. Trate todos os itens [WARN] como tarefas prioritárias antes de ir ao ar.
Configure também rotação de logs para evitar que containers consumam todo o espaço em disco do host:
docker run \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
nome-da-imagem
Problemas comuns e como resolver
Sintoma: container reinicia em loop com erro "permission denied"
Causa: o Dockerfile define um usuário não-root com USER appuser, mas os arquivos da aplicação ou volumes montados pertencem ao root, impedindo leitura ou escrita.
Solução: corrija a propriedade dos arquivos no Dockerfile com COPY --chown=appuser:appuser . . e, para volumes do host, ajuste as permissões antes de montar: sudo chown -R 1000:1000 /caminho/do/volume. Verifique o UID do usuário criado no container com docker run --rm nome-da-imagem id e alinhe com o UID do diretório no host.
Sintoma: Trivy reporta vulnerabilidades críticas em imagem que não consigo atualizar
Causa: a imagem base está desatualizada ou o pacote vulnerável é uma dependência transitiva que não pode ser removida imediatamente.
Solução: como medida temporária, adicione uma camada de atualização no Dockerfile: RUN apt-get update && apt-get upgrade -y && rm -rf /var/lib/apt/lists/*. Para dependências de linguagem (npm, pip, gem), atualize o arquivo de lock e reconstrua a imagem. Documente a exceção no pipeline de CI/CD com prazo definido para resolução definitiva.
Sintoma: containers não conseguem se comunicar após criação de redes personalizadas
Causa: os containers foram conectados a redes diferentes ou o nome do serviço usado como hostname não resolve dentro da rede bridge personalizada.
Solução: confirme que ambos os containers estão na mesma rede com docker network inspect nome-da-rede. No Docker Compose, containers na mesma rede se resolvem pelo nome do serviço definido no docker-compose.yml. Teste a resolução com docker exec container-a ping container-b. Se usar redes criadas manualmente, conecte os containers explicitamente: docker network connect nome-da-rede nome-do-container.
Sintoma: docker inspect revela variáveis de ambiente com senhas em texto claro
Causa: credenciais foram passadas via -e SENHA=valor ou no bloco environment do Compose sem uso de secrets.
Solução: migre imediatamente para Docker secrets (modo Swarm) ou arquivos .env com permissão 600 fora do repositório. Remova o container comprometido, rotacione todas as credenciais expostas e recrie o container com a configuração correta. Adicione uma verificação no pipeline de CI/CD para detectar variáveis sensíveis antes do deploy.
Sintoma: daemon Docker falha ao iniciar no modo rootless com erro "rootlesskit: ... newuidmap"
Causa: o pacote uidmap não está instalado ou o arquivo /etc/subuid não contém uma entrada para o usuário atual.
Solução: instale o pacote com sudo apt-get install -y uidmap e verifique as entradas: grep $(whoami) /etc/subuid /etc/subgid. Se não houver entradas, adicione-as manualmente: echo "$(whoami):100000:65536" | sudo tee -a /etc/subuid /etc/subgid. Em seguida, execute novamente dockerd-rootless-setuptool.sh install.
Perguntas frequentes sobre checklist de segurança do Docker
É seguro rodar containers Docker como root?
Rodar containers como root é um risco sério: se o processo dentro do container for comprometido, o atacante pode escalar privilégios para o host. O correto é definir um usuário não-root no Dockerfile com a instrução USER e usar o modo rootless do Docker sempre que possível. Em ambientes de produção, essa configuração deve ser tratada como requisito, não como recomendação opcional.
Como impedir que um container acesse a rede do host no Docker?
Crie redes bridge personalizadas para isolar containers entre si e do host. Use a flag --network=none para containers que não precisam de conectividade externa, e restrinja portas expostas ao mínimo necessário com -p 127.0.0.1:PORTA:PORTA para não expor serviços publicamente. Desative também a comunicação inter-container na rede padrão com "icc": false no daemon.json.
O que são Docker secrets e quando devo usá-los?
Docker secrets são mecanismos para armazenar dados sensíveis como senhas, tokens e chaves privadas fora das imagens e variáveis de ambiente. Devem ser usados sempre que a aplicação precisar de credenciais, pois variáveis de ambiente ficam visíveis via docker inspect e em logs de orquestração. No modo Swarm, os secrets são criptografados em repouso e em trânsito, sendo disponibilizados como arquivos temporários dentro do container.
Como verificar vulnerabilidades em imagens Docker antes de subir para produção?
Use ferramentas como Trivy ou Docker Scout para escanear imagens em busca de CVEs conhecidos. Execute trivy image nome-da-imagem antes de qualquer deploy e configure pipelines de CI/CD para bloquear imagens com vulnerabilidades críticas automaticamente usando a flag --exit-code 1. Mantenha o banco de dados do Trivy atualizado com trivy image --download-db-only regularmente.
O que é o modo rootless do Docker e como ativar?
O modo rootless permite executar o daemon Docker e os containers sem privilégios de root no host, reduzindo drasticamente a superfície de ataque. Para ativar, instale as dependências com apt install uidmap e execute dockerd-rootless-setuptool.sh install como usuário comum. Após a instalação, configure a variável DOCKER_HOST apontando para o socket do usuário e habilite o serviço com systemctl --user enable docker.
Conclusão
Aplicar o checklist de segurança do Docker antes de ir ao ar não é uma tarefa única, mas um processo contínuo que abrange desde a construção das imagens até o monitoramento em produção. Os pontos mais críticos a reter são:
- Nunca suba para produção sem escanear imagens: execute
trivy imageem todo pipeline de CI/CD e bloqueie deploys com CVEs críticos automaticamente - Elimine root dos containers e do daemon: use a instrução
USERnos Dockerfiles,--cap-drop ALLno runtime e ative o modo rootless sempre que o ambiente permitir - Isole redes, limite recursos e gerencie segredos corretamente: redes bridge personalizadas, limites de CPU/memória e Docker secrets são a base de um ambiente containerizado resiliente a ataques
Leia também
- Entenda o que é Fail2Ban: como funciona e exemplos práticos
- Otimizar a Configuração do Firewall Firewalld para Segurança e Performance em VPS Linux e Servidor Dedicado
- Passo a passo para configurar firewall com nftables em VPS Linux e servidor dedicado
Precisa de ajuda com Docker e segurança de containers?
Configurar um ambiente Docker seguro exige uma base de infraestrutura confiável. Os planos de VPS da AviraHost oferecem servidores Linux com acesso root completo, suporte a Docker e recursos dedicados para que você aplique cada item deste checklist sem limitações de ambiente.