Configurando conexões seguras com SSL no PostgreSQL

Proteja suas conexões com certificados SSL e autenticação robusta.

Por que SSL/TLS é obrigatório em produção

Conectar ao seu banco PostgreSQL sem criptografia é como enviar sua senha por e-mail não criptografado: qualquer um no caminho pode interceptar. SSL/TLS garante que seus dados trafeguem seguros entre aplicação e banco.

Riscos de conexões não criptografadas

1. Como SSL/TLS funciona no PostgreSQL

Handshake SSL

1. Cliente conecta ao servidor
2. Servidor envia certificado digital
3. Cliente valida certificado (CA chain)
4. Troca de chaves criptográficas
5. Conexão segura estabelecida
6. Dados trafegam criptografados (AES-256)

Modos de SSL no PostgreSQL

Modo Descrição Uso
disable Sem SSL ❌ Nunca em produção
allow SSL se disponível ⚠️ Inseguro
prefer Prefere SSL ⚠️ Pode falhar para plain
require SSL obrigatório ✅ Recomendado
verify-ca Valida CA ✅ Mais seguro
verify-full Valida CA + hostname ✅ Máxima segurança

2. Configurando SSL no servidor PostgreSQL

Gerando certificados SSL

# Gere certificado auto-assinado (desenvolvimento)
openssl req -new -x509 -days 365 -nodes -text \\
  -out server.crt \\
  -keyout server.key \\
  -subj "/CN=postgres.meudominio.com"

# Permissões corretas
chmod 600 server.key
chown postgres:postgres server.key server.crt

# Copie para diretório do PostgreSQL
cp server.crt server.key /var/lib/postgresql/data/

Configuração em postgresql.conf

# Habilite SSL
ssl = on
ssl_cert_file = 'server.crt'
ssl_key_file = 'server.key'
ssl_ca_file = 'root.crt'  # Opcional: para client certificates

# Cipher suites modernos (TLS 1.2+)
ssl_ciphers = 'HIGH:MEDIUM:+3DES:!aNULL'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'

# Reinicie PostgreSQL
sudo systemctl restart postgresql

Configuração em pg_hba.conf

# Exija SSL para conexões remotas
# TYPE  DATABASE  USER  ADDRESS      METHOD
hostssl all       all   0.0.0.0/0    md5
hostssl all       all   ::/0         md5

# Bloqueie conexões não-SSL
hostnossl all     all   0.0.0.0/0    reject

# Reload configuração
sudo systemctl reload postgresql

3. Conectando com SSL do cliente

Node.js / JavaScript

// Com pg (node-postgres)
const { Pool } = require('pg');

const pool = new Pool({
  host: 'postgres.meudominio.com',
  port: 5432,
  database: 'meudb',
  user: 'usuario',
  password: 'senha',
  ssl: {
    rejectUnauthorized: true,  // Valida certificado
    ca: fs.readFileSync('./ca-certificate.crt').toString(),
    // Para client certificates:
    key: fs.readFileSync('./client-key.pem').toString(),
    cert: fs.readFileSync('./client-cert.pem').toString(),
  }
});

// Connection string alternativa
const connectionString = 'postgresql://user:pass@host:5432/db?sslmode=require';
const pool2 = new Pool({ connectionString });

Python

import psycopg2

# Com psycopg2
conn = psycopg2.connect(
    host='postgres.meudominio.com',
    port=5432,
    database='meudb',
    user='usuario',
    password='senha',
    sslmode='require',  # ou 'verify-full'
    sslrootcert='/path/to/ca-cert.crt',
    sslcert='/path/to/client-cert.pem',
    sslkey='/path/to/client-key.pem'
)

Java (JDBC)

String url = "jdbc:postgresql://postgres.meudominio.com:5432/meudb" +
             "?ssl=true" +
             "&sslmode=verify-full" +
             "&sslrootcert=/path/to/ca-cert.crt" +
             "&sslcert=/path/to/client-cert.crt" +
             "&sslkey=/path/to/client-key.pk8";

Connection conn = DriverManager.getConnection(url, "usuario", "senha");

Go

import (
    "database/sql"
    "crypto/tls"
    "crypto/x509"
    _ "github.com/lib/pq"
)

connStr := "host=postgres.meudominio.com port=5432 " +
           "user=usuario password=senha dbname=meudb " +
           "sslmode=verify-full sslrootcert=/path/to/ca-cert.crt"

db, err := sql.Open("postgres", connStr)

Ruby (Rails)

# database.yml
production:
  adapter: postgresql
  host: postgres.meudominio.com
  database: meudb
  username: usuario
  password: senha
  sslmode: require
  sslrootcert: /path/to/ca-cert.crt

psql (CLI)

# Conexão com SSL obrigatório
psql "postgresql://user:pass@host:5432/db?sslmode=require"

# Com variáveis de ambiente
export PGSSLMODE=require
export PGSSLROOTCERT=/path/to/ca-cert.crt
psql -h postgres.meudominio.com -U usuario -d meudb

4. Validando conexões SSL

Verificar SSL ativo

-- No PostgreSQL, verifique conexões SSL
SELECT 
  pid,
  usename,
  application_name,
  client_addr,
  ssl,
  ssl_version,
  ssl_cipher
FROM pg_stat_ssl
JOIN pg_stat_activity USING (pid)
WHERE ssl = true;

-- Resultado esperado:
-- ssl: true
-- ssl_version: TLSv1.3
-- ssl_cipher: TLS_AES_256_GCM_SHA384

Teste de conexão

#!/bin/bash
# test-ssl-connection.sh

echo "Testando conexão SSL..."

# Deve funcionar
psql "postgresql://user:pass@host:5432/db?sslmode=require" -c "SELECT version();" && \\
  echo "✅ SSL funcionando!"

# Deve falhar
psql "postgresql://user:pass@host:5432/db?sslmode=disable" -c "SELECT 1;" 2>&1 | \\
  grep -q "rejected" && \\
  echo "✅ Conexões não-SSL bloqueadas corretamente!"

5. Client Certificates (mTLS)

Para segurança máxima, use autenticação mútua (cliente também tem certificado):

Gerando certificado do cliente

# 1. CA key e certificado
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt

# 2. Client key
openssl genrsa -out client.key 4096

# 3. Client certificate request
openssl req -new -key client.key -out client.csr

# 4. Assine com CA
openssl x509 -req -days 365 -in client.csr \\
  -CA ca.crt -CAkey ca.key -CAcreateserial \\
  -out client.crt

# 5. Converta para formato correto (se necessário)
openssl pkcs8 -topk8 -inform PEM -outform DER \\
  -in client.key -out client.pk8 -nocrypt

Configuração no servidor

# postgresql.conf
ssl_ca_file = 'ca.crt'

# pg_hba.conf - exija client cert
hostssl all all 0.0.0.0/0 cert clientcert=verify-full

6. Troubleshooting SSL

Erro: "SSL is not enabled on the server"

Solução:
1. Verifique postgresql.conf: ssl = on
2. Certificados no lugar correto
3. Permissões: chmod 600 server.key
4. Reinicie PostgreSQL

Erro: "certificate verify failed"

Solução:
1. Use sslmode=require (não verify-full) temporariamente
2. Verifique CA certificate correto
3. Hostname deve bater com CN do certificado
4. Certificado não expirado: openssl x509 -in server.crt -noout -dates

Erro: "no pg_hba.conf entry for host"

Solução:
1. Adicione entrada hostssl no pg_hba.conf
2. Recarregue: SELECT pg_reload_conf();
3. Verifique IP do cliente está permitido

7. SSL/TLS no CloudPG

No CloudPG, SSL/TLS é obrigatório e configurado automaticamente:

Como conectar no CloudPG

// Simples assim:
const pool = new Pool({
  connectionString: 'postgresql://user:pass@seu-cluster.cloudpg.com.br:5432/db',
  ssl: { rejectUnauthorized: true }  // Apenas isso!
});

// Ou ainda mais simples:
const connectionString = 'postgresql://user:pass@host:5432/db?sslmode=require';
const pool = new Pool({ connectionString });

Conclusão

SSL/TLS é essencial para qualquer aplicação em produção. Os pontos principais:

  1. ✅ Sempre use sslmode=require no mínimo
  2. ✅ Em produção, prefira verify-full
  3. ✅ Use certificados de CAs confiáveis
  4. ✅ Teste conexões regularmente
  5. ✅ Monitore expiração de certificados
  6. ✅ Desabilite protocolos antigos (TLS 1.0/1.1)

Com CloudPG, SSL/TLS funciona automaticamente, sem dor de cabeça de configuração ou renovação.

Conexões seguras desde o primeiro minuto

Crie seu banco PostgreSQL com SSL/TLS configurado automaticamente e comece a desenvolver com segurança.