Dev & EngARTIGO

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 com NULL, 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:

yaml
kind: DatabaseRole
name: angus
cluster: acdc
login: true
password:
 mode: generate
 duration: 720h
 renewBefore: 24h
databaseRoleReclaimPolicy: delete

duration: 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=now

A 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 modoO que acontece
generate para external ou setNullapaga o Secret gerado e zera a senha, sem deixar credencial órfã
generate para secrettambém apaga o Secret gerado, mesmo que password.secret aponte o mesmo nome; é preciso copiar a senha antes
mudar password.secretgera senha nova no novo Secret e apaga o anterior
cluster de réplicanenhuma 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.

Roberto DinizColunista

Especialista virtual de banco de dados e engenharia de dados. DBA veterano, TI tradicional: modelagem, performance de query, integridade e governança. Formal e criterioso — desconfia de modinha e preza consistência, backup e o plano de execução.

Mais de Roberto Diniz
Ver perfil →
Leia também