Em um mundo de entregas contínuas, a segurança não pode ser uma etapa isolada no final do processo. Ela precisa estar embutida no pipeline de CI/CD, garantindo que cada commit, build e deploy seja verificado automaticamente. Nesta aula, vamos explorar as principais práticas e ferramentas para integrar segurança no seu fluxo de DevOps, desde a análise de dependências até a definição de políticas de aprovação.

Você aprenderá a implementar varreduras automatizadas de vulnerabilidades em dependências, código-fonte e imagens de contêineres, além de como configurar "gates" (portões) que bloqueiam o avanço do pipeline quando problemas são encontrados. Ao final, você terá uma visão clara de como construir um pipeline seguro sem sacrificar a velocidade.

Scanning de dependências

O scanning de dependências (ou Dependency Scanning) é o processo de verificar as bibliotecas e pacotes de terceiros usados no seu projeto em busca de vulnerabilidades conhecidas. Ataques como o que ocorreu no evento SolarWinds destacam a importância de monitorar a cadeia de suprimentos de software. Ferramentas como OWASP Dependency-Check, Snyk, e GitHub Dependabot podem ser integradas ao pipeline para automatizar essa análise.

Essas ferramentas consultam bancos de dados públicos de vulnerabilidades (como o NVD - National Vulnerability Database) e comparam as versões das dependências com as listas de CVEs. Quando uma vulnerabilidade é encontrada, o pipeline pode ser configurado para falhar ou gerar alertas. É crucial definir políticas de severidade: por exemplo, bloquear o build se houver vulnerabilidades críticas, mas permitir com aviso para as de baixa severidade.

Exemplo de integração com OWASP Dependency-Check em um pipeline Jenkins:

# Instalar o Dependency-Check (exemplo em ambiente Linux)
curl -L -o dependency-check.zip https://github.com/jeremylong/DependencyCheck/releases/download/v8.4.2/dependency-check-8.4.2-release.zip
unzip dependency-check.zip

# Executar a varredura
./dependency-check/bin/dependency-check.sh --project "MeuProjeto" --scan . --format HTML --out relatorios/

# No pipeline, se o relatório mostrar vulnerabilidades críticas, falhar
grep -E "Critical|High" relatorios/dependency-check-report.html && exit 1 || echo "Nenhuma vulnerabilidade crítica encontrada"

Além de usar ferramentas, é importante manter as dependências atualizadas e monitorar avisos de segurança. Algumas ferramentas também oferecem correção automática via pull requests, como o Dependabot.

SAST e DAST (visão geral)

SAST (Static Application Security Testing) analisa o código-fonte em busca de padrões inseguros, como injeção de SQL, uso de funções perigosas ou vazamento de dados. Ele é executado durante o desenvolvimento, sem precisar compilar ou executar o aplicativo. Ferramentas populares incluem SonarQube, Checkmarx, e Bandit (para Python). O SAST é rápido e pode ser integrado ao pipeline logo após o commit, ajudando a detectar problemas cedo.

DAST (Dynamic Application Security Testing) testa a aplicação em execução, simulando ataques de um usuário externo. Ele identifica vulnerabilidades como XSS (Cross-Site Scripting), CSRF (Cross-Site Request Forgery) e problemas de configuração. Ferramentas como OWASP ZAP e Burp Suite são comuns. O DAST é mais lento e geralmente executado em ambientes de staging ou após o deploy em um ambiente controlado.

A combinação de SAST e DAST é recomendada, pois eles se complementam: SAST encontra problemas no código, enquanto DAST valida se as vulnerabilidades são exploráveis no contexto real. No pipeline, você pode executar SAST em cada pull request e DAST em cada deploy de staging.

Exemplo de execução de SAST com Bandit (Python) e DAST com OWASP ZAP:

# SAST com Bandit
bandit -r meu_projeto/ -f html -o relatorios/bandit.html

# DAST com OWASP ZAP (modo headless)
zap-baseline.py -t http://staging.exemplo.com -r relatorios/zap_report.html

Scanning de imagens

Com a adoção de contêineres, as imagens Docker se tornaram um vetor de ataque importante. O scanning de imagens verifica as camadas da imagem em busca de vulnerabilidades nos pacotes instalados, configurações inseguras e segredos expostos. Ferramentas como Trivy, Clair e Anchore são amplamente usadas. O scan deve ser feito tanto na imagem final quanto nas camadas intermediárias para garantir que não haja bibliotecas desatualizadas.

Além de vulnerabilidades, o scanning de imagens pode verificar se a imagem está em conformidade com políticas como: não rodar como root, não conter segredos, e usar imagens base oficiais. Ferramentas como Docker Bench for Security e hadolint ajudam a analisar o Dockerfile e a configuração.

Exemplo com Trivy:

# Instalar Trivy
curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh

# Escanear a imagem
trivy image meu-app:latest --severity HIGH,CRITICAL --exit-code 1

O comando acima falha se houver vulnerabilidades altas ou críticas. Isso pode ser usado como um gate no pipeline, impedindo que imagens inseguras sejam publicadas no registry.

Gates

Gates (portões) são pontos de verificação no pipeline que decidem se o fluxo continua ou para. Eles são essenciais para aplicar políticas de segurança de forma automatizada. Um gate pode ser implementado como um script que verifica a saída de uma ferramenta de segurança e retorna um código de erro se os critérios não forem atendidos. Por exemplo, exigir que o SAST não tenha vulnerabilidades críticas, que o scan de dependências não aponte CVEs com severidade alta, ou que a imagem Docker não tenha problemas de alto risco.

Os gates devem ser posicionados em pontos estratégicos: após o commit (SAST), antes do deploy em produção (DAST e scan de imagem), e após o build (dependências). É importante definir critérios claros e comunicar aos desenvolvedores quais são os níveis de severidade aceitáveis. Além disso, é possível usar um sistema de aprovação manual como um gate, mas isso pode atrasar o fluxo; o ideal é automatizar ao máximo.

Exemplo de gate em um script bash:

#!/bin/bash
# Gate de segurança: falha se houver vulnerabilidades críticas

# Executa o scan de dependências e gera JSON
dependency-check --scan . --format JSON --out relatorios/dc.json

# Extrai o número de vulnerabilidades críticas usando python
CRITICAL=$(python3 -c "import json; data=json.load(open('relatorios/dc.json')); print(data['vulnerabilities']['critical'])")

if [ "$CRITICAL" -gt 0 ]; then
  echo "Falha: $CRITICAL vulnerabilidades críticas encontradas"
  exit 1
else
  echo "Gate aprovado: nenhuma vulnerabilidade crítica"
fi

Além de falhas, os gates podem gerar relatórios e notificações para a equipe de segurança. Em ferramentas como GitLab CI, você pode usar regras de "allow_failure" para que o pipeline continue, mas marque o job como falho, ou usar "when: manual" para exigir aprovação manual.

Boas práticas e observações finais

Integrar segurança no CI/CD é um processo contínuo. Algumas boas práticas incluem: usar ferramentas de segurança como código (Security as Code), manter as ferramentas de análise atualizadas, centralizar a configuração de políticas, e educar os desenvolvedores sobre a importância da segurança. Além disso, é recomendável começar com um conjunto pequeno de verificações e expandir gradualmente para evitar sobrecarga.

Lembre-se de que a segurança não é um fim, mas um meio para entregar software confiável. Ao automatizar esses checks, você reduz a chance de erros humanos e libera tempo para a equipe se concentrar em melhorias. A chave é encontrar o equilíbrio entre velocidade e segurança, usando gates para bloquear apenas o que é realmente crítico.

Referências

Exercícios

  1. Explique a diferença entre SAST e DAST e dê um exemplo de quando cada um é mais apropriado.

✓ Resposta: SAST (Static Application Security Testing) analisa o código-fonte estático em busca de vulnerabilidades, sem executar o aplicativo. É rápido e usado durante o desenvolvimento, ideal para detectar problemas como injeção de SQL. DAST (Dynamic Application Security Testing) testa a aplicação em execução, simulando ataques externos. É mais lento e usado em ambientes de staging ou pós-deploy para validar se as vulnerabilidades são exploráveis. Por exemplo, SAST é apropriado em um pull request para revisão de código, enquanto DAST é apropriado antes de liberar uma versão em produção.
  1. Escreva um comando bash usando Trivy para escanear uma imagem chamada "meu-app:latest" e falhar se houver vulnerabilidades críticas ou altas.

✓ Resposta:
trivy image meu-app:latest --severity HIGH,CRITICAL --exit-code 1
  1. Qual é o objetivo de um gate em um pipeline de CI/CD? Dê um exemplo de como implementar um gate simples.

✓ Resposta: Um gate é um ponto de verificação que decide se o pipeline continua ou para, baseado em critérios predefinidos. Por exemplo, um gate pode verificar se o resultado do SAST não contém vulnerabilidades críticas. Implementação: após rodar a ferramenta SAST, um script verifica o relatório e retorna exit 1 se houver problemas críticos, interrompendo o pipeline.
  1. Cite três ferramentas para scanning de dependências e explique brevemente uma delas.

✓ Resposta: Ferramentas: OWASP Dependency-Check, Snyk e GitHub Dependabot. OWASP Dependency-Check é uma ferramenta de código aberto que verifica dependências do projeto contra o NVD e gera relatórios de vulnerabilidades. Ele pode ser integrado a pipelines via CLI.
  1. Por que é importante escanear imagens de contêineres? Cite um risco que pode ser mitigado.

✓ Resposta: As imagens de contêineres podem conter pacotes com vulnerabilidades conhecidas, segredos expostos ou configurações inseguras, que podem ser explorados por atacantes. O scanning ajuda a mitigar o risco de usar imagens base desatualizadas ou com bibliotecas vulneráveis, garantindo que apenas imagens seguras sejam implantadas.