La seguridad de una base de datos productiva no se limita a GRANT SELECT. Frente a auditorías de compliance (PCI-DSS, ISO 27001, GDPR), un cluster PostgreSQL serio combina autenticación robusta, auditoría automática, cifrado en reposo y en columnas sensibles, y políticas declarativas de aislamiento. Esta lección integra todas estas piezas.
Autenticación: SCRAM-SHA-256 como mínimo
Hasta hace poco PostgreSQL aceptaba contraseñas con el algoritmo MD5 por defecto. MD5 está roto y no debería usarse en ningún sistema productivo. La alternativa es SCRAM-SHA-256, disponible desde PostgreSQL 10:
# postgresql.conf
password_encryption = scram-sha-256
# pg_hba.conf - solo aceptar SCRAM
host all all 10.0.0.0/8 scram-sha-256
Tras cambiar la configuración, las contraseñas existentes siguen en el algoritmo viejo. Hay que forzar el cambio:
-- Ver el formato actual de las contraseñas
SELECT rolname, rolpassword FROM pg_authid WHERE rolpassword LIKE 'md5%';
-- Forzar a un usuario a recambiar (su nueva contrasena se guardara en SCRAM)
ALTER USER alice PASSWORD 'nueva_contrasena_robusta';
El cambio puede requerir actualizar también las librerías cliente. Versiones antiguas de PostgreSQL JDBC, libpq o psycopg2 no soportan SCRAM y conviene auditar esa dependencia primero.
Integración LDAP y Kerberos
En entornos corporativos las contraseñas deberían venir del directorio central (Active Directory u OpenLDAP). PostgreSQL soporta ldap y gss (Kerberos) en pg_hba.conf:
# pg_hba.conf con LDAP
host all all 10.0.0.0/8 ldap \
ldapserver=ldap.empresa.com \
ldapport=636 \
ldaptls=1 \
ldapprefix="cn=" \
ldapsuffix=", ou=usuarios, dc=empresa, dc=com"
Los usuarios PostgreSQL deben existir como ROLE previamente; LDAP solo gestiona la autenticación, no la autorización:
CREATE USER alice;
GRANT lectura_pedidos TO alice;
Para Kerberos/Active Directory el método es
gss. Permite single sign-on: el usuario que ya inició sesión en su workstation con AD se conecta a PostgreSQL sin volver a introducir contraseña.
pgaudit: auditoría detallada
PostgreSQL log estándar registra mensajes y errores, pero no detalla quién ejecutó cada operación con qué parámetros. Para compliance se necesita la extensión pgaudit:
CREATE EXTENSION IF NOT EXISTS pgaudit;
# postgresql.conf
shared_preload_libraries = 'pgaudit, pg_stat_statements'
pgaudit.log = 'ddl, role, write'
pgaudit.log_catalog = off
pgaudit.log_parameter = on
pgaudit.log_relation = on
Tras reiniciar, cada DDL, cambio de rol o escritura genera una entrada de log:
2026-04-15 14:22:11.234 UTC [12345] LOG: AUDIT: SESSION,1,1,DDL,CREATE TABLE,
TABLE,public.tenants,CREATE TABLE tenants (id SERIAL PRIMARY KEY, nombre TEXT)
Auditoría granular por rol o por objeto:
-- Auditar todas las operaciones de un rol concreto
ALTER ROLE auditor SET pgaudit.log = 'all';
-- Auditar acceso a una tabla sensible
GRANT pgaudit_role TO usuario;
ALTER TABLE pacientes SECURITY LABEL FOR pgaudit IS 'log_select';
pgaudit genera mucho log. Conviene enviarlo a un sistema centralizado (CloudWatch, Splunk, Loki) y rotar localmente cada hora para evitar llenar el disco.
Cifrado de columnas con pgcrypto
PostgreSQL no cifra las columnas por defecto. Para datos especialmente sensibles (DNI, números de tarjeta, datos de salud) se usa pgcrypto con cifrado simétrico:
CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Cifrar al insertar
INSERT INTO pacientes (nombre, historia_cifrada)
VALUES (
'Juan Perez',
pgp_sym_encrypt('Diagnóstico confidencial...', current_setting('app.master_key'))
);
-- Descifrar al consultar
SELECT nombre, pgp_sym_decrypt(historia_cifrada, current_setting('app.master_key')) AS historia
FROM pacientes
WHERE id = 42;
La clave maestra se inyecta en cada sesión:
SET LOCAL app.master_key = '<<recuperada de Vault>>';
El cifrado a nivel de columna no sustituye al cifrado en reposo (LUKS, EBS encryption). Es una capa adicional para datos críticos donde quieres garantía aunque alguien obtenga acceso al filesystem.
Cifrado en reposo
PostgreSQL no cifra los archivos del cluster nativamente. Las opciones habituales:
- LUKS o dm-crypt en Linux para cifrar el disco.
- AWS EBS encryption, GCP persistent disk encryption, Azure disk encryption en cloud.
- TDE (Transparent Data Encryption) mediante extensiones comerciales como pgsodium o pg_tde.
Para la mayoría de casos, el cifrado del disco a nivel de sistema operativo o cloud provider es suficiente y transparente para PostgreSQL.
Row-Level Security para multi-tenant
RLS aísla los datos por tenant a nivel del motor, no de aplicación. Combinado con SET LOCAL por sesión, es la forma más robusta de evitar que un bug de aplicación filtre datos entre tenants.
ALTER TABLE pedidos ENABLE ROW LEVEL SECURITY;
CREATE POLICY pedidos_tenant_isolation ON pedidos
FOR ALL
TO app_user
USING (tenant_id = current_setting('app.tenant_id')::INT)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::INT);
Y en cada request de la aplicación:
BEGIN;
SET LOCAL app.tenant_id = '42';
SELECT * FROM pedidos; -- solo ve pedidos del tenant 42
INSERT INTO pedidos (...) VALUES (...); -- solo puede insertar para tenant 42
COMMIT;
El
SET LOCALsolo afecta a la transacción actual. Si la conexión vuelve al pool, el siguiente request usará su propio tenant. Nunca usesSETglobal; rompe el aislamiento.
Roles con BYPASSRLS
Algunos roles deben saltarse RLS: jobs de mantenimiento, herramientas de backup, DBAs auditando datos:
ALTER USER backup_user BYPASSRLS;
Estos roles no deberían usarse desde la aplicación. Reserva BYPASSRLS para tareas operacionales puntuales y audita su uso con pgaudit.
SSL/TLS para conexiones
Toda conexión PostgreSQL en producción debería ir cifrada. Configuración:
# postgresql.conf
ssl = on
ssl_cert_file = '/etc/postgresql/server.crt'
ssl_key_file = '/etc/postgresql/server.key'
ssl_ca_file = '/etc/postgresql/ca.crt'
ssl_min_protocol_version = 'TLSv1.2'
# pg_hba.conf - rechazar conexiones sin SSL
hostssl all all 10.0.0.0/8 scram-sha-256
hostnossl all all 0.0.0.0/0 reject
Y desde el cliente, exigir SSL con verificación de certificado:
psql "host=db.empresa.com port=5432 dbname=produccion sslmode=verify-full sslrootcert=/etc/ssl/empresa-ca.crt"
El modo
verify-fullvalida que el certificado corresponda al hostname y esté firmado por una CA confiable. Sin esto, un atacante con MITM podría descifrar el tráfico.
Gestión de secretos
Las contraseñas y claves no deberían ir en código fuente ni en archivos sin cifrar. Patrones aceptables:
- HashiCorp Vault: secret manager con auditoría, rotación automática y políticas.
- AWS Secrets Manager / GCP Secret Manager: nativos del cloud.
- Kubernetes Secrets (con encriptación etcd habilitada).
- systemd credentials para deployments con systemd.
# Ejemplo con Vault
DB_PASSWORD=$(vault kv get -field=password secret/db/produccion)
PGPASSWORD="$DB_PASSWORD" psql -U app_user -h db.empresa.com produccion
Lista de verificación de seguridad
Antes de declarar un cluster productivo:
password_encryption = scram-sha-256y todas las contraseñas migradas.- Conexiones forzadas a SSL con certificados válidos.
pg_hba.confrevisado: nada detrust, IPs concretas o autenticación robusta.- Roles con principio de mínimo privilegio: la aplicación nunca usa SUPERUSER.
- RLS habilitado en tablas multi-tenant con policies específicas.
- pgaudit registrando DDL y modificaciones.
- Logs centralizados y retenidos según política de compliance.
- Cifrado de disco activo (LUKS o EBS).
- Backups cifrados con clave separada.
- Rotación de credenciales documentada y automatizada.
- Penetration test al menos anual.
flowchart LR
A[Cliente con SSL] --> B[Authentication LDAP/SCRAM]
B --> C[Authorization GRANT/RLS]
C --> D[Acceso a datos]
D --> E[Auditoria pgaudit]
E --> F[Log centralizado]
G[Vault/Secrets Manager] --> A
H[LUKS/EBS] --> D
I[pgcrypto] --> D
La seguridad en PostgreSQL no es un único interruptor sino un conjunto de capas defensivas. Bien configuradas, transforman el cluster en un componente que pasa auditorías sin sobresaltos y resiste tanto a errores accidentales como a ataques deliberados.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, SQL es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de SQL
Explora más contenido relacionado con SQL y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Configurar SCRAM-SHA-256 como método de autenticación obligatorio. Integrar PostgreSQL con LDAP/Active Directory. Activar pgaudit para auditoría de DDL, DML y ROLE changes. Cifrar columnas sensibles con pgcrypto y gestión externa de claves. Combinar RLS con SET LOCAL para aislamiento multi-tenant en aplicaciones SaaS.
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje