Segurança
Permissões no PostgreSQL: controle sem travar a operação
Todo mundo com superuser é o padrão mais comum e o mais caro. Como estruturar roles, privilégios e auditoria no PostgreSQL sem criar atrito diário.
O caminho é separar quem executa de quem tem privilégio: privilégio mora em roles de grupo, pessoas e aplicações apenas herdam. Quando cada usuário e cada serviço recebe permissão direta, ninguém consegue responder quem pode fazer o quê, e a saída prática que todo time acaba tomando — dar superuser para destravar — elimina a pergunta junto com o controle.
O ponto não é endurecer o acesso. É que permissão espalhada custa caro nos dois sentidos: não protege, porque na prática todos podem tudo, e atrapalha, porque cada mudança vira um chamado.
Onde o controle se perde
Superuser como solução de problema. A conta de aplicação não conseguia criar uma tabela na migração; alguém concedeu superuser para destravar o deploy e ninguém reverteu. superuser ignora todas as verificações de privilégio, inclusive as que impedem leitura de dados sensíveis e escrita em objetos do sistema.
Permissão concedida a usuário, não a grupo. Quando cada pessoa recebeu seus próprios GRANT ao longo dos anos, o desligamento de alguém não tem procedimento claro e a revisão de acesso não tem por onde começar.
pg_hba.conf permissivo. O controle de privilégio dentro do banco não importa se a regra de conexão aceita autenticação fraca ou faixas de rede amplas. Esse arquivo é a primeira porta, e é avaliado de cima para baixo — a primeira regra que casa decide.
Objetos criados por quem não deveria ser dono. O dono de uma tabela pode alterá-la e removê-la independentemente dos GRANT existentes. Se as tabelas de produção pertencem à conta da aplicação, essa conta pode derrubar o schema inteiro por acidente.
Para levantar o estado atual:
-- Quem tem atributos elevadosSELECT rolname, rolsuper, rolcreaterole, rolcreatedb, rolbypassrls, rolcanloginFROM pg_rolesWHERE rolsuper OR rolcreaterole OR rolcreatedb OR rolbypassrls; -- Quem pertence a quais gruposSELECT r.rolname AS role, m.rolname AS membroFROM pg_auth_members AS amJOIN pg_roles AS r ON r.oid = am.roleidJOIN pg_roles AS m ON m.oid = am.memberORDER BY 1, 2;
Uma estrutura que se sustenta
A separação entre roles de grupo (sem login) e roles de acesso (com login) é o que torna a permissão auditável. Grupos definem o que pode ser feito; contas apenas herdam.
-- Grupos: os privilégios vivem aquiCREATE ROLE app_leitura NOLOGIN;CREATE ROLE app_escrita NOLOGIN; GRANT USAGE ON SCHEMA vendas TO app_leitura;GRANT SELECT ON ALL TABLES IN SCHEMA vendas TO app_leitura;GRANT app_leitura TO app_escrita;GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA vendas TO app_escrita; -- Contas: só herdamCREATE ROLE svc_pedidos LOGIN PASSWORD '...';GRANT app_escrita TO svc_pedidos;
Falta uma peça que quase sempre é esquecida: os GRANT acima valem para as tabelas que existem hoje. Uma tabela criada amanhã nasce sem eles, e o time descobre isso em produção. ALTER DEFAULT PRIVILEGES resolve na origem:
ALTER DEFAULT PRIVILEGES IN SCHEMA vendas GRANT SELECT ON TABLES TO app_leitura; ALTER DEFAULT PRIVILEGES IN SCHEMA vendas GRANT INSERT, UPDATE, DELETE ON TABLES TO app_escrita;
Vale notar que privilégios padrão se aplicam aos objetos criados pelo role que executou o comando. Se a migração roda com um usuário e a operação com outro, é preciso declarar para cada um — ou padronizar um único dono para os objetos do schema.
O schema public mudou
Até o PostgreSQL 14, o schema public vinha com permissão de criação para todos os usuários do banco. A partir do 15, esse privilégio deixou de ser concedido por padrão, e o dono do schema passou a ser o dono do banco.
Isso tem duas consequências práticas. Em bancos novos, scripts antigos que criavam objetos em public com um usuário comum passam a falhar. Em bancos migrados de versões anteriores, a permissão antiga permanece — a mudança vale para bancos criados na versão nova, não como correção retroativa. Vale verificar explicitamente em vez de assumir:
SELECT nspname, nspowner::regrole AS dono, nspaclFROM pg_namespaceWHERE nspname = 'public';
Ler dado sensível é privilégio, não detalhe
Separar leitura de escrita não separa quem vê CPF de quem vê código de produto. Duas ferramentas cobrem isso sem reescrever a aplicação.
Privilégio por coluna funciona quando poucas colunas são sensíveis: GRANT SELECT (id, nome) ON clientes TO app_atendimento permite a consulta e nega as demais colunas.
Row Level Security funciona quando o recorte é por linha — cada filial enxerga apenas seus registros. A política é avaliada no banco, o que significa que vale para qualquer caminho de acesso, inclusive psql. Dois cuidados: RLS não se aplica ao dono da tabela a menos que se use FORCE ROW LEVEL SECURITY, e o atributo BYPASSRLS ignora as políticas — outro motivo para manter a lista de roles elevados curta.
Auditoria: saber depois também vale
O log padrão do PostgreSQL registra conexões e erros, mas não o que foi executado, a menos que se ative log_statement — que em all produz volume alto e nenhum recorte. A extensão pgaudit existe para isso: permite registrar por classe de comando (DDL, escrita, leitura) e por objeto, mantendo o volume administrável.
O mínimo defensável, mesmo sem extensão: log_connections e log_disconnections ativos, tentativas de autenticação falhas registradas, e alguém olhando. Log que ninguém lê tem valor forense depois do incidente, não preventivo — e ainda assim vale mais que log inexistente.
Revisão periódica é o que mantém o desenho vivo
Estrutura de permissão degrada por acúmulo: exceção temporária que virou permanente, conta de projeto encerrado que continua ativa, superuser concedido numa madrugada. Uma revisão trimestral com três perguntas cobre a maior parte: quem tem atributo elevado e por quê; quais contas com login não se conectam há meses; e quais permissões foram concedidas direto a usuários em vez de grupos.
Essa revisão convive bem com a rotina de saúde do banco — a mesma em que se acompanha bloat, autovacuum e idade de transação, tratada em autovacuum, bloat e wraparound no PostgreSQL.
Próximo passo
Se hoje a resposta para "quem pode ler a tabela de clientes" exige investigação, o controle de acesso existe no papel e não no banco.
A H1 Data faz um diagnóstico gratuito do ambiente PostgreSQL que inclui o mapa de roles e privilégios efetivos, exposição de dados sensíveis e regras de conexão, com o que corrigir primeiro sem interromper a operação.