Pass, GPG e um backup que não depende de uma máquina só

Hoje terminei uma parte importante da organização das minhas senhas: exportei uma cópia do meu cofre do KeePassXC e coloquei os dados no pass, o gerenciador de senhas simples do mundo Unix.

O motivo principal não foi abandonar o KeePassXC imediatamente. Foi experimentar uma integração melhor com o terminal. Como eu já passo bastante tempo no shell, queria conseguir consultar senhas, copiar credenciais e gerar códigos OTP sem sair desse ambiente.

Por enquanto vou manter os dois fluxos: o KeePassXC continua sendo a referência principal e o pass fica como uma segunda cópia em estudo. Ainda estou avaliando a melhor forma de sincronizar os dois cofres sem criar conflitos ou perder alterações.

A ideia do pass é direta: cada entrada vira um arquivo de texto criptografado com GPG. O nome da entrada organiza o cofre e a senha fica na primeira linha.

A saída do KeePassXC

O ponto de partida foi o meu cofre do KeePassXC. O KeePassXC permite exportar as entradas para CSV, então fiz essa exportação antes de começar a migração.

O CSV é útil para transportar os dados, mas não é um formato adequado para deixar espalhado por aí: ele contém as senhas em texto puro. Por isso tratei o arquivo como uma etapa temporária e restrita, sem colocá-lo no Git, no servidor remoto ou na nuvem.

Depois da exportação, criei uma versão sanitizada do arquivo. Nessa etapa eu:

  • conferi as colunas e a quantidade de registros;
  • preservei usuário, senha, URL, notas e tokens TOTP;
  • normalizei os grupos para nomes mais simples;
  • removi acentos dos identificadores;
  • troquei espaços nos nomes por pontos;
  • verifiquei títulos duplicados e caminhos que poderiam virar nomes inválidos.

O arquivo intermediário foi:

~/caminho/para/senhas.sanitized.csv

Só depois dessa normalização o conteúdo foi importado para o pass. Ao final, o CSV continuou protegido com permissões restritas e não foi adicionado ao repositório de configurações.

Do CSV para o cofre

Eu tinha um arquivo com minhas senhas em CSV. Ele tinha usuários, senhas, URLs, anotações e alguns tokens de autenticação em dois fatores.

Antes de importar, organizei os nomes dos grupos. Em vez de caminhos longos como meu cofre/família/pessoa, passei a usar nomes mais curtos:

familia.pessoa
familia.outro
empresa.exemplo
empresa.outro

Também substituí espaços nos nomes dos itens por pontos. Assim, uma entrada ficou parecida com:

empresa.exemplo/ambiente.de.stage
familia.pessoa/banco.inter

O processo ficou assim:

CSV sanitizadoArquivos .gpgImportação com passNormalização dos nomesVault de senhas

Foram importadas 223 entradas. Depois conferi se todas podiam ser descriptografadas e se as senhas estavam na primeira linha, que é o formato esperado pelo pass.

OTP sem gambiarra

Também instalei a extensão pass-otp. Ela usa as URIs padrão otpauth:// para gerar códigos de autenticação de dois fatores.

Na primeira importação, eu tinha colocado a URI assim:

TOTP: otpauth://totp/...

Parecia organizado, mas a extensão não encontrava o token. O formato correto é deixar a URI em uma linha própria:

otpauth://totp/...

Depois de ajustar o CSV, zerei o cofre e importei tudo novamente. O resultado foi melhor: as entradas com OTP passaram a funcionar com o comando:

pass otp "empresa.exemplo/servico.otp"

Ou copiando o código diretamente para a área de transferência:

pass otp -c "empresa.exemplo/servico.otp"

Adicionando novas senhas

Para criar uma nova entrada, uso pass insert:

pass insert empresa.exemplo/nova-senha

O pass pede a senha no terminal e salva o resultado criptografado. Para guardar também usuário, URL e outras informações, uso o modo multiline:

pass insert --multiline empresa.exemplo/nova-senha

O formato fica assim:

minha-senha
Username: meu.usuario
URL: https://servico.example
Notes: alguma observação

A senha fica na primeira linha. Isso permite usar pass -c para copiar somente a senha:

pass -c empresa.exemplo/nova-senha

Adicionando novos OTPs

Para adicionar um token de autenticação, uso a extensão pass-otp:

pass otp insert empresa.exemplo/nova-senha

O comando pede uma URI no formato otpauth://. Normalmente ela vem do QR Code exibido pelo serviço ao ativar o segundo fator.

Se eu já tenho uma entrada de senha e quero adicionar o OTP nela, uso append:

pass otp append empresa.exemplo/nova-senha

Depois posso gerar o código com:

pass otp empresa.exemplo/nova-senha

Ou copiá-lo para a área de transferência:

pass otp -c empresa.exemplo/nova-senha

A URI do OTP é armazenada como uma linha própria dentro da entrada, começando diretamente com otpauth://.

O cofre também é um repositório Git

Meu ~/.password-store já era um repositório Git com um servidor remoto configurado. Isso significa que o pass consegue criar commits quando uma entrada é adicionada ou atualizada.

Depois da reorganização, os nomes antigos foram removidos e as entradas novas ficaram nos grupos empresa.* e familia.*. Fiz a consolidação em um commit e enviei para o servidor remoto.

O fluxo ficou assim:

Backup versionadoServidor Git remotoEntrada .gpgGit localChave GPG privadapass

O servidor remoto recebe somente os arquivos criptografados. Mesmo assim, o repositório não substitui o backup da chave GPG. Sem a chave privada, os arquivos .gpg continuam inacessíveis.

O problema da máquina única

Foi aí que veio a próxima pergunta: e se esta máquina quebrar?

A chave GPG não deve ficar somente em um computador. Também não é uma boa ideia colocar uma cópia sem proteção em um serviço de nuvem.

Em vez de copiar todo o ~/.gnupg, preparei um script genérico no meu repositório de configurações pessoais:

scripts/backup-gnupg.sh

O script exporta somente o que importa para recuperar a identidade:

  • chave pública;
  • chave privada;
  • subchaves privadas;
  • ownertrust;
  • certificados de revogação;
  • configurações GPG existentes.

Ele não copia sockets, cache, locks nem arquivos temporários do agente GPG.

O resultado é um arquivo 7-Zip criptografado com uma senha própria:

Chaves GPGMídia física offlineNuvem pessoalExportação seletivaArquivo 7z criptografado

A senha do arquivo 7-Zip é diferente da senha da chave GPG. Isso é importante: são duas camadas diferentes de proteção.

O que ficou versionado

O repositório dotfiles é o lugar das minhas configurações pessoais e dos pequenos scripts que ajudam a recuperar o ambiente.

Para este setup, versionei o script genérico de backup seletivo do GPG e sua documentação. O backup criado não foi colocado no repositório. O Git guarda o script que sabe criar o backup, não o arquivo com as minhas chaves privadas.

Fechando o dia

O mais importante de hoje não foi somente trocar um gerenciador de senhas. Foi experimentar um fluxo mais próximo do terminal sem abandonar o KeePassXC antes de entender bem a sincronização.

Por enquanto, os dois cofres convivem. Foi uma migração controlada, não uma troca definitiva.

Também consegui separar melhor as coisas:

  • o KeePassXC continua como referência principal;
  • o pass guarda uma cópia criptografada e acessível pelo terminal;
  • o Git registra as mudanças;
  • o servidor remoto guarda uma cópia dos arquivos criptografados;
  • o GPG protege e recupera a identidade;
  • a nuvem pessoal e a mídia física guardam um backup criptografado;
  • o repositório dotfiles documenta como refazer o setup.

Ainda quero testar a restauração completa em uma máquina virtual. Backup bom não é o que existe. É o que foi restaurado com sucesso pelo menos uma vez.