Introdução
O arquivo pg_hba.conf (PostgreSQL Host-Based Authentication) é uma peça fundamental na configuração de segurança de qualquer instância PostgreSQL. Ele define as regras de autenticação e acesso ao banco de dados, determinando quem pode se conectar, de onde e como essas conexões são autenticadas. Neste artigo, exploraremos as diversas opções de configuração disponíveis no pg_hba.conf, desde os métodos de autenticação até a especificação de IPs, usuários e grupos. Também abordaremos os modelos de autenticação mais comuns, como TRUST, password, md5 e scram-sha-256, além de métodos específicos como ident e peer. Ao final, você será capaz de configurar esse arquivo para garantir um ambiente seguro e eficiente para suas aplicações.
Roteiro:
- Modelo de autenticação
- TYPE (tipos de conexão)
- local
- host
- hostssl
- DATABASE (banco de dados)
- USER (usuários ou grupos de usuários)
- ADDRESS (endereços)
- METHOD (método)
- OPTIONS (opções)
- Exemplos
- Considerações importantes
- TYPE (tipos de conexão)
- Ident file
Modelo de autenticação
O modelo de autenticação define como a autenticação será realizada e gerenciada, verificando a identidade dos usuários do banco de dados de diferentes formas. No PostgreSQL, o principal modelo é baseado no arquivo pg_hba.conf. Ele pode estar localizado em diferentes locais, dependendo do seu ambiente:
- /var/lib/pgsql/<versão>/data/ nos ambientes Linux Red Hat e derivados (como CentOS);
- /etc/postgresql/<versão>/<cluster>/pg_hba.conf nos ambientes Linux Debian e derivados (como Ubuntu);
- C:\Program Files\PostgreSQL\<versão>\data\pg_hba.conf em Windows;
- Se você criou o seu cluster de dados em um diretório específico e não está utilizando o Linux Debian, o pg_hba.conf deverá estar nesse diretório, que chamamos de $PGDATA (que é a variável de ambiente que contém essa localização).
O pg_hba.conf tem como características regras específicas que suportam vários métodos de autenticação, que podem ainda ser aplicados de forma seletiva.
A estrutura básica do pg_hba.conf é (em cada linha):
TYPE DATABASE USER ADDRESS METHOD [OPTIONS]
Sendo que TYPE se refere ao tipo de conexão, DATABASE, ao banco de dados ao qual a regra se aplica, USER, a usuário ou grupo de usuários, ADDRESS, ao endereço IP ou intervalo (range) de IPs, METHOD ao método de autenticação, e OPTIONS a algumas opções que podem existir de acordo com o método escolhido, respectivamente.
Além disso, no pg_hba.conf, as linhas de regras são divididas por seções, sendo uma para conexões locais, outra para IPv4, outra para IPv6 e mais uma para replicações.
Apenas para lembrar, é tradição no universo Linux/Unix (de onde o PostgreSQL surgiu) usar o caractere ‘#‘ para marcar comentários no início da linha.
Confira um exemplo de conteúdo do pg_hba.conf:
# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 scram-sha-256
# IPv6 local connections:
host all all ::1/128 scram-sha-256
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 scram-sha-256
host replication all ::1/128 scram-sha-256
TYPE (tipos de conexão)
O PostgreSQL suporta diversos tipos de conexão, cada um com suas próprias características e casos de uso, que determinam como os clientes podem se conectar ao servidor de banco de dados. Entre os principais e mais utilizados, estão:
- local: conexões feitas através de Unix sockets no mesmo sistema onde o servidor PostgreSQL está rodando, ou seja, conexões locais, portanto, não sendo necessário passar a informação da coluna ADDRESS;
- host: conexões TCP/IP tanto locais quanto remotas não criptografadas, ou seja, sem criptografia SSL;
- hostssl: para conexões TCP/IP seguras, ou seja, criptografadas via SSL. É o que recomendamos utilizar e teremos um artigo especial dedicado a ele.
Existem ainda as opções mais incomuns: hostnossl (sem SSL), hostgssenc (com criptografia GSSAPI) e hostnogssenc (sem criptografia GSSAPI).
DATABASE (banco de dados)
Para isolar as regras de autenticação, deve-se especificar a qual banco a linha com as instruções se refere, sendo possível utilizar all para aplicação em todos os bancos. Além disso, há a opção samerole, que é particularmente útil em ambientes com multitenancy, onde diferentes usuários ou grupos precisam acessar seus próprios bancos de dados sem interferir em outros. Com samerole, o Postgres permite que um usuário se conecte apenas a bancos de dados cujo nome coincide com uma role (grupo) da qual ele é membro. Assim, é possível definir que cada usuário tenha acesso apenas aos bancos relacionados ao seu papel, reforçando a segurança e o isolamento entre bancos de dados de diferentes usuários.
USER (usuários ou grupos de usuários)
É possível especificar usuários individuais do PostgreSQL no pg_hba.conf pelo campo USER ou, ainda, usar all para corresponder a todos os usuários, assim como para os bancos de dados.
Podemos também indicar grupos de usuários com o prefixo +, por exemplo, +admins, o que torna fácil o processo de gerenciar permissões de vários usuários simultaneamente. É importante lembrar que não são grupos do sistema operacional, mas, sim, roles definidas no PostgreSQL.
No contexto do PostgreSQL, um “grupo de usuários” é, na verdade, uma role à qual outras roles (usuários) recebem grants (privilégios). Isso permite agrupar vários usuários sob uma mesma role, facilitando o gerenciamento de permissões e acessos em ambientes mais complexos.
Além disso, também podemos informar nomes de usuário como expressões regulares, indicando com o prefixo /, e também é possível gerenciar os usuários, com nome ou expressões regulares, em um arquivo separado, que deve ser mencionado com o prefixo @. Há ainda o caso de replicação, que trata-se de uma conexão usada para sincronizar dados entre servidores, e que deve ser indicada nessa coluna com a palavra-chave replication.
ADDRESS (endereços)
O campo ADDRESS no pg_hba.conf permite especificar quais endereços podem se conectar:
- Subnet: permite conexões de uma faixa de IPs, por exemplo:
- 192.168.1.1/32 ou fe80::7a31:c1ff:fa34:9eb3/128 – permite apenas um IP específico;
- 127.0.0.1 ou ::1/128 - (ipv6) – permite apenas conexões locais;
- 192.168.1.0/24 – permite todos os IPs classe C, de 192.168.1.0 a 192.168.1.255;
- 192.168.0.0/16 – permite todos os IPs classe B, de 192.168.0.0 a 192.168.255.255;
- 192.0.0.0/8 – permite todos os IPs classe A, de 192.0.0.0 a 192.255.255.255;
- 0.0.0.0/0 ou ::0/0 (ipv6) – permite qualquer IP (não recomendamos usar esta configuração em ambiente de produção).
- IP-mask: permite a definição de uma faixa de IPs, semelhante a anterior, mas em vez de usar a subnet, colocamos o IP e a máscara de IPs:
- 192.168.1.0 ou 255.255.255.0 – permite todos os IPs classe C, de 192.168.1.0 a 192.168.1.255;
- 192.168.0.0 ou 255.255.0.0 – permite todos os IPs classe B, de 192.168.0.0 a 192.168.255.255.
- Hostname: além de endereços IP, podemos utilizar um hostname, no qual o PostgreSQL realiza várias verificações para garantir a correspondência entre o hostname especificado e o cliente. Lembrando que qualquer lentidão na resolução de nomes pelo DNS irá provocar uma lentidão no processo de conexão em si.
- Hostname específico: é só colocá-lo, como exemplo.com;
- Subdomínios: necessário colocar o prefixo “.” antes do hostname, e assim qualquer endereço com esse subdomínio será autorizado, como em .exemplo.com permitiria conexão de sub.exemplo.com, app.exemplo.com etc. (mas não o próprio exemplo.com).
- Também podemos utilizar all para permitir a conexão de qualquer IP, samehost para permitir qualquer IP do próprio servidor e samenet para permitir qualquer IP em qualquer sub-rede à qual o servidor esteja conectado.
METHOD (método)
Os métodos de autenticação no PostgreSQL são as diferentes maneiras que o banco de dados usa para verificar e realizar a autenticação, indo desde a exigência de senhas até a confiança total e permissão absoluta. Os principais são:
- trust: permite conexões sem nenhuma autenticação, ou seja, se o seu IP for contemplado na lista de endereços autorizados, não será necessário fornecer senhas, por isso é adequado apenas para ambiente de testes e desenvolvimento local ou com redes totalmente isoladas e confiáveis endereçando apenas um IP local ou um IP único confiável;
- password / md5 / scram-sha-256: é exigida uma senha no momento da conexão, que varia entre essas três opções com diferentes níveis de segurança:
- password: senha em texto simples, sem criptografia durante a transmissão pela rede;
- md5: usa hash MD5 para criptografar a senha durante a transmissão, o que torna o processo um pouco mais seguro, mas seu uso está sendo descontinuado em favor do próximo método considerado mais seguro;
- scram-sha-256: usa o método SCRAM (Salted Challenge Response Authentication Mechanism) como hash SHA-256, o que o torna a opção baseada em senha mais segura, já que seu protocolo de autenticação não transmite a senha real, e sua criptografia é considerada muito forte.
É importante saber que o tipo de encriptação padrão da senha (md5 ou scram-sha-256) é definido pelo parâmetro password_encryption, que significa que todos os seus usuários criados com senha, ou com a senha alterada, vão tê-la com a criptografia apontada por esse parâmetro. O nosso padrão é scram-sha-256, porém fizemos alterações para exemplificar diferentes cenários;
- ident: usa o serviço de identificação do sistema operacional (Ident ou identd) para autenticar, confiando na informação que o SO passa, por isso requer que o cliente esteja em um servidor ident (mais comum em ambientes Linux, em que o serviço Ident já vem ativado por padrão);
- peer: confia nas informações de usuários do SO local, ou seja, diferente do ident, não precisa de um serviço externo para isso e só funciona para redes locais. É esse o método de autenticação que costumamos usar para acessar o psql com usuário postgres (estando conectado ao usuário postgres do SO);
- Além desses, o PostgreSQL suporta vários outros métodos, incluindo:
- reject: rejeita todas as conexões, podendo ser usado para filtrar e impedir grupos;
- sspi: autenticação nativa do Windows;
- ldap: para autenticação via servidores LDAP;
- radius: para autenticação via servidores RADIUS;
- cert: usa certificados SSL do cliente para autenticação.
OPTIONS (opções)
Além de todas as configurações que vimos, é possível ainda inserir mais opções para o método de autenticação, que devem ter o formato de nome=valor, e servem para especificar opções adicionais para o método escolhido. Algumas delas são:
- clientcert: além das opções específicas de cada método de autenticação, existe essa opção geral, que pode ser usada em qualquer entrada do tipo hostssl. Essa opção tem dois valores possíveis: verify-ca e verify-full, sendo que o primeiro exige que o cliente apresente um certificado SSL válido e confiável, e o segundo, além de exigir um certificado válido, também verifica se o Common Name (CN) no certificado do cliente corresponde ao nome de usuário ou a um mapeamento aplicável. Isso fornece um nível extra de segurança;
- clientname: quando você está usando autenticação com certificado de cliente (usando o método cert ou a opção clientcert), você pode usar essa opção para especificar qual parte das credenciais do certificado do cliente deve ser comparada com o nome de usuário, sendo as subopções clientname=CN, em que o nome de usuário será comparado com o Common Name (CN) do certificado, e clientname=DN, em que o nome de usuário será comparado com o Distinguished Name (DN) completo do certificado, conforme o formato RFC 2253;
- include, include_if_exists e include_dir: essas opções permitem definir suas regras de autenticação em um arquivo separado, sendo necessário passar o local do arquivo entre aspas simples. A diferença entre essas opções é que a primeira apenas checa o local do arquivo informado e tenta substituir as regras, a segunda faz isso apenas se o arquivo existir, caso contrário será exibida uma mensagem indicando que o arquivo não foi lido, e a última reconhece todos os arquivos de um diretório.
Exemplos
Conexão local de todos os usuários com peer
local all all peer
Este é o caso que possibilita o acesso ao psql pelo usuário postgres do SO, pulando a etapa de fornecimento de senha (acessamos o banco também chamado postgres):
postgresdebian:~$ psql -U postgres -d postgres
psql (16.2 (Debian 16.2-1.pgdg120+2))
Type "help" for help.
postgres=#
Além desse usuário, poderíamos repetir esse tipo de acesso com qualquer outro usuário que existisse tanto no banco de dados quanto no SO, claro, com o mesmo nome nos dois lugares:
ludmila@debian:~$ psql -U ludmila -d postgres
psql (16.2 (Debian 16.2-1.pgdg120+2))
Type "help" for help.
postgres=>
Além disso, conforme explicado, podemos aplicar as regras por banco de dados, então, se fosse especificado o método de conexão peer apenas para o banco postgres, não seria possível acessar sem senha em outros bancos.
Conexão host com IP específico e senha sem criptografia
host all all 192.168.1.10/32 password
Como você pode notar, foi solicitada a senha para acessar o banco de outro IP:
fabio@debian-2:~$ psql -h 64.23.248.23 -p 5432 -U fabio -d postgres
Password for user fabio:
psql (16.4 (Debian 16.4-1.pgdg120+1), server 16.2 (Debian 16.2-1.pgdg120+2))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
postgres=>
Mas, se a tentativa de acessar fosse feita da rede local com o mesmo usuário fabio, considerando que temos no mesmo arquivo a linha de regras exemplificadas anteriormente, este seria o resultado:
fabio@debian:~$ psql -U fabio -d postgres
psql (16.2 (Debian 16.2-1.pgdg120+2))
Type "help" for help.
postgres=>
Conexão host para grupo de usuários com IP específico e trust
host all +groupname 192.168.1.20/32 trust
Esse cenário permite que os usuários pertencentes ao grupo editors se conectem de um IP específico sem a necessidade de informar senha. No nosso caso, o usuário ana está neste grupo:
ana@debian-2:~$ psql -h 64.23.248.23 -p 5432 -U ana -d postgres
psql (16.4 (Debian 16.4-1.pgdg120+1), server 16.2 (Debian 16.2-1.pgdg120+2))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
postgres=>
Conexão host para bancos de dados com o mesmo proprietário (samerole)
host samerole all 192.168.1.0/24 md5
Com essa configuração, se o usuário user1 tentar acessar o banco de dados que ele mesmo possui, a senha será solicitada, porém, se ele tentar acessar um banco que pertence a outro usuário, como user2, ele não conseguirá, pois a regra só se aplica aos bancos que possuem o mesmo proprietário.
Considerações importantes
- As regras são aplicadas na ordem em que aparecem no arquivo;
- As primeiras regras têm prioridade, então coloque as mais restritivas no início;
- Após modificar o pg_hba.conf, recarregue as configurações com o comando systemctl reload postgresql;
- Se não funcionar, deve-se checar os logs do banco ou então consultar a tabela pg_hba_file_rule do catálogo para entender onde está o erro dentro do pg_hba.conf ;
$ tail postgresql-16-main.log
2024-11-13 17:29:31.029 UTC [141035] LOG: received SIGHUP, reloading configuration files
2024-11-13 17:29:31.037 UTC [141035] LOG: invalid connection type "hoost"
2024-11-13 17:29:31.037 UTC [141035] CONTEXT: line 126 of configuration file "/etc/postgresql/16/main/pg_hba.conf"
2024-11-13 17:29:31.037 UTC [141035] LOG: /etc/postgresql/16/main/pg_hba.conf was not reloaded
postgres=# select * from pg_hba_file_rules ;
rule_number | file_name | line_number | type | database | user_name | address | netmask | auth_method | options | error
-------------+-------------------------------------+-------------+-------+---------------+------------+-----------+-----------------------------------------+---------------+---------+---------------------------------
1 | /etc/postgresql/16/main/pg_hba.conf | 118 | local | {all} | {postgres} | | | peer | |
2 | /etc/postgresql/16/main/pg_hba.conf | 125 | local | {all} | {all} | | | trust | |
| /etc/postgresql/16/main/pg_hba.conf | 126 | | | | | | | | invalid connection type "hoost"
3 | /etc/postgresql/16/main/pg_hba.conf | 128 | host | {all} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | scram-sha-256 | |
4 | /etc/postgresql/16/main/pg_hba.conf | 131 | local | {replication} | {all} | | | peer | |
5 | /etc/postgresql/16/main/pg_hba.conf | 132 | host | {replication} | {all} | 127.0.0.1 | 255.255.255.255 | scram-sha-256 | |
6 | /etc/postgresql/16/main/pg_hba.conf | 133 | host | {replication} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | scram-sha-256 | |
(7 rows)
- Teste as configurações em um ambiente de desenvolvimento antes de aplicá-las em produção.
Ident file
O ident file é um arquivo utilizado pelo PostgreSQL para mapear nomes de usuários do sistema operacional para nomes de usuários do banco de dados. Ele é útil quando você usa o método de autenticação ident, que verifica a identidade do usuário que está tentando se conectar ao banco de dados com base no nome de usuário do sistema operacional.
Para fazer essa autenticação baseada nos usuários do SO, o PostgreSQL consulta o ident file para mapear o nome de usuário do SO para o nome de usuário do banco de dados.
Esse arquivo geralmente é chamado pg_ident.conf e está localizado no mesmo diretório que o arquivo pg_hba.conf (/etc/postgresql/<versão>/<cluster>/pg_hba.conf para sistemas de base Linux).
Seu conteúdo é simples, com cada linha contendo três colunas:
- Mapa de identidade: nome de um grupo de mapeamento definido;
- Nome de usuário do SO: nome do usuário no sistema operacional;
- Nome de usuário do banco: nome do usuário no banco de dados que corresponde ao usuário do SO.
Após feita a configuração do arquivo pg_ident.conf, para utilizá-lo basta selecionar como método de autenticação no pg_hba.conf o ident e, então, como última opção da linha de regra, informar o nome do mapa definido no ident file. Exemplo:
mymap seu_usuario_os seu_usuario_db
Nesse caso, mymap é o nome do seu mapeamento, seu_usuario_os é o nome do usuário no sistema operacional, e seu_usuario_db é o nome do usuário no banco de dados.
Para aplicar isso no pg_hba.conf, poderíamos incluir essa linha nas regras do arquivo:
host all all 192.168.1.10/32 ident mymap
Sendo que ident é o método escolhido, e a opção extra mymap refere-se ao mapeamento que queremos utilizar (considerando que podemos mapear vários usuários no ident file).
Conclusão
O pg_hba.conf é uma peça fundamental na definição de políticas de acesso ao banco de dados. Ele é relativamente simples de configurar e tem uma sintaxe bastante intuitiva se compararmos com outros bancos de dados por aí. No entanto, conhecer as opções disponíveis é uma condição indispensável para administrar um ambiente de produção de forma minimamente segura.
Por padrão, as instalações do PostgreSQL vêm apenas habilitadas para permitir conexões locais, o que gera uma certa frustração em novatos. Algumas pessoas, na pressa de colocar o banco de dados no ar, acabam utilizando o método TRUST ou colocando faixas de IPs abertas para o mundo todo com 0.0.0.0/0, o que deixa o servidor completamente vulnerável a ataques. Na mesma linha, você deve utilizar o ALL para usuários, e nomes de bancos de dados devem ser utilizados com moderação. Aqui vale a regra do “menor privilégio possível”. Você deve sempre colocar as regras mais restritas possíveis para permitir que as aplicações e os usuários acessem o banco de dados com segurança.
Outra tendência forte é utilizar conexões com criptografia SSL para todas as conexões que não forem locais, evitando possíveis ataques de pessoas que ficam escutando o tráfego da sua rede. Isso é tão importante hoje que escrevemos um artigo só sobre isso, que você poderá conferir mais adiante. Portanto, seja cuidadoso e crie regras com prudência. Lembre-se, você pode alterá-las e adicionar quantas linhas forem necessárias depois; e recarregar o arquivo pg_hba.conf sem precisar reiniciar o serviço do PostgreSQL, apenas dando um RELOAD.