id: ADR-017 title: La autenticación entrante resuelve los principales canónicos antes de la autorización date: 2026-08-14 status: propuesto relates-to:
- ADR-010
- https://github.com/zeroclaw-labs/zeroclaw/issues/7141
- https://github.com/zeroclaw-labs/zeroclaw/issues/8289
- https://github.com/zeroclaw-labs/zeroclaw/issues/8290
- https://github.com/zeroclaw-labs/zeroclaw/issues/8076
- https://github.com/zeroclaw-labs/zeroclaw/issues/7142
- https://github.com/zeroclaw-labs/zeroclaw/issues/6996
- https://github.com/zeroclaw-labs/zeroclaw/pull/8063
- https://github.com/zeroclaw-labs/zeroclaw/pull/8272
- crates/zeroclaw-api/src/principal.rs
- crates/zeroclaw-api/src/grants.rs
- crates/zeroclaw-runtime/src/security/auth_provider.rs
- crates/zeroclaw-runtime/src/security/principal_resolver.rs
- crates/zeroclaw-runtime/src/rpc/dispatch.rs
- crates/zeroclaw-runtime/src/rpc/wss.rs
- crates/zeroclaw-memory/src/sqlite_permissions.rs
ADR-017: La autenticación entrante resuelve los principales canónicos antes de la autorización
Contexto
ZeroClaw tiene varias formas de que actores externos lleguen al daemon: RPC local, WSS remoto, la puerta de enlace web, clientes CLI y Zerocode, canales y futuras rutas de agente a agente. Antes del RFC aceptado #7141, esas superficies no compartían una respuesta aplicada de forma común a “¿quién está actuando?” y “¿qué puede hacer este actor?”.
TLS y los tokens de reconexión no son suficientes. TLS puede proteger una conexión sin demostrar que el cliente conectado tiene autoridad de ZeroClaw, y el mecanismo existente tui_id / tui_sig es continuidad de reconexión, no una prueba de identidad independiente. Un cliente WSS remoto, un usuario del navegador, un proceso local, un remitente de canal y un cliente de servicio deben converger en el mismo modelo de autorización antes de que comience cualquier trabajo privilegiado del runtime.
El riesgo no es solo la falta de autenticación en una ruta. El riesgo mayor es la existencia de sistemas de seguridad paralelos: tokens de emparejamiento nativos, credenciales de pares, claves SSH, contraseñas, subjects OIDC, remitentes de canales y credenciales de servicio, cada uno definiendo su propia identidad de usuario, vocabulario de roles, claves de propiedad y comportamiento de respaldo. Si eso ocurre, un claim admin de un proveedor, un nombre de usuario local o una cadena de subject reutilizada pueden eludir accidentalmente la política de la que depende otra superficie.
La RFC #7141 aceptada resuelve la dirección arquitectónica. Requiere que los proveedores verifiquen las credenciales, que un resolutor compartido asigne las identidades verificadas a principales canónicos de ZeroClaw y a concesiones de perfiles de permisos, y que las superficies de tiempo de ejecución consuman esos principales resueltos en lugar de reinterpretar las credenciales por sí mismas. La secuencia de implementación corresponde a #8289, mientras que el trabajo detallado sobre sesiones, memoria y autorización por remitente se sigue en #8290. Este ADR registra la decisión duradera sin afirmar que el despliegue esté completo.
Decisión
Separar la identidad entrante en verificación, resolución y aplicación
La autenticación entrante tiene tres etapas separadas:
- Un
AuthProviderverifica una credencial y devuelve una identidad autenticada con procedencia del proveedor, sujeto, tipo de actor, claims o vinculación con el listado local de usuarios, caducidad y metadatos de revalidación. - Un resolvedor compartido de ZeroClaw asigna esa identidad autenticada a un
PrincipalIdcanónico y a los permisos otorgados del perfil de permisos vigente. - Los controladores de despacho, los manejadores de gateway, las sesiones, la memoria, las herramientas, la configuración y las demás superficies de ejecución privilegiadas aplican el principal resuelto y los permisos concedidos.
El tipo de implementación en Rust puede combinar tipos internamente, pero los límites de autoridad siguen siendo independientes. Los proveedores verifican la identidad. No generan concesiones de ejecución de ZeroClaw, no reinterpretan los roles del IdP como permisos ni eluden el resolver compartido.
Usa principales canónicos que no puedan colisionar por accidente de cadena
A principal es la identidad duradera de ZeroClaw para el actor una vez que la autenticación se ha completado correctamente. La identidad del principal es globalmente inequívoca dentro de una implementación.
Las identidades humanas OIDC se identifican por el emisor validado y sub, no solo por sub. Un alias de proveedor puede aparecer en la salida de auditoría, pero no puede hacer que cadenas sub iguales de emisores distintos representen al mismo actor.
Las identidades locales se asignan mediante la configuración explícita del roster. Distintas credenciales locales solo pueden resolverse al mismo principal cuando la configuración las vincula. Un cambio de nombre visible en el roster debe conservar un identificador de principal estable o migrar de forma atómica los registros de sesión, memoria, aprobación y auditoría que le pertenecen.
client_credentials se resuelve a una entidad de servicio, no a un usuario humano. Las entidades de servicio no deben heredar sesiones del navegador, supuestos de usuario interactivo ni memoria privada de personas solo porque las afirmaciones tengan nombres similares.
La vinculación nativa sigue siendo una ruta de compatibilidad. A menos que se configure más adelante una asignación explícita de token a principal, un token de vinculación compartido se resuelve en el operador compartido y no en una persona concreta.
La igualdad de cadenas entre proveedores nunca vincula cuentas. La vinculación de cuentas entre proveedores requiere configuración explícita y una ruta de migración auditable.
Haz que los perfiles de permisos sean el único vocabulario de concesión en tiempo de ejecución
Los perfiles de permisos son el único vocabulario de autorización en tiempo de ejecución. Las notificaciones sin procesar del proveedor, los grupos de IdP, los nombres de usuario locales, los remitentes de canales o los nombres de clientes de servicio no otorgan ningún permiso hasta que el resolutor compartido los asigna a perfiles de permisos de ZeroClaw.
Cuando una identidad se asigna a varios perfiles de permisos, el resolutor inicial combina las concesiones explícitas mediante una unión determinista. Los selectores de grano fino se componen mediante intersección con la concesión de recurso correspondiente. Las listas de selectores vacías no conceden ninguna instancia, y el acceso amplio requiere una concesión explícita de comodín, de selector «todos» o de administrador.
Toda operación privilegiada de RPC, gateway, herramienta, configuración, sesión y memoria está clasificada y se deniega por defecto. Una ruta o método añadido sin clasificación no se permite implícitamente. El acceso administrativo no anula la propiedad; el acceso entre principales requiere una concesión administrativa explícita y genera un evento de auditoría.
Las semánticas de denegación explícita, los lenguajes de políticas específicos de cada proveedor, las APIs más amplias de administración de políticas y las distintas reglas de precedencia son decisiones separadas. No surgen como efectos secundarios de este ADR.
Mantén la autenticación y los permisos activos el tiempo suficiente para poder revocarlos
initialize es el protocolo de enlace de autenticación RPC. Solo se ejecutan los métodos mínimos necesarios para completar la autenticación antes de que se vincule un principal. Todo método privilegiado rechaza a los llamadores no autenticados.
La transformación de credenciales es explícita. Cuando un formato de credencial no identifica de forma segura a su proveedor, el handshake identifica el alias del proveedor previsto. Un bearer opaco no se envía a todos los endpoints de introspección, y un fallo con el método o proveedor seleccionado no puede recurrir a un acceso de operador compartido ni a una autoridad más amplia.
Las conexiones establecidas no mantienen instantáneas de autorización indefinidas. Antes de la siguiente operación privilegiada posterior a un cambio de generación de la política de autorización, el runtime vuelve a resolver los permisos efectivos a partir de la configuración actual de perfiles de permisos y de asignación de claims. Eliminar o restringir un perfil, una asignación, una entrada del roster, un proveedor o un token de emparejamiento debe afectar a la autorización establecida en el límite de generación o de revalidación documentado, en lugar de esperar a una reconexión o a un reinicio del daemon.
La caducidad de credenciales y la revocación del proveedor se aplican a las conexiones establecidas dentro de las garantías reales del proveedor. El Principal canónico, los registros de propiedad, los registros y los registros de auditoría siguen sin ser secretos. Si la revalidación en vivo necesita material de portador o un identificador secreto equivalente, el proveedor conserva únicamente ese material mínimo en un contexto de revalidación propiedad del proveedor, con alcance a la conexión, a través del límite de almacenamiento secreto compatible. Los consumidores de tiempo de ejecución ordinarios no pueden leerlo, y se destruye al desconectar, al caducar la credencial, al eliminar el proveedor o al revocarlo.
El propósito del token OIDC es explícito. El flujo Authorization Code con PKCE desde el navegador valida un ID token como evidencia del evento de autenticación y establece una sesión de ZeroClaw. Las rutas bearer de API y RPC aceptan únicamente un access token destinado a ZeroClaw. Device Authorization Grant cubre clientes humanos sin navegador, y client_credentials cubre principales de servicio. La validación JWT sin conexión está limitada por la expiración del token y por una duración máxima de autenticación configurada; los despliegues que necesiten una revocación más rápida deben usar introspección, revocación por canal posterior (back-channel) u otra autoridad en línea.
Aplicar la propiedad del principal en los límites de almacenamiento de sesiones y memoria
Cada sesión autenticada pertenece a un principal canónico. La búsqueda, aprobación, adjuntado, reanudación, modificación y eliminación de sesiones deben coincidir con ese propietario antes de que la operación tenga éxito. Los registros desconocidos, conflictivos o heredados sin propietario fallan de forma segura (fail closed) para los principales con ámbito, a menos que una migración documentada los asigne al principal del operador compartido.
La memoria privada se indexa por principal y agente y solo es visible para ese principal, a menos que una concesión administrativa explícita permita el acceso. La memoria compartida del agente es un ámbito independiente y solo es visible cuando está habilitada y concedida.
La propiedad del principal es una dimensión de almacenamiento adicional; no reemplaza las dimensiones de agente, sesión, espacio de nombres ni inquilino. Las lecturas, escrituras, upserts y eliminaciones de memoria privada incluyen la propiedad del principal en el predicado de almacenamiento atómico. Una comprobación previa seguida de una mutación más amplia, o una lectura seguida de un filtrado posterior, no es suficiente.
El trabajo iniciado internamente no debe elegir un propietario por accidente. Las ejecuciones programadas, iniciadas por SOP u otras ejecuciones no interactivas que escriben estado de sesión o de memoria con propietario necesitan una regla de principal explícita antes de que la primera porción de implementación dependa de un valor predeterminado.
Mantén las implementaciones de proveedor y de transporte separadas de la autoridad de autorización
Todas las superficies de entrada consumen el mismo modelo de principal y de perfil de permisos, pero no necesitan la misma implementación de transporte. El RPC local puede usar credenciales de par, el WSS remoto puede usar emparejamiento nativo u OIDC, la puerta de enlace web se autentica en el límite del enrutador, y los clientes CLI o Zerocode exponen flujos de inicio de sesión adecuados para cada proveedor.
La vinculación nativa y las credenciales de par local son rutas de compatibilidad obligatorias para el primer despliegue de aplicación, de modo que la autenticación remota de WSS no se publique en un estado aplicado pero inutilizable. OIDC es el primer proveedor externo obligatorio. El inicio de sesión en el navegador con contraseña local, el desafío-respuesta con clave SSH, la identidad mTLS, el aprovisionamiento al estilo SCIM, la identidad de canal y la identidad de agente a agente son extensiones compatibles, no requisitos de cierre para la primera entrega de OIDC, salvo que una decisión posterior los promueva.
Controles de aceptación
Este ADR permanece propuesto hasta que se cumplan todas estas condiciones:
-
el registro canónico de proveedores, el contrato de identidad autenticada, el modelo de identidad de principal, el vocabulario de perfiles de permisos, el resolutor compartido, el enrutamiento explícito de credenciales y la re-resolución de concesiones consciente de generaciones se entregan juntos con pruebas para el espacio de nombres, las identidades no asignadas, el comportamiento de denegación por defecto de los selectores y el rechazo de respaldo de proveedor;
-
emparejamiento nativo, credenciales locales del par, despacho de RPC, validación de inicio de WSS y continuidad de reconexión garantizan la autenticación por construcción sin crear un intervalo remoto aplicado pero inutilizable;
-
Los flujos OIDC JWT/JWKS, la introspección, Authorization Code con PKCE en el navegador, Device Authorization Grant sin navegador,
client_credentialspara servicios, la separación de propósito de los tokens, la revalidación acotada y la propagación del principal del gateway funcionan a través del mismo resolutor y fallan en modo cerrado (fail closed) cuando no hay credenciales, estado del proveedor o contexto de revalidación disponibles; -
las sesiones, aprobaciones, adjuntos, reanudaciones, eliminaciones, lecturas de memoria privada y mutaciones de memoria privada aplican la pertenencia del principal en el límite de almacenamiento, incluido el tratamiento documentado para registros heredados y una regla explícita de propietario de origen interno para el trabajo programado o iniciado por SOP;
-
existing remote WSS and Nevis users have documented and tested migration paths, and local-only recovery can repair lockout without restoring unauthenticated remote access;
Wait, I need to clarify: the source text is already English, and I’m to translate it to Spanish. Translating:
Los usuarios existentes de WSS remoto y de Nevis cuentan con rutas de migración documentadas y probadas, y la recuperación solo local puede resolver el bloqueo sin restaurar el acceso remoto no autenticado;
-
la documentación explica identidades, tipos de actor, mapeo de claims, perfiles de permisos, concesiones, memoria privada frente a memoria compartida, garantías del proveedor, migración, recuperación y el vocabulario de handshake alineado con estándares, cuando corresponda; y
-
La implementación se divide en límites de seguridad independientes, revisables y reversibles, rastreados en #8289 y #8290, en lugar de una única rama combinada que incluya proveedor, despachador, gateway, almacenamiento, migración y documentación.
La base neutral en cuanto a comportamiento del punto de costura Principal / AuthProvider y de las pruebas de contrato se ha integrado mediante #8063 y #8272. Esos fragmentos son solo una base de trabajo, no una prueba de que los criterios de aceptación completos de este ADR estén cumplidos.
Consecuencias
Consecuencias positivas:
-
Se pueden añadir nuevos proveedores entrantes sin que cada proveedor cree su propio sistema de autorización.
-
Un futuro revisor puede plantear una pregunta en cada límite privilegiado: ¿qué principal resuelto y qué permisos concedidos se están aplicando aquí?
-
OIDC, las credenciales locales, el emparejamiento nativo y las credenciales de servicio no pueden entrar en conflicto solo porque compartan una cadena.
-
Las revocaciones y los cambios de perfil de permisos tienen límites activos documentados, en lugar de esperar indefinidamente a una reconexión o un reinicio.
-
La aislamiento de sesión y de memoria privada se convierte en propiedades de almacenamiento en lugar de un filtrado de mejor esfuerzo por encima del almacén.
Hmm, correction for grammar: “El aislamiento” is masculine.
El aislamiento de sesión y de memoria privada se convierte en propiedades de almacenamiento en lugar de un filtrado de mejor esfuerzo por encima del almacén.
Consecuencias negativas:
- Este es un cambio incompatible en materia de seguridad para el comportamiento WSS remoto no autenticado, por lo que la compatibilidad nativa y la recuperación deben publicarse junto con la ruta de aplicación.
- El resolutor compartido, el vocabulario de perfiles y la revalidación consciente de generaciones añaden más infraestructura que una comprobación de roles local al proveedor.
- La implementación de OIDC debe preservar el propósito del token, el descubrimiento, la actualización de JWKS, la introspección y los límites de metadatos conformes con los estándares, en lugar de aceptar cualquier token con apariencia válida.
- Dado que la propiedad principal afecta al almacenamiento de sesiones y de memoria, la migración y la reversión requieren más cuidado que una comprobación de autenticación solo en el perímetro.
- Algunas extensiones útiles, como el inicio de sesión con contraseña, la autenticación con clave SSH, mTLS, SCIM, la identidad de canal y la identidad de agente a agente, siguen siendo trabajo de seguimiento independiente.
Referencias
- RFC #7141: Autenticación entrante conectable y principales canónicos
- Seguimiento #8289: hito OIDC: principales canónicos y autenticación entrante
- Tracker #8290: hito multiusuario: aislamiento por principal + autorización por remitente
- Issue #8076: proveedor local de usuario/contraseña
- Issue #7142: pipeline de decisiones de seguridad gestionado por el runtime (https://github.com/zeroclaw-labs/zeroclaw/issues/7142)
- Issue #6996: política de sandbox del sistema operativo
- PR #8063: Costura entre
PrincipalyAuthProvider - PR #8272: Pruebas de contrato de
PrincipalyAuthOutcome - ADR-010: Límites de autoridad de la memoria
- Modelo de seguridad
crates/zeroclaw-api/src/principal.rscrates/zeroclaw-api/src/grants.rs- crates/zeroclaw-runtime/src/security/auth_provider.rs
crates/zeroclaw-runtime/src/security/principal_resolver.rscrates/zeroclaw-runtime/src/rpc/dispatch.rscrates/zeroclaw-runtime/src/rpc/wss.rs- crates/zeroclaw-memory/src/sqlite_permissions.rs