Signing commits com GPG

1. Por que assinar commits?

Assinar commits com GPG é uma prática fundamental para garantir a autenticidade e integridade do histórico de um repositório Git. Quando você assina um commit, está criptograficamente provando que foi você quem o criou, e não um impostor.

Verificação de autenticidade: Sem assinatura, qualquer pessoa que tenha acesso ao seu e-mail e nome de usuário pode criar commits em seu nome. Com GPG, o servidor remoto (GitHub, GitLab, etc.) verifica se a assinatura corresponde à chave pública que você registrou.

Integridade do histórico: Um commit assinado não pode ser alterado sem que a assinatura seja invalidada. Isso impede que alguém modifique o conteúdo de commits antigos sem deixar rastros.

Confiança em projetos open source: Projetos que exigem commits assinados transmitem maior credibilidade. Mantenedores podem verificar que contribuições vieram de fontes legítimas, reduzindo riscos de código malicioso.

2. Gerando e configurando uma chave GPG

Instalação do GPG

  • Linux (Ubuntu/Debian): sudo apt install gnupg
  • macOS: brew install gnupg (via Homebrew)
  • Windows: Baixe e instale Gpg4win

Criação do par de chaves

Execute o comando interativo:

gpg --full-generate-key

Opções recomendadas:
- Tipo de chave: RSA (padrão)
- Tamanho: 4096 bits
- Expiração: 2 anos (ou sem expiração, se preferir)
- Nome e e-mail: devem corresponder exatamente aos configurados no Git
- Passphrase: forte e memorável

Listando e exportando a chave pública

Liste suas chaves secretas:

gpg --list-secret-keys --keyid-format=long

Exemplo de saída:

/Users/joao/.gnupg/pubring.kbx
--------------------------------
sec   rsa4096/1A2B3C4D5E6F7G8H 2025-01-01 [SC]
      ABCDEF1234567890ABCDEF1234567890ABCDEF12
uid                   [ultimate] Joao Silva <joao@email.com>
ssb   rsa4096/9H8G7F6E5D4C3B2A 2025-01-01 [E]

Exporte a chave pública (o ID é o hash após rsa4096/):

gpg --armor --export 1A2B3C4D5E6F7G8H

Copie a saída (começa com -----BEGIN PGP PUBLIC KEY BLOCK-----).

3. Vinculando a chave GPG ao Git e ao GitHub/GitLab

Configuração local do Git

Defina a chave de assinatura globalmente:

git config --global user.signingkey 1A2B3C4D5E6F7G8H

Para assinar todos os commits automaticamente:

git config --global commit.gpgsign true

Adicionando a chave pública ao GitHub

  1. Acesse Settings > SSH and GPG keys
  2. Clique em New GPG key
  3. Cole a chave pública exportada (incluindo os cabeçalhos -----BEGIN/END-----)
  4. Clique em Add GPG key

No GitLab: Settings > GPG Keys e siga o mesmo processo.

Testando a assinatura

Crie um commit assinado manualmente:

git commit -S -m "Meu primeiro commit assinado"

Se commit.gpgsign estiver como true, o -S é opcional.

Após o push, o GitHub exibirá um selo "Verified" ao lado do commit.

4. Assinando commits e tags no dia a dia

Assinatura manual vs automática

  • Manual: Use git commit -S quando quiser assinar apenas commits específicos
  • Automática: Configure git config --global commit.gpgsign true para assinar todos

Assinando tags

Crie uma tag assinada:

git tag -s v1.0 -m "Versão 1.0 estável"

Verifique a assinatura da tag:

git tag -v v1.0

Saída esperada:

object abc123...
type commit
tag v1.0
tagger Joao Silva <joao@email.com> 1700000000 +0000

Versão 1.0 estável
gpg: Signature made ... using RSA key ID 1A2B3C4D5E6F7G8H
gpg: Good signature from "Joao Silva <joao@email.com>"

Verificando commits assinados localmente

Exiba assinaturas no log:

git log --show-signature

Verifique um commit específico:

git verify-commit HEAD

5. Gerenciamento de chaves e segurança

Protegendo a chave privada

  • Use uma passphrase forte (mínimo 16 caracteres, com maiúsculas, números e símbolos)
  • Faça backup da pasta ~/.gnupg/ em local seguro (criptografado)
  • Nunca compartilhe a chave privada

Revogação de chaves

Crie um certificado de revogação imediatamente após gerar a chave:

gpg --gen-revoke 1A2B3C4D5E6F7G8H > revogacao.asc

Mantenha este arquivo em local seguro. Se sua chave for comprometida, publique o certificado em servidores de chaves e atualize o GitHub/GitLab.

Expiração de chaves

Para definir expiração durante a criação, use gpg --full-generate-key e escolha um período. Para alterar depois:

gpg --edit-key 1A2B3C4D5E6F7G8H
> expire
> 2y
> save

A expiração não invalida commits passados — apenas impede o uso futuro da chave.

6. Solução de problemas comuns

Erro "gpg: signing failed: secret key not available"

Causas comuns:
- A variável GPG_TTY não está configurada. Adicione ao ~/.bashrc:

export GPG_TTY=$(tty)
  • O agente GPG não está rodando. Inicie com:
gpgconf --launch gpg-agent
  • No Windows, certifique-se de que o Gpg4win está no PATH e o Kleopatra está configurado como agente.

Múltiplas chaves GPG

Para usar chaves diferentes por repositório, configure localmente:

git config user.signingkey OUTRA_CHAVE_ID

Verifique qual chave está ativa:

git config --get user.signingkey

Compatibilidade entre sistemas

  • Linux: Funciona nativamente com gpg
  • macOS: Requer pinentry-mac para interface gráfica de passphrase
  • Windows: Gpg4win inclui Kleopatra para gerenciamento visual. Configure o Git para usar gpg do Gpg4win:
git config --global gpg.program "C:/Program Files (x86)/GnuPG/bin/gpg.exe"

7. Boas práticas e integração com CI/CD

Assinatura em pipelines (GitHub Actions)

Exemplo de workflow que verifica commits assinados:

name: Verificar assinatura
on: [push]
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Importar chave pública
        run: |
          echo "${{ secrets.GPG_PUBLIC_KEY }}" | gpg --import
      - name: Verificar último commit
        run: |
          git verify-commit HEAD

Proteção de branches

No GitHub: Settings > Branches > Add rule e marque Require signed commits.

No GitLab: Settings > Repository > Protected branches e ative a opção de commits assinados.

Auditoria de commits

Script para validar assinaturas em massa:

#!/bin/bash
for commit in $(git rev-list --all); do
  if ! git verify-commit $commit 2>/dev/null; then
    echo "Commit não assinado: $commit"
  fi
done

Referências