Gerenciamento de Software Ágil

Aula 06 - Dependências, Vulnerabilidades e Gerenciamento de Incidentes

  • Objetivos: Abordar dependências, vulnerabilidades e incidentes, fortalecendo a confiabilidade operacional.
  • Curso: CST em Análise e Desenvolvimento de Sistemas
  • Série: 4º período (semestral)
  • Disciplina: Gerenciamento de Projetos Ágil

Visão geral da aula

Nesta aula, conectamos a gestão de dependências e vulnerabilidades à operação e ao gerenciamento de incidentes. O objetivo é reduzir riscos de cadeia de suprimentos de software, elevar o padrão de qualidade e criar respostas eficazes a incidentes, mantendo a continuidade do serviço e a confiança do usuário.

Fundamentos de confiabilidade operacional

  • Confiabilidade como propriedade emergente: resulta de escolhas em arquitetura, automação, testes, observabilidade e resposta a incidentes.
  • Cadeia de suprimentos de software: bibliotecas, imagens de contêiner, ferramentas de build, pipelines e infraestrutura como código.
  • Princípios orientadores:
    • Prevenção > Detecção > Resposta > Aprendizado contínuo.
    • Automação segura por padrão (secure-by-default) e mínima superfície de ataque.
    • Transparência e rastreabilidade (SBOM, auditorias de build, assinaturas).

6.1 Dependências e vulnerabilidades

Tipos de dependências e seus riscos

  • Dependências diretas e transitivas: vulnerabilidades frequentemente entram por transitivas.
  • Ambientes e escopos: runtime vs. desenvolvimento; produção vs. teste.
  • Imagens base e runtimes: SO, contêineres, VMs, funções serverless.

Versionamento e reprodutibilidade

  • Versionamento semântico (SemVer): MAJOR.MINOR.PATCH.
  • Faixas de versão:
    • Fixa (pinning) aumenta reprodutibilidade.
    • Caret/til (~, ^) acelera updates, mas amplia superfície de risco.
  • Lockfiles e hashes: garantem integridade de resolução de dependências.

Exemplo (Node.js) com política de versões e lockfile:

{
  "name": "app-segura",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "express": "4.19.2",         // versão fixa para reprodutibilidade
    "pino": "^9.0.0"             // caret para obter correções rápidas (avaliar risco)
  },
  "devDependencies": {
    "eslint": "~9.9.0"           // til para fixar minor e permitir patch
  },
  "engines": {
    "node": ">=20.11.0"
  }
}

Python com pinning e verificação por hash:

# requirements.txt
flask==3.0.3 --hash=sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
gunicorn==22.0.0 --hash=sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

SBOM (Software Bill of Materials)

  • O que é: manifesto de componentes, versões, licenças e origem.
  • Padrões comuns: CycloneDX, SPDX.
  • Benefícios: triagem acelerada em incidentes, conformidade, gestão de risco.

Gerando SBOM (CycloneDX para Node.js):

npm install --save-dev @cyclonedx/cyclonedx-npm
npx @cyclonedx/cyclonedx-npm --output-format json --output-file sbom.json

Vulnerabilidades: identificação e classificação

  • Bases e padrões: CVE, CVSS (Base/Temporal/Environmental).
  • Severidade vs. explorabilidade vs. exposição:
    • Severidade CVSS não é risco; risco = severidade × probabilidade × impacto × exposição.
  • Contexto: recurso exposto à internet? há autenticação? dados sensíveis?

Triagem orientada a risco: - Inventário afetado (via SBOM). - Exploit conhecido (KEV/CISA) e compensações ativas (WAF, feature flags). - Janela de manutenção e impacto no usuário.

Ferramentas e automação de varredura

Varreduras complementares: - SCA (Software Composition Analysis) para bibliotecas e imagens. - SAST/DAST para código e comportamento em runtime. - Scan de IaC e segredos.

Pipeline exemplo (GitHub Actions) com SCA e scan de contêiner:

name: security-pipeline

on:
  pull_request:
  push:
    branches: [ "main" ]

jobs:
  sca:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
      - run: npm ci
      - name: Dependency Review
        uses: actions/dependency-review-action@v4
  container_scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build image
        run: docker build -t app:ci .
      - name: Trivy Scan
        uses: aquasecurity/trivy-action@0.20.0
        with:
          image-ref: app:ci
          format: 'table'
          vuln-type: 'os,library'
          severity: 'CRITICAL,HIGH'
          ignore-unfixed: true

Scan de IaC (Terraform/Kubernetes) com Checkov:

pip install checkov
checkov -d infra/

Políticas de atualização e governança de dependências

  • Política de janelas de atualização:
    • Patches: contínuo/automático (quando seguro).
    • Minor: quinzenal/mensal com smoke tests.
    • Major: trimestral/semestral com plano de rollback.
  • Renovation bots (ex.: Renovate) com regras de agrupamento e auto-merge de patches.

Exemplo de configuração (Renovate):

{
  "extends": ["config:recommended"],
  "rangeStrategy": "replace",
  "packageRules": [
    {
      "matchUpdateTypes": ["patch"],
      "automerge": true,
      "groupName": "patches-seguros"
    },
    {
      "matchManagers": ["npm"],
      "matchPackageNames": ["express", "pino"],
      "separateMinorPatch": true
    }
  ],
  "vulnerabilityAlerts": {
    "enabled": true
  }
}

Mitigação e correção

  • Patching direto vs. hotfix/rollback.
  • Workarounds: flags de recurso, bloqueio de endpoints, regras temporárias no WAF.
  • Exceções temporárias com prazo e proprietário (risk acceptance timeboxed).
  • Testes:
    • Testes de regressão automatizados e smoke tests em canários.
    • Testes de segurança: fuzzing leve em interfaces críticas.

Boas práticas em contêineres e SO

  • Imagens mínimas (distroless, alpine com critério).
  • Usuário não-root e drop de capabilities.
  • Atualizações regulares de base image com re-scan.
  • Multi-stage builds e varredura antes do push.

Exemplo de Dockerfile com healthcheck e usuário não-root:

FROM gcr.io/distroless/nodejs20:latest
WORKDIR /app
COPY --chown=nonroot:nonroot package*.json ./
COPY --chown=nonroot:nonroot dist/ ./dist/
USER nonroot
ENV NODE_ENV=production
EXPOSE 3000
CMD ["dist/server.js"]
HEALTHCHECK --interval=30s --timeout=3s --retries=3 CMD ["node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]

6.2 Operação e gerenciamento de incidentes

Conceitos-chave

  • SLI/SLO e Orçamento de Erros:
    • SLI Service Level Indicator (Indicador de Nível de Serviço): indicadores de nível de serviço (latência p95, taxa de sucesso).
    • SLO Service Level Objective (Objetivo de Nível de Serviço): alvo (ex.: 99,9% sucesso mensal).
    • Orçamento de erros: margem permitida para falhas → decisões de lançamento e endurecimento.
  • Observabilidade:
    • Logs estruturados, métricas cardinalidade controlada, traces distribuídos.
    • Correlação: request-id, trace-id.

Ciclo de vida de incidentes

  • Detecção: alertas confiáveis e deduplicados.
  • Triagem: classificar severidade (SEV-1 a SEV-4).
  • Resposta: contenção, mitigação, comunicação.
  • Recuperação: restaurar serviço ao estado alvo.
  • Aprendizado: pós-incidente sem culpa (blameless) e ações.

Diagrama de fluxo do incidente:

Diagrama 1

Classificação de severidade (exemplo)

  • SEV-1: indisponibilidade total ou impacto crítico a segurança/dados.
  • SEV-2: degradação severa com workaround limitado.
  • SEV-3: impacto moderado com workaround claro.
  • SEV-4: impacto baixo, sem urgência operacional.

Papéis e comunicação

  • Incident Commander (coordena), Communications Lead (status), Tech Lead(s) (diagnóstico/mitigação), Scribe (linha do tempo).
  • Canais e cadência:
    • Interno: canal dedicado, atualização a cada 15–30 min em SEV-1/2.
    • Externo: status page e comunicado objetivo.

Template de comunicado (externo): - O que ocorreu (alto nível, sem culpas). - Impacto e escopo. - Status atual e próximos passos. - Janela de tempo e canais de suporte.

Estratégias de contenção e recuperação

  • Rollback atômico e versionado (blue/green, canary).
  • Feature flags para desativar componentes problemáticos sem redeploy.
  • Rate limiting e circuit breakers para proteger dependências.

Exemplo simples de circuit breaker (Node.js com opossum):

import CircuitBreaker from "opossum";

async function callPayment(payload) {
  const res = await fetch("https://payments/api", { method: "POST", body: JSON.stringify(payload) });
  if (!res.ok) throw new Error("payment failed");
  return res.json();
}

const breaker = new CircuitBreaker(callPayment, {
  timeout: 3000,
  errorThresholdPercentage: 50,
  resetTimeout: 10000
});

breaker.fallback(() => ({ status: "degraded", message: "Pagamento indisponível. Tente mais tarde." }));

export async function pay(payload) {
  return breaker.fire(payload);
}

Runbooks e preparação

  • Runbook: passos claros para diagnosticar e mitigar classes de incidentes (latência alta, erro 5xx, fila atrasada, DB saturado).
  • Pré-requisitos: alarmes com thresholds alinhados a SLO, dashboards prontos, acessos de emergência (break-glass) auditados, backups testados (RTO/RPO definidos).

Runbook (exemplo, latência alta): - Validar se a latência excede SLO por ≥5 min (p95 > 800 ms). - Checar erros 5xx, saturação de CPU, conexões DB. - Aplicar contenção: ampliar pods, ativar cache, reduzir timeouts a jusante. - Se persistir: rollback para versão estável, comunicar status. - Registrar linha do tempo e evidências para postmortem.

Pós-incidente e aprendizado

  • Postmortem sem culpa:
    • Linha do tempo factual.
    • Análise causal (5 Porquês, diagrama de Ishikawa).
    • Ações priorizadas (donos, prazos, métricas de eficácia).
  • Integração ao backlog: itens de resiliência, testes, automação, dívidas operacionais.
  • Medidas de sucesso: tempo de detecção (MTTD), de reconhecimento (MTTA), de mitigação (MTTM), de recuperação (MTTR), regressão de incidentes.

Integração entre segurança e operação (DevSecOps)

  • Assinatura e verificação de artefatos (Sigstore/Cosign).
  • Build reproduzível e cadeias verificáveis (SLSA níveis iniciais).
  • Gestão de segredos: vaults, rotação, varredura de vazamentos.
  • Gate de qualidade no pipeline: bloqueio por vulnerabilidades críticas sem exceção documentada.
  • Auditoria leve: trilhas de quem aprovou, quando e por quê (PR templates com risco e rollback plan).

Exemplo: assinatura de imagem com Cosign

cosign generate-key-pair
cosign sign --key cosign.key registry.example.com/app:1.2.3
cosign verify --key cosign.pub registry.example.com/app:1.2.3

Estudos de caso (síntese)

  • Caso A: CVE crítico em biblioteca transitiva.
    • Descoberta via alerta SCA; mitigação com override/patch; rollout canário; verificação de regressão.
  • Caso B: Latência elevada após release.
    • Detecção por SLI; rollback imediato; ajuste de timeouts; postmortem aponta N+1 queries → ação: índice e teste de carga.
  • Caso C: Segredo exposto no repositório.
    • Revogação/rotação imediata; varredura histórica; políticas de pre-commit; treinamento de equipe.

Checklists úteis

Checklist de dependências - SBOM atualizado por release - Lockfile versionado e reproduzível - Renovate/Dependabot ativo e regras definidas - Varredura de imagens base e SO - Exceções de risco com owner e prazo

Checklist de incidentes - SLO/SLI definidos e visíveis - Alertas com runbooks vinculados - Rotas de escalonamento claras - Canal e template de comunicação - Postmortems publicados e acompanhados


Conclusão

Gerenciar dependências e vulnerabilidades com disciplina reduz a superfície de risco e acelera a triagem quando algo falha. Ao integrar observabilidade, SLO/SLI e um processo claro de resposta a incidentes, equipes aumentam a confiabilidade operacional e a previsibilidade de entrega. Automação, padronização (SBOM, pipelines) e aprendizado contínuo fecham o ciclo de melhoria.

Próxima aula

Planejamento de releases e conformidade: estratégias de versionamento e janelas de lançamento, rastreabilidade leve, auditoria de mudanças e fundamentos de LGPD aplicados ao ciclo de vida do produto.