DevSecOps para Todos: Implementando Serviços de Desenvolvimento Seguro com Orçamento Limitado

DevSecOps para Todos: Implementando Serviços de Desenvolvimento Seguro com Orçamento Limitado

Este artigo detalha a implementação de um pipeline de desenvolvimento seguro de baixo custo, focando na configuração de ferramentas essenciais como GitLab, Nexus, HashiCorp Vault, DefectDojo e Dependency-Track. O objetivo é construir uma infraestrutura robusta para práticas de DevSecOps.

MundiX News·09 de junho de 2026·15 min de leitura·👁 8 views

Na parte anterior deste ciclo, estabelecemos as bases para nosso pipeline de desenvolvimento seguro (РБПО): configuramos máquinas virtuais, o servidor Ubuntu, a rede, o firewall e o Docker. Essencialmente, criamos a plataforma onde a construção do pipeline de desenvolvimento seguro pode começar. Agora, é hora de povoar nossas máquinas virtuais com os componentes necessários. Continuando a analogia, vamos adicionar os primeiros habitantes ao nosso reino de desenvolvimento seguro: um guardião de segredos, um supervisor de artefatos, um cronista de vulnerabilidades e outros personagens úteis. Isso significa instalar e configurar GitLab, Nexus, HashiCorp Vault, DefectDojo e Dependency-Track, além de preparar uma máquina virtual separada com um conjunto de ferramentas CLI para análise de segurança. A maioria desses serviços será executada em contêineres Docker, então também abordaremos a configuração de armazenamento persistente, Docker Compose e algumas particularidades de configuração de componentes individuais.

Aviso Importante: Este ciclo de artigos não substitui os requisitos de metodologias sérias de desenvolvimento seguro como GOST, OWASP SAMM ou BSIMM. É um exemplo prático de como organizar um pipeline de desenvolvimento seguro de software com investimento mínimo. Toda a experiência descrita é pessoal e não representa a posição oficial de empregadores atuais ou anteriores. Não copie cegamente; teste em ambientes de laboratório, faça backups e aborde os experimentos com cautela. Erros são possíveis e devem ser vistos como oportunidades de aprendizado para construir processos mais robustos.

GitLab: Decidimos instalar o GitLab Community Edition (CE) devido a restrições orçamentárias. A instalação é simples, geralmente com um único comando. Primeiro, adicionamos o repositório oficial do GitLab para que nosso gerenciador de pacotes saiba de onde baixar:

bash
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash

Em seguida, instalamos o pacote:

bash
sudo apt install -y gitlab-ce

Após a instalação, é crucial configurar o URL externo pelo qual o GitLab será acessível. Edite o arquivo /etc/gitlab/gitlab.rb e localize a linha external_url, substituindo-a pelo IP ou domínio desejado (neste exemplo, http://192.168.0.201:9090). Evite a porta 8080, pois ela já está em uso pelo servidor Puma interno.

bash
sudo nano /etc/gitlab/gitlab.rb
external_url ‘http:// 192.168.0.201:9090’;

Aplique a configuração:

bash
sudo gitlab-ctl reconfigure

Verifique o status dos serviços:

bash
sudo gitlab-ctl status

O GitLab estará acessível em http://192.168.0.201:9090. O login padrão é root, e a senha inicial é gerada durante a instalação e pode ser encontrada em /etc/gitlab/initial_root_password.

Nexus: Em vez de baixar o Nexus diretamente, optamos por implantá-lo via Docker para contornar possíveis bloqueios. Para garantir a persistência dos dados, configuraremos um volume no host. Embora alguns possam considerar isso inseguro, em um ambiente de laboratório, é uma abordagem justificável. Criaremos um diretório para os dados do Nexus, definiremos as permissões corretas para o usuário interno do contêiner (UID 200) e, em seguida, usaremos o Docker Compose para configurar o volume e o mapeamento de portas (8081).

Criamos o diretório de dados:

bash
sudo mkdir -p /opt/nexus-data

Definimos as permissões:

bash
sudo chown -R 200:200 /opt/nexus-data

Criamos o arquivo docker-compose.yml:

yaml
version: '3'
services:
  nexus:
    image: sonatype/nexus3:latest
    container_name: nexus
    restart: unless-stopped
    ports:
      - "8081:8081"
    volumes:
      - nexus-data:/nexus-data
volumes:
  nexus-data:
    driver_opts:
      type: none
      device: /opt/nexus-data
      o: bind

Iniciamos o Nexus:

bash
docker-compose up -d

O Nexus estará acessível em http://192.168.0.202:8081/. A senha inicial do administrador pode ser obtida com docker exec nexus cat /nexus-data/admin.password. Para testar a persistência, pare, remova o contêiner e reinicie-o via Docker Compose. Se o login com a senha alterada funcionar, o armazenamento está correto.

HashiCorp Vault: Para gerenciar segredos como senhas e tokens, implantaremos o HashiCorp Vault, também via Docker Compose e com armazenamento persistente. Para um ambiente de laboratório, o modo file é suficiente, mas para produção, o modo raft é recomendado para alta disponibilidade e escalabilidade. Para este exemplo, usaremos o modo file.

Criamos a estrutura de diretórios e o arquivo de configuração /vault/config/config.hcl:

hcl
storage "file" {
  path = "/vault/data"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = true
}

ui           = true
disable_mlock = true   # Necessário para rodar em contêiner

O docker-compose.yml para o Vault:

yaml
version: '3.8'
services:
  vault:
    image: hashicorp/vault:latest
    container_name: vault
    restart: unless-stopped
    ports:
      - "8200:8200"
    volumes:
      - ./data:/vault/data:rw
      - ./config/config.hcl:/vault/config/config.hcl:ro
    cap_add:
      - IPC_LOCK
    environment:
      - VAULT_ADDR=http://127.0.0.1:8200
    command: vault server -config=/vault/config/config.hcl

Iniciamos o Vault:

bash
docker-compose up -d

Em seguida, inicializamos o Vault dentro do contêiner. É crucial salvar as chaves de deslacração (unseal keys) e o token root gerados:

bash
docker exec -it vault sh
export VAULT_ADDR=http://127.0.0.1:8200
vault operator init

Verifique o status com vault status. Para testar a persistência, deslacre o Vault usando uma das chaves (vault operator unseal <KEY>), faça login com o token root, crie um segredo (vault kv put secret/test message="Hello Persistent Storage") e, após reiniciar o contêiner, verifique se o segredo ainda existe.

DefectDojo e Dependency-Track: Instalaremos ambos em uma única máquina virtual, cada um em sua porta. Usaremos Docker Compose com volumes persistentes. O DefectDojo requer vários componentes (PostgreSQL, Redis, Nginx, uWSGI, Celery), enquanto o Dependency-Track é mais direto (API Server, Frontend, PostgreSQL).

Para o DefectDojo, criamos diretórios e clonamos o repositório oficial. Configuramos o docker-compose.yml para usar volumes persistentes para PostgreSQL (/opt/defectdojo/postgres) e arquivos de mídia (/opt/defectdojo/media). Ajustamos a porta para 9090 para evitar conflitos com o Dependency-Track. Um arquivo de configuração Nginx customizado (nginx/conf.d/dojo.conf) é necessário para o correto roteamento.

nginx
upstream django {
    server uwsgi:9090;
}

server {
    listen 8080;
    server_name _;
    client_max_body_size 100M;

    location / {
        uwsgi_pass django;
        include /etc/nginx/uwsgi_params;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /static/ {
        alias /app/static/;
    }

    location /media/ {
        alias /app/media/;
    }
}

Executamos as migrações do banco de dados e criamos um superusuário:

bash
docker compose exec uwsgi /bin/bash -c "python manage.py migrate"
docker compose exec uwsgi /bin/bash -c "python manage.py createsuperuser"

O DefectDojo estará acessível em http://192.168.0.204:9090/.

Para o Dependency-Track, editamos o docker-compose.yml padrão para mapear os volumes do Docker para diretórios específicos no host (e.g., /opt/dependency-track/data para o API Server e /opt/dependency-track/tmp para os arquivos temporários). A configuração do ambiente API_BASE_URL deve ser ajustada para o IP correto (e.g., http://localhost:8081).

yaml
services:
  apiserver:
    image: dependencytrack/apiserver
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      EXTRA_JAVA_OPTIONS: "-Xmx4G -Xms2G -Djava.io.tmpdir=/data/tmp"
      ALPINE_DATABASE_MODE: "external"
      ALPINE_DATABASE_URL: "jdbc:postgresql://postgres:5432/dtrack"
      ALPINE_DATABASE_DRIVER: "org.postgresql.Driver"
      ALPINE_DATABASE_USERNAME: "dtrack"
      ALPINE_DATABASE_PASSWORD: "dtrack"
    deploy:
      resources:
        limits:
          memory: 6g
      restart_policy:
        condition: on-failure
    ports:
    - '8081:8080'
    volumes:
    - "/opt/dependency-track/data:/data"
    - "/opt/dependency-track/tmp:/data/tmp"
    restart: unless-stopped
frontend:
    image: dependencytrack/frontend
    depends_on:
      apiserver:
        condition: service_healthy
    environment:
      API_BASE_URL: "http://localhost:8081"
    ports:
      - "8080:8080"
    restart: unless-stopped

  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_DB: "dtrack"
      POSTGRES_USER: "dtrack"
      POSTGRES_PASSWORD: "dtrack"
      POSTGRES_SHARED_BUFFERS: 256MB
      POSTGRES_EFFECTIVE_CACHE_SIZE: 512MB
    healthcheck:
      test: [ "CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}" ]
      interval: 5s
      timeout: 3s
      retries: 3
    volumes:
    - "postgres-data:/var/lib/postgresql/data"
    restart: unless-stopped
volumes:
  dtrack-data: {}
  postgres-data: {}

Iniciamos o Dependency-Track:

bash
docker compose up -d

O frontend estará acessível em http://ip_servidor:8080/ com login admin/admin (a senha será solicitada para alteração no primeiro acesso).

Ferramentas CLI: Em uma quinta máquina virtual, reuniremos um conjunto de utilitários para análise de segurança, incluindo ferramentas para DAST, análise de código-fonte e verificação de segredos. Instalaremos Checkov, Trivy, Gitleaks, OpenGrep, Nuclei e outros. A instalação varia entre APT, downloads diretos do GitHub e scripts.

Instalamos Node.js e npm, seguidos por Checkov (via pip) e Trivy (via repositório oficial). Para Gitleaks, baixamos o binário do GitHub. OpenGrep requer um script de instalação e a adição do diretório ao PATH. Nuclei é baixado e descompactado do GitHub.

Conclusão: Estabelecemos a infraestrutura básica para um ambiente de desenvolvimento seguro, com GitLab, Nexus, HashiCorp Vault, DefectDojo e Dependency-Track, além de uma VM com ferramentas CLI de segurança. Este é o fundamento; na próxima parte, integraremos esses componentes para criar um pipeline DevSecOps completo, configurando repositórios, runners, autenticação e projetos.

📤 Compartilhar & Baixar