SOPS + age: Gerenciamento de segredos declarativo, seguro e sem a dor de cabeça do GPG

Neste post
Como já discuti anteriormente no post sobre secret management no macOS e no Linux, o grande problema de gerenciar chaves e tokens não é a criptografia em si, mas sim reduzir o vazamento acidental sem transformar a rotina do sysadmin num inferno burocrático. Nos últimos anos, porém, uma dupla de ferramentas ganhou espaço e mudou completamente essa dinâmica: o Mozilla SOPS e o age. Juntos, eles permitem uma abordagem declarativa (GitOps-friendly), extremamente segura e com fricção quase zero. Este post é uma análise detalhada sobre o funcionamento dessas ferramentas e como integrá-las de forma prática no seu dia a dia.
age: Criptografia moderna para a vida real#
O age (criado por Filippo Valsorda) foi projetado com uma premissa simples: ser uma ferramenta de criptografia de arquivos moderna, segura e, acima de tudo, descomplicada. Ele foi feito para substituir o GPG nos casos de uso cotidianos de infraestrutura.
Enquanto o GPG é um monólito com décadas de legado e suporte a dezenas de algoritmos obsoletos, o age usa criptografia de ponta por padrão (como X25519 e ChaCha20-Poly1305) e não tenta gerenciar sua identidade. Ele não tem “trust networks” ou base de dados local de chaves.
Uma chave do age é simplesmente um arquivo de texto contendo duas strings:
- A chave pública (que começa com
age1...), usada para criptografar. - A chave privada (que começa com
AGE-SECRET-KEY-1...), usada para descriptografar.
O age na prática#
Instalar o age é trivial em qualquer sistema. No macOS você usa brew install age, e na maioria das distribuições Linux ele já está nos repositórios oficiais (apt install age).
Para gerar um par de chaves, basta rodar:
age-keygen -o key.txt
O arquivo gerado será parecido com isto:
# created: 2026-05-26T07:15:00-03:00
# public key: age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns
AGE-SECRET-KEY-1R4X2QYLWMVPTQYP...
Criptografar um arquivo usando a chave pública é direto:
age -r age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns -o segredos.enc segredos.txt
E para descriptografar usando a chave privada:
age -d -i key.txt segredos.enc
É apenas isso. Sem demônios em background, sem chaves expiradas travando seu script, sem chaves públicas importadas em um banco de dados local. Apenas arquivos de texto e fluxos de entrada e saída.
Mozilla SOPS: Criptografia parcial e inteligente#
Embora o age resolva o problema da criptografia de arquivos de forma brilhante, ele ainda opera no nível do arquivo inteiro. Se você tem um arquivo YAML de configuração com 50 linhas e apenas duas delas são segredos (como a senha do banco de dados), criptografar o arquivo inteiro com age traz dois problemas clássicos no controle de versão:
- Você perde a visibilidade do que mudou no Git (o diff vira apenas um bloco binário opaco).
- Resolver conflitos de merge em arquivos binários criptografados é virtualmente impossível.
É aqui que entra o Mozilla SOPS (Secrets Operations).
O SOPS é um editor de arquivos criptografados que suporta YAML, JSON, TOML, arquivos .env e binários. A sua grande sacada é a criptografia parcial: ele analisa a estrutura do seu arquivo e criptografa apenas os valores, mantendo as chaves estruturais em texto claro.
O SOPS em ação#
Imagine que você tem o seguinte arquivo de configuração (secrets.yaml):
database:
host: db.internal
username: app_user
password: "minha-senha-super-secreta"
api:
token: "sk_live_abcdef123456"
Ao rodar o comando do SOPS configurado para usar a sua chave do age:
sops --encrypt --age age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns secrets.yaml > secrets.enc.yaml
O arquivo secrets.enc.yaml resultante terá esta cara:
database:
host: db.internal
username: app_user
password: ENC[AES256_GCM,data:lTqgB4e5aY1G8pQ=,iv:...,tag:...]
api:
token: ENC[AES256_GCM,data:2u7gB4a...,iv:...,tag:...]
sops:
age:
- recipient: age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
...
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-05-26T07:22:00Z"
version: 3.9.0
Repare no quanto isso é elegante:
- As chaves
database.hostedatabase.usernamepermanecem legíveis. Qualquer um que ler o repositório sabe que o host édb.internal. - Apenas os valores confidenciais (
passwordetoken) foram criptografados com AES-256-GCM. - Os metadados sobre como descriptografar o arquivo (incluindo a chave pública do destinatário) ficam anexados na chave
sops.
No Git, se você alterar o host do banco de dados, o diff mostrará exatamente essa linha mudando. Se você rotacionar a senha, apenas a linha do valor criptografado mudará. O diff continua limpo, legível e útil.
Além disso, editar o arquivo é extremamente transparente. Se você definir a variável de ambiente SOPS_AGE_KEY_FILE=/path/to/key.txt e rodar:
sops secrets.enc.yaml
O SOPS lerá a sua chave privada, descriptografará o arquivo temporariamente na memória, abrirá o seu editor padrão (definido na variável $EDITOR), esperará você fazer as alterações, re-criptografará o arquivo e o salvará de volta no disco assim que o editor for fechado. A chave privada nunca toca o arquivo salvo e o texto claro nunca toca o disco.
O poder do arquivo .sops.yaml#
Ficar passando chaves públicas na linha de comando toda vez que você criptografa um arquivo é inviável e propício a erros. O SOPS resolve isso através de um arquivo de configuração declarativo colocado na raiz do seu repositório: o .sops.yaml.
Este arquivo define regras sobre quais chaves devem criptografar quais arquivos baseando-se em expressões regulares.
Aqui está um exemplo real de infraestrutura:
creation_rules:
# Regra para segredos de produção
- path_regex: secrets/production/.*\.yaml$
key_groups:
- age:
- age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns # Dev Principal (Janio)
- age1r78k4u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlq928asl0212 # Chave do Servidor de Prod
- age1backup9u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqkey00 # Chave de Backup Fria
# Regra para segredos de staging/desenvolvimento
- path_regex: secrets/staging/.*\.yaml$
key_groups:
- age:
- age1y3d8q2u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyv2pns # Dev Principal
- age1dev01u9vx8zux5mshq8387hws55v7pyll6zdfp4slx2p8nlyspqyvdev01 # Chave do time de desenvolvimento
Com essa estrutura, quando qualquer pessoa do time executa sops secrets/production/app.yaml, o SOPS lê a configuração automaticamente e criptografa o arquivo de forma que qualquer um dos três destinatários listados na regra de produção consiga descriptografá-lo usando sua respectiva chave privada do age.
Isso elimina a necessidade de compartilhar chaves privadas. O desenvolvedor usa a chave dele, o servidor usa a chave dele, e o backup usa a chave dele.
Adicionando novas máquinas e rotacionando chaves#
Se você precisar autorizar um novo servidor a ler os segredos de produção, o fluxo é simples:
- Gere uma chave
ageno novo servidor. - Pegue a chave pública e adicione-a na lista de destinatários em
.sops.yaml. - No seu computador de administrador, aplique a nova configuração aos arquivos existentes rodando:
sops updatekeys secrets/production/app.yaml
O SOPS vai descriptografar o arquivo usando a sua chave privada e re-criptografá-lo adicionando o novo servidor à lista de destinatários. Em seguida, basta commitar as mudanças no Git.
Como consumir os segredos na prática (Sem fricção)#
Embora o ecossistema sops + age seja incrivelmente robusto para armazenamento, você ainda precisa ler esses segredos para utilizá-los nos seus scripts, deploys e aplicações. A boa notícia é que o SOPS oferece várias maneiras de fazer isso com fricção mínima.
1. Injetando segredos no ambiente via CLI (sops exec-env)#
Se você tem um script, container ou aplicação que espera encontrar as chaves de API e senhas como variáveis de ambiente tradicionais, você não precisa mantê-las salvas em arquivos .env em texto puro. O SOPS possui um comando específico para descriptografar os segredos em memória e injetá-los no processo da sua aplicação:
sops exec-env secrets.enc.yaml 'npm run start'
O comando npm run start será iniciado com acesso a todas as variáveis definidas no arquivo descriptografado, mas assim que o processo terminar, essas variáveis deixam de existir. Nenhum segredo foi persistido em texto claro no disco.
2. Lendo segredos estruturados em scripts de Shell#
Se você precisa extrair apenas um valor específico de dentro de um arquivo YAML criptografado no seu script de automação, você pode combinar o SOPS com o utilitário yq (ou o próprio parser interno do SOPS):
# Usando o extrator nativo do SOPS
DB_PASS=$(sops -d --extract '["database"]["password"]' secrets.enc.yaml)
Isso é ideal para scripts de backup ou deploys automatizados via SSH, permitindo ler exatamente o segredo necessário na hora do uso.
3. Integração direta no seu código (Python)#
Em linguagens de programação, você pode ler os arquivos criptografados do SOPS invocando o binário via subprocesso de forma limpa, retornando um dicionário estruturado diretamente em memória.
Aqui está um helper simples em Python para carregar segredos sem nunca tocá-los no disco em formato legível:
import json
import subprocess
def load_sops_secrets(filepath: str) -> dict:
# Decodifica o arquivo diretamente na memória em formato JSON
result = subprocess.run(
["sops", "-d", "--output-type", "json", filepath],
capture_output=True,
text=True,
check=True
)
return json.loads(result.stdout)
# Uso prático
secrets = load_sops_secrets("secrets.enc.yaml")
db_password = secrets["database"]["password"]
Essa abordagem garante que mesmo se o servidor for comprometido e o disco for copiado, os segredos continuarão seguros (já que a chave do age pode estar isolada sob permissões restritas em /etc/ ou apenas carregada no agent do servidor).
Conclusão: Segurança real é aquela que você realmente usa#
Uma das maiores lições na administração de sistemas é que a segurança é inversamente proporcional à fricção. Se um método de segurança exige 10 passos manuais complexos, as pessoas vão encontrar um atalho — e esse atalho geralmente é uma senha em plaintext em um arquivo desprotegido.
A combinação de SOPS + age brilha porque ela remove o “teatro de segurança”. Ela permite que você mantenha uma infraestrutura 100% declarativa, versionada e segura no Git, sem precisar gerenciar chaves GPG complexas ou provisionar servidores de segredos pesados para ambientes pequenos e médios.
Quando você integra essa fundação na sua rotina de automação, o gerenciamento de segredos deixa de ser um peso operacional para se tornar uma parte natural, fluida e transparente do desenvolvimento.
E você? Como gerencia os segredos na sua infraestrutura hoje? Já deu uma chance para o age ou ainda sofre com chaves GPG? Compartilhe sua experiência nos comentários abaixo.
Sysadmin, 53 anos, brasileiro trabalhando de casa para o mundo todo. Cuida de servidores Linux, containers LXC, e de gatos que não saem de cima do teclado.