Alternar tema

Como gerenciar secrets no GitHub Actions: do risco de vazamento à implantação sem chaves com OIDC

Easton editorial illustration: modular system blueprint

Em um fim de semana de março de 2025, a equipe de segurança do GitHub enviou um e-mail urgente aos responsáveis por mais de 23.000 repositórios.

Os secrets deles poderiam ter vazado.

O responsável era uma action chamada tj-actions/changed-files. A ferramenta, amplamente usada, havia sido comprometida por invasores e roubava silenciosamente todas as variáveis de ambiente e secrets dos workflows. Talvez você esteja pensando: meu projeto também usa essa action; será que fui afetado?

O incidente colocou em evidência uma questão que muita gente ignora: afinal, como gerenciar secrets no GitHub Actions?

Vamos tratar de três pontos: como escolher entre os três níveis de secrets, como aplicar oito regras fundamentais de segurança e como o OIDC permite abandonar de vez o risco de vazamento de credenciais estáticas.

1. Os três níveis de GitHub Actions Secrets

O GitHub oferece três níveis para armazenar secrets: Repository, Environment e Organization. Qual escolher? Depende do seu cenário.

Repository Secrets: a primeira opção para projetos pessoais

Este é o nível mais simples. Os secrets ficam no repositório e todos os workflows podem acessá-los. Para um projeto pessoal, um repositório monolítico ou um projeto sem vários ambientes de implantação, isso basta.

A única desvantagem é não conseguir diferenciar um secret com o mesmo nome em staging e production. Se você tem um DATABASE_URL com valores diferentes nesses dois ambientes, precisa usar Environment Secrets.

Environment Secrets: essenciais para vários ambientes

Environment Secrets permitem separar os secrets por ambiente e também oferecem fluxos de aprovação. Nas configurações do repositório do GitHub, você pode criar os ambientes staging e production e definir secrets diferentes para cada um.

Uma característica importante: somente um job que faz referência ao ambiente pode acessar os secrets correspondentes. Isso deixa os limites de segurança mais claros.

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging  # faz referência ao ambiente staging
    steps:
      - run: echo "Deploying to staging..."
      - env:
          API_KEY: ${{ secrets.API_KEY }}  # secret do ambiente staging

  deploy-production:
    runs-on: ubuntu-latest
    environment: production  # faz referência ao ambiente production (pode exigir aprovação)
    steps:
      - run: echo "Deploying to production..."
      - env:
          API_KEY: ${{ secrets.API_KEY }}  # secret do ambiente production

Nessa configuração, deploy-staging só acessa os secrets do ambiente staging, enquanto deploy-production só acessa os de production. Um não interfere no outro.

Além disso, Environment oferece regras de proteção. O ambiente de production, por exemplo, pode exigir aprovação manual antes da execução. Isso é especialmente útil para equipes.

Organization Secrets: compartilhamento e gestão centralizada para equipes

Se sua equipe tem dezenas de repositórios e todos precisam do mesmo AWS_ACCESS_KEY, copiar a configuração para cada um e depois repetir todas as alterações é um trabalho enorme.

Organization Secrets resolvem esse problema. Você configura o secret uma vez no nível da organização e todos os repositórios autorizados podem usá-lo. Também pode controlar o escopo do acesso: todos os repositórios ou apenas uma lista específica.

# No workflow do repositório, o uso é igual ao de repository secrets
steps:
  - env:
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

Qual nível escolher?

Em resumo:

CenárioNível recomendado
Projeto pessoal, ambiente únicoRepository Secrets
Implantação em vários ambientes (staging/production)Environment Secrets
Vários repositórios de uma equipe, credenciais compartilhadasOrganization Secrets

Pela minha experiência, muitos projetos começam com Repository Secrets e só migram para Environment Secrets quando surge a necessidade de vários ambientes. A migração não custa muito, mas ainda assim vale planejar antes.

2. Boas práticas de segurança para secrets: oito regras fundamentais

Até aqui vimos onde armazenar os secrets. Agora vamos falar de como usá-los. Reuni oito regras aprendidas na prática, cada uma delas acompanhada de alguma lição.

1. Padronize os nomes

Use letras maiúsculas e separe as palavras com sublinhado, como AWS_ACCESS_KEY_ID. Evite minúsculas e camelCase. O motivo é simples: assim fica evidente que se trata de um secret, sem confusão com variáveis comuns.

2. Não armazene um JSON inteiro em um único secret

Esta é uma armadilha clássica. Algumas pessoas colocam o arquivo de configuração inteiro em um secret:

{"api_key": "xxx", "db_url": "yyy", "token": "zzz"}

Depois, usam fromJson para analisá-lo no workflow. O problema é que, se esse secret vazar, todas as informações confidenciais vazam de uma vez. O correto é armazenar cada valor em um secret separado.

3. Passe os secrets explicitamente, sem inseri-los diretamente no comando

# Forma incorreta ❌
- run: my-cli --token ${{ secrets.MY_TOKEN }}

# Forma correta ✅
- env:
    MY_TOKEN: ${{ secrets.MY_TOKEN }}
  run: my-cli --token $MY_TOKEN

Por quê? Uma pesquisa da GitGuardian mostra que outros processos na mesma máquina podem ver argumentos de linha de comando por meio de ps x -w. Variáveis de ambiente são relativamente mais seguras.

4. Faça a rotação regularmente

Troque os secrets a cada 30 a 90 dias. Eu sei que a rotação dá trabalho, mas é muito menos onerosa que remediar um vazamento. A equipe da Blacksmith recomenda combinar serviços de nuvem, como AWS e GCP, com OIDC para dispensar completamente essa etapa.

5. Fixe actions por SHA

Esta é a primeira linha de defesa contra ataques à cadeia de suprimentos.

# Forma incorreta ❌
- uses: tj-actions/changed-files@v45

# Forma correta ✅
- uses: tj-actions/changed-files@b827595e0a7e97537d7c7a2f458b5a8e6d5c8e39

Use o commit SHA, não a tag de versão. Um invasor pode alterar uma tag; o SHA é imutável.

6. Conceda apenas o menor privilégio ao GITHUB_TOKEN

O GitHub fornece automaticamente um GITHUB_TOKEN para cada workflow. As permissões padrão são amplas demais: ele pode escrever código e alterar issues. Recomendo defini-lo como read-only no workflow ou nas configurações do repositório:

permissions:
  contents: read

7. Confirme que os secrets estão ocultos corretamente nos logs

O GitHub substitui automaticamente ${{ secrets.XXX }} por *** nos logs. Porém, se você escrever:

- run: echo "Token is $MY_TOKEN"

o valor real do token aparecerá no log. Teste o workflow e confirme que nada foi exposto por acidente.

8. Registre valores confidenciais derivados

Se o workflow gerar um novo valor confidencial a partir de um secret, como um JWT criado com uma API key, registre também esse novo valor como secret em vez de apenas mantê-lo na memória.


Essas oito regras não são apenas teoria. Depois do incidente com o tj-actions, a equipe da StepSecurity auditou milhares de repositórios públicos e constatou que uma parcela considerável violava essas regras. Corrigir os problemas não é difícil, mas exige algum tempo para revisar cada item.

3. OIDC: autenticação de implantação na nuvem sem chaves

Duas das regras anteriores mencionam a rotação periódica de secrets. Para ser sincero, essa tarefa é incômoda: a cada vez é preciso alterar manualmente o console da AWS, atualizar os secrets do GitHub e avisar a equipe.

O OIDC (OpenID Connect) oferece uma saída: não armazenar secrets.

Como o OIDC funciona?

No método tradicional, você cria um usuário IAM na AWS, gera uma access key e armazena a chave nos GitHub secrets. Sempre que o workflow é executado, ele usa essa chave estática para solicitar recursos da AWS.

Com OIDC, o GitHub atua como provedor de identidade e comprova à AWS que o workflow vem do repositório eastondev/my-repo. Após a validação, a AWS emite um token JWT de curta duração, válido por alguns minutos ou horas. O workflow usa o token temporário para concluir a tarefa, e ele perde a validade automaticamente depois de expirar.

Não há credenciais de longo prazo para armazenar, nenhuma rotação é necessária e não existe risco de vazamento dessas credenciais.

Exemplo de configuração do OIDC na AWS

O processo tem duas partes: configurar a relação de confiança na AWS e solicitar o token no GitHub.

Na AWS (operações no console):

  1. Crie um IAM Identity Provider e defina a URL como https://token.actions.githubusercontent.com
  2. Crie uma IAM Role e restrinja a política de confiança ao seu repositório:
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
        "token.actions.githubusercontent.com:sub": "repo:eastondev/my-repo:ref:refs/heads/main"
      }
    }
  }]
}

Essa configuração determina que somente a branch main do repositório eastondev/my-repo pode assumir essa role.

No GitHub (configuração do workflow):

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write  # obrigatório: solicita o token OIDC
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
          aws-region: us-east-1
      - run: aws s3 sync ./dist s3://my-bucket

Observe que não há nenhum secrets.AWS_ACCESS_KEY: a autenticação usa a role diretamente.

GCP e Azure

As três principais plataformas de nuvem oferecem suporte a OIDC, com configurações semelhantes:

Plataforma de nuvemGitHub ActionTermos para buscar na documentação oficial
AWSaws-actions/configure-aws-credentialsOIDC federation
GCPgoogle-github-actions/authWorkload Identity Federation
Azureazure/loginFederated Identity Credentials

Um benefício inesperado do OIDC

Segundo testes do johal.in, a latência da autenticação com OIDC é cerca de 87% menor que no método tradicional com secrets. O motivo é simples: não é necessário ler as credenciais pela API de secrets do GitHub; o token temporário é obtido diretamente pela troca do JWT local.

Na minha experiência, OIDC é a melhor opção para implantações na nuvem. A única barreira é uma configuração um pouco mais complexa, mas, depois de concluí-la uma vez, você não precisa mais se preocupar.

4. Proteção contra ataques à cadeia de suprimentos: análise do incidente com o tj-actions

Voltando ao incidente com tj-actions/changed-files mencionado no início: como ele aconteceu e o que podemos aprender?

O que aconteceu

Em março de 2025, invasores obtiveram acesso de maintainer ao repositório do tj-actions. O método exato ainda estava sob investigação e poderia ter envolvido vazamento de credenciais ou comprometimento de conta. Eles inseriram um script malicioso no código da versão v45. Durante a execução do workflow, o script lia silenciosamente todas as variáveis de ambiente e secrets e os enviava a um servidor controlado pelos invasores.

Segundo a análise da Semgrep, todos os workflows que usavam tj-actions/changed-files@v45 foram afetados. Isso valia tanto para GitHub secrets quanto para OIDC: qualquer variável de ambiente acessível à action poderia ser roubada.

Um relatório da Unit 42, da Palo Alto, apontou que mais de 23.000 repositórios usavam essa action, incluindo forks de alguns projetos conhecidos.

Lições

O incidente expôs vários problemas:

  1. Tags de versão de actions não são confiáveis: um invasor pode fazer uma tag apontar para um commit malicioso
  2. Actions de terceiros podem acessar seus secrets: se forem comprometidas, todos os secrets acessíveis ficam expostos
  3. Logs de execuções anteriores podem vazar informações confidenciais: mesmo após a correção, execuções passadas ainda podem conter vestígios

Sua lista de verificação

Se você já usou tj-actions/changed-files, verifique cada item:

□ Verifique os logs do workflow e confirme que nenhum secret vazou na saída
□ Faça a rotação de todos os secrets que possam ter sido expostos (API keys, tokens etc.)
□ Fixe a action por commit SHA, não por tag de versão
□ Audite a origem dos maintainers de outras actions de terceiros
□ Considere usar Dependabot ou Renovate para automatizar a verificação de versões das actions

Para projetos que ainda não foram comprometidos, fixar por SHA é a medida de proteção mais importante. Embora o SHA seja menos legível que um número de versão, essa é a única forma de impedir alterações de tag.

Além disso, o GitHub mencionou uma direção importante em seu roteiro de segurança para 2026: separar as permissões para contribuir com código das permissões para gerenciar credenciais. No futuro, talvez sejam introduzidos controles de acesso mais granulares, permitindo que actions de terceiros acessem somente os secrets necessários, em vez de todos. É uma boa notícia, mas, por enquanto, ainda precisamos proteger nossos próprios limites.

Conclusão

Gerenciar GitHub Actions Secrets não é um problema técnico complexo, mas uma prática de segurança que exige atenção contínua. Em resumo:

Como escolher entre os três níveis: use Repository Secrets em projetos pessoais, migre para Environment Secrets em implantações com vários ambientes e use Organization Secrets para compartilhamento em equipe.

Como aplicar as regras de segurança: fixar por SHA, passar secrets explicitamente e fazer rotação periódica são as três mais importantes.

Como autenticar implantações na nuvem: OIDC é a primeira opção, pois dispensa o armazenamento e a rotação de secrets.

Como evitar ataques à cadeia de suprimentos: limite o acesso de actions de terceiros aos secrets e audite a origem dos maintainers.

Depois de aprender com o incidente do tj-actions, passei a fixar todas as actions por SHA, usar OIDC em todas as implantações na nuvem e auditar secrets uma vez por mês. Levei cerca de duas semanas para estabelecer esse processo, mas o custo de manutenção desde então tem sido baixo.

Se você ainda não começou essas verificações, vale executar hoje mesmo a lista deste artigo. Prevenir custa muito menos que remediar um incidente.

Configurar uma implantação sem chaves no GitHub Actions com OIDC

Configure a autenticação OIDC para a AWS e faça implantações seguras sem armazenar credenciais estáticas

⏱️ Estimated time: 30 min

  1. 1

    Step 1: Criar um IAM Identity Provider

    Crie um provedor de identidade no console do AWS IAM:

    • Provider URL: https://token.actions.githubusercontent.com
    • Audience: sts.amazonaws.com
    • Anote o Provider ARN gerado
  2. 2

    Step 2: Criar uma IAM Role e configurar a política de confiança

    Crie uma IAM Role e restrinja a política de confiança ao seu repositório do GitHub:

    ```json
    {
    "Version": "2012-10-17",
    "Statement": [{
    "Effect": "Allow",
    "Principal": {
    "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
    "StringEquals": {
    "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
    "token.actions.githubusercontent.com:sub": "repo:OWNER/REPO:ref:refs/heads/main"
    }
    }
    }]
    }
    ```

    • Substitua ACCOUNT_ID pelo ID da sua conta AWS
    • Substitua OWNER/REPO pelo seu repositório do GitHub
    • Remova :ref:refs/heads/main se quiser permitir todas as branches
  3. 3

    Step 3: Configurar o workflow para usar OIDC

    Solicite um token OIDC no workflow do GitHub Actions:

    ```yaml
    jobs:
    deploy:
    runs-on: ubuntu-latest
    permissions:
    id-token: write # obrigatório: solicita o token OIDC
    contents: read
    steps:
    - uses: aws-actions/configure-aws-credentials@v4
    with:
    role-to-assume: arn:aws:iam::ACCOUNT_ID:role/GitHubActionsRole
    aws-region: us-east-1
    - run: aws s3 sync ./dist s3://my-bucket
    ```

    • id-token: write é uma declaração de permissão obrigatória
    • Não é necessário configurar secrets.AWS_ACCESS_KEY_ID
  4. 4

    Step 4: Testar e validar

    Execute o workflow para validar a configuração OIDC:

    • Confira os logs do workflow e confirme que a autenticação foi bem-sucedida
    • Verifique se role-to-assume está correto
    • Confirme que os recursos da AWS podem ser acessados sem credenciais estáticas
    • Teste a operação desejada, como sincronização com S3 ou envio para o ECR

FAQ

Qual é a diferença entre Repository Secrets e Environment Secrets?
Repository Secrets são armazenados no nível do repositório e ficam disponíveis para todos os workflows. Environment Secrets são separados por ambiente: somente jobs que fazem referência ao ambiente podem acessar os secrets correspondentes, e também é possível exigir aprovação. Para implantações em vários ambientes, prefira Environment Secrets.
Como usar secrets com segurança em um workflow?
Siga três princípios:

• Passagem explícita: injete pelo campo env em vez de usar ${{ secrets.XXX }} diretamente na linha de comando
• Menor privilégio: passe o secret somente ao step que precisa dele; ao usar GITHUB_TOKEN, defina permissions: contents: read
• Rotação periódica: troque os secrets a cada 30 a 90 dias; em implantações na nuvem, use OIDC para dispensar a rotação
O que é OIDC e por que ele é mais seguro que secrets tradicionais?
OIDC (OpenID Connect) permite que o GitHub, como provedor de identidade, comprove à plataforma de nuvem a identidade do workflow; a plataforma então emite um token JWT de curta duração. As vantagens são não armazenar credenciais estáticas, não precisar de rotação e eliminar o risco de vazamento dessas credenciais. A latência de autenticação é cerca de 87% menor que no método tradicional com secrets.
Como evitar ataques à cadeia de suprimentos, como o incidente do tj-actions?
As principais medidas de proteção são:

• Fixar actions por commit SHA, não por tag de versão
• Limitar a passagem de secrets somente a actions confiáveis
• Auditar a origem dos maintainers de actions de terceiros
• Executar Dependabot ou Renovate regularmente para verificar atualizações de versão
Os secrets podem vazar nos logs?
O GitHub substitui automaticamente ${{ secrets.XXX }} por *** nos logs. No entanto, se você usar diretamente uma variável de ambiente, como echo ${MY_TOKEN}, o valor real aparecerá no log. Teste os logs do workflow para confirmar que não há exposição acidental.
Para quais situações Organization Secrets são indicados?
Eles são indicados para equipes com vários repositórios que compartilham credenciais. Você configura o secret uma vez no nível da organização e todos os repositórios autorizados podem usá-lo. O acesso pode incluir todos os repositórios ou apenas uma lista específica. Por exemplo, quando vários projetos compartilham AWS_ACCESS_KEY, Organization Secrets evitam repetir a configuração em cada repositório.

11 min de leitura · Publicado em: 18 abr 2026 · Atualizado em: 8 set 2026

Comentários

Entre com GitHub para comentar

Easton BlogEaston Blog