DevSecOps 'para os Pobres': Configurando Serviços de Desenvolvimento Seguro

DevSecOps 'para os Pobres': Configurando Serviços de Desenvolvimento Seguro

Este artigo detalha a configuração essencial de ferramentas para um pipeline de desenvolvimento seguro, incluindo GitLab, Nexus, HashiCorp Vault, DefectDojo e Dependency-Track. O objetivo é criar um ambiente DevSecOps funcional com investimento mínimo.

MundiX News·12 de junho de 2026·9 min de leitura·👁 7 views

Na última parte desta série, concluímos a implantação da infraestrutura para um pipeline de desenvolvimento seguro (DevSecOps): instalamos GitLab, Nexus, HashiCorp Vault, Dependency-Track e DefectDojo, preparamos uma máquina virtual separada com ferramentas de segurança e confirmamos que todos os serviços estavam rodando com sucesso. No entanto, instalar os serviços é apenas metade do trabalho. Agora, eles precisam ser configurados e preparados para trabalhar juntos. Sem isso, o GitLab permanecerá apenas um GitLab, o Vault apenas um repositório de segredos, e o DefectDojo e o Dependency-Track serão apenas interfaces web bonitas sem utilidade prática. Nesta parte, focaremos na configuração básica. Configuraremos o GitLab e o GitLab Runner, prepararemos o Nexus para receber artefatos, ensinaremos o Vault a confiar no GitLab através da autenticação JWT e criaremos as entidades necessárias no DefectDojo e Dependency-Track.

Aviso Legal É importante estabelecer um acordo inicial: este ciclo de artigos não substitui os requisitos de metodologias sérias de desenvolvimento seguro como GOST, OWASP SAMM, BSIMM, entre outras. É, antes, um exemplo prático de como organizar um pipeline de desenvolvimento seguro de software com investimento mínimo. Tudo o que é descrito no ciclo é puramente minha experiência pessoal, os percalços que enfrentei e os resultados de longas noites debruçado sobre o teclado. Não representa a posição oficial dos meus empregadores atuais ou anteriores. Não encare este artigo como um guia para cópia cega. Teste tudo em ambientes de teste, faça backups e aborde os experimentos com a cabeça fria. Erros são possíveis, e não se deve ter medo de cometê-los. O principal é tirar conclusões e construir gradualmente processos que serão mais confiáveis do que os de ontem.

Para ser franco, não configurei HTTPS dentro do laboratório doméstico. Há várias razões para isso: o ambiente é para aprendizado, não para produção; meu roteador não suporta a configuração de DNS local; para um esquema completo com uma autoridade certificadora interna, seria necessário levantar uma máquina virtual adicional, e restam poucos recursos livres – o ambiente atual já consome 22 GB de RAM. Portanto, por enquanto, trabalharemos via HTTP. Mas trocamos as senhas imediatamente – isso é sagrado.

GitLab "Cada casa tem sua ordem", pensei, e a primeira coisa que fiz foi organizar a estrutura do GitLab. Após o primeiro login com a senha root (que descobri com o comando sudo cat /etc/gitlab/initial_root_password na máquina virtual com o serviço), troquei imediatamente a senha pela minha. Em seguida, criei um grupo de repositórios para projetos de serviço, templates de pipeline, configurações de IaC (Infrastructure as Code) e para as aplicações em desenvolvimento. Se não se tratar de um ambiente de demonstração, mas de desenvolvimento real, é melhor dividir os projetos em vários grupos de acordo com sua finalidade.

Em seguida, carreguei o código da nossa aplicação vulnerável no repositório. Para executar os pipelines, precisaremos do GitLab Runner – um agente que recebe tarefas do GitLab e executa as etapas correspondentes do pipeline CI/CD. Vamos instalá-lo na quinta máquina virtual (sec-vm), pois ela já possui Docker e todas as ferramentas de segurança necessárias. Após a instalação, registrei dois runners: um com executor Docker e outro com executor Shell. Para eles, especifiquei as tags docker, linux, devsecops e shell, linux, local, respectivamente. Também ativei o auto-start para que, após a reinicialização da máquina virtual, os runners retornem automaticamente ao trabalho.

Adiciono o repositório:

bash
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

Instalo o pacote:

bash
sudo apt install -y gitlab-runner

Registro o runner (interativamente ou através de parâmetros):

bash
sudo gitlab-runner register

Durante o registro, precisarei de:

  • URL do GitLab – no meu caso, http://192.168.0.201:9090/.
  • Token de registro, que deve ser obtido no GitLab em Admin Area → CI/CD → Runners → Register an instance runner.
  • Descrição – um nome arbitrário para o runner, como docker-runner ou shell-runner.
  • Tags: docker, linux, devsecops (essas tags serão usadas posteriormente nos pipelines).
  • Executor – o tipo de executor. No nosso caso, precisaremos registrar dois runners: um com executor docker e outro com executor shell.
  • Imagem padrão: alpine:latest. Ativo o auto-start:
bash
sudo systemctl enable gitlab-runner

Verifico o status:

bash
sudo systemctl status gitlab-runner

Após o registro, verifico se o runner apareceu na lista e tem status verde. Nas configurações do repositório, proibi o push direto para o branch main – apenas através de Merge Request e apenas para mantenedores.

Variáveis CI/CD Para que o pipeline possa interagir com os outros serviços do nosso pipeline, ele precisará de alguns parâmetros: o endereço do Vault, os identificadores de projetos no Dependency-Track e o identificador do produto no DefectDojo. Para todos os projetos, adicionei duas variáveis globais:

VariávelValorProteção/Mascaramento
VAULT_AUTH_ROLEci-roleNão proteger/mascarar
VAULT_ADDRhttp://192.168.0.203:8200Mascarar

Elas podem ser adicionadas em Admin → CI/CD → Variables. Para cada projeto, será necessário criar um conjunto próprio de variáveis:

VariávelValorProteção/Mascaramento
DEPENDENCY_TRACK_PROJECT_DOCKER_UUIDUUID do projeto no qual analisarei a composição do contêiner Docker, obtido do Dependency-TrackMascarar
DEPENDENCY_TRACK_PROJECT_UUIDUUID do projeto obtido do Dependency-TrackMascarar
DOJO_PRODUCT_IDID do produto obtido do DefectDojoMascarar

Essas variáveis são adicionadas em Settings → CI/CD → Variables do projeto específico.

Nexus "O repositório é a cabeça de tudo", disse eu e comecei a organizar o Nexus. Após o login com a senha do arquivo /nexus-data/admin.password, troquei-a imediatamente. Para criar um repositório físico de dados, configuro os Blob Stores:

  1. Vou para Administration → Repository → Blob Stores.
  2. Crio Blob Stores separados para diferentes tipos de dados. Por exemplo, docker-blob, npm-blob, pgsql-dump-blob. Isso permitirá gerenciar a localização dos arquivos no disco e simplificará o backup.

Crio um repositório para armazenar contêineres Docker. Caminho: Administration → Repository → Repositories → Create repository. Para Docker (hosted):

  • Escolho a receita docker (hosted).
  • Em Storage, seleciono o Blob Store criado anteriormente.
  • Em Repository Connectors, mantenho Path based routing, pois não terei um domínio e não poderei expor uma porta separada. O repositório estará acessível em http://192.168.0.202:8081/repository/docker/.

No âmbito da configuração de acesso para CI/CD, crio um usuário separado para o GitLab CI. Para isso:

  1. Crio a role nx-deployment. Vou para Security → Users → Roles (concedo permissões apenas para trabalhar com repositórios). Para imagens Docker, precisamos das seguintes permissões:
  • nx-repository-view-docker-*-read – leitura;
  • nx-repository-view-docker-*-add – adição de novos artefatos;
  • nx-repository-view-docker-*-edit – edição;
  • nx-repository-view-docker-*-browse – visualização do conteúdo;
  1. Em seguida, vou para Security → Users → Create local user e crio um novo usuário:
  • Insiro o ID: gitlab-ci.
  • Insiro a Senha: defina uma senha forte.
  • Em Roles, adiciono nx-deployment (esta é a nossa role criada anteriormente). Agora o GitLab CI poderá fazer push de imagens e relatórios sem expor a senha no código.

HashiCorp Vault Para que os pipelines possam obter segredos do Vault de forma segura, precisamos ensiná-lo a confiar no GitLab. Para isso, configuraremos a autenticação JWT. Escondi o token root bem longe – ele é apenas para configuração inicial. Uma observação importante sobre a segurança do token root: nunca use o token root no trabalho diário, e muito menos em CI/CD! O token root é necessário apenas para a configuração inicial. Após a criação de políticas e roles, o acesso aos segredos deve ser feito apenas através delas.

Autenticação JWT Na máquina virtual vault-vm, entro no contêiner com o Vault e faço login.

bash
docker exec -it vault sh
export VAULT_ADDR=http://127.0.0.1:8200
vault login <root_token>

Ativo o motor kv-v2 no caminho secret e carrego nossos segredos lá (URLs e chaves de API do DefectDojo, Dependency-Track, Nexus).

bash
vault secrets enable -path=secret kv-v2
vault kv put secret/dependency-track url="http://192.168.0.204:8081" api_key=""
vault kv put secret/defectdojo url="http://192.168.0.204:9090" token=""
vault kv put secret/nexus url="http://192.168.0.202:8081" docker-repo="docker" registry="192.168.0.202:8081" username="gitlab-ci" password=""

Em seguida, crio a política ci-policy com permissões de leitura para esses caminhos.

bash
vault policy write ci-policy - <<EOF
path "secret/data/defectdojo" {
  capabilities = ["read"]
}
path "secret/data/dependency-track" {
  capabilities = ["read"]
}
path "secret/data/nexus" {
  capabilities = ["read"]
}
EOF

E o mais interessante – configuro a autenticação JWT.

bash
vault write auth/jwt/role/gitlab-role \
    role_type="jwt" \
    vault write auth/jwt/config \
    oidc_discovery_url="http://192.168.0.201:9090" \
    bound_issuer="http://192.168.0.201:9090" \
    groups_claim="groups" \
    policies="gitlab-policy" \
    ttl=1h

Se aprofundarmos um pouco, dentro do comando definimos:

  • auth/jwt/role/gitlab-role – o caminho para a role.
  • role_type="jwt" – indica explicitamente que a role usa JWT.
  • bound_audiences – o aud obrigatório do token JWT. O GitLab emite tokens com um aud específico, que deve ser especificado.
  • groups_claim – o campo que contém a lista de grupos do GitLab, para que o Vault possa mapeá-los para as políticas.
  • policies – as políticas do Vault que serão atribuídas após a autenticação bem-sucedida.
  • ttl – o tempo de vida do token do Vault obtido.

O GitLab CI é capaz de emitir um ID_TOKEN para cada job. Configurei o Vault para confiar nos tokens assinados pelo meu GitLab. Foi aí que encontrei um obstáculo: a autorização não funcionava até que eu adicionasse o jwks_url e o default_role corretos à configuração JWT.

bash
vault write auth/jwt/config \
    jwks_url="http://192.168.0.201:9090/oauth/discovery/keys" \
    default_role="ci-role"

Depois disso, tudo funcionou. O pipeline recebia um token, acessava o Vault, e o Vault lhe fornecia os segredos. Que beleza!

DefectDojo Agora, prepararemos o DefectDojo para receber os resultados da varredura. É para cá que nossas ferramentas de segurança enviarão as vulnerabilidades encontradas, portanto, primeiro configuraremos o acesso para CI/CD e depois criaremos um produto – essencialmente, um cartão da nossa aplicação, ao qual os resultados das verificações serão vinculados. Para começar, gero um token de API, que será necessário posteriormente para os pipelines do GitLab:

  1. No canto superior direito, clico no ícone do usuário.
  2. Clico no botão Get API Key.
  3. Copio o token gerado – este será o DOJO_API_TOKEN para o GitLab. Em seguida, crio um produto. No menu esquerdo, seleciono Products → Add Product. Preencho o nome e a descrição do produto, clico no botão Submit. E o mais importante – ativo a desduplicação global nas configurações do sistema, para que os defeitos de segurança não sejam duplicados em novas varreduras. É uma ferramenta muito útil, caso contrário, você pode se afogar em bugs repetidos. No DefectDojo, vamos para Settings → System Settings. Encontro a opção Deduplicate findings e Delete duplicates e a ativo. Isso ativará o algoritmo de desduplicação para todas as importações futuras. Pronto, agora nossos scanners enviarão relatórios para cá.

Dependency-Track Agora, preparamos o Dependency-Track para funcionar. Este serviço será responsável por analisar a composição da nossa aplicação e contêineres, rastrear vulnerabilidades em componentes utilizados e armazenar informações sobre os problemas encontrados. "O grafo de dependências é como uma teia, você se perde", suspirei e criei um projeto no Dependency-Track com a versão 1.0.0. Em seguida, em Administration → Access Management → Teams, criei a equipe Automation com o tipo Automation e as permissões: BOM_UPLOAD, PROJECT_CREATION_UPLOAD, VIEW_PORTFOLIO.

Gerei uma chave de API e a salvei no Vault. Agora o GitLab CI poderá carregar arquivos SBOM, e o Dependency-Track atualizará automaticamente as vulnerabilidades e construirá gráficos bonitos. Configurei os projetos:

  1. Fui para Projects → Create Project.
  2. Especifiquei o nome e a versão. Foram criados 2 projetos – um para o SBOM do próprio software em desenvolvimento e outro para o SBOM do contêiner. Posteriormente, ao carregar o SBOM (Software Bill of Materials) via API, o Dependency-Track atualizará automaticamente os dados deste projeto.
  3. A partir de setembro de 2025, o serviço exige autenticação para acesso à API, portanto, para que o analisador funcione, é necessário registrar uma conta gratuita no site do OSS Index e inserir as credenciais obtidas nas configurações do Dependency-Track.

Conclusão Neste ponto, a fase preparatória pode ser considerada concluída. Configuramos os principais serviços do futuro pipeline de desenvolvimento seguro: GitLab, Nexus, Vault, DefectDojo e Dependency-Track, e também os conectamos onde for necessário para automação futura. Na próxima parte, faremos o que tudo isso foi planejado: escreveremos o principal "pergaminho" do nosso reino de desenvolvimento seguro – o arquivo .gitlab-ci.yml, onde toda a lógica do pipeline será descrita. Também montaremos um pipeline completo com as etapas build, sbom, code-scan e upload, conectaremos templates comuns do repositório devsecops, aprenderemos a obter segredos do Vault via JWT e a enviar automaticamente os resultados do trabalho para Nexus, DefectDojo e Dependency-Track. Até a próxima parte do ciclo!

Links para as fontes originais Para um estudo mais aprofundado de cada tópico, aqui estão os links diretos para a documentação oficial:

  • GitLab: GitLab Docs: Security Best Practices – recomendações gerais.
  • Nexus: Sonatype Support: Nexus Repository Manager – documentação oficial.
  • Vault: HashiCorp Developer: Vault Documentation – guia completo.
  • DefectDojo: DefectDojo Documentation – documentação oficial do projeto.
  • Dependency-Track: Dependency-Track Documentation – tudo sobre configuração e uso.

📤 Compartilhar & Baixar