Secrets e variáveis no GitHub Actions

Secrets no GitHub Actions são a forma segura de armazenar chaves SSH, tokens de API e senhas de banco que o CI/CD precisa, não ficam expostos nos logs e são criptografados em repouso. Entender a diferença entre secrets, variáveis e environments é essencial para uma pipeline segura e bem organizada.

Tipos de secrets e variáveis

GitHub Actions tem quatro escopos para secrets e variáveis:

yaml
# 1. Repository Secrets — disponíveis em todos os workflows do repositório
# Settings → Secrets and variables → Actions → New repository secret
# SSH_PRIVATE_KEY, DATABASE_URL, etc.

# 2. Environment Secrets — disponíveis apenas em jobs de um ambiente específico
# Settings → Environments → production → Add secret
# Permite aprovação manual antes de usar (protection rules)

# 3. Organization Secrets — compartilhados entre múltiplos repositórios
# Organization Settings → Secrets → New secret
# Útil para token de deploy compartilhado entre microserviços

# 4. Variables (não secrets) — valores não sensíveis, visíveis nos logs
# Settings → Secrets and variables → Variables
# NODE_VERSION=22, APP_PORT=3000, etc.

# Acessar no workflow:
env:
  # Secret (mascarado nos logs)
  DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
  # Variável (visível nos logs)
  NODE_ENV: ${{ vars.NODE_ENV }}
  # Variável automática do GitHub (sempre disponível)
  BRANCH: ${{ github.ref_name }}

Environments com aprovação manual

Environments adicionam uma camada de controle, exigem aprovação antes de fazer deploy em produção:

yaml
# Settings → Environments → production → Protection rules:
# ✓ Required reviewers: adicione pessoas que devem aprovar
# ✓ Wait timer: aguardar N minutos antes de executar
# ✓ Deployment branches: apenas main

# No workflow — referenciar o environment:
jobs:
  deploy-prod:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://seudominio.com.br    # URL exibida no GitHub após deploy

    steps:
      # Aqui o job pausa e aguarda aprovação dos reviewers
      - name: Deploy para produção
        run: echo "Fazendo deploy..."

# O job só executa após aprovação na interface do GitHub
# Secrets do environment production ficam disponíveis apenas neste job

OIDC: autenticação sem secrets de longa duração

OpenID Connect elimina a necessidade de armazenar chaves de acesso como secrets, o GitHub gera tokens temporários:

yaml
# Para AWS (sem AWS_ACCESS_KEY_ID/SECRET armazenados):
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write    # necessário para OIDC
      contents: read

    steps:
      - name: Configurar AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-deploy
          aws-region: sa-east-1

      - name: Deploy no ECS/S3/EC2
        run: aws ecs update-service ...

# O token AWS é temporário (1h) e gerado automaticamente
# Sem credenciais de longa duração armazenadas no GitHub
# Configuração requer criar IAM Role com trust policy para GitHub OIDC

Boas práticas para não vazar secrets

Erros comuns que expõem secrets e como evitá-los:

yaml
# ❌ NUNCA faça:

# 1. Imprimir secrets diretamente
- run: echo "Minha senha: ${{ secrets.DB_PASSWORD }}"

# 2. Passar secrets em args de linha de comando (visível em ps aux)
- run: mysql -u root -p${{ secrets.DB_PASSWORD }} -e "SELECT 1"

# 3. Commitar .env com secrets no repositório
- run: git add .env && git commit

# ✅ FAÇA:

# 1. Usar variáveis de ambiente (mascaradas pelo runner)
- name: Conectar ao banco
  env:
    DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
  run: mysql -u root -p"$DB_PASSWORD" -e "SELECT 1"

# 2. Escrever em arquivo temporário
- name: Criar .env
  run: |
    cat > .env << EOF
    DB_PASSWORD=${{ secrets.DB_PASSWORD }}
    EOF
  # O arquivo não é commitado — only em memória do runner

# 3. Verificar que .env está no .gitignore
- name: Verificar .gitignore
  run: grep -q "^.env" .gitignore || (echo ".env não está no .gitignore!" && exit 1)

Gerenciar secrets via GitHub CLI

Automatize a criação e atualização de secrets com gh CLI:

bash
# Instalar GitHub CLI (se não tiver)
# https://cli.github.com

# Login
gh auth login

# Criar ou atualizar secret
gh secret set SSH_PRIVATE_KEY < ~/.ssh/id_ed25519_github_actions
gh secret set DATABASE_URL --body "postgresql://user:pass@host:5432/db"

# Criar secret de environment específico
gh secret set DATABASE_URL --env production --body "postgresql://..."

# Listar secrets (nomes apenas — valores nunca são exibidos)
gh secret list
gh secret list --env production

# Deletar secret
gh secret delete OLD_SECRET

# Criar variável (não secret)
gh variable set NODE_VERSION --body "22"
gh variable list

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

GITHUB_TOKEN: gerado automaticamente por workflow, escopo limitado ao repositório, expira ao final do job, use para operações no próprio repo (push, PR comments, packages). PAT: criado manualmente, escopo configurável, não expira, use para acessar outros repositórios, organizações ou APIs externas. Prefira GITHUB_TOKEN sempre que possível.

Não. Uma vez criado, o valor do secret nunca é exibido na interface do GitHub, só pode ser sobrescrito ou deletado. Nos logs de workflow: o runner mascara automaticamente qualquer ocorrência do valor. Armazene os valores em um gerenciador de senhas externo (1Password, Bitwarden) além do GitHub.

Gere o novo valor externamente (nova chave SSH, novo token), atualize com gh secret set NOME --body "novo-valor", e faça o deploy. Para rotação automática programada: use um workflow com schedule: cron que regenera tokens usando APIs dos provedores e atualiza os secrets via gh CLI.

Não por padrão. PRs de forks externos não têm acesso a secrets do repositório original, isso evita que contribuidores maliciosos exfiltrem credenciais. Para forks aprovados: use pull_request_target (cuidado: dá acesso ao código do fork ao contexto de segurança do repo).

100 repository secrets, 100 environment secrets por environment, 100 organization secrets por organização, cada um com limite de 64 KB de tamanho. Para chaves grandes (certificados, chaves PEM): armazene em base64 (base64 < chave.pem | tr -d "\n") e decodifique no workflow.