Hardening de segurança do Docker
Docker facilita o deploy mas introduz superfície de ataque nova — containers rodando como root, imagens com vulnerabilidades conhecidas, portas expostas desnecessariamente e acesso ao socket Docker. Aplicar hardening reduz drasticamente o risco de um container comprometido escalar para o host.
Rodar containers como usuário não-root
A configuração de segurança mais impactante no Docker:
# No Dockerfile — criar usuário não-root:
FROM node:22-alpine
# Criar grupo e usuário:
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --omit=dev
# Trocar para o usuário não-root:
USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]
# Verificar que o container não roda como root:
docker run --rm minha-imagem id
# Deve mostrar: uid=1000(appuser) gid=1000(appgroup)
# No docker-compose.yml — usar user: diretiva:
services:
api:
image: minha-imagem
user: "1000:1000" # UID:GID
# Verificar usuário de containers em execução:
docker ps -q | xargs docker inspect --format '{{.Name}} {{.Config.User}}'Limitar capabilities e recursos dos containers
Remover permissões desnecessárias dos containers:
# docker-compose.yml — configuração segura:
services:
api:
image: minha-api:latest
# Remover todas as capabilities, adicionar apenas as necessárias:
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # se precisar bindar porta < 1024
# Tornar sistema de arquivos somente leitura:
read_only: true
# tmpfs para diretórios que precisam de escrita:
tmpfs:
- /tmp
- /var/run
# Sem privilégios extras:
security_opt:
- no-new-privileges:true
# Limitar recursos:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
memory: 128M
# Sem acesso ao socket Docker:
# NÃO monte /var/run/docker.sock a menos que seja absolutamente necessárioRedes isoladas e configuração do daemon
Isolar containers em redes separadas e configurar o Docker daemon:
# docker-compose.yml — redes isoladas:
services:
api:
networks:
- frontend # acessa nginx
- backend # acessa banco
nginx:
networks:
- frontend # apenas nginx fica na rede pública
postgres:
networks:
- backend # banco só acessível pela api
redis:
networks:
- backend
networks:
frontend:
backend:
internal: true # sem acesso à internet — apenas comunicação interna
# /etc/docker/daemon.json — configuração segura do daemon:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"no-new-privileges": true,
"live-restore": true,
"userland-proxy": false,
"default-address-pools": [
{ "base": "172.17.0.0/16", "size": 24 }
]
}
# Aplicar mudanças no daemon:
sudo systemctl reload dockerGerenciar secrets com segurança
Nunca colocar credenciais em variáveis de ambiente ou imagens:
# Antipadrão — NUNCA faça isso no Dockerfile:
ENV DATABASE_PASSWORD=minhaSenha # fica na imagem para sempre
# Correto — usar arquivos .env (não commitados no git):
# docker-compose.yml:
services:
api:
env_file: .env # carregado do arquivo .env local
environment:
# Apenas variáveis não-sensíveis inline:
NODE_ENV: production
PORT: 3000
# .env (no .gitignore):
DATABASE_URL=postgresql://user:senha@postgres:5432/db
JWT_SECRET=segredo_jwt
# Docker Secrets (modo Swarm) — mais seguro que env vars:
# echo "minha_senha_forte" | docker secret create db_password -
# Para VPS sem Swarm: usar bind mount de arquivo secreto:
services:
api:
volumes:
- /run/secrets/db_password:/run/secrets/db_password:ro
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
# Verificar se imagem expõe secrets:
docker history --no-trunc minha-imagem | grep -i "password|secret|key"Scanning de vulnerabilidades em imagens
Detectar vulnerabilidades conhecidas antes de colocar em produção:
# Trivy — scanner de vulnerabilidades de containers (gratuito):
# Instalar:
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \
| sh -s -- -b /usr/local/bin
# Escanear imagem:
trivy image nginx:latest
# Escanear apenas vulnerabilidades críticas/altas:
trivy image --severity HIGH,CRITICAL minha-api:latest
# Escanear a imagem e retornar erro se houver vuln crítica (útil no CI):
trivy image --exit-code 1 --severity CRITICAL minha-api:latest
# No GitHub Actions:
- name: Scan de vulnerabilidades
uses: aquasecurity/trivy-action@master
with:
image-ref: 'ghcr.io/usuario/minha-api:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
# docker scout (integrado ao Docker Desktop):
docker scout cves minha-imagem:latest
docker scout recommendations minha-imagem:latest$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.