Control de Acceso Basado en Relaciones (ReBAC): la autorización como grafo

El Control de Acceso Basado en Relaciones explicado: derivar permisos de un grafo de relaciones entre entidades en lugar de roles o atributos aislados. Cómo ReBAC responde '¿estás conectado con este recurso de la forma correcta?', la tupla de relación y las reescrituras de userset en el corazón de Google Zanzibar, cómo una comprobación de permiso se vuelve un recorrido de grafo, los problemas de consistencia y rendimiento que Zanzibar tuvo que resolver, y el ecosistema que generó — OpenFGA, SpiceDB, Permify y Ory Keto.

La pregunta que los modelos anteriores esquivaban

Cada modelo hasta ahora respondía la autorización con una propiedad del sujeto o del recurso. RBAC preguntaba “¿qué rol ocupas?”. ABAC preguntaba “¿qué atributos llevan tú y el recurso?”. PBAC preguntaba “¿qué dice la política sobre esos atributos?”. Pero una enorme fracción de las decisiones de acceso que toma el software real no tratan realmente de roles ni de atributos — tratan de relaciones. Puedes editar este documento porque perteneces al equipo que posee la carpeta donde vive. Puedes ver esta foto porque quien la publicó es tu amigo. Puedes aprobar este gasto porque eres el jefe de quien lo presentó. Fíjate en que ninguna de esas frases nombra un rol ni prueba un atributo; cada una traza una conexión desde el sujeto, a través de otras entidades, hasta el recurso.


El Control de Acceso Basado en Relaciones (ReBAC) toma esa observación y la convierte en todo el modelo. El acceso se concede cuando el sujeto está conectado con el recurso a través de una cadena permitida de relaciones. Representa cada relación como una arista de un grafo — Sara es miembro de Ingeniería, Ingeniería es editora de /research, /research es padre de roadmap.md — y una pregunta de autorización se convierte en una pregunta de alcanzabilidad: ¿existe un camino permitido desde este sujeto hasta este recurso? Si lo hay, permite; si no, deniega. Ese es todo el núcleo conceptual, y su elegancia es la razón por la que hoy sostiene los sistemas de autorización de algunas de las empresas de software más grandes del planeta.


Este artículo es el último del recorrido modelo por modelo. Cierra una progresión que se ha ido construyendo en silencio: de el dueño decide (DAC), a la etiqueta decide (MAC), a el rol decide (RBAC), a el atributo decide (ABAC), a la política decide (PBAC), y ahora a la relación decide. Cada modelo respondió “¿en qué debe basarse el acceso?” con un sustantivo distinto. La respuesta de ReBAC — las conexiones entre las cosas — resulta ser la que encaja con el software colaborativo, jerárquico y centrado en compartir como ninguna otra lo lograba.


Un poco de historia: el problema de autorización de Google

ReBAC como idea es anterior a su fama — el trabajo académico sobre control de acceso basado en relaciones se remonta a finales de la década de 2000, planteado alrededor de redes sociales donde “amigo de un amigo” es literalmente un camino en un grafo. Pero el modelo se volvió una fuerza de la industria en 2019, cuando Google publicó un artículo describiendo Zanzibar, su sistema de autorización global interno. Google tenía un problema muy concreto: decenas de productos — Drive, Docs, Calendar, YouTube, Photos, Cloud — cada uno necesitaba responder “¿puede este usuario hacer esto a este objeto?”, los objetos se contaban por billones, las comprobaciones llegaban a los millones por segundo, y una respuesta equivocada significaba o una función rota o una filtración de privacidad en los titulares. Construir un sistema de autorización separado por producto era como habían empezado, y no escalaba ni organizativa ni técnicamente.


La intuición de Zanzibar fue convertir la autorización en un servicio único, uniforme y basado en relaciones que todo producto pudiera compartir. Modela todos los permisos como tuplas de relación, guárdalos en una única base de datos a escala planetaria, y expón una API pequeña — sobre todo una llamada Check (“¿se cumple esta relación?”) — que cualquier producto pueda invocar. El artículo hizo dos cosas que reconfiguraron la industria: demostró que ReBAC funciona a escala extrema, y publicó las respuestas de ingeniería a los problemas difíciles que la escala crea — consistencia y rendimiento — a los que llegaremos. En pocos años, Zanzibar había inspirado a toda una generación de motores de código abierto y comerciales construidos para llevar el mismo modelo a todos los demás. Cuando hoy alguien dice “autorización estilo Zanzibar”, se refiere a ReBAC.


La unidad atómica: la tupla de relación

Todo en ReBAC se construye a partir de un hecho diminuto y uniforme llamado tupla de relación (o “tupla de relación”). Su forma es deliberadamente mínima:


⟨objeto⟩#⟨relación⟩@⟨sujeto⟩

Léela de derecha a izquierda como una frase: este sujeto tiene esta relación con este objeto. Unas cuantas tuplas concretas describen nuestro escenario recurrente:


document:roadmap#editor@user:sara        // Sara es editora del documento roadmap
folder:research#parent@document:roadmap  // roadmap vive en la carpeta research
folder:research#editor@user:sara         // Sara es editora de la carpeta research
group:eng#member@user:daniel             // Daniel es miembro del grupo de ingeniería

Cada tupla es una arista única e independiente en el grafo de autorización. Aquí no hay un modelo de objetos cargado de esquema, ni una tabla de permisos por aplicación — solo un flujo uniforme de estos pequeños hechos. Esa uniformidad es la clave: como cada permiso de cada producto se expresa como el mismo tipo de tupla, un solo motor puede almacenar y evaluar la autorización de todos ellos. Conceder acceso es escribir una tupla; revocarlo es borrar una. El conjunto completo de tuplas, en su conjunto, es el grafo que el motor recorre para responder cualquier pregunta.



Usersets y reescrituras: donde vive el poder

Si las tuplas fueran siempre objeto#relación@user:alguien, ReBAC sería poco más que una lista de control de acceso distribuida — expresiva pero plana. El salto viene de dos características que permiten que las relaciones sean calculadas en lugar de solo almacenadas.


La primera es el userset: el sujeto de una tupla puede ser él mismo un conjunto de usuarios definido por otra relación, no un único usuario. Escribir folder:research#editor@group:eng#member dice “los editores de la carpeta research incluyen a todo miembro del grupo de ingeniería”. Ahora añadir a Daniel a group:eng#member lo convierte en silencio en editor de la carpeta, sin cambiar ninguna tupla de la carpeta. Esta es exactamente la indirección de grupos que nos dio RBAC, pero generalizada: cualquier relación puede apuntar al conjunto de sujetos de cualquier otra relación, de modo que grupos, equipos y membresías anidadas surgen de la misma primitiva.


La segunda es la regla de reescritura (o “reescritura de userset”), declarada en el modelo y no en los datos. Una reescritura define una relación en términos de otras relaciones. Dominan dos patrones. Unión / implicación — “un viewer es cualquiera que sea directamente visor o sea editor” — codifica jerarquías de permiso (los editores obviamente pueden ver) sin duplicar tuplas. Tuple-to-userset (la joya de la corona) — “los viewer de un documento incluyen a los viewer de su carpeta parent” — codifica herencia: define la visualización una vez sobre las carpetas y todo documento dentro la hereda a través de la arista parent. Ese único mecanismo es cómo ReBAC expresa la herencia de permisos por árbol de carpetas que todo producto de compartición de archivos necesita y que RBAC y ABAC manejan con torpeza.


Junta las dos y un modelo compacto más un puñado de tuplas expresa reglas que en otros modelos exigirían tablas de roles desbordadas o políticas ABAC intrincadas: Sara puede ver roadmap.md porque es editora de la carpeta (editor implica visor), y roadmap.md hereda sus visores de esa carpeta (tuple-to-userset). Ninguna tupla dijo jamás “Sara puede ver roadmap.md” — el motor lo derivó siguiendo aristas. Esa derivación es la esencia de ReBAC.


Grafo de relaciones ReBAC: los permisos viven en las conexiones Un grafo de relaciones dibujado a mano. Sara (usuaria) --miembro de--> Ingeniería (grupo) --editor de--> /research (carpeta) --padre de--> roadmap.md (documento), todos conectados por un camino grueso verde, anotado "existe un camino ⇒ acceso concedido". Debajo, Daniel (usuario) está aislado sin relaciones; una línea gris punteada hacia el grupo Ingeniería termina en una X, anotada en rojo "sin camino ⇒ sin acceso". Sara usuaria miembro de Ingeniería grupo editor de /research carpeta padre de roadmap.md documento existe un camino ⇒ acceso concedido Daniel usuario sin camino ⇒ sin acceso
ReBAC visto como grafo. Los permisos no se guardan en el sujeto ni en el recurso; emergen de las conexiones entre entidades. Una comprobación tiene éxito cuando existe un camino permitido del sujeto al recurso — Sara alcanza roadmap.md a través de su grupo y su carpeta — y falla cuando no existe tal camino, como con Daniel.

Responder una comprobación es recorrer un grafo

Como los permisos son aristas y los permisos derivados son reglas de reescritura, responder la pregunta central — Check(document:roadmap, viewer, user:sara), “¿puede Sara ver el roadmap?” — es una búsqueda en grafo. El motor arranca en el par (objeto, relación) solicitado y lo expande según el modelo hasta que encuentra al sujeto o agota el grafo alcanzable. Conceptualmente:


Check(document:roadmap, viewer, sara)?
  viewer(roadmap) = visores directos de roadmap
                  ∪ editores de roadmap             (reescritura de unión: editor implica visor)
                  ∪ visores del parent de roadmap   (tuple-to-userset: heredar de la carpeta)
  → seguir la arista parent: folder:research
  → viewer(research) ⊇ editor(research) ∋ sara      (Sara es editora de la carpeta)
  → PERMITE

El diagrama de abajo muestra esa resolución tal como el motor la realiza en realidad — una expansión recursiva de la relación objetivo a través de aristas de unión y herencia hasta alcanzar al sujeto o agotar la búsqueda.


flowchart TD
  accTitle: Resolver una comprobación de permiso ReBAC como recorrido recursivo de grafo
  accDescr: La evaluación empieza en un nodo que pregunta si Sara es visor del documento roadmap. Se expande en tres ramas según el modelo de autorización. La primera rama comprueba los visores directos del documento y no encuentra ninguno. La segunda rama es una reescritura de unión que incorpora a los editores del documento, tampoco ninguno directamente. La tercera rama es una reescritura tuple-to-userset que sigue la arista padre del documento hasta la carpeta research y pregunta si Sara es visor de esa carpeta. Eso se expande a si Sara es editora de la carpeta, lo cual confirma una tupla almacenada. Como se encuentra un camino hasta Sara, el resultado global es permite. Si ninguna rama hubiera alcanzado a Sara, el resultado sería deniega.
  Q["Check: viewer de document:roadmap = user:sara?"] --> D["Visores directos de roadmap"]
  Q --> E["Unión: editores de roadmap<br/>(editor implica visor)"]
  Q --> P["Tuple-to-userset:<br/>seguir arista parent"]
  D --> DN["ninguno"]
  E --> EN["ninguno directo"]
  P --> F["visor de folder:research?"]
  F --> FE["editor de folder:research?"]
  FE --> T["tupla: folder:research#editor@user:sara ✓"]
  T --> Y["PERMITE — camino hasta Sara"]
  DN -.-> Y
  EN -.-> Y
Resolver una comprobación ReBAC recorriendo el grafo. El motor expande la relación solicitada (visor del roadmap) según las reglas de reescritura del modelo — una comprobación directa, una unión que incorpora a los editores y un salto tuple-to-userset que hereda los visores de la carpeta padre — siguiendo aristas de relación hasta alcanzar al sujeto y devolver permite, o agotar el grafo alcanzable y devolver deniega.

Este modelo de recorrido es lo que hace que ReBAC responda una pregunta que los otros modelos encuentran genuinamente difícil: “¿quién tiene acceso a este objeto concreto?”. En RBAC tendrías que enumerar cada rol que concede el permiso y cada usuario en esos roles; en ABAC tendrías que evaluar la política contra cada usuario. En ReBAC, “¿quién puede ver roadmap.md?” es simplemente el recorrido ejecutado a la inversa — expande la relación viewer del objeto y recolecta todo sujeto que el grafo alcanza. Ese poder de búsqueda inversa (Zanzibar lo llama Expand; otros lo llaman “list objects” o “list users”) es una operación de primera clase, y por eso los motores ReBAC son el backend natural de los diálogos de “compartir” y los paneles de “personas con acceso”.


Cómo se compara ReBAC con los modelos anteriores

Los modelos son complementarios, no competidores, y cada uno responde mejor una pregunta distinta. Ayuda alinearlos:


ModeloPregunta centralLos permisos vienen deEncaje naturalPunto débil
RBAC¿Qué rol ocupas?Asignaciones de rolFunciones laborales establesCompartición por objeto, herencia
ABAC¿Qué atributos aplican?Atributos de sujeto/recurso/entornoReglas contextuales, de grano finoConsultas “¿quién puede acceder a X?”
PBAC¿Qué dice la política?Política formal externalizadaConsistencia entre muchas apps(Vehículo, no base de decisión)
ReBAC¿Cómo estás conectado?Aristas del grafo de relacionesColaboración, jerarquía, compartirCondiciones de tiempo/riesgo/importe

La fila que más importa para ReBAC es la última. Su encaje natural — colaboración, jerarquía, compartir — es precisamente el caso que RBAC y ABAC manejan peor, porque esos escenarios tratan de objetos individuales relacionados con sujetos individuales, no de roles amplios ni de atributos intrínsecos. Y su punto débil — condiciones sobre tiempo, riesgo o importe — es exactamente el territorio de ABAC. Esa simetría es la razón por la que la frontera de la autorización no es “elige uno” sino “combina el grafo con condiciones”, un híbrido al que volvemos abajo.


Los dos problemas difíciles que Zanzibar tuvo que resolver

La idea de ReBAC es simple; hacerla funcionar a la escala de Google sacó a la luz dos problemas profundos que cualquier motor de relaciones serio debe afrontar. Entenderlos separa un juguete de un sistema de producción.


Consistencia y el problema del “nuevo enemigo”

Los datos de autorización cambian constantemente, y a menudo se replican entre regiones por velocidad. Eso crea una ventana peligrosa: si una comprobación de permiso puede leer datos replicados obsoletos, podría conceder un acceso que acaba de ser revocado — o, peor, honrar una concesión antigua en combinación con un objeto nuevo. Zanzibar bautizó la forma más aguda de esto como el problema del “nuevo enemigo”. Imagínalo: Sara quita a un excompañero de un documento, y luego añade contenido sensible. Si una comprobación posterior para ese compañero lee una réplica donde la eliminación aún no ha llegado, el “nuevo enemigo” ve contenido del que fue específicamente excluido antes de que existiera. Las dos escrituras fueron ordenadas correctamente por la aplicación, pero las lecturas obsoletas las reordenaron, produciendo una brecha real.


La respuesta de Zanzibar es el “zookie” — un pequeño token de snapshot opaco devuelto cuando se escriben datos. Cuando la aplicación realiza después una comprobación, puede pasar el zookie para decir “evalúa esto al menos tan fresco como aquella escritura”. El motor entonces garantiza que la decisión refleja un snapshot no más antiguo que el token, cerrando la ventana. Esta es la encarnación específica de ReBAC de la tensión frescura-contra-latencia que ya has visto en sesiones, revocación de tokens, caché de atributos de ABAC y carga de datos de PBAC — la pregunta recurrente de la identidad “¿qué tan actuales son los datos sobre los que decido?” — aquí respondida con un token que permite a quien llama exigir la frescura que una decisión concreta requiere.



Rendimiento: grafos profundos, presupuestos de latencia mínimos

El segundo problema es la velocidad. Un solo Check puede, en el peor caso, abrirse en abanico por un grafo profundo y ancho — grupos anidados dentro de grupos, carpetas dentro de carpetas — y aun así debe responder en milisegundos, y el sistema debe sostener millones de comprobaciones por segundo a nivel global. Un recorrido recursivo ingenuo que reexamine los mismos grupos en cada solicitud no puede cumplir ese presupuesto. Las respuestas de Zanzibar incluyeron caché agresivo de resultados intermedios, un índice especializado (apodado “Leopard”) que precalcula membresías de grupo aplanadas y transitivamente cerradas de modo que un “¿es X miembro de Y?” muy anidado sea una búsqueda rápida en lugar de un recorrido profundo, y hedging de solicitudes para domar la latencia de cola entre réplicas. No necesitas estos detalles internos para usar ReBAC, pero explican por qué los motores de relaciones son bases de datos hechas a propósito y no una tabla en el Postgres de tu app: responder alcanzabilidad sobre un grafo enorme y en constante cambio dentro de un presupuesto de un milisegundo es genuinamente difícil, y es la mayor parte de la ingeniería de un sistema estilo Zanzibar.


El ecosistema que Zanzibar generó

Zanzibar en sí es interno de Google, pero su artículo fue lo bastante detallado como para sembrar un ecosistema próspero de código abierto y comercial. La forma es siempre la misma — almacenar tuplas de relación, declarar un modelo con reglas de reescritura, exponer una API estilo Check/Expand — pero los proyectos difieren en lenguaje, gobernanza y énfasis:


MotorOrigenNotas
OpenFGAAuth0 / Okta, ahora CNCFEstándar abierto; DSL amigable y SDKs; las “conditions” añaden atributos estilo ABAC
SpiceDBAuthZedImplementación fiel de Zanzibar; controles de consistencia explícitos (“zedtokens” equivalentes al zookie)
PermifyPermifyMotor Zanzibar orientado a desarrolladores con herramientas de esquema
Ory KetoOryServidor de permisos de código abierto temprano inspirado en Zanzibar
Warrant / otrosvarios”Autorización como servicio” alojada sobre el mismo modelo

Dos merecen mención aparte. OpenFGA, nacido en Auth0 y donado a la Cloud Native Computing Foundation, se ha convertido en algo así como un estándar comunitario, con un DSL de modelado accesible y — algo importante — conditions que permiten a una relación llevar una prueba sobre atributos, mezclando ReBAC con ABAC (más sobre esto a continuación). SpiceDB, de AuthZed, es una reimplementación cercana y centrada en rendimiento del diseño de Zanzibar, que expone controles de consistencia (sus “zedtokens” son zookies con otro nombre) para que quien llama pueda intercambiar frescura por latencia en cada solicitud. Lo que todos comparten es el pacto esencial de ReBAC: modela tu dominio como relaciones una vez, y toda pregunta de autorización se vuelve una consulta contra un único grafo.


Cómo se ve el modelo en la práctica

Para hacerlo concreto, aquí está el escenario recurrente como un modelo de autorización estilo OpenFGA. Fíjate en que declara tipos, sus relaciones y las reescrituras — esto es el esquema, distinto de los datos de las tuplas:


model
  type user
 
  type group
    relations
      define member: [user, group#member]      // los grupos pueden anidarse
 
  type folder
    relations
      define editor: [user, group#member]
      define viewer: [user, group#member] or editor   // editor implica visor
 
  type document
    relations
      define parent: [folder]
      define editor: [user, group#member] or editor from parent
      define viewer: [user, group#member] or editor or viewer from parent

Las frases editor from parent y viewer from parent son la herencia tuple-to-userset; or editor es la implicación por unión. Diez líneas de modelo más un flujo de tuplas expresan ahora herencia por árbol de carpetas, grupos anidados y jerarquías de permiso — un conjunto de reglas que en los otros modelos se desbordaría por decenas de roles o una gruesa política ABAC.


Dónde brilla ReBAC — y dónde se tensa

El punto dulce de ReBAC es inconfundible una vez que tienes el modelo en la cabeza. El software colaborativo — documentos, carpetas, repositorios, tableros, wikis — está construido con relaciones: dueños, editores, visores, compartición y contención. Las jerarquías — organizaciones, árboles de carpetas, grupos de recursos, estructuras multi-inquilino de clientes — son exactamente las aristas padre/hijo que tuple-to-userset fue diseñado para recorrer, de modo que un conjunto de permisos puesto una vez en la cima desciende gratis. Las plataformas sociales y de contenido — donde la visibilidad sigue a la amistad, el seguimiento o la propiedad — son grafos de relaciones por su propia naturaleza. Y cualquier producto que deba renderizar “¿quién tiene acceso a esto?” o “¿qué puede alcanzar este usuario?” obtiene esas consultas como recorridos de primera clase en lugar de escaneos costosos. Si tus frases de autorización contienen naturalmente la palabra “porque” seguida de una cadena de propiedad o membresía, ReBAC es con mucha probabilidad el modelo correcto.


La tensión aparece cuando el acceso depende de cosas que no son relaciones. “Solo en horario laboral.” “Solo si el dispositivo está gestionado.” “Solo para transacciones por debajo de 10.000.” “Solo si la puntuación de riesgo es baja.” Estas son condiciones ambientales y calculadas — la competencia central de ABAC — y un grafo de relaciones puro no tiene un lugar natural donde ponerlas. La respuesta histórica era anteponer una comprobación ABAC a la comprobación ReBAC en el código de la aplicación, lo cual funciona pero parte la lógica de autorización en dos. La respuesta moderna son las relaciones condicionales: motores como OpenFGA permiten ahora que una tupla lleve una condición (una pequeña expresión sobre atributos) que debe cumplirse para que la arista cuente, de modo que “editor mientras la hora actual esté dentro del horario laboral” se convierte en una única arista condicionada. Esa convergencia — un grafo de relaciones con condiciones sobre atributos en sus aristas — es hacia donde se dirige la autorización de grano fino, y es la forma práctica de los híbridos RBAC-más-ABAC-más-ReBAC que diseñarás en el artículo final.



Un ejemplo resuelto: el roadmap de Sara, resuelto como relaciones

Hemos resuelto el acceso de Sara a /research/roadmap.md bajo cada modelo de este módulo; ReBAC lo resuelve como un grafo. Las tuplas dicen solo los hechos llanos: Sara es member de group:eng; group:eng#member es editor de folder:research; document:roadmap tiene parent folder:research. Ninguna tupla menciona a Sara y el roadmap juntos. Cuando la app pregunta Check(document:roadmap, viewer, user:sara), el motor deriva la respuesta: viewer del documento incluye viewer del parent; el parent es folder:research; viewer de la carpeta incluye editor; editor de la carpeta incluye group:eng#member; Sara es miembro — permite. Cada salto fue una relación almacenada; el permiso fue calculado.


Ahora observa con qué naturalidad se propaga el cambio, que es el superpoder silencioso de ReBAC. Mueve el documento a otra carpeta — escribe una nueva tupla parent — y todo su conjunto de permisos cambia al instante al de esa carpeta, porque el acceso siempre se heredó, nunca se copió. Añade a Daniel a group:eng — una tupla — e inmediatamente se vuelve editor de la carpeta y de todo documento dentro de ella, sin tocar nada en esos objetos. Revoca borrando la tupla de membresía, y el acceso derivado se desvanece en la siguiente comprobación. Compara esto con RBAC, donde re-emparentar un documento significa re-derivar qué roles deberían concederlo, o con ABAC, donde re-evaluarías una política por usuario. En ReBAC el grafo es el modelo de permisos, así que editar el grafo es editar permisos — directamente, localmente y con toda la estructura heredada preservada. Ese es el beneficio que el modelo entero se construyó para entregar.


Hay un límite incluso aquí, y es la costura hacia el resto del módulo. Supón que vuelve la regla de la fintech de antes: un agente de soporte puede editar una cuenta solo en horario laboral y solo si hay un ticket abierto. “Asignado al agente” y “pertenece a la cuenta” son relaciones que ReBAC expresa de maravilla — pero “en horario laboral” y “hay un ticket abierto” son condiciones, no conexiones. Un grafo puro no puede sostenerlas; necesitas aristas condicionadas o una comprobación ABAC acompañante. Ese hueco entre conexión y condición es exactamente por qué los modelos de autorización rara vez aparecen solos en producción, y por qué el siguiente modelo se propuso unificarlos bajo una abstracción única y más general.


Recapitulación

El Control de Acceso Basado en Relaciones deriva permisos de un grafo de conexiones entre entidades:


  1. Relaciones, no roles ni atributos. El acceso se concede cuando el sujeto está conectado con el recurso por una cadena permitida de relaciones; la pregunta de autorización se vuelve “¿existe un camino permitido?” — un recorrido de grafo.
  2. La tupla es el átomo. Cada permiso es un hecho uniforme objeto#relación@sujeto; un userset permite a una tupla apuntar a un conjunto de sujetos, y las reglas de reescritura (unión y tuple-to-userset) calculan relaciones, dando grupos, jerarquías de permiso y herencia a partir de una primitiva diminuta.
  3. Zanzibar lo hizo real a escala y tuvo que resolver dos problemas difíciles: consistencia (el problema del “nuevo enemigo”, respondido con “zookies” de snapshot) y rendimiento (caché más un índice de cierre transitivo para recorrer grafos profundos en milisegundos).
  4. Le siguió un ecosistema rico — OpenFGA, SpiceDB, Permify, Ory Keto — todos almacenando tuplas, declarando un modelo y exponiendo Check/Expand.
  5. Brilla en colaboración, jerarquía y compartición, responde “¿quién puede acceder a esto?” de forma nativa, y solo se tensa con condiciones como el tiempo o el riesgo — por eso los motores modernos añaden conditions sobre atributos a las aristas, convergiendo ReBAC con ABAC.


Tres preguntas para autoevaluarte

  1. Expresa la frase “puedes editar este documento porque eres miembro del equipo que posee su carpeta” como un conjunto de tuplas de relación ReBAC más las reglas de reescritura necesarias para derivar el permiso de edición. Identifica qué regla hace la herencia y cuál hace la indirección de grupos.
  2. Explica el problema del “nuevo enemigo” con tus propias palabras, incluyendo por qué las dos escrituras implicadas fueron ordenadas correctamente por la aplicación, y describe cómo un token de snapshot (“zookie”) previene la brecha sin obligar a cada comprobación a leer los datos más frescos posibles.
  3. Un equipo quiere aplicar “un editor puede editar una cuenta solo en horario laboral”. Explica por qué un grafo de relaciones puro no puede expresar la condición de tiempo, y describe dos formas de manejarla (una comprobación ABAC acompañante o una arista condicionada). ¿Cuál mantiene la lógica de autorización en un solo lugar?

Ejercicios prácticos

  1. Modela un árbol de carpetas en OpenFGA. Usando el playground de OpenFGA, declara los tipos user, folder y document con relaciones viewer/editor, herencia parent (viewer from parent) y editor implica viewer. Añade tuplas que hagan a un usuario editor de una carpeta superior, luego ejecuta un Check que demuestre que puede ver un documento tres niveles más abajo. Borra una tupla y observa cómo desaparece el acceso.
  2. Escribe la consulta inversa. Para el mismo modelo, usa la operación “list objects” (Expand) para responder “¿qué documentos puede ver este usuario?” y “¿quién puede ver este documento?”. Fíjate en cómo estas consultas — escaneos costosos en RBAC o ABAC — son recorridos nativos aquí.
  3. Encuentra la costura. Toma una regla de autorización de un sistema que conozcas y divídela en su parte de relación (“…porque posee/pertenece a/gestiona…”) y su parte de condición (“…pero solo si tiempo/importe/riesgo…”). Decide cuál pertenece a un grafo de relaciones y cuál necesita una condición sobre atributos, y esboza cómo una arista condicionada dejaría a un único motor ReBAC llevar ambas.

Preguntas frecuentes

¿Qué es el Control de Acceso Basado en Relaciones (ReBAC)?

El Control de Acceso Basado en Relaciones es un modelo en el que los permisos se derivan de las relaciones entre entidades y no de roles o atributos aislados. El acceso se concede cuando un sujeto está conectado con un recurso a través de una cadena permitida de relaciones — por ejemplo, puedes editar un documento porque eres miembro del equipo que posee la carpeta donde vive el documento. ReBAC representa esas relaciones como un grafo y responde una solicitud de autorización comprobando si existe un camino válido entre el sujeto y el recurso. Es el modelo detrás de Google Zanzibar y sus sucesores, y encaja de forma natural en el software colaborativo donde compartir y anidar definen quién puede hacer qué.

¿Qué es una tupla de relación en ReBAC?

Una tupla de relación es la unidad atómica de los datos de ReBAC: un pequeño hecho de la forma objeto#relación@sujeto, que se lee como 'este sujeto tiene esta relación con este objeto'. Por ejemplo, document:roadmap#editor@user:sara significa que Sara es editora del documento roadmap, y folder:research#parent@document:roadmap significa que el roadmap vive en la carpeta research. Las tuplas pueden apuntar a otros conjuntos de usuarios en lugar de a uno solo — group:eng#member@user:sara más folder:research#editor@group:eng#member expresa 'todo miembro del grupo de ingeniería es editor de la carpeta research'. El conjunto completo de tuplas es el grafo que el motor de autorización recorre para responder una comprobación.

¿Qué es Google Zanzibar?

Zanzibar es el sistema de autorización global de Google, descrito en un artículo de 2019, que almacena permisos como tuplas de relación y responde miles de millones de comprobaciones de autorización por segundo en productos como Drive, YouTube, Calendar y Cloud. Popularizó ReBAC e introdujo el ahora estándar modelo de tupla más reescritura de userset, junto con respuestas de ingeniería a la consistencia a escala — sobre todo los 'zookies', tokens de snapshot que permiten a quien llama exigir una decisión al menos tan fresca como una escritura previa para evitar el problema del 'nuevo enemigo'. Zanzibar es el ancestro directo de motores de código abierto como OpenFGA, SpiceDB y Permify.

¿Cuál es la diferencia entre RBAC, ABAC y ReBAC?

RBAC decide a partir de los roles de un sujeto ('¿eres editor?'), ABAC decide a partir de atributos del sujeto, el recurso, la acción y el entorno ('¿tu región coincide con la del recurso?'), y ReBAC decide a partir de relaciones entre entidades ('¿estás conectado con este recurso por un camino permitido — miembro del grupo que posee la carpeta donde vive?'). RBAC es fuerte para funciones laborales estables, ABAC para reglas contextuales y de grano fino, y ReBAC para permisos jerárquicos, compartidos y por objeto como los de las apps colaborativas. Son complementarios, no rivales, y los sistemas modernos combinan cada vez más grafos de relaciones con condiciones sobre atributos.

¿Cuándo conviene usar ReBAC?

ReBAC encaja cuando el acceso se define por cómo están conectadas las entidades y no por roles fijos: documentos y carpetas colaborativos con compartición y herencia, jerarquías multi-inquilino donde los permisos descienden por un árbol organizativo, plataformas sociales y de contenido donde la visibilidad sigue a la amistad o la propiedad, y cualquier sistema que deba responder eficientemente '¿quién tiene acceso a este objeto concreto?'. Por sí solo es menos apto para reglas que dependen de condiciones ambientales o calculadas como la hora del día, el riesgo del dispositivo o el importe de una transacción — ese es el fuerte de ABAC, y por eso ambos se combinan con frecuencia.