CloudNativePG 1.31 automatiza geração e rotação de senhas do PostgreSQL com enforcement nativo
Um pull request mesclado em 24 de outubro de 2026 ensina o operador a criar, rotacionar e expirar senhas de roles do PostgreSQL, com o próprio banco aplicando o prazo via VALID UNTIL.
O operador CloudNativePG está prestes a resolver um incômodo que qualquer DBA que roda PostgreSQL↳PostgreSQL11 conteúdosPostgreSQL via SSL com GolangData · abr 20195 itens legais sobre data types do PostgreSQLData · mar 20195 serviços gratuitos na cloud para bancos de dados PostgresData · fev 2025Ver tudo em Data → em Kubernetes↳Kubernetes18 conteúdosGerenciamento de infraestrutura multicloud com Kubernetes proporciona otimização e economiaDevSecOps · set 2021Azure Kubernetes Services – AKS: referências gratuitas e dicas para solução de problemas comunsDevSecOps · abr 2019Kubernetes em produção: o que ninguém te conta e você aprende tarde demaisDev (Back & Front) · abr 2026Ver tudo em DevSecOps → conhece bem: de onde vem a senha de um role e quem garante que ela não fica eterna. Em 24 de outubro de 2026, foi mesclado o pull request que ensina o recurso DatabaseRole a gerar sua própria senha, guardá-la num Secret que o operador controla e rotacioná-la num cronograma. O relato é de Gabriele Bartolini, engenheiro na EDB, na 28ª edição de sua série CNPG Recipes publicada no Planet PostgreSQL.
O código fechou a issue #3788, aberta há tempos pela comunidade, e deve entrar na versão 1.31 do CloudNativePG, prevista para o último trimestre de 2026. Ainda não há release: quem quiser testar precisa compilar o snapshot de desenvolvimento a partir do repositório cloudnative-pg/artifacts, instalável com kubectl apply --server-side -f apontando para o operator-manifest.yaml do branch principal. Vale só em cluster descartável, tipo kind, porque nada ali é garantia de API estável.
A lacuna que o CloudNativePG 1.30 deixou aberta
A versão 1.30 introduziu o DatabaseRole como forma declarativa de modelar roles do PostgreSQL, incluindo autenticação por certificado TLS sem senha. Mas se o role precisava de senha, o trabalho de criar o Secret correspondente continuava manual: o operador aplicava o valor, porém de onde ele vinha e por quanto tempo permanecia válido era problema do operador humano, não do CloudNativePG. Essa assimetria é o tipo de lacuna que vira incidente de segurança em produção, porque senha que ninguém rotaciona tende a vazar e ficar valendo indefinidamente.
A nova stanza password e seus quatro modos
A correção chega como uma stanza password dentro do DatabaseRole, com um campo mode obrigatório. Ele substitui a combinação antiga de passwordSecret e disablePassword, que o próprio Bartolini descreve como pouco legível e que agora fica deprecada (mas ainda funciona, sem poder ser combinada com a nova stanza). Os quatro modos cobrem todo o ciclo de vida de uma credencial:
generate: o operador cria a senha e mantém o Secret sob sua posse.secret: o operador lê a senha de um Secret fornecido por você e nunca escreve nele.external: o operador não mexe na senha, porque algo externo a gerencia.setNull: o operador zera a senha comNULL, desligando autenticação por senha para o role.
Não existe modo padrão de propósito: pedir uma senha sem dizer como ela é gerenciada é ambíguo, e um palpite errado tanto cria quanto remove uma credencial.
Um DatabaseRole com rotação mensal, na prática
O exemplo da fonte parte de um cluster mínimo de uma instância e declara um role que faz login com senha gerada e rotacionada a cada 30 dias:
kind: DatabaseRole
name: angus
cluster: acdc
login: true
password:
mode: generate
duration: 720h
renewBefore: 24h
databaseRoleReclaimPolicy: deleteduration: 720h dá 30 dias de vida à senha, e renewBefore: 24h pede ao operador que a substitua um dia antes do vencimento, o que na prática faz a senha trocar a cada 29 dias. Bartolini resume a lógica por trás dessa cadência numa frase que vale reter:
Essa é a cadência com que eu começaria na maioria das cargas de trabalho: frequente o suficiente para que uma credencial vazada tenha vida limitada, rara o suficiente para que ninguém seja acordado por causa dela.
That is the cadence I would start with for most workloads: frequent enough that a leaked credential has a bounded lifetime, rare enough that nobody gets paged because of it.Gabriele Bartolini, engenheiro na EDB e autor da série CNPG Recipes
O que vai para dentro do Secret, e quem aplica o quê
O operador cria um Secret do tipo kubernetes.io/basic-auth, nomeado como <role>-password (no exemplo, angus-password), com três chaves: username, password e pgpass, esta última já no formato de uma linha de .pgpass pronta para uso, com host e banco coringados (*:5432:*:angus:<senha>). Colar essa linha em ~/.pgpass evita que a senha apareça em connection string ou em histórico de shell. O Secret tem referência de posse (owner reference) ao DatabaseRole: apagar o role apaga o Secret junto, independentemente da política de retenção configurada para o role no PostgreSQL.
PostgreSQL aplica o prazo, não é só boa vontade do operador
No banco, a senha é armazenada como verificador SCRAM-SHA-256, e o role recebe um VALID UNTIL alinhado ao vencimento da senha gerada. Isso significa que o prazo não é uma política que depende do operador funcionar: o próprio PostgreSQL recusa a senha expirada em novas conexões, mesmo que a rotação do operador falhe silenciosamente por algum motivo. Para quem vem de DBA tradicional, é a diferença entre confiar num script de rotação e confiar numa trava no motor do banco.
Observando e forçando rotação
O estado da senha fica no status do DatabaseRole, com campos como issuedAt, expiration e appliedExpiration. issuedAt é o único campo que de fato sustenta o cálculo: a cada reconciliação o operador recalcula expiration a partir dele, de duration e de renewBefore, então mudar qualquer um dos dois parâmetros já no manifesto tem efeito imediato. kubectl get databaseroles mostra PASSWORD EXPIRATION como coluna, e eventos como PasswordGenerated e PasswordRotated ficam no histórico do recurso via kubectl describe databaserole.
Para forçar uma rotação fora do cronograma, por exemplo após suspeita de vazamento, basta anotar o recurso:
kubectl annotate databaserole angus cnpg.io/rotatePassword=nowA anotação é de disparo único: o operador a remove assim que a rotação acontece, e um evento PasswordRotated (ou PasswordRotationIgnored, se a condição não se aplicar) informa o resultado.
Moldando a senha com criteria
Por padrão o operador gera 24 caracteres com dígitos e letras maiúsculas e minúsculas, sem símbolos, deliberadamente: símbolos exigem escaping em connection strings, URIs e arquivos .pgpass. Quando a política de segurança exige símbolos, o bloco criteria, modelado no gerador de senhas do External Secrets Operator, permite ajustar length, digits, symbols, symbolCharacters, noUpper e allowRepeat. Combinações impossíveis, como mais símbolos do que symbolCharacters contém, são rejeitadas já no kubectl apply; combinações que só o gerador consegue detectar aparecem em status.password.message, e o operador espera a correção em vez de tentar indefinidamente.
Por que rotação não vem ligada por padrão
duration é opcional, e sem ele a senha é gerada uma vez e nunca muda. A razão é estrutural: um role do PostgreSQL tem exatamente uma senha, sem sobreposição como existe na renovação de certificado, então assim que o ALTER ROLE roda, a senha antiga para de funcionar para novas conexões.
Na prática o impacto é menor do que parece, porque o PostgreSQL avalia a senha só no momento da conexão: sessões abertas continuam funcionando, e uma aplicação que relê o Secret a cada reconexão simplesmente pega a senha nova. O cuidado é com aplicações que fazem cache da senha para a vida inteira do processo, que falham na próxima reconexão após um failover ou uma instabilidade de rede.
Comportamentos que importam para GitOps
Algumas regras de transição merecem atenção de quem versiona manifestos em pull request:
| Mudança de modo | O que acontece |
|---|---|
generate para external ou setNull | apaga o Secret gerado e zera a senha, sem deixar credencial órfã |
generate para secret | também apaga o Secret gerado, mesmo que password.secret aponte o mesmo nome; é preciso copiar a senha antes |
mudar password.secret | gera senha nova no novo Secret e apaga o anterior |
| cluster de réplica | nenhuma senha é gerada, porque o role pertence à primária; a geração só começa após a promoção |
O operador nunca sobrescreve ou apaga um Secret que não criou: se já existir um Secret com o nome esperado, o conflito aparece em status.password.message e nada é gerado até a situação ser resolvida manualmente.
O que isso não substitui
Quem já centraliza segredos num vault e os distribui com o External Secrets Operator (ESO) não precisa abandonar esse fluxo: mode: secret apontando para o Secret produzido pelo ESO continua sendo a escolha certa, e a documentação de desenvolvimento do CloudNativePG já traz um exemplo funcional dessa integração. mode: generate serve ao caso oposto, mais comum em cargas de trabalho menores: quando a credencial nasce, vive e morre junto com o role, e não vale o custo de manter mais um componente de infraestrutura só para isso.
O que fica em aberto
O recurso está mesclado no trunk, mas não em nenhuma versão lançada do CloudNativePG, e o próprio autor pede feedback agora, antes do lançamento, via pull request ou no Slack da comunidade CNCF do projeto. Vale lembrar também que outro recurso relacionado está planejado para a mesma 1.31: duração e renewBefore configuráveis para os certificados de cliente TLS de um DatabaseRole, tema já tratado na Recipe 25 de Bartolini e rastreado na issue #11312.
Quem administra PostgreSQL em Kubernetes com volume relevante de roles com senha fixa ganha, com isso, um caminho declarativo de endurecer a política de credenciais sem depender de script externo nem de disciplina humana para lembrar de trocar senha.
Fonte: Planet PostgreSQL
Este artigo foi escrito por Roberto Diniz, colunista de banco de dados. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.
PostgreSQL 19 ganha extensão que roda SPARQL sem precisar de um segundo banco
A extensão pg_knowledge_base embute o motor SPARQL do Oxigraph dentro do PostgreSQL 19, guardando triplas em tabelas comuns e lendo tabelas existentes como RDF via R2RML, tudo sob a mesma transação.









