Comparativo de gestores de segredos self-hosted
Compare OpenBao, Infisical, SOPS com age, credenciais do systemd e ficheiros env protegidos para escolher o gestor certo em um único VPS e conhecer os custos.
O que um gestor de segredos self-hosted faz que um gestor de palavras-passe não faz
Um gestor de segredos self-hosted fornece credenciais a processos. Um gestor de palavras-passe fornece credenciais a pessoas. Tudo o resto resulta desta diferença. Um gestor de palavras-passe é desbloqueado por uma pessoa presente e atenta. Um gestor de segredos tem de fornecer a palavra-passe de uma base de dados à sua aplicação às 03:00, quando ninguém está acordado.
Os modos de falha são diferentes de uma forma importante. Um gestor de palavras-passe bloqueado é um incómodo: introduz novamente a palavra-passe principal. Um gestor de segredos selado causa uma indisponibilidade: todos os serviços que reiniciem enquanto ele está selado arrancam sem credenciais e permanecem parados. Executar o Vaultwarden como o seu próprio gestor de palavras-passe resolve bem o problema humano. Não resolve o problema das máquinas, e nunca foi concebido para isso. Se executar um destes serviços em paralelo com este, os elementos que vale a pena reforçar são o seu token de administrador e o ficheiro de cópia de segurança, e não o conteúdo do cofre, que o cliente já cifra; uma revisão de segurança do Vaultwarden abrange ambos.
As opções realistas para um servidor dividem-se em dois grupos. OpenBao e Infisical são serviços: uma API, uma base de dados, TLS (transport layer security), uma etapa de início de sessão e um processo que agora tem de manter ativo. SOPS com age, credenciais do systemd e Docker secrets são ficheiros: cifrados em repouso e decifrados por algo que já está em execução, sem nada adicional para monitorizar.
A resposta direta é esta. Para um único servidor com uma ou duas pessoas, as opções baseadas em ficheiros são normalmente as corretas. Um OpenBao que ninguém sela corretamente e cujas credenciais ninguém roda é pior do que um ficheiro de ambiente com modo 600, porque acrescenta uma componente móvel e uma cópia de segurança que será configurada incorretamente, sem oferecer qualquer rotação que já não estivesse a ser feita manualmente.
Um ficheiro de ambiente com modo 600 é suficiente?
Muitas vezes, sim. A ameaça que ele evita é outro utilizador do servidor ler a palavra-passe da base de dados. As permissões de ficheiros Unix impedem isso antes de a rede estar ativa.
sudo install -d -m 750 -o root -g myapp /etc/myapp
sudo install -m 640 -o root -g myapp /dev/null /etc/myapp/env
sudoedit /etc/myapp/envVerifique pelos dois lados:
sudo -u myapp cat /etc/myapp/env
sudo -u nobody cat /etc/myapp/envO primeiro comando imprime o ficheiro. O segundo imprime cat: /etc/myapp/env: Permission denied, porque nobody não pertence ao grupo myapp e o ficheiro não tem permissões para outros utilizadores. Esse é todo o modelo de segurança, e ele é efetivo.
A fuga acontece a seguir. Uma unidade systemd com EnvironmentFile= copia esses valores para o ambiente do processo, e o ambiente do processo pode ser lido.
[Service]
User=myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/local/bin/myappsudo cat /proc/$(pgrep -n myapp)/environ | tr '\0' '\n'Esse comando imprime os seus segredos em texto simples, porque /proc/<pid>/environ pode ser lido por root e pelo utilizador com que o processo é executado. Um sistema de recolha de falhas que anexe o ambiente a um relatório verá a mesma informação. O mesmo acontece com qualquer ferramenta executada na mesma conta. Por isso, manter os segredos fora dos agentes de IA começa por removê-los do ambiente. Associe o ficheiro a um utilizador de serviço dedicado com poucos privilégios para que “o utilizador com que o processo é executado” não seja root.
SOPS com age: segredos encriptados que pode versionar no git
O SOPS (secrets operations) encripta os valores num ficheiro YAML ou JSON e mantém as chaves em texto simples. O age é uma ferramenta de encriptação pequena que fornece um par de chaves e nenhum servidor de chaves. Em conjunto, permitem versionar secrets.enc.yaml juntamente com o código, enquanto git diff continua a mostrar qual definição mudou sem revelar a um leitor o novo valor.
O age está disponível como pacote no Ubuntu 24.04. O SOPS não está, por isso descarregue o .deb a partir da página de releases. A versão 3.13.3 era a atual em agosto de 2026.
sudo apt update && sudo apt install -y age
curl -LO https://github.com/getsops/sops/releases/download/v3.13.3/sops_3.13.3_amd64.deb
sudo apt install -y ./sops_3.13.3_amd64.deb
sops --versionGere um par de chaves. age-keygen grava a chave privada no ficheiro e mostra a chave pública, pelo que verá uma linha começada por Public key: age1....
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
chmod 600 ~/.config/sops/age/keys.txt
age-keygen -y ~/.config/sops/age/keys.txtColoque a chave pública em .sops.yaml, na raiz do repositório, para não ter de indicar o destinatário na linha de comandos.
creation_rules:
- age: age1s3cqcks5genc6ru8chl0hkkd04zmxvczsvdxq99ekffe4gmvjpzsedk23csops encrypt secrets.yaml > secrets.enc.yaml
sops decrypt secrets.enc.yamlUma regra sem path_regex corresponde a tudo, que é o comportamento pretendido inicialmente. Se adicionar uma regra mais tarde, escreva-a para corresponder ao ficheiro passado a sops, porque as regras são avaliadas com base no caminho de entrada e não no ficheiro para o qual redireciona a saída.
Em tempo de execução, entregue os valores a um único processo e a mais nada:
sops exec-env secrets.enc.yaml './myapp'sops exec-env desencripta os valores na memória e define-os no ambiente do processo filho, por isso nenhum texto simples é gravado no disco. A ressalva sobre o ambiente da secção anterior continua a aplicar-se a esse processo filho.
Há dois problemas frequentes neste caso. O erro Failed to get the data key required to decrypt the SOPS file no systemd quase sempre significa que o SOPS procurou no diretório pessoal errado, porque uma unidade não herda o seu HOME. Defina explicitamente o caminho com Environment=SOPS_AGE_KEY_FILE=/etc/sops/age.txt na unidade. Além disso, editar .sops.yaml não volta a encriptar o que já existe: adicionar a chave pública de um colega afeta apenas ficheiros novos, por isso execute sops updatekeys secrets.enc.yaml em cada ficheiro existente. Se a sua configuração já for executada através do Ansible, encriptar os mesmos valores com o Ansible Vault produz o mesmo resultado sem uma segunda ferramenta.
credenciais do systemd: segredos que nunca chegam ao ambiente
O Ubuntu 24.04 inclui o systemd 255, portanto não é necessário instalar nada. systemd-creds cifra um segredo no host, e o systemd decifra-o num diretório privado que apenas o serviço correspondente pode ler.
sudo systemd-creds setup
sudo install -d -m 700 /etc/myapp
echo -n 'hunter2' | sudo systemd-creds encrypt --name=db_password - /etc/myapp/db_password.cred[Service]
User=myapp
LoadCredentialEncrypted=db_password:/etc/myapp/db_password.cred
ExecStart=/usr/local/bin/myappO serviço lê o valor de um ficheiro chamado db_password dentro do diretório indicado por $CREDENTIALS_DIRECTORY. O valor não está no ambiente, portanto /proc/<pid>/environ não mostra nada útil, e o texto simples nunca é gravado no sistema de ficheiros raiz.
Verifique se o ficheiro é decifrado antes de o associar a uma unidade:
sudo systemd-creds decrypt /etc/myapp/db_password.cred -Saiba qual foi a chave usada para o cifrar, porque isso determina se a sua cópia de segurança será útil. O --with-key=auto predefinido usa o chip TPM2 (trusted platform module version 2) quando este está presente e utilizável; caso contrário, usa a chave do host. A maioria das instâncias VPS não tem TPM2.
systemd-analyze has-tpm2no significa que foi usada a chave do host, que fica em /var/lib/systemd/credential.secret e só pode ser lida por root. Restaure db_password.cred num VPS novo sem esse ficheiro e nada o poderá decifrar. Copie credential.secret para a mesma cópia de segurança ou mantenha o texto simples num local ao qual ainda consiga aceder.
Segredos do Docker: ficheiros em /run/secrets
O Compose lê um ficheiro do host e monta-o no contentor em /run/secrets/<name>.
services:
app:
image: myapp:latest
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./db_password.txtdocker compose exec app cat /run/secrets/db_password
docker compose exec app env | grep -i passwordO primeiro comando imprime o segredo. O segundo imprime apenas DB_PASSWORD_FILE=/run/secrets/db_password, que é precisamente o objetivo: o valor nunca fica no ambiente do contentor, por isso não aparece na saída de docker inspect. Muitas imagens oficiais já esperam este formato, e a imagem do Postgres lê POSTGRES_PASSWORD_FILE exatamente desta forma.
Tenha isto claro. Fora do modo Swarm, não existe encriptação em nenhuma camada: ./db_password.txt é um ficheiro de texto simples no host, e a única proteção é o seu modo e proprietário. Defina ambos manualmente, porque o Compose monta sem qualquer aviso um ficheiro legível por todos. O conjunto mais amplo de compromissos face ao atalho simples env_file está no guia sobre ficheiros env e segredos do Compose.
O custo real de executar OpenBao e Vault
OpenBao é o fork de HashiCorp Vault mantido pela Linux Foundation, iniciado depois de a HashiCorp relicenciar o Vault sob a Business Source License em 2023. O OpenBao continua sob a MPL 2.0 (Mozilla Public License). A versão 2.6.2 era a atual em agosto de 2026. Quase tudo o que é apresentado abaixo também se aplica ao Vault, porque o fork manteve a mesma interface de comandos.
docker pull docker.io/openbao/openbaoOs pacotes para Debian e Ubuntu estão disponíveis na página de downloads do OpenBao, se preferir usar o apt para gerir as atualizações. O servidor precisa de um ficheiro de configuração com um listener e um backend de armazenamento:
listener "tcp" {
address = "127.0.0.1:8200"
tls_cert_file = "/path/to/full-chain.pem"
tls_key_file = "/path/to/private-key.pem"
}
storage "raft" {
path = "/path/to/raft/data"
node_id = "raft_node_1"
}Depois, inicie-o uma vez:
bao operator initPor predefinição, isto divide a root key em 5 shares e exige 3 delas para fazer unseal. Essas opções são os flags -key-shares e -key-threshold. O comando apresenta as shares e o initial root token uma única vez e nunca mais os apresenta.
Agora, a parte que é omitida na maioria das comparações. Um servidor reiniciado fica sealed. O OpenBao mantém a root key apenas na memória. Por isso, depois de um reinício, não consegue desencriptar o próprio armazenamento até alguém fornecer o número mínimo de shares. Uma atualização do kernel ou uma terminação por falta de memória resulta, portanto, num servidor sealed e em aplicações que não conseguem iniciar sessão.
Num VPS usado por uma só pessoa, a divisão de Shamir não protege nada, porque as cinco shares acabam no mesmo gestor de palavras-passe, pertencente à mesma pessoa. O auto unseal move a key para um dispositivo ou serviço de confiança. Numa cloud de grande dimensão, isso significa normalmente um serviço de gestão de chaves. No seu VPS, normalmente significa um ficheiro de key no mesmo disco que os dados que protege. Isto reduz efetivamente a segurança, em troca de um servidor que volta a ficar operacional sozinho depois de um reboot. Faça esta escolha de forma consciente e registe qual das opções adotou.
Infisical: uma interface web, uma base de dados e uma chave mestra que continua na sua posse
Infisical é uma plataforma de secrets com interface web, projetos, ambientes e controlo de acesso por utilizador. A instalação em self-hosting com Compose é curta:
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
docker compose -f docker-compose.prod.yml up -dEdite .env antes de executar o último comando. Dois valores têm de ser definidos por si, e um deles nunca poderá mudar depois:
openssl rand -hex 16
openssl rand -base64 32O primeiro é ENCRYPTION_KEY, uma string hexadecimal de 16 bytes. É a chave usada para encriptar os seus secrets no PostgreSQL. Se a perder, um backup perfeito da base de dados transforma-se num conjunto de ciphertext. Se a alterar numa instância em execução, os secrets existentes deixam de ser desencriptados. O segundo é AUTH_SECRET, uma string base64 de 32 bytes usada para as sessões. SITE_URL tem de ser o URL absoluto através do qual irá realmente aceder ao serviço, incluindo o protocolo. Caso contrário, o redirecionamento do login falha.
Infisical é mais adequado do que OpenBao quando aquilo de que realmente precisa são pessoas: uma interface web para uma equipa pequena e separação entre ambientes, em vez de credenciais de base de dados que expiram automaticamente. Em contrapartida, passa a ter de manter, corrigir e salvaguardar o PostgreSQL, o Redis e um certificado TLS.
O que acontece quando o serviço de segredos está indisponível e a aplicação reinicia
Esta pergunta determina se um serviço de segredos deve ficar num único servidor. Os ficheiros podem ser lidos antes de a rede arrancar. Um serviço não pode.
Reinicie o servidor e a aplicação e o OpenBao arrancam ao mesmo tempo. A aplicação pede a palavra-passe da base de dados, o OpenBao ainda está selado, o pedido falha e o systemd reinicia a aplicação continuamente até alguém introduzir manualmente as partes necessárias para a abertura. Nada está avariado. Mas nada está disponível.
Há duas formas corretas de lidar com isto. Ordene as unidades e permita que a aplicação tente novamente: After= o serviço de segredos, além de Restart=on-failure e de um RestartSec= suficientemente longo para não sobrecarregar a API. Ou obtenha o segredo no momento da implantação, em vez do arranque: materialize-o num ficheiro com modo 600 ou numa credencial do systemd, para que o sistema em execução dependa de um ficheiro e não de uma API.
A expiração do token é o mesmo problema, mas num relógio mais lento. Os tokens e os leases do OpenBao têm um tempo de vida. Por isso, um processo de execução prolongada que nunca os renova perde o acesso num momento sem relação com qualquer implantação. Esta falha é confusa precisamente porque nada mudou nesse dia.
Fazendo backup do armazenamento
Todas as opções aqui têm uma chave, e um backup sem essa chave não tem utilidade. Registe onde a sua está guardada.
Num ficheiro env, o próprio ficheiro é o segredo, por isso o backup tem de ser encriptado. No SOPS, o ficheiro encriptado pode ser colocado em qualquer local público, e a chave privada age em ~/.config/sops/age/keys.txt é o elemento que não pode perder. Para credenciais do systemd, faça backup de /var/lib/systemd/credential.secret juntamente com os ficheiros .cred. No Infisical, faça um dump do PostgreSQL e guarde ENCRYPTION_KEY num local separado.
O OpenBao com armazenamento raft cria o seu próprio snapshot:
bao operator raft snapshot save backup.snap
bao operator raft snapshot restore backup.snapO snapshot contém o armazenamento encriptado, por isso restaurá-lo num servidor novo ainda requer as partilhas de unseal de bao operator init. Um job noturno que copia snapshots para o armazenamento de objetos, enquanto as partilhas não estão guardadas em nenhum local, é um backup de nada. Teste o restauro numa VPS descartável antes de depender dele.
Auditoria: quem leu qual segredo
Os ficheiros não fornecem um registo de auditoria. O modo e o proprietário indicam quem poderia ler o segredo. Nunca indicam quem o fez. auditd com monitorização do caminho é o substituto mais próximo e informa que um ficheiro foi aberto, mas não qual valor foi utilizado.
O OpenBao regista cada pedido num dispositivo de auditoria que tem de ativar explicitamente:
bao audit enable file file_path=/var/log/openbao_audit.logEsse registo tem dois aspetos que alteram a forma como gere o servidor. A maioria das cadeias de caracteres nos pedidos e nas respostas é submetida a hash com HMAC-SHA256 e um salt. Assim, pode comparar um valor que já conhece com o registo sem que o próprio registo contenha o texto simples. Os inteiros e os valores booleanos são escritos sem proteção, pelo que um segredo numérico não beneficia desse hashing.
Existe ainda uma armadilha operacional: o OpenBao não responde aos pedidos quando nenhum dispositivo de auditoria ativado os consegue registar. Um dispositivo que falhe de forma bloqueante faz com que os pedidos fiquem pendentes até alguém corrigir o problema. Um disco cheio em /var/log faz a API de segredos ficar indisponível por definição. Reserve espaço próprio para o registo de auditoria e crie uma regra do logrotate logo no primeiro dia, não depois da primeira indisponibilidade.
Qual gestor de segredos self-hosted deve executar?
Conte as máquinas e conte as pessoas. Depois escolha.
- Uma máquina, uma pessoa: use um ficheiro de ambiente com modo 600, pertencente a root e lido por um utilizador de serviço. Adicione credenciais do systemd quando quiser retirar o valor do ambiente do processo.
- Uma máquina, duas a cinco pessoas, com a configuração já num repositório git: use SOPS com age. Cada pessoa recebe um par de chaves, e
.sops.yamllista todas as chaves públicas autorizadas a desencriptar. - Várias máquinas, um repositório de configuração e sem necessidade de credenciais com validade: continue a usar SOPS com age, com uma chave de destinatário por anfitrião, para que uma chave de anfitrião roubada desencripte apenas os ficheiros desse anfitrião.
- Várias máquinas e várias equipas que realmente precisam de credenciais de bases de dados com validade, além de um registo de auditoria que alguém consulta: use OpenBao e reserve uma hora por mês de trabalho do operador para procedimentos de unseal e testes de restauro.
A regra subjacente aos quatro casos é a mesma. Execute a solução mais pequena que cumpra um requisito que consiga declarar claramente, porque um gestor de segredos indisponível não se distingue de um gestor de segredos vazio.
FAQ
Um gestor de segredos autoalojado vale a pena para uma VPS única?
Normalmente, não, se estiver a referir-se a um serviço como o OpenBao ou o Infisical. Numa única máquina, com uma ou duas pessoas, um ficheiro de ambiente com permissões mode 600 ou uma credencial encriptada do systemd oferece a mesma proteção contra outro utilizador local, sem uma etapa de unseal e sem outro serviço para corrigir. Um serviço de segredos começa a compensar quando existem várias máquinas e várias pessoas, ou quando há uma necessidade real de credenciais que expirem sem que alguém tenha de as rodar manualmente.
Qual é a diferença entre um gestor de palavras-passe e um gestor de segredos?
Um gestor de palavras-passe armazena credenciais introduzidas por uma pessoa, e um utilizador desbloqueia-o enquanto está presente. Um gestor de segredos fornece credenciais a processos, por isso tem de funcionar às 03:00 sem ninguém a monitorizá-lo. A consequência é o que os distingue: um gestor de palavras-passe bloqueado obriga a introduzir novamente uma palavra-passe principal, enquanto um gestor de segredos selado interrompe todos os serviços que reiniciem enquanto permanecer selado.
O que acontece às minhas aplicações se o OpenBao ficar selado depois de um reboot?
Não conseguem obter os segredos, por isso falham ao iniciar, e o systemd reinicia-as num ciclo até alguém fornecer o limiar de unseal, que é 3 de 5 partes por predefinição. O OpenBao mantém a root key apenas em memória, por isso cada reinício volta a selá-lo. Ative o auto unseal, aceitando que, numa VPS única, a unseal key acaba no mesmo disco que os dados, ou escreva os segredos num ficheiro no momento do deploy, para que o arranque nunca dependa da API.
Posso enviar ficheiros encriptados pelo SOPS para um repositório público?
Os valores estão encriptados, por isso estão protegidos contra quem não tiver a age private key. As chaves não estão encriptadas: um leitor consegue ver que detém STRIPE_SECRET_KEY e SMTP_PASSWORD, bem como a frequência com que cada uma muda. Esses metadados são aceitáveis para a maioria dos projetos e inaceitáveis para alguns. Mantenha a age private key fora do repositório e execute sops updatekeys em todos os ficheiros existentes sempre que adicionar ou remover um destinatário.