Published

Runbook · OpenFGA — el grafo de permisos

Connect any source, model it as an ontology, transform it, and operationalize it, analytics, automation and machine learning, under one governed, self-hostable roof. --- Most teams stitch the...

Runbook · OpenFGA — el grafo de permisos

F4·0 · COMPLETADO 2026-08-06/07. El sustrato ReBAC del que penden la autorización de
Trino (vía el bridge OPA) y, más adelante, el filtrado del grafo semántico.

El porqué está en catalogo-como-origen-del-grafo.md
y ontology-projection.md. Aquí está el cómo.

⚠️ F4·0 despliega OpenFGA y NADA MÁS. LAKEKEEPER__AUTHZ_BACKEND sigue en
allowall
a propósito: encender el authorizer es F4·1, y va después de poblar los
permisos. Invertir el orden deja el catálogo deny-by-default y vacío — o sea, todo
roto a la vez.


🏁 Estado

PiezaValor
Servicioopenfga en Railway · proyecto cozy-comfort
Imagenopenfga/openfga:v1.14.0 (Lakekeeper exige ≥ v1.11; v1.14 es la que ellos prueban)
Datastoreopenfga, una BD propia en el Postgres que ya existía (el mismo servidor que usa Lakekeeper — un servicio menos, aislamiento lógico suficiente)
PuertosHTTP 8080 · gRPC 8081 · métricas 2112
Autenticaciónpreshared
ExposiciónNINGUNA — cero dominios públicos, sólo openfga.railway.internal
DeploymentSUCCESS

Los logs que lo cierran:

[INFO] running all migrations → migration done
[INFO] using 'preshared' authentication
[INFO] 🚀 starting gRPC server on '[::]:8081'
[INFO] 🚀 starting HTTP server on '0.0.0.0:8080'

1 · Cómo se levantó, y las tres cosas que no son obvias

① La imagen no arranca sola: necesita subcomando

openfga/openfga sin argumentos imprime la ayuda y sale — el servicio queda EXITED sin ningún error que lo explique. Hay que fijar el arranque explícitamente, igual que Lakekeeper (/home/nonroot/lakekeeper serve):

startCommand     = /openfga run
preDeployCommand = /openfga migrate

② La migración va en preDeployCommand, no encadenada

openfga migrate es un one-shot que crea las tablas e índices. No se puede hacer migrate && run: la imagen es mínima y no hay shell donde encadenar. Railway tiene preDeployCommand justo para esto, y lo corre antes de cada despliegue — migrate es idempotente, así que repetirlo es gratis.

③ La CLI no expone el startCommand — se pone por la API

railway add --image crea el servicio, pero no hay flag para el comando de arranque. Se fija con la API GraphQL:

mutation($e:String!,$s:String!,$i:ServiceInstanceUpdateInput!){
  serviceInstanceUpdate(environmentId:$e, serviceId:$s, input:$i)
}
# input: { startCommand: "/openfga run", preDeployCommand: ["/openfga migrate"] }

⚠️ Y después hay que forzar un DESPLIEGUE NUEVO, no un redeploy. railway redeploy reusa el deployment anterior con su configuración vieja — se queda EXITED otra vez y parece que el cambio no se guardó. El que vale es serviceInstanceDeployV2.

El token de la API está en ~/.railway/config.jsonuser.accessToken.


2 · Seguridad — dos capas, y la segunda no era opcional

① Sin exposición públicacero dominios. Sólo alcanzable en openfga.railway.internal
preshared authenticationel primer arranque logueó [WARN] authentication is disabled — OpenFGA por defecto no autentica nada. En una red privada es tolerable; como única capa, no

La clave vive en las variables del servicio (OPENFGA_AUTHN_PRESHARED_KEYS), y es la que Lakekeeper necesitará en F4·1. Se lee con railway variables --service openfga --kv; no está en git ni debe estarlo.

⚠️ Si algún día se le pone dominio público, la preshared key deja de bastar — un token estático en internet es una llave sin caducidad. Ese día toca OIDC (OPENFGA_AUTHN_METHOD=oidc), que OpenFGA soporta y Keycloak ya puede emitir.


3 · Verificación

Lo que está verificado: deployment SUCCESS, migración hecha, autenticación preshared activa y los dos servidores escuchando.

Lo que NO está verificado todavía, y es a propósito: que alguien le hable. Como no tiene dominio público, la prueba real es Lakekeeper conectando en F4·1 — y ése es el gate honesto. Un /healthz desde fuera no se puede hacer sin exponerlo, y exponerlo para probarlo sería empeorar lo que se quiere comprobar.

Para diagnóstico interno hay SSH (railway ssh --service <x>), con la clave ya registrada. [confirmar] el known_hosts: la primera conexión falla con Host key verification failed.


4 · Lo que viene, y el ORDEN importa

FaseQuéPor qué en este orden
F4·0desplegar OpenFGAinerte: nadie lo usa todavía
F4·1conectar Lakekeeper (LAKEKEEPER__OPENFGA__*) y poblar los permisos desde principal_grants⚠️ poblar ANTES de flipear. El flip a openfga es deny-by-default: con el store vacío, todo deja de funcionar a la vez
F4·2LAKEKEEPER__AUTHZ_BACKEND=openfgael flip. Rollback = volver a allowall, una variable
F4·3bridge OPA + Trinolos mismos 403 de F2, ahora decididos por el motor
F4·4🔬 el experimento de la proyección: un tipo propio relacionado con Table, y ver si check heredaes el que decide si el grafo hereda nativamente

⚠️ Y una limpieza pendiente que no depende de nada

Hoy conviven LAKEKEEPER__AUTHZ_BACKEND=allowall y LAKEKEEPER__CEDAR__POLICY_SOURCES__LOCAL_FILES apuntando a un fichero de políticas. Cedar no está en el build OSS y nadie lee ese fichero: es «una configuración que parece aplicada y no lo está», que es la trampa que ya costó una tarde. Se quita al flipear a openfga.


5 · Rollback

NivelCómo
El flip de F4·2LAKEKEEPER__AUTHZ_BACKEND=allowall — una variable
El servicio enteroborrar openfga en Railway. La BD openfga sobrevive y se puede reusar; para limpiarla, DROP DATABASE openfga

Nada de esto toca el dato. OpenFGA guarda tuplas de permisos, no filas del Warehouse.


Cruza con: catalogo-como-origen-del-grafo.md · ontology-projection.md · f4-opa-reconocimiento.md (el terreno medido) · infra/lakekeeper/policies/README.md (Cedar, y por qué no).