Multi-stage e segurança de imagem
Objetivos desta aula
- Separar build de runtime
- Rodar como usuário não-root com filesystem read-only
- Escanear vulnerabilidades
Multi-stage build resolve um conflito antigo: para compilar você precisa de compilador, dependências de dev e ferramentas; para rodar, precisa apenas do artefato. Com estágios separados, o resultado final contém somente o necessário — imagem menor, build mais rápido e superfície de ataque reduzida.
Segurança de container tem uma lista curta e obrigatória: usuário não-root, sem segredo embutido, base atualizada e fixada, filesystem read-only quando possível, capabilities descartadas e limites de recurso definidos. Cada item desses aparece em checklist de auditoria real.
Scan de imagem no pipeline transforma segurança em processo. Falhe o build em vulnerabilidade crítica com correção disponível e gere SBOM para saber o que existe dentro do artefato — exigência crescente em contratos corporativos.
1. Multi-stage: build pesado, runtime enxuto
O primeiro estágio tem compiladores e dependências de desenvolvimento; o último copia só o resultado. Uma imagem Node cai de ~1 GB para ~150 MB, com menos superfície de ataque.
2. Imagens base mínimas
Alpine, slim e distroless reduzem pacotes (e vulnerabilidades). Distroless nem tem shell, o que dificulta invasores e também o debug — use kubectl debug ou imagens :debug quando necessário.
3. Não rode como root
Use USER node (ou um UID numérico). Se o processo for comprometido, o estrago fica limitado. Em Kubernetes, reforce com runAsNonRoot e readOnlyRootFilesystem.
4. Scan de vulnerabilidades e SBOM
Trivy ou Grype listam CVEs por severidade. Falhe o pipeline em CRITICAL com correção disponível. Gere um SBOM (lista de componentes) para responder rápido quando surgir uma nova CVE.
5. Checagem final
Sua imagem deve ser multi-stage, não-root, sem CVEs críticas corrigíveis e menor que 200 MB.
Na prática
Frontend Vue em multi-stage com Nginx
dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build # gera /app/dist
FROM nginx:1.27-alpine AS runtime
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx.conf /etc/nginx/conf.d/app.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
USER nginx
CMD ["nginx", "-g", "daemon off;"]Scan, SBOM e execução endurecida
bash
DOCKER_BUILDKIT=1 docker build -t cloudshop-web:v1 .
docker images cloudshop-web:v1 --format '{{.Size}}'
trivy image --severity HIGH,CRITICAL --exit-code 1 cloudshop-web:v1
docker sbom cloudshop-web:v1 2>/dev/null | head
docker run -d --name web \
--read-only --tmpfs /tmp --tmpfs /var/cache/nginx \
--cap-drop ALL --security-opt no-new-privileges \
--memory 256m --cpus 0.5 -p 8080:80 cloudshop-web:v1
docker history cloudshop-web:v1 | head # confirme que nao ha segredoNota de segurança: docker history revela comandos de build. Se um segredo passou por ARG, considere-o comprometido e rotacione.
Multi-stage não-root
dockerfile
FROM node:20.15-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
USER 1000 # nao-root
CMD ["dist/server.js"]Scan e SBOM
bash
trivy image --severity CRITICAL,HIGH --ignore-unfixed --exit-code 1 cloudshop-api:1.4.0
trivy image --format cyclonedx -o sbom.json cloudshop-api:1.4.0
docker images cloudshop-api --format '{{.Tag}} {{.Size}}'Por que isso importa
Imagem grande custa tempo de pipeline e dinheiro de registry; imagem insegura custa incidente.
Erro comum
Deixar devDependencies e ferramentas de build na imagem final.
Dica de produção
Use BuildKit com cache mount para dependências e mantenha a imagem final abaixo de 200 MB.
Alerta de segurança
Rodar como root com filesystem gravável permite que uma RCE na aplicação se torne persistente.
Pergunta de entrevista
Quais são as cinco medidas que você aplica para endurecer uma imagem de container?
Glossário
- multi-stage
- Dockerfile com vários FROM, copiando apenas artefatos entre estágios.
- SBOM
- Inventário dos componentes de software presentes no artefato.
- distroless
- Imagem sem gerenciador de pacotes nem shell, só o runtime necessário.
- CVE
- Identificador público de uma vulnerabilidade conhecida.
- SBOM
- Lista de todos os componentes e versões de um software.
Conexão com o CloudShop
Reduzir a imagem do frontend do CloudShop e bloquear o build em vulnerabilidade crítica.
Quiz da aula
1. Qual o principal benefício do multi-stage build?
2. Principal ganho do multi-stage?
3. Por que não rodar como root?
Minhas anotações
Salvo automaticamente neste navegador.