Segurança em pipelines de CI/CD

1. Fundamentos da Segurança em Pipelines

1.1. O que são pipelines de CI/CD e por que são alvos críticos

Pipelines de CI/CD automatizam a construção, teste e deploy de software. Eles representam o caminho crítico entre o código-fonte e a produção. Por concentrarem acesso a múltiplos sistemas, repositórios e credenciais, tornam-se alvos prioritários para atacantes. Uma única vulnerabilidade no pipeline pode comprometer toda a cadeia de fornecimento de software.

1.2. Ameaças comuns: injeção de código, vazamento de secrets e supply chain attacks

As principais ameaças incluem:

  • Injeção de código: parâmetros maliciosos em triggers de pull requests
  • Vazamento de secrets: tokens expostos em logs de build ou variáveis de ambiente
  • Supply chain attacks: dependências comprometidas inseridas durante o build

1.3. Princípios de confiança zero aplicados a pipelines

Confiança zero significa nunca confiar automaticamente em nenhuma etapa do pipeline. Cada job deve verificar identidades, validar entradas e operar com privilégios mínimos. Exemplo de configuração mínima:

# .gitlab-ci.yml com princípios de confiança zero
stages:
  - verify
  - build
  - test
  - deploy

variables:
  GIT_DEPTH: "1"  # Reduz superfície de ataque

before_script:
  - echo "Verificando ambiente seguro..."
  - env | grep -i "token\|secret\|password" > /dev/null && exit 1 || true

2. Proteção de Credenciais e Secrets no Pipeline

2.1. Gerenciamento seguro de secrets

Nunca armazene secrets diretamente no código ou configurações do pipeline. Use cofres externos como HashiCorp Vault, AWS Secrets Manager ou Azure Key Vault.

# Exemplo: recuperando secret do Vault no pipeline
vault read -field=value secret/ci/github-token > /tmp/github_token
export GITHUB_TOKEN=$(cat /tmp/github_token)
rm -f /tmp/github_token

2.2. Evitando hardcoding

Nunca coloque tokens ou chaves SSH em arquivos YAML ou scripts versionados. Utilize variáveis de ambiente criptografadas da ferramenta de CI:

# GitHub Actions - secrets criptografados
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy with secure token
        env:
          DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
        run: ./deploy.sh --token "$DEPLOY_TOKEN"

2.3. Rotação e revogação automática

Implemente políticas de rotação automática para todas as credenciais usadas no pipeline:

# Script de rotação de chaves SSH
#!/bin/bash
# Gerar nova chave e atualizar no cofre
ssh-keygen -t ed25519 -f /tmp/deploy_key -N ""
vault write secret/ci/deploy-key key=@/tmp/deploy_key
# Remover chave antiga dos servidores
ansible-playbook rotate-keys.yml

3. Controle de Acesso e Permissões no Pipeline

3.1. RBAC em ferramentas de CI/CD

Configure permissões granulares para quem pode modificar jobs e configurações:

# Exemplo de permissões no GitHub Actions
permissions:
  contents: read
  pull-requests: write
  deployments: write

3.2. Isolamento de estágios e ambientes

Separe claramente ambientes de desenvolvimento, staging e produção:

# Jenkinsfile com ambientes isolados
pipeline {
    agent none
    stages {
        stage('Build') {
            agent { label 'build-node' }
            steps { sh 'make build' }
        }
        stage('Test') {
            agent { label 'test-node' }
            steps { sh 'make test' }
        }
        stage('Deploy Staging') {
            agent { label 'staging-node' }
            when { branch 'develop' }
            steps { sh 'deploy staging' }
        }
        stage('Deploy Production') {
            agent { label 'prod-node' }
            when { branch 'main' }
            input { message 'Confirmar deploy em produção?' }
            steps { sh 'deploy production' }
        }
    }
}

3.3. Uso de identidades efêmeras

Utilize tokens de curta duração e identidades temporárias para cada execução:

# Azure DevOps - token efêmero
- task: AzureCLI@2
  inputs:
    azureSubscription: '$(serviceConnection)'
    scriptType: 'bash'
    scriptLocation: 'inlineScript'
    inlineScript: |
      # Token válido apenas durante o job
      az account get-access-token --resource https://vault.azure.net

4. Segurança na Execução de Scripts e Comandos

4.1. Validação de entrada e sanitização

Nunca execute comandos diretamente com parâmetros de usuários ou branches:

# Perigoso: injeção de comando
- run: echo "Branch: ${{ github.head_ref }}"

# Seguro: validação e sanitização
- name: Validate branch name
  run: |
    BRANCH="${{ github.head_ref }}"
    if [[ ! "$BRANCH" =~ ^[a-zA-Z0-9_/-]+$ ]]; then
      echo "Branch name contains invalid characters"
      exit 1
    fi
    echo "Branch validated: $BRANCH"

4.2. Evitando injeção via variáveis

Proteja-se contra injeção através de variáveis de ambiente e artefatos:

# Exemplo seguro: escapando variáveis
- name: Safe variable usage
  env:
    USER_INPUT: ${{ github.event.pull_request.title }}
  run: |
    # Escapar caracteres especiais
    SAFE_INPUT=$(echo "$USER_INPUT" | sed 's/[^a-zA-Z0-9]//g')
    echo "Processed: $SAFE_INPUT"

4.3. Uso de runners seguros

Utilize runners efêmeros em containers ou VMs descartáveis:

# GitHub Actions - runner em container
jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: node:18-alpine
      options: --read-only --cap-drop=ALL

5. Verificação de Dependências e Artefatos

5.1. Escaneamento de vulnerabilidades

Integre ferramentas de SBOM e análise de dependências:

# Geração de SBOM com Syft
- name: Generate SBOM
  run: |
    syft packages dir:. -o cyclonedx-json > sbom.json

# Escaneamento com Trivy
- name: Scan for vulnerabilities
  run: |
    trivy fs --severity CRITICAL,HIGH .

5.2. Assinatura e verificação de artefatos

Assine imagens Docker e pacotes antes do deploy:

# Assinatura de imagem Docker com Cosign
- name: Sign Docker image
  run: |
    cosign sign --key cosign.key \
      registry.example.com/app:${GITHUB_SHA}

5.3. Políticas de aprovação manual

Implemente gates de aprovação para estágios críticos:

# GitHub Environments com proteção
environment:
  name: production
  url: https://app.example.com
  protection_rules:
    - required_reviewers: ['security-team']
    - wait_timer: 300

6. Monitoramento e Auditoria de Pipelines

6.1. Logs centralizados e alertas

Configure alertas para atividades suspeitas:

# Logging para auditoria
- name: Audit pipeline execution
  run: |
    echo "{\"timestamp\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"pipeline\":\"$GITHUB_RUN_ID\",\"actor\":\"$GITHUB_ACTOR\",\"event\":\"$GITHUB_EVENT_NAME\"}" | \
    curl -X POST -H "Content-Type: application/json" \
      -d @- https://logs.example.com/audit

6.2. Imutabilidade de logs

Garanta que logs de build não possam ser adulterados:

# Envio de logs para armazenamento imutável
- name: Store immutable logs
  run: |
    cat build.log | openssl dgst -sha256 -sign private.key > build.log.sig
    aws s3 cp build.log s3://immutable-logs/ --storage-class GLACIER

6.3. Revisão periódica

Agende auditorias regulares das configurações:

# Script de auditoria de permissões
#!/bin/bash
# Verificar permissões excessivas em workflows
for file in .github/workflows/*.yml; do
  if grep -q "permissions: write-all" "$file"; then
    echo "ALERTA: $file tem permissões excessivas"
  fi
done

7. Integração com Ferramentas de Segurança (SAST/DAST)

7.1. Gatilhos automáticos para análise estática

Execute SAST em cada commit e pull request:

# GitHub Actions com Semgrep
- name: SAST Scan
  uses: semgrep/semgrep-action@v1
  with:
    config: p/default
    severity: ERROR

7.2. Testes dinâmicos em staging

Realize DAST antes do deploy em produção:

# DAST com OWASP ZAP
- name: DAST Scan
  run: |
    docker run -v $(pwd):/zap/wrk/:rw \
      ghcr.io/zaproxy/zaproxy:stable \
      zap-full-scan.py -t https://staging.example.com \
      -r report.html

7.3. Quebra de pipeline por severidade

Configure thresholds para bloquear deploys com vulnerabilidades críticas:

# Política de quebra de pipeline
- name: Check vulnerability threshold
  run: |
    CRITICAL=$(jq '.results[].vulnerabilities | length' trivy-report.json)
    if [ "$CRITICAL" -gt 0 ]; then
      echo "Pipeline bloqueado: $CRITICAL vulnerabilidades críticas encontradas"
      exit 1
    fi

Referências