Segurança no CI: scan de imagens Docker e dependências
Cada imagem Docker que você faz deploy pode conter vulnerabilidades conhecidas. Integrar scanners de segurança no pipeline de CI detecta CVEs críticos antes que cheguem à produção — sem custo adicional, usando ferramentas open-source que rodam diretamente no GitHub Actions.
Trivy: scanner de imagens Docker no CI
Detectar CVEs em imagens Docker com Trivy no GitHub Actions:
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # scan semanal às 6h toda segunda
jobs:
scan-docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build imagem para scan
run: docker build -t scan-target:latest .
- name: Scan com Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: scan-target:latest
format: 'sarif' # formato para GitHub Security tab
output: trivy-results.sarif
severity: 'CRITICAL,HIGH'
exit-code: '1' # falhar CI se encontrar CRITICAL ou HIGH
- name: Upload resultados para GitHub Security
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: trivy-results.sarif
# Relatório no PR:
- name: Scan com saída em tabela (para comentário)
if: github.event_name == 'pull_request'
uses: aquasecurity/trivy-action@master
with:
image-ref: scan-target:latest
format: 'table'
severity: 'CRITICAL,HIGH,MEDIUM'
exit-code: '0' # não falhar neste step (já falhou acima)Scan de dependências npm com npm audit
Detectar vulnerabilidades em dependências antes do deploy:
# .github/workflows/security.yml — adicionar job:
scan-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: npm ci
# npm audit nativo — falhar para vulnerabilidades críticas:
- name: npm audit
run: npm audit --audit-level=high
# --audit-level: low, moderate, high, critical
# Relatório detalhado:
- name: npm audit report
if: failure()
run: npm audit --json | jq '.vulnerabilities | keys[] as $k | .[$k] | select(.severity == "high" or .severity == "critical") | {name: $k, severity: .severity, via: .via[0]}'
# Para ignorar vulnerabilidades conhecidas sem correção:
# npm audit --audit-level=high --production
# (ignora devDependencies)
# Alternativa mais rica: audit-ci
# npm install -g audit-ci
- name: audit-ci (com allowlist)
run: |
npx audit-ci --high \
--allowlist GHSA-xxxx-yyyy-zzzz # ignorar CVE específico com justificativaDependabot: atualizações automáticas de segurança
Configurar Dependabot para criar PRs de atualização automáticos:
# .github/dependabot.yml — na raiz do repositório:
version: 2
updates:
# Dependências npm:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "America/Sao_Paulo"
# Criar PRs separados para cada dependência (não agrupar):
open-pull-requests-limit: 10
# Reviewer automático:
reviewers:
- "meu-usuario"
# Labels para fácil filtragem:
labels:
- "dependabot"
- "security"
# Agrupar atualizações de patch (menos PRs):
groups:
patch-updates:
update-types:
- "patch"
# Dependências do GitHub Actions:
- package-ecosystem: "github-actions"
directory: "/.github/workflows"
schedule:
interval: "weekly"
labels:
- "ci"
# Dockerfile base images:
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"Scan de secrets no código com Gitleaks
Detectar senhas e tokens acidentalmente commitados:
# .github/workflows/security.yml — scan de secrets:
scan-secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # histórico completo para escanear todos os commits
- name: Scan de secrets com Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} # gratuito para repositórios públicos
# .gitleaks.toml — configuração de regras customizadas:
title = "Gitleaks Config"
[extend]
useDefault = true
[[rules]]
description = "Variável customizada de produção"
id = "prod-db-url"
regex = '''DATABASE_URL=postgresql://[^s]+'''
tags = ["secret", "database"]
[[allowlist]]
description = "Ignorar arquivos de teste"
paths = ['''test/.*''', '''.test.ts#x27;'']
[[allowlist]]
description = "Ignorar exemplos de código"
regexes = ['''exemplo|placeholder|your-''']Policy as code com OPA/Conftest
Validar que o Dockerfile segue políticas de segurança:
# policy/docker.rego — políticas de segurança para Dockerfiles:
package main
# Proibir rodar como root:
deny[msg] {
input[i].Cmd == "cmd"
# Sem USER definido = root por padrão:
not any([c | c := input[_]; c.Cmd == "user"])
msg := "Dockerfile não define USER não-root"
}
# Exigir HEALTHCHECK:
deny[msg] {
not any([c | c := input[_]; c.Cmd == "healthcheck"])
msg := "Dockerfile não tem HEALTHCHECK definido"
}
# Exigir versão pinada na imagem base (não :latest):
deny[msg] {
input[i].Cmd == "from"
image := input[i].Value[0]
endswith(image, ":latest")
msg := sprintf("Imagem base usa :latest: %s", [image])
}
# .github/workflows/security.yml — validar com Conftest:
check-dockerfile:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Instalar Conftest
run: |
curl -L https://github.com/open-policy-agent/conftest/releases/download/v0.46.0/conftest_0.46.0_Linux_x86_64.tar.gz | tar xz
mv conftest /usr/local/bin/
- name: Validar Dockerfile
run: conftest test Dockerfile --policy policy/$ runstack deploy --plan starter
Não quer configurar manualmente?
Não quer configurar manualmente? Implante o VPS para Docker em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.