Brasil 10:56 UTC−3·squads trabajando ahora
NDA primerocódigo 100 % suyoRGPD · LGPD
<alkwar.com/es/insights/saas-multi-tenant-postgresql-rls

SaaS multi-tenant con row-level security en PostgreSQL

Cuando todos los clientes comparten las mismas tablas, un WHERE olvidado puede mostrar los datos de una empresa a otra. El row-level security saca esa regla de la aplicación y la lleva a la base de datos.

AUTOR[ PLACEHOLDER · Autor ]
PUBLICADO[ Fecha ]
LECTURA8 min

01Por qué debe garantizarlo la base de datos

En un SaaS con esquema compartido, cada tabla tiene una columna tenant_id y cada consulta debe filtrar por ella. La aplicación puede hacerlo, pero tiene que hacerlo siempre, en cada consulta, escrita por cada ingeniero. Con row-level security (RLS) es PostgreSQL quien aplica el filtro, y una cláusula olvidada no devuelve nada en lugar de devolver datos de otro cliente.

02La configuración mínima

Active RLS en la tabla y cree una política que compare el tenant de la fila con un valor definido para la transacción actual.

<schema.sql
01ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
02ALTER TABLE invoices FORCE ROW LEVEL SECURITY;
03
04CREATE POLICY tenant_isolation ON invoices
05 USING (tenant_id = current_setting('app.tenant_id')::uuid)
06 WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);

USING filtra lo que una consulta puede leer. WITH CHECK bloquea inserts y updates que escribirían una fila en otro tenant. FORCE aplica la política también al propietario de la tabla.

03Definir el tenant en cada petición

La API obtiene el tenant del usuario autenticado y lo define al inicio de cada transacción. El tercer argumento de set_config limita el valor a la transacción, algo importante cuando las conexiones están en un pool.

<TenantScope.java
01@Transactional
02public <T> T inTenant(UUID tenantId, Supplier<T> work) {
03 jdbc.queryForObject("SELECT set_config('app.tenant_id', ?, true)",
04 String.class, tenantId.toString());
05 return work.get();
06}

04Tres errores que rompen el aislamiento

<Conectar como superusuario o con un rol con BYPASSRLS. Las políticas se ignoran sin ningún error. Use un rol dedicado para la aplicación.
<Definir el tenant a nivel de sesión con un pool de conexiones. La siguiente petición en la misma conexión hereda el tenant anterior.
<Olvidar las tablas nuevas. Añada una verificación en las migraciones que falle cuando una tabla con tenant_id no tenga RLS.
RLS es una segunda línea de defensa. Mantenga también los filtros de tenant en la aplicación y pruebe el aislamiento en CI con dos tenants y las mismas consultas.

05Probarlo en CI

<isolation_test.sql
01BEGIN;
02SELECT set_config('app.tenant_id', '00000000-0000-0000-0000-0000000000a1', true);
03SELECT count(*) FROM invoices
04 WHERE tenant_id = '00000000-0000-0000-0000-0000000000b2';
05-- expected: 0
06ROLLBACK;

Ejecutamos esta verificación para cada tabla con columna de tenant en cada pull request. Tarda segundos y detecta el único error que costaría un cliente.

[ FOTO ]
SOBRE EL AUTOR[ PLACEHOLDER · Nombre, cargo y una línea de trayectoria ]
< Todos los artículos
POR QUÉ CONFÍAN EN NOSOTROS
NDA primeroFirmamos su NDA antes de ver una línea de su código.
Su propiedadEl 100 % del código y de la propiedad intelectual es suyo.
GDPR y LGPDDatos personales tratados según el RGPD europeo y la ley brasileña.
Acceso desde el día 1Repositorio y tablero compartidos desde el primer día.
Demo semanalSoftware funcionando, presentado en vivo cada semana.
Una empresa de WGB Soluções de Software · Santa Rita do Sapucaí, Brasil
[ PLACEHOLDER · Sello Clutch ][ PLACEHOLDER · Sello Upwork ]
CONTACTO

¿Tiene un proyecto con fecha límite?

Envíenos los requisitos. Respondemos con alcance, cronograma y precio cerrado.

QUÉ PASA DESPUÉS
Día 0Una llamada de 30 minutos con un tech lead. Firmamos su NDA antes, si lo necesita.
Día 1Un resumen por escrito de la llamada y nuestras preguntas.
Días 3–7Una propuesta con alcance, plazo, equipo y precio cerrado.