Segurança em containers Docker no DevOps
1. Princípios Fundamentais de Segurança em Containers
1.1. Isolamento vs. Compartilhamento: entendendo os riscos do kernel compartilhado
Diferente de máquinas virtuais, containers compartilham o kernel do host. Isso significa que uma vulnerabilidade no kernel pode comprometer todos os containers em execução. O isolamento fornecido por namespaces e cgroups é eficaz, mas não absoluto. Um atacante que escape do container pode acessar o host e, consequentemente, outros containers.
# Verificar namespaces ativos de um container
docker inspect --format '{{.State.Pid}}' meu-container
ls -la /proc/<PID>/ns/
1.2. O modelo de confiança zero aplicado a containers
No modelo Zero Trust, nenhum container é confiável por padrão. Toda comunicação deve ser autenticada e autorizada. Isso implica:
- Não assumir que a rede interna é segura
- Criptografar tráfego entre containers (mTLS)
- Validar identidade antes de qualquer comunicação
# Exemplo de rede isolada no Docker
docker network create --internal rede-isolada
docker run --network rede-isolada --name app-segura nginx:alpine
1.3. Superfície de ataque reduzida com imagens mínimas e imutáveis
Imagens mínimas como alpine (5MB) ou distroless (sem shell, sem package manager) reduzem drasticamente a superfície de ataque. Imagens imutáveis garantem que o mesmo hash sempre produza o mesmo ambiente.
# Comparação de tamanho de imagens base
docker images | grep -E "ubuntu|alpine|distroless"
ubuntu:22.04 ~77MB
alpine:3.19 ~7MB
gcr.io/distroless/base-debian12 ~25MB (sem shell)
2. Imagens Seguras: Da Construção ao Registry
2.1. Boas práticas de Dockerfile: usuários não-root e camadas mínimas
O princípio do menor privilégio exige que containers nunca executem como root. Combine isso com camadas mínimas para reduzir vulnerabilidades.
# Dockerfile seguro
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY --from=builder /app /app
WORKDIR /app
EXPOSE 3000
CMD ["node", "server.js"]
2.2. Multi-stage builds para eliminar ferramentas de build e secrets
Multi-stage builds permitem que ferramentas de compilação e secrets fiquem apenas em estágios intermediários, não na imagem final.
# Multi-stage build com segurança
FROM golang:1.21 AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app .
FROM scratch
COPY --from=build /app /app
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/app"]
2.3. Scan de vulnerabilidades (Trivy, Snyk) antes do push para o Registry
Integrar scanners no pipeline CI/CD evita que imagens vulneráveis cheguem à produção.
# Scan com Trivy no pipeline
trivy image --severity HIGH,CRITICAL --exit-code 1 minha-imagem:latest
# Exemplo de saída
# Total: 3 (HIGH: 2, CRITICAL: 1)
# CVE-2024-XXXXX (CRITICAL) - pacote libssl1.1
3. Controle de Acesso e Gerenciamento de Secrets
3.1. Evitando secrets em variáveis de ambiente e camadas da imagem
Secrets em variáveis de ambiente ficam visíveis em docker inspect e logs. Prefira montar arquivos de secrets ou usar ferramentas especializadas.
# ❌ Errado: secret em variável de ambiente
docker run -e DB_PASSWORD=senha123 meu-app
# ✅ Correto: secret montado como arquivo
docker run --secret db_password meu-app
3.2. Uso de Docker Secrets e ferramentas externas
Docker Swarm oferece secrets nativos. Para Kubernetes, use Secrets do Kubernetes ou HashiCorp Vault.
# Docker Swarm Secret
echo "minha-senha-segura" | docker secret create db_password -
docker service create --secret db_password --name app meu-app
# HashiCorp Vault (exemplo conceitual)
vault kv put secret/db password=supersecret
3.3. RBAC no Docker Registry e autenticação para pull/push
Configure autenticação e autorização no registry para evitar acesso não autorizado.
# Configurar autenticação básica no Docker Registry
docker run -d -p 5000:5000 --name registry \
-v /auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
registry:2
# Login
docker login localhost:5000 -u admin -p senha
4. Hardening do Host e do Docker Daemon
4.1. Configuração segura do Docker daemon
Habilite TLS para comunicação com o daemon, use rootless mode e perfis de segurança.
# /etc/docker/daemon.json
{
"tls": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"userns-remap": "default",
"selinux-enabled": true,
"live-restore": true
}
4.2. Limitação de recursos com cgroups e ulimits
Evite ataques de negação de serviço limitando CPU, memória e número de processos.
# Limitar recursos do container
docker run -d --name app \
--memory="512m" \
--cpus="0.5" \
--ulimit nofile=1024:2048 \
--pids-limit=100 \
nginx:alpine
4.3. Uso de runtime seccomp e perfis de segurança personalizados
Seccomp restringe chamadas de sistema que o container pode fazer.
# Perfil seccomp personalizado (apenas chamadas essenciais)
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{"names": ["read", "write", "open", "close", "exit", "exit_group"], "action": "SCMP_ACT_ALLOW"}
]
}
# Aplicar ao container
docker run --security-opt seccomp=perfil-seguro.json nginx:alpine
5. Healthchecks e Resiliência como Camada de Segurança
5.1. Healthchecks para detecção de falhas e auto-recuperação
Healthchecks evitam que containers com falha continuem recebendo tráfego.
# Dockerfile com healthcheck
FROM nginx:alpine
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
5.2. Prevenção de containers zumbis e loops de restart
Configure restart policies adequadas e evite loops infinitos.
# Política de restart segura
docker run --restart=on-failure:5 --memory="256m" meu-app
5.3. Integração com orquestradores (Kubernetes liveness/readiness probes)
No Kubernetes, probes garantem que apenas containers saudáveis recebam tráfego.
# Kubernetes deployment com probes
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: app
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 3
periodSeconds: 5
6. Monitoramento, Logs e Auditoria
6.1. Logs centralizados e seguros
Evite expor dados sensíveis em logs. Use drivers de log seguros e filtre informações confidenciais.
# Configurar driver de log json-file com rotação
docker run --log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
--log-opt labels=environment \
meu-app
# No docker-compose.yml
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
6.2. Detecção de anomalias com Falco
Falco monitora chamadas de sistema e detecta comportamentos suspeitos.
# Instalar Falco
docker run -d --name falco \
--privileged \
-v /var/run/docker.sock:/host/var/run/docker.sock \
-v /proc:/host/proc:ro \
falcosecurity/falco
# Regra personalizada (exemplo)
- rule: Shell em container
desc: Detecta shell interativo em container
condition: spawned_process and container and proc.name = bash
output: "Shell detectado (user=%user.name container=%container.name)"
priority: WARNING
6.3. Rastreamento de atividades do container
Eventos do Docker daemon fornecem auditoria detalhada.
# Monitorar eventos do Docker
docker events --filter 'type=container' --filter 'event=start' --filter 'event=stop'
# Kubernetes audit logs (exemplo de policy)
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["pods", "secrets"]
7. Integração Contínua e Segurança no Pipeline DevOps
7.1. Pipeline CI/CD com gate de segurança
Integre scanning e assinatura de imagens no pipeline.
# Pipeline conceitual (GitHub Actions)
jobs:
security:
steps:
- name: Scan de vulnerabilidades
run: trivy image --severity HIGH,CRITICAL --exit-code 1 minha-imagem
- name: Assinar imagem com Cosign
run: |
cosign sign --key cosign.key minha-imagem:latest
cosign verify --key cosign.pub minha-imagem:latest
- name: Push para registry
run: docker push minha-imagem:latest
7.2. Políticas de imagem permitidas
No Kubernetes, use ImagePolicyWebhook para restringir quais imagens podem ser implantadas.
# ImagePolicyWebhook (exemplo de configuração)
apiVersion: v1
kind: ImagePolicy
spec:
imageRules:
- match:
prefix: "registry-seguro.com/"
deny:
conditions:
- expression: "!image.endsWith(':signed')"
7.3. Implantação automatizada com verificação de compliance
Use OPA/Gatekeeper para aplicar políticas de segurança automaticamente.
# OPA Gatekeeper - proibir containers privilegiados
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
name: prohibit-privileged-containers
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
exemptImages: ["gcr.io/k8s-prow/*"]
Referências
- Docker Security Documentation — Documentação oficial sobre segurança no Docker Engine, incluindo seccomp, AppArmor e TLS
- Trivy - Vulnerability Scanner for Containers — Scanner open-source para detectar vulnerabilidades em imagens Docker, usado em pipelines CI/CD
- Falco - Cloud Native Runtime Security — Ferramenta de detecção de anomalias em tempo de execução para containers e Kubernetes
- Open Policy Agent (OPA) - Gatekeeper — Políticas de compliance automatizadas para Kubernetes, integrando segurança no pipeline DevOps
- Cosign - Container Signing and Verification — Ferramenta para assinar e verificar imagens de containers, garantindo integridade e proveniência
- HashiCorp Vault - Secrets Management — Gerenciamento centralizado de secrets para containers e Kubernetes, com rotação automática e auditoria
- Kubernetes Security Best Practices — Guia oficial de segurança do Kubernetes, cobrindo RBAC, Pod Security Standards e network policies