Permisos Multi-Tenant vs Claude Code ACL
Un restaurante no debería ver los datos de otro. Una IA no debería ejecutar rm -rf / sin preguntar. Dos dominios, un mismo problema: ¿quién puede hacer qué?
Los sistemas de permisos son aburridos — hasta que fallan. En un restaurante multi-tenant, un permiso mal configurado significa que el competidor ve tu menú y precios. En Claude Code, un permiso mal evaluado significa que la IA borra tu rama main sin preguntar.
Este artículo compara dos enfoques de producción: el RBAC multi-tenant de Cadences Platform (usado por decenas de verticales SaaS) y el sistema ACL tri-state de Claude Code (que inventó algo que la mayoría de frameworks RBAC no tiene: el estado "ask").
Al final proponemos un patrón híbrido: AI-Enhanced RBAC — RBAC clásico con los tres superpoderes que Claude Code descubrió.
RBAC Multi-Tenant Clásico
Cadences Platform ejecuta múltiples verticales SaaS (restaurantes, viajes, salud) en una infraestructura compartida de Cloudflare Workers + D1. El aislamiento entre tenants es absoluto: cada query lleva WHERE tenant_id = ?.
🏢 Arquitectura RBAC
// Cadences Permission Model Tenant (restaurante/agencia/clínica) └── Roles ├── owner → full access + billing ├── admin → settings + staff management ├── manager → operations + analytics ├── staff → daily operations only └── viewer → read-only Enforcement: middleware en Workers request → extract tenant_id → extract role → check: role >= required_role? → allow / deny Resources: menu_items, orders, settings, integrations, analytics, staff
Es un modelo probado y simple. Los permisos se resuelven en una sola comparación: ¿el rol del usuario tiene acceso a este recurso? Sí o no. No hay ambigüedad, no hay estados intermedios.
✓ Fortalezas
- Simple: una tabla de roles × recursos
- Aislamiento absoluto por tenant
- Predecible (sin sorpresas)
- Auditable en D1
- Latency cercano a cero
✗ Debilidades
- Binario: no hay "depende del contexto"
- No diferencia entre operaciones de distinto riesgo
- Sin confirmación humana para edge cases
- Escala mal con operaciones granulares
- No hay IA evaluando patrones anómalos
ACL Tri-State con Cascading
Claude Code inventó algo que la mayoría de frameworks RBAC no tiene: un tercer estado. No es allow. No es deny. Es ask — preguntarle al humano si esta operación específica está bien.
🔐 Sistema de Permisos
// Claude Code Permission Sources (cascading) Level 1: Platform rules ← Anthropic define Level 2: Organization ACL ← empresa define Level 3: Project ACL ← .claude/settings.json Level 4: User preferences ← ~/.claude/settings.json // Evaluation order (deny-first) for source in [platform, org, project, user]: if source.denies(tool, args): → DENY if source.allows(tool, args): → ALLOW if mode == "auto": → consult yolo classifier if mode == "plan": → ASK always if mode == "default": → ASK if destructive
Los 3 estados
Se ejecuta sin preguntar. Para herramientas de solo lectura y operaciones seguras.
Nunca se ejecuta. Para operaciones prohibidas por política.
El humano decide. Para operaciones de riesgo variable que dependen del contexto.
El Yolo Classifier: IA como juez
Cuando el modo es auto y una herramienta está en estado "ask", Claude Code no pregunta directamente — primero consulta al yolo classifier: un modelo de IA que evalúa si la operación específica es segura en el contexto actual.
LOW risk → auto-aprueba MEDIUM/HIGH risk → pregunta al humano 💡 ¿Por qué importa? El yolo classifier convierte permisos binarios en permisos contextuales. write_file("test.js") es auto-aprobado. write_file("package.json") pregunta. Misma herramienta, diferente riesgo según los argumentos.
✓ Fortalezas
- Tri-state: permite "depende del contexto"
- 4 fuentes cascading (alta flexibilidad)
- Content-aware (glob patterns)
- IA evalúa riesgo por operación
- Circuit breaker de seguridad
✗ Debilidades
- Efímero (session-only, no persiste)
- Sin aislamiento multi-tenant
- Complejidad: 4 fuentes × 3 estados
- Riesgo de false positives en classifier
- Latencia del classifier (model call)
Tabla Comparativa
| Aspecto | Cadences | Claude Code |
|---|---|---|
| Tipo | RBAC multi-tenant | Cascading rules + AI judge |
| Estados | 2 (allow/deny) | 3 (allow/deny/ask) |
| Granularidad | Role → Resource | Tool + Content (glob patterns) |
| Fuentes | 1 (rol del usuario) | 4 (platform → org → project → user) |
| IA para permisos | No | Sí (yolo classifier) |
| Confirmación humana | No (binario) | Sí (ask mode) |
| Persistencia | D1 (permanente) | Session (efímero) |
| Auditoría | D1 logs | In-session tracking |
| Override | Solo admin | User override project |
| Glob matching | No | Sí (*.sql, tests/*) |
Por Qué "Ask" lo Cambia Todo
El RBAC tradicional es binario. Puedes o no puedes. Pero en el mundo real hay operaciones que dependen del contexto:
🏢 En Cadences (hoy: binario)
- ¿Borrar un item del menú? ALLOW si manager
- ¿Borrar todo el menú? También ALLOW si manager
- ¿Cambiar precio de 1€ a 100€? ALLOW si manager
- ⚠️ Los tres tienen el mismo "permiso" pero riesgos muy distintos
🤖 Con tri-state (propuesto)
- ¿Borrar un item? ALLOW
- ¿Borrar todo el menú? ASK owner review
- ¿Cambiar precio >50%? ASK confirmación
- ✓ Mismo rol, pero riesgo evaluado por contenido
"Ask" es el estado que le falta a la mayoría de sistemas RBAC. No todo es blanco o negro — a veces la respuesta correcta es "puede, pero primero confirma con alguien".
4 Niveles de Control
Claude Code tiene 4 fuentes de permisos en cascada. Cada nivel puede override al anterior con deny (nunca puede re-allow un deny del nivel superior). Cadences tiene un equivalente natural:
Claude Code
Cadences (propuesto)
🎯 Content-aware rules: Claude Code usa glob patterns (*.sql deny, tests/*.sql allow). Cadences podría usar el mismo concepto: menu.* allow, menu.bulk_delete ask. La granularidad por contenido es el salto que separa RBAC estático de RBAC inteligente.
IA Evaluando Permisos en SaaS
El yolo classifier de Claude Code es un modelo que clasifica operaciones por riesgo. ¿Podría Cadences usar el mismo concepto? Absolutamente:
Bulk delete detection
Un manager borra 3 items → normal. Un manager borra 200 items → la IA evalúa como anómalo → ASK al owner.
Price anomaly detection
Cambio de precio de 12€ a 13€ → normal. Cambio de 12€ a 120€ → la IA detecta anomalía → ASK confirmación.
Off-hours operations
Staff edit a las 10:00 AM → normal. Staff bulk edit a las 3:00 AM → la IA detecta patrón inusual → ASK.
⚠️ Riesgos del AI-as-Judge
False positives
Operaciones legítimas bloqueadas. El manager quiere realmente borrar el menú por renovation.
Latencia
El classifier necesita un model call. En hot paths podría agregar 100-300ms.
Model failures
Si el classifier falla, ¿se auto-aprueba? Claude Code: deny por defecto. Correcto.
Design Pattern: AI-Enhanced RBAC
Combinando lo mejor de ambos mundos, proponemos un patrón de 4 capas para sistemas SaaS con herramientas de IA:
🔮 AI-Enhanced RBAC
RBAC tradicional — Role → Resource → Allow/Deny. La base sigue siendo la misma. Simple, predecible, auditable.
Añadir estado "Ask" — Para operaciones de alto riesgo dentro de un rol permitido. No cambia el modelo — añade un tercer valor posible.
Cascading sources — Platform → Vertical → Tenant → User. Cada nivel hereda y puede override. Deny domina siempre.
AI classifier en "Ask" — Cuando el estado es Ask, un modelo evalúa los argumentos específicos. Baja risk → auto-aprueba. Alta risk → escala al humano.
Circuit breaker — Después de N anomalías consecutivas, el sistema pasa a deny-all para la sesión. Exactamente como Claude Code.
⚡ Sketch de Implementación
// AI-Enhanced RBAC in Cadences Workers async function evaluatePermission(request, env) { const { tenantId, role, action, resource, args } = request; // Layer 0: RBAC base const rbac = await getRBAC(env.DB, tenantId, role); if (rbac[resource] === 'deny') return DENY; if (rbac[resource] === 'allow') { // Layer 1: ¿es una operación ask? const askRules = await getAskRules(env.DB, tenantId); const matchedRule = askRules.find(r => r.action === action && matchGlob(r.pattern, args) ); if (!matchedRule) return ALLOW; // Layer 2: AI classifier const risk = await classifyRisk(env.AI, { action, resource, args, context: { tenantId, role, timestamp: Date.now() } }); if (risk === 'LOW') return ALLOW; if (risk === 'MEDIUM') return ASK(args.reviewer); if (risk === 'HIGH') return DENY; } // Layer 3: circuit breaker if (await getConsecutiveDenials(env.DB, tenantId) >= 3) { return DENY_ALL_SESSION; } return ASK(role.owner); }
El RBAC no está muerto — le faltaban tres cosas: un tercer estado (ask), fuentes en cascada, y un modelo de IA que entienda el contenido de la operación, no solo el tipo.
¿Tu SaaS necesita permisos más inteligentes?
En Cadences implementamos AI-Enhanced RBAC — el patrón que descubrimos comparando nuestro multi-tenant con Claude Code. Si tus permisos son demasiado binarios, podemos ayudar.
Gonzalo Monzón
Fundador de CadencesLab. Arquitecto de permisos multi-tenant por el día, analista de Claude Code por la noche, obsesionado con que ninguna IA haga lo que no debe.