Segredos em CI/CD: seu pipeline é o cofre real de produção
Segredos em CI/CD são segredos de produção, mesmo quando o job diz test. Se um invasor controla um workflow por seis minutos, importa o que ele pode publicar, implantar, ler ou exfiltrar.
Segredos em CI/CD costumam ter mais poder que a aplicação que eles implantam. Um serviço em produção talvez acesse um banco, uma fila e um bucket. Um pipeline muitas vezes consegue ler credenciais cloud, publicar pacotes, assumir roles de deploy, assinar artefatos, baixar dependências privadas, escrever releases, atualizar infraestrutura e expor logs de cada passo intermediário.
Isso transforma CI/CD em um runtime privilegiado, não em uma camada de conveniência. O erro perigoso é tratar workflows como cola enquanto o código da aplicação recebe toda a atenção de segurança. Se um invasor controla o pipeline por seis minutos, a pergunta certa não é "os testes passaram?". É o que esse workflow pode implantar, publicar, rotacionar, ler ou exfiltrar antes que um limite o detenha.
Segredos em CI/CD são segredos de produção, não variáveis de build
Segredos em CI/CD são segredos de produção porque o pipeline costuma ter a autoridade que muda produção. Um DATABASE_URL em um job de teste pode ser inofensivo. Uma role cloud que pode fazer deploy, ler parameter stores, atualizar Kubernetes, publicar containers ou enviar pacotes não fica inofensiva por viver dentro de um workflow.
O rótulo "CI" esconde o privilégio. Jobs de build parecem temporários. Runners parecem descartáveis. Logs parecem operacionais. Mas um runner de vida curta ainda pode emitir um token cloud, publicar um pacote malicioso, subir um artefato contaminado ou vazar uma chave de assinatura durante os poucos minutos em que existe. A duração do runtime não reduz o blast radius quando a credencial pode mudar a realidade dos clientes.
O primeiro diagnóstico é brutalmente simples:
- Se este workflow for comprometido, o que ele pode implantar?
- Em quais registries ele pode publicar?
- Quais ambientes ele pode ler?
- Quais segredos aparecem em memória, variáveis de ambiente, logs, caches ou artefatos?
- Quais credenciais precisariam ser rotacionadas depois de uma execução suspeita?
Qualquer resposta que diga "tudo no repositório" já é um achado. Conveniência no nível do repositório não é modelo de segurança. É um convite para tornar cada workflow tão sensível quanto o job mais privilegiado do repo.
Todo workflow é um limite de segurança
Todo workflow é um limite de segurança porque os triggers decidem qual código roda com qual confiança. A diferença entre pull_request, pull_request_target, push, workflow_dispatch e workflow_run não é apenas ergonomia. É a diferença entre código não confiável, código confiável, código acionado por humanos, contexto herdado e autoridade produtiva.
O padrão de falha mais comum é cruzar esse limite por acidente. Um workflow de pull request faz checkout de código de um fork externo, instala dependências, executa scripts de build, restaura caches compartilhados ou chama um reusable workflow que herda segredos. O YAML parece comum. O modelo de confiança está quebrado.
Um modelo mais seguro separa quatro fases:
| Fase | Nível de confiança | Autoridade permitida |
|---|---|---|
| Construir código não confiável | Baixo | Ler source, rodar testes, sem segredos, sem publish. |
| Verificar artefatos | Médio | Ler artefatos, validar provenance, sem deploy. |
| Publicar pacotes | Alto | Token de registry ou OIDC limitado, sem segredos alheios. |
| Implantar produção | Máximo | Ambiente protegido, aprovação, role cloud limitada. |
Um workflow pode conter essas fases, mas um job não deve misturá-las. Um job que constrói código de um fork não deveria receber id-token: write, autoridade de publicação, segredos de deploy nem permissões amplas de GITHUB_TOKEN. Um job que implanta produção deveria partir de um artefato limpo e confiável, não de um cache mutável restaurado de trabalho anterior.
A disciplina de blast radius aplicada a sistemas agentic também se aplica aqui. O modelo de blast radius em agentic coding ajuda porque ações de CI também vivem em uma escada: ler arquivos, rodar testes, escrever artefatos, publicar pacotes, modificar infraestrutura e implantar produção. Cada degrau precisa de um gate diferente.
Segredos em CI/CD devem viver por job, não por repositório
Segredos em CI/CD devem ser limitados ao menor job que precisa deles, não a todos os workflows de um repositório. Segredos no nível do repositório são fáceis de configurar e difíceis de raciocinar. Eles fazem o repositório parecer o limite de segurança quando o limite real é o contexto de execução.
Um token de publicação de pacotes não deveria existir em um job de lint. Uma role de deploy produtivo não deveria estar disponível para uma matriz de testes. Uma chave service_role não deveria ser alcançável por qualquer workflow que execute código não confiável. O artigo sobre segurança de Supabase em produção explica por que essas chaves são especialmente sensíveis; CI torna a mesma chave mais perigosa quando ela pode vazar por logs, artefatos ou scripts.
O padrão base em GitHub Actions deveria ser negação explícita:
name: ci
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- run: npm ci
- run: npm test
deploy:
runs-on: ubuntu-latest
needs: test
environment: production
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac
- run: ./scripts/deploy.shO ponto importante não é o YAML exato. O ponto importante é a postura: read-only por padrão, escalonamento por job, deploy atrás de um environment e OIDC apenas onde o job precisa pedir identidade. Se um job não precisa de uma permissão, ele não deve recebê-la.
Segredos também precisam de nome e ownership. AWS_ACCESS_KEY_ID diz quase nada. PROD_DEPLOY_ROLE_BILLING_API diz escopo, ambiente e intenção. Durante um incidente, essa diferença economiza horas porque responders conseguem identificar o que rotacionar antes que o invasor consiga uma segunda execução.
OIDC ajuda apenas quando as trust policies são estreitas
OIDC ajuda a remover segredos cloud de longa duração de CI/CD, mas não torna seguro um workflow amplo. Ele muda o formato da credencial. Em vez de armazenar um segredo estático, o job prova sua identidade e recebe um token de curta duração de um provedor cloud, registry ou secrets manager.
Isso é uma melhoria real. Chaves de longa duração em segredos de repositório ampliam a janela de exposição. Tokens OIDC expiram rápido e podem ser vinculados a claims como repositório, branch, environment, actor, caminho do workflow ou propriedades customizadas. O detalhe crítico é que a trust policy precisa ser estreita o suficiente para significar algo.
Uma policy perigosa de OIDC diz, na prática: "qualquer workflow deste repositório pode assumir esta role". Uma policy mais segura diz: "apenas este caminho de workflow, nesta branch protegida, para este environment, a partir deste repositório, pode assumir esta role". Essa diferença decide se OIDC é least privilege ou uma versão de vida mais curta do mesmo excesso.
OIDC deve vir junto com três controles:
- Dar
id-token: writeapenas ao job que precisa do token. - Vincular a trust policy externa a branch, environment, workflow e repository claims.
- Isolar jobs de publish e deploy de código não confiável, caches mutáveis e actions de terceiros desnecessárias.
Credenciais de curta duração ainda importam em memória. Um token que expira em minutos ainda pode ser roubado durante os minutos em que é válido. Por isso isolamento de runner, limites de cache, pinning de actions e monitoramento de egress importam. OIDC remove uma classe de segredo. Não remove a necessidade de desenhar o workflow como limite de confiança.
Resposta a incidentes começa com inventário de credenciais
Resposta a incidentes em CI/CD começa antes do incidente com uma lista de credenciais que cada workflow consegue tocar. Sem esse inventário, uma execução suspeita vira adivinhação. Equipes leem YAML, buscam variáveis de ambiente, inspecionam logs e rotacionam aquilo que lembram primeiro.
Um inventário útil mapeia cada workflow contra autoridade:
| Workflow | Segredos ou identidades | Sistemas externos | Owner de rotação |
|---|---|---|---|
ci.yml | nenhum | download de pacotes | Plataforma |
publish.yml | OIDC para npm trusted publishing | npm registry | Developer platform |
deploy-api.yml | role cloud de deploy | Kubernetes, registry, secrets manager | Infraestrutura |
migrate.yml | role de migração de banco | banco de produção | Backend |
Esse inventário muda a resposta. Se publish.yml se comporta de forma estranha, o time sabe quais permissões de registry, artefatos, attestations, versões de pacote e logs do runner revisar. Se deploy-api.yml roda a partir de um actor ou branch inesperado, o time sabe qual role cloud e qual environment de deploy revogar primeiro.
O playbook de rotação deve estar escrito antes:
- Desabilitar o workflow suspeito.
- Revogar sessões cloud ativas e trust OIDC quando possível.
- Rotacionar segredos estáticos alcançáveis pelo workflow.
- Invalidar tokens de registry e credenciais de publish.
- Reconstruir artefatos em um runner limpo.
- Revisar logs, caches, artefatos e destinos de rede de saída.
- Restaurar deploy apenas depois de corrigir o limite do workflow.
O pior momento para descobrir que um segredo implanta todos os serviços é depois que um runner já o vazou.
Quais segredos e permissões de CI/CD são amplos demais?
Segredos e permissões de CI/CD são amplos demais quando sobrevivem fora do job, environment e workflow que precisam deles. Um bom teste é se a credencial pode ser explicada em uma frase sem dizer "por via das dúvidas".
Workflows de pull request devem acessar credenciais próximas de produção?
Workflows de pull request não devem acessar credenciais próximas de produção quando rodam código influenciado pela pull request. Eles podem etiquetar, comentar, lintar, testar ou construir sem autoridade sensível. Qualquer workflow que combine input de contribuição externa com segredos precisa de revisão de design.
Escopo de segredo no nível do repositório é aceitável?
Escopo no nível do repositório é aceitável apenas para credenciais de baixo impacto ou repositórios pequenos com poucos workflows e ownership claro. Quando um repositório tem workflows separados de build, publish, deploy, migração e release, o escopo de repositório fica grosseiro demais. Escopo por environment, workflow ou job deve substituí-lo quando a plataforma permite.
OIDC substitui rotação de segredos?
OIDC reduz a quantidade de segredos de longa duração que precisam de rotação, mas não elimina o trabalho de rotacionar. Credenciais estáticas ainda podem existir para registries, bancos, webhooks, ferramentas de assinatura e sistemas legados. Trust policies de OIDC também precisam de revisão depois de comportamento suspeito em workflows.
Qual permissão deve ser removida primeiro?
A primeira permissão a remover é autoridade ampla de escrita em jobs que não publicam, não implantam e não alteram estado. Comece pelo GITHUB_TOKEN padrão, tokens de package registry, roles cloud de deploy e id-token: write. Um job de build read-only é mais fácil de confiar e investigar.
O ponto de vista oposto afirma que permissões estritas atrasam delivery
O ponto de vista oposto afirma que permissões estritas em CI atrasam delivery porque equipes precisam de automação para continuar rápidas. Ninguém quer que todo deploy fique preso em approvals, que todo workflow vire cinco arquivos ou que todo pedido de segredo vire ticket. Essa preocupação é válida. Um modelo de segurança que torna doloroso o caminho normal será contornado.
A resposta não é tornar CI rígido. A resposta é tornar privilégio explícito. A maioria dos jobs deve ser rápida porque quase não tem autoridade. Os poucos jobs que podem publicar, implantar, migrar ou alterar estado cloud merecem gates mais estreitos porque seu modo de falha não é um build vermelho. Seu modo de falha é um release comprometido, dados vazados ou um incidente de produção criado pela automação que deveria evitá-lo.
O que vale a pena lembrar
- Segredos em CI/CD são segredos de produção quando podem publicar, implantar, assinar ou ler sistemas sensíveis.
- Todo trigger de workflow define um limite de confiança, não apenas um evento de automação.
- Segredos devem ser limitados a jobs, environments e workflows em vez de repositórios inteiros.
- OIDC remove chaves cloud de longa duração apenas quando trust policies são estreitas e auditáveis.
id-token: writepertence apenas a jobs que realmente precisam de identidade externa.- Resposta a incidentes começa com inventário de credenciais mapeado para workflows e owners.
- Um pipeline seguro não é lento por padrão; ele é explícito sobre quais jobs carregam perigo.
Conclusão
O pipeline agora faz parte da superfície de ataque de produção. Ele constrói artefatos, prova identidade, publica releases, implanta infraestrutura e muitas vezes carrega as credenciais que recuperam ou destroem o sistema. Proteger apenas a aplicação enquanto CI/CD fica amplo e implícito é como trancar a porta da frente e deixar o console de release aberto.
Segurança de CI/CD melhora quando equipes param de perguntar se um workflow é conveniente e começam a perguntar que autoridade ele possui. O objetivo prático não é YAML perfeito. É automação limitada: código não confiável sem segredos, publish sem autoridade alheia, deploy atrás de gates explícitos e inventário que permite rotacionar antes do pânico.


