Mejores Prácticas Multi-inquilino
Prueba las fugas entre inquilinos en CI con casos negativos. La corrección multi-inquilino es una propiedad de seguridad; trátala como la autenticación, no como una convención de nombres.
Cómo Usar Esta Lista
- Aplica a cada nueva tabla y punto final de API propiedad del inquilino.
- Ejecuta pruebas negativas de inquilino en CI en cada PR que toque código de acceso a datos.
- Reaudita al añadir herramientas de BI, consolas de soporte o trabajos en segundo plano.
- Elige el nivel de aislamiento (compartido, esquema, base de datos) por contrato; documéntalo en el registro de inquilinos.
A - Modelo de Datos
- Pon
tenant_iden cada fila propiedad del inquilino (esquema compartido). Las claves primarias y foráneas compuestas incluyentenant_id. - Usa
UNIQUE (tenant_id, ...)noUNIQUEglobal. Las slugs y los correos electrónicos colisionan entre inquilinos por diseño. - Indexa con
tenant_idcomo columna líder. Coincide conWHERE tenant_id = $1en todas las rutas activas. - Separa los datos de referencia globales de los datos del inquilino. Documenta las tablas sin
tenant_idcomo intencionalmente globales. - Registra la slug del inquilino, esquema, base de datos y nivel en el plano de control. Fuente única para el enrutamiento de conexiones.
B - Aplicación
- Habilita
FORCE ROW LEVEL SECURITYen tablas de inquilino. Políticas en SELECT, INSERT, UPDATE, DELETE según sea necesario. - Establece
app.tenant_id(o equivalente) en cada solicitud. Nunca confíes en el inquilino proporcionado por el cliente sin vinculación de autenticación. - Restablece el estado de la sesión al extraer del pool. PgBouncer
server_reset_query = DISCARD ALLo equivalente. - Prohíbe conexiones de aplicaciones con BYPASSRLS. Las migraciones usan un rol separado en un pipeline controlado.
- Claves foráneas compuestas en enlaces padre-hijo. Evita uniones de
document_idque crucen inquilinos.
C - Pruebas y Operaciones
- Prueba negativa en CI: el inquilino A no puede leer filas del inquilino B. Requerido por clase de tabla, no una prueba de integración opcional.
- Alerta sobre anomalías de crecimiento de filas por inquilino. Detección de vecinos ruidosos en la plataforma de métricas.
- Runbook para exportación y eliminación por inquilino. Las solicitudes GDPR/CCPA no deben requerir restauración completa del clúster.
- Automatiza el aprovisionamiento de esquemas/bases de datos de forma idempotente. Rutas de registro y actualización de nivel probadas en staging.
- Audita las consultas de omisión de soporte y administración. Registra el contexto del inquilino para roles de plataforma con acceso elevado.
D - Estrategia de Nivel
- Nivel SMB predeterminado: esquema compartido + RLS. Menor costo operativo con filtros disciplinados.
- Nivel Business: evalúa esquema por inquilino cuando los contratos lo requieran. Limita el recuento de inquilinos con inversión en automatización.
- Nivel Enterprise: base de datos o instancia por inquilino cuando se exija. El precio refleja el multiplicador operativo.
- No mezcles niveles sin enrutamiento explícito. La cadena de conexión incorrecta equivale a una fuga de datos.
- Revisa los límites de nivel anualmente. El cumplimiento y la escala cambian los patrones aceptables.
Preguntas Frecuentes
¿Cuál es la prueba mínima de CI para multi-inquilino?
Siembra los inquilinos A y B, autentícate como A, consulta cada punto final/tabla, afirma que no se devuelven filas de B. Falla la compilación ante cualquier fuga.
¿Es RLS suficiente sin filtros de aplicación?
RLS es defensa en profundidad. Las aplicaciones aún deben filtrar; las políticas atrapan errores, no reemplazan el diseño intencional de consultas.
¿Cómo pruebo las fugas de pooling de PgBouncer?
Dos solicitudes secuenciales de diferentes inquilinos a través del mismo pool sin restablecimiento no deberían ver datos cruzados; automatízalo en staging.
¿Qué pasa con los trabajadores en segundo plano?
Los trabajadores deben establecer el GUC del inquilino por carga útil del trabajo. Los trabajadores globales iteran explícitamente sobre los inquilinos; nunca escanees la tabla completa sin filtro.
¿Debería aparecer tenant_id en los logs?
Sí, para pistas de auditoría; evita PII en la misma línea de log. Correlaciona tenant_id con el ID de solicitud para la respuesta a incidentes.
¿Cómo elijo el nivel de aislamiento?
Comienza con esquema compartido + RLS. Pasa a esquema/base de datos cuando los contratos, las métricas de vecinos ruidosos o los SLAs de restauración lo exijan.
¿Cuál es la principal causa de incidentes multi-inquilino?
Falta WHERE tenant_id en un método del repositorio o GUC obsoleto en una conexión agrupada.
¿Necesitan las réplicas de lectura RLS?
Sí, si las aplicaciones se conectan con roles que no son superusuario. Las políticas de réplica coinciden con las primarias; prueba las fugas en la réplica en CI también.
¿Cómo evitan las migraciones el impacto entre inquilinos?
Esquema compartido: una DDL afecta a todas; prueba en el fixture del inquilino más grande. Esquemas/bases de datos por inquilino: paraleliza con alertas de fallo.
¿Puedo omitir tenant_id en las tablas de auditoría?
No: los logs de auditoría son datos propiedad del inquilino y necesitan el mismo aislamiento e índices.
Relacionado
- Conceptos Básicos Multi-inquilino - resumen del patrón
- Tenencia de Seguridad a Nivel de Fila - plantillas de políticas
- Esquema Compartido + tenant_id - detalles de indexación
- Base de Datos por Inquilino - nivel empresarial
Versiones de Stack: Esta página fue escrita para PostgreSQL 18.4 (estable 18, mantenimiento 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, y PostGIS 3.5+.