Secrets e variáveis no GitHub Actions

    Vazar um segredo de produção em um workflow do GitHub Actions é um dos erros mais comuns — e mais custosos — de segurança em times de desenvolvimento. Entender a hierarquia de secrets, usar environments corretamente e nunca imprimir secrets em logs são práticas que protegem sua infraestrutura.

    Hierarquia de secrets no GitHub

    Como os secrets são organizados por escopo:

    bash
    # Três níveis de secrets no GitHub:
    
    # 1. Organization secrets — compartilhados entre repositórios:
    #    GitHub Org → Settings → Secrets and variables → Actions
    #    Exemplo: DOCKER_HUB_TOKEN, SLACK_WEBHOOK
    
    # 2. Repository secrets — apenas para um repositório:
    #    Repo → Settings → Secrets and variables → Actions → New secret
    #    Exemplo: SSH_PRIVATE_KEY, DATABASE_URL
    
    # 3. Environment secrets — vinculados a um ambiente (production/staging):
    #    Repo → Settings → Environments → production → Add secret
    #    Exemplo: PROD_DATABASE_URL (só disponível no job que usa environment: production)
    
    # Hierarquia de prioridade (do mais específico ao mais geral):
    # Environment > Repository > Organization
    
    # Variáveis (não-secretas, visíveis nos logs):
    # Repo → Settings → Secrets and variables → Actions → Variables
    # Exemplo: NODE_VERSION, AWS_REGION, APP_NAME
    
    # No workflow — usar secrets:
    # ${{ secrets.NOME_DO_SECRET }}
    # ${{ vars.NOME_DA_VARIAVEL }}  (variáveis não-secretas)

    Usar secrets com segurança nos workflows

    Boas práticas para evitar vazamento de secrets:

    yaml
    # .github/workflows/deploy.yml
    name: Deploy
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        environment: production   # ← ativa os secrets do ambiente production
    
        steps:
          - uses: actions/checkout@v4
    
          # ✅ CORRETO — passar secret como variável de ambiente:
          - name: Deploy
            env:
              DATABASE_URL: ${{ secrets.DATABASE_URL }}
              SSH_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
            run: ./scripts/deploy.sh
    
          # ❌ ERRADO — nunca interpolar secret diretamente no script inline:
          # - run: echo ${{ secrets.DATABASE_URL }}  # vaza no log!
    
          # ❌ ERRADO — nunca usar secret em contexto de shell não-confiável:
          # - run: curl -u ${{ secrets.API_KEY }} http://...  # expansão no shell
    
          # ✅ CORRETO — GitHub mascara automaticamente os valores de secrets nos logs:
          - name: Testar conexão (o valor do secret fica mascarado nos logs)
            env:
              SSH_HOST: ${{ secrets.SSH_HOST }}
            run: |
              echo "Conectando em $SSH_HOST"  # exibe "Conectando em ***"
              # O GitHub mascara automaticamente o valor do secret
    
          # ✅ Criar arquivo de configuração a partir de secrets:
          - name: Criar .env de produção
            run: |
              cat > /tmp/.env.production << EOF
              DATABASE_URL=${{ secrets.DATABASE_URL }}
              REDIS_URL=${{ secrets.REDIS_URL }}
              JWT_SECRET=${{ secrets.JWT_SECRET }}
              EOF

    Environments com aprovação manual

    Proteger o ambiente de produção com revisores obrigatórios:

    yaml
    # Configurar environment com proteção:
    # GitHub → Repo → Settings → Environments → New environment
    
    # Environment: production
    # ✓ Required reviewers: adicionar @username ou @team
    # ✓ Wait timer: 0 minutes (ou X para delay obrigatório)
    # ✓ Deployment branches: "Selected branches" → main only
    
    # No workflow:
    jobs:
      deploy-staging:
        environment: staging   # sem proteção — deploy automático
        runs-on: ubuntu-latest
        steps:
          - run: echo "Deploy em staging"
    
      deploy-production:
        needs: deploy-staging
        environment: production  # ← pausa aqui para aprovação manual
        runs-on: ubuntu-latest
        steps:
          - run: echo "Deploy em produção (após aprovação)"
    
    # Fluxo:
    # 1. Push em main
    # 2. Tests passam
    # 3. Deploy em staging automaticamente
    # 4. GitHub envia notificação para os revisores
    # 5. Revisor acessa a URL de aprovação e clica "Approve and deploy"
    # 6. Deploy em produção executa
    
    # Secrets específicos do environment:
    # ${{ secrets.DATABASE_URL }} no job de production usa o valor
    # configurado em Environments → production → Secrets

    OpenID Connect: credenciais temporárias sem secrets

    Autenticar no AWS sem armazenar access keys permanentes:

    yaml
    # OIDC elimina a necessidade de armazenar AWS_ACCESS_KEY_ID no GitHub.
    # O GitHub Actions se autentica diretamente no AWS com token temporário.
    
    # .github/workflows/deploy-aws.yml:
    jobs:
      deploy:
        runs-on: ubuntu-latest
        permissions:
          id-token: write    # necessário para OIDC
          contents: read
    
        steps:
          - uses: actions/checkout@v4
    
          - name: Configurar credenciais AWS via OIDC
            uses: aws-actions/configure-aws-credentials@v4
            with:
              role-to-assume: arn:aws:iam::123456789:role/GitHubActionsRole
              aws-region: sa-east-1
              # Nenhum access key necessário — token OIDC é gerado automaticamente
    
          # A partir daqui, aws CLI está autenticado com credenciais temporárias:
          - name: Push imagem para ECR
            run: |
              aws ecr get-login-password --region sa-east-1 | \
                docker login --username AWS --password-stdin 123456789.dkr.ecr.sa-east-1.amazonaws.com
              docker push 123456789.dkr.ecr.sa-east-1.amazonaws.com/minha-api:latest
    
    # Na AWS — configurar IAM Role para GitHub Actions:
    # Trust policy do Role:
    # {
    #   "Principal": {
    #     "Federated": "arn:aws:iam::123456789:oidc-provider/token.actions.githubusercontent.com"
    #   },
    #   "Condition": {
    #     "StringEquals": {
    #       "token.actions.githubusercontent.com:sub": "repo:org/repo:ref:refs/heads/main"
    #     }
    #   }
    # }

    Auditoria de secrets e boas práticas

    Detectar secrets vazados e prevenir exposição acidental:

    bash
    # Ferramentas para detectar secrets no código:
    
    # 1. git-secrets (AWS) — instalar e configurar:
    brew install git-secrets  # ou apt
    git secrets --install     # instalar hooks no repositório
    git secrets --register-aws  # patterns do AWS
    
    # 2. gitleaks — detectar secrets em commits:
    # .github/workflows/security.yml:
      secret-scan:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0  # histórico completo
          - uses: gitleaks/gitleaks-action@v2
            env:
              GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    
    # 3. .gitignore — sempre ignorar:
    # .env
    # .env.local
    # .env.production
    # *.pem
    # *.key
    # credentials.json
    
    # 4. Se um secret vazar em um commit:
    # (a) Rotacionar IMEDIATAMENTE — assume comprometido
    # (b) Remover do histórico: git filter-repo --path .env --invert-paths
    # (c) Force push (após comunicar o time)
    # AVISO: remover do histórico não garante que foi deletado de forks ou caches
    
    # 5. Rotação programada de secrets:
    # Use secrets com expiração (tokens de 90 dias)
    # Configure lembretes no calendário para renovar

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS para APIs em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes