ADR-0002 · Multi-tenancy híbrida (lógico SMB default + físico enterprise opt-in)¶
- Status: Accepted
- Date: 2026-04-30
- Deciders: Cristian Fernández (Zerviz Group)
- Supersedes: N/A
- Related: ADR-0003 (persistencia), ADR-0005 (auth),
docs/discovery/00-phase1-prerequisites.mdAnexo A-02.
Context¶
El sistema debe soportar N tenants con onboarding programático sin redeploy. La regla base prohíbe asumir baseline costoso. Tenants vienen en dos perfiles:
- SMB: mayoría esperada. Requieren costo bajo, onboarding rápido, sin SLA de aislamiento físico.
- Enterprise: minoría con requisitos regulatorios o contractuales de aislamiento (cuenta AWS dedicada, KMS propio, datos aislados a nivel infra).
IPLACEX es fixture de prueba SMB; Zerviz interno también es SMB.
Decision¶
Modelo de dos tiers:
Tier lógico (default — SMB)¶
- Una sola cuenta AWS por env (
ze-dev,ze-qa,ze-prod). - Cognito User Pool único compartido (
ze-{env}-users) con claimcustom:tenant_iden cada usuario. - RDS Postgres común (ver ADR-0003) con RLS sobre cada tabla que toque datos de tenant:
CREATE POLICY tenant_iso ON <tabla> USING (tenant_id = current_setting('app.tenant_id')::uuid);. - DynamoDB compartido con
PK = TENANT#<id>y SK por entidad. Item-level access via IAM condynamodb:LeadingKeys. - KMS CMK por tenant (
alias/ze-{env}-tenant-<id>) para datos sensibles (PII de conversaciones, transcripciones, audit). Buckets S3 y secretos del tenant cifran con esta CMK. - Onboarding: API
POST /tenantsentenant-mgmt. Crea tenant en RDSze_control_plane.tenants, provisiona CMK + alias, registra en Cognito (grouptenant-<id>), publicaTenantCreated.
Tier físico (opt-in — enterprise)¶
- Cuenta AWS dedicada por tenant (
ze-prod-tenant-<id>), provisionada por AWS Organizations. - Stack Terraform
infra/tenants/<tenant>/aplicado convar.tenant_id. Todos los recursos del tenant (Lambdas, RDS propio, DDB propio, S3, Cognito UP propio, KMS propio) viven en esa cuenta. - Control plane (
tenant-mgmt,auth-bff, EventBridge bus de plataforma, billing) sigue en la cuentaze-prod. - Cross-account roles: la cuenta-tenant asume roles del control plane sólo para publicar eventos de plataforma y emitir métricas de billing.
- No RLS dentro del tenant (innecesario, aislamiento ya es físico).
- Costos del tier físico se cargan al tenant.
Decisión por tenant¶
tenant-mgmt mantiene tenants.tier ∈ {logical, physical}. Cambio de tier = migración planificada (no automática). En V1 sólo el equipo de plataforma activa el tier físico; opt-in vía form / contrato.
Consequences¶
Positive¶
- SMB onboardea en minutos sin Terraform.
- Enterprise obtiene aislamiento físico verificable (auditable a nivel cuenta AWS).
- Cumple ISO 27001 A.13.1.3 (segregación en redes) en tier físico.
- KMS CMK por tenant facilita compliance individual (Ley 19.628 cuando aplique).
Negative¶
- Doble pipeline de provisioning (lógico + físico) → más Terraform modules a mantener.
- RLS en Postgres requiere
SET app.tenant_iden cada conexión; olvido ⇒ leak entre tenants. Mitigado con middleware obligatorio enpackages/tenant-context. - Cross-account billing del tier físico requiere AWS Organizations + tag enforcement.
Alternatives considered¶
- Sólo tier lógico: rechazado — algunos prospects enterprise requieren aislamiento físico contractual.
- Sólo tier físico: rechazado — costo prohibitivo para SMB (~ USD 50/mes/tenant baseline).
- Database per tenant en una cuenta: rechazado — no escala a N alto y no resuelve aislamiento de compute/secrets.
Tenant-isolation impact¶
(Es el ADR de aislamiento. Resumen en sección Decision.) Tests de aislamiento obligatorios en cada servicio:
tests/integration/tenant-isolation.test.ts: dado tenant A y tenant B, una request del A no puede leer ni escribir filas del B.- Test de bypass: forzar
tenant_idfaltante / falsificado en JWT debe devolver 403.
Blast radius¶
- Tier lógico: bug que rompe RLS ⇒ leak entre todos los tenants SMB del env. Crítico. Mitigado por
packages/tenant-context+ tests + revisión obligatoria de queries. - Tier físico: blast radius limitado a la cuenta del tenant.
Cost note¶
- Tier lógico: incremental por tenant ≈ USD 0–2/mes (sólo CMK + entradas Cognito + filas RDS).
- Tier físico: baseline USD 50–200/mes/tenant según engine RDS y volumen — facturado al tenant.
ISO 27001 controls touched¶
- A.9.4.1 (restricción de acceso a información): RLS + IAM
LeadingKeys. - A.10.1.1 (políticas de uso de criptografía): KMS CMK por tenant.
- A.13.1.3 (segregación en redes): tier físico = cuenta AWS separada.
- A.18.1.4 (privacidad y protección de datos personales): KMS + Object Lock por tenant.
Sources¶
docs/discovery/00-phase1-prerequisites.mdU-04, 1.3, Anexo A-02.- Playbook §2 (multi-tenant model).