Ir al contenido

Cuentas, usuarios y acceso

Tu organización es un tenant en CORE-M — tu propia porción aislada de la plataforma. Cada petición que tú y tu equipo hacen lleva una identidad que pertenece a tu tenant, y CORE-M responde dos preguntas en cada llamada: quién eres (autenticación) y tienes permiso para hacer esto (autorización). Los datos de tu tenant se acotan automáticamente a ti y nunca son visibles para ningún otro tenant.

Esta página explica todo lo que gestionas para tu propio tenant: usuarios y el modelo de roles, permisos de página basados en grupos, el ciclo de vida del JWT, el rate limiting de inicio de sesión, las claves de API, la configuración de SSO, y cómo el aislamiento mantiene tus datos separados.

Tu tenant es tu límite de aislamiento de nivel superior. Cuando se crea tu tenant obtienes:

  • Un tenant_id único que acota cada parte de tus datos.
  • Un usuario administrador inicial (rol tenant_admin), con la contraseña almacenada con hash bcrypt.
  • Una clave de API para acceso programático, devuelta una sola vez.
  • Un grupo por defecto llamado “All Users” con todos los permisos de página (dashboard, devices, telemetry, rules, anchors). Tu administrador inicial no se añade a él — los administradores omiten las comprobaciones de grupo a través de su rol.

Los nombres de tenant son únicos; un nombre duplicado se rechaza con ALREADY_EXISTS.

Cada usuario de tu tenant tiene exactamente un rol. Los roles definen el alcance administrativo y son de grano grueso; el acceso de grano fino para los usuarios estándar proviene de los grupos.

RolAlcanceQué otorga
platform_adminTodo el sistemaReservado para el equipo de plataforma de Kronox Data que opera CORE-M. No asignable por tu tenant.
tenant_adminTu tenantAcceso completo dentro de tu tenant: usuarios, grupos, dispositivos, reglas, claves de API y configuración. Omite los permisos de grupo dentro de tu tenant.
memberTu tenantUsuario estándar. El acceso se controla por completo mediante las membresías de grupo. Sin acceso a /manage/* ni /admin/*.

Los grupos son colecciones de usuarios acotadas al tenant con un conjunto definido de permisos de página. Un usuario puede pertenecer a varios grupos, y sus permisos efectivos son la unión deduplicada de los permisos de todos sus grupos.

Permisos de página disponibles:

PermisoDa acceso a
dashboardResumen del dashboard
devicesVer y gestionar dispositivos
telemetryDashboards y gráficos de telemetry
rulesVer y gestionar reglas
anchorsDatos de prueba en blockchain en las páginas de detalle de dispositivo

Reglas de permisos en la práctica:

  • Un member sin grupos no tiene ningún acceso y ve: “Tu cuenta no tiene permisos asignados. Contacta a tu administrador.”
  • Un member que intenta una acción fuera de sus permisos se rechaza con PERMISSION_DENIED y “missing permission: rules” (o la página correspondiente).
  • Cambiar los permisos de un grupo no reescribe los tokens en vivo. Los JWT existentes quedan obsoletos y adoptan los nuevos permisos en el siguiente refresco de token.
  • Eliminar un grupo quita a todos sus miembros y recalcula sus permisos efectivos, lo que puede retirarles el acceso a algunas páginas.

Los usuarios se autentican con email y contraseña. Las contraseñas se almacenan con hash bcrypt en reposo. Las respuestas de inicio de sesión son seguras frente a ataques de temporización (timing-safe) y nunca revelan si el email o la contraseña fueron incorrectos — un usuario inexistente es indistinguible de una contraseña errónea.

Un inicio de sesión exitoso emite dos tokens, ambos firmados con Ed25519:

  • Un access token, con expiración de 15 minutos, presentado en cada llamada a la API.
  • Un refresh token, con expiración de 7 días, usado únicamente para acuñar nuevos access tokens.
flowchart TD
  login([Login: email + password]) -->|valid| issue["Issue access (15 min)<br/>+ refresh (7 day)"]
  login -->|invalid| fail["UNAUTHENTICATED<br/>(timing-safe, no field hint)"]
  issue --> use["Call API with access token"]
  use -->|access valid| ok([Request authorized])
  use -->|access expired| refresh{Refresh token<br/>still valid?}
  refresh -->|yes| rotate["Issue new access token<br/>+ rotate refresh token<br/>(old refresh invalidated)"]
  rotate --> use
  refresh -->|no| relogin([Redirect to login])

El refresh es rotatorio: cada llamada RefreshToken invalida el refresh token anterior y emite uno nuevo junto con el nuevo access token. Un refresh token expirado se rechaza con UNAUTHENTICATED, lo que obliga a un nuevo inicio de sesión.

El access token se firma con Ed25519 usando la clave de la variable de entorno AUTH_SIGNING_KEY. Los servicios downstream verifican la firma y leen los claims — no vuelven a llamar al servicio de autenticación por cada petición.

Un member del tenant T1, en los grupos “Engineering” (devices, telemetry) y “Monitoring” (dashboard, rules), recibe un access token cuyo payload se ve así:

{
"sub": "9f2c1e44-1b3a-4c8e-9d77-6a0b2f5e1c90",
"tid": "1a2b3c4d-0000-4e5f-8a9b-112233445566",
"role": "member",
"groups": [
"grp-engineering-001",
"grp-monitoring-002"
],
"permissions": [
"dashboard",
"devices",
"rules",
"telemetry"
],
"iat": 1747396800,
"exp": 1747397700
}
ClaimSignificado
subID de usuario
tidTenant ID — la clave de aislamiento para todas las consultas downstream
roleUno de platform_admin, tenant_admin, member
groupsIDs de los grupos a los que pertenece el usuario
permissionsUnión deduplicada de todos los permisos de página de los grupos
iat / expEmitido-en y expiración (ventana de 15 minutos para los access tokens)

Para mitigar el credential-stuffing y la fuerza bruta, los inicios de sesión fallidos se limitan por tasa en dos dimensiones independientes, ambas con un TTL de 900 segundos (15 minutos):

DimensiónUmbralClave de AerospikeTTL
Por email5 intentos fallidos en 15 min → bloquea el 6.ºlogin:email:{sha256(email)}900s
Por IP de origen20 intentos fallidos en 15 min → bloquea el 21.ºlogin:ip:{ip}900s

Una petición limitada por tasa se rechaza con RESOURCE_EXHAUSTED y “too many login attempts, try again later”. La respuesta no revela si la cuenta existe, y corem_auth_login_rate_limited_total se incrementa. Como el estado de bloqueo vive en una clave de Aerospike con un TTL, el límite se libera por sí solo una vez que la ventana expira — no hay ningún paso de desbloqueo manual.

Las claves de API autentican las llamadas de dispositivo a plataforma y las llamadas programáticas hacia tu tenant.

  • Formato: prefijo sk_live_ seguido de 32 bytes criptográficamente aleatorios, codificados en base32 en minúsculas.
  • Almacenamiento: solo se almacena el hash — nunca la clave en bruto.
  • Visualización: la clave en bruto se devuelve exactamente una vez en la creación. No hay forma de recuperarla más tarde; si la pierdes, la rotas.

Presentar una clave como Authorization: Bearer sk_live_… permite a CORE-M resolver tu tenant_id (y, para las claves de dispositivo, el device_id) y acotar la petición a tu tenant. Una clave revocada se rechaza con UNAUTHENTICATED.

Configuración de SSO (solo configuración en v1)

Sección titulada «Configuración de SSO (solo configuración en v1)»

CORE-M almacena y valida la configuración del proveedor de SSO para tu tenant para SAML 2.0 y OIDC.

CampoSAML 2.0OIDC
Protocolosamloidc
Metadatos / discovery del IdPURL del XML de metadatos o XML subidoDiscovery URL (.well-known/openid-configuration)
Entity ID / Client IDSP Entity IDClient ID
Client SecretN/DClient Secret (cifrado en reposo)
HabilitadoSi la configuración almacenada está habilitada para una integración futuraIgual

Una prueba de configuración comprueba que el endpoint de metadatos del IdP o de discovery de OIDC es alcanzable y válido, e informa los atributos descubiertos. La prueba nunca crea ni actualiza usuarios de CORE-M.

El aislamiento proviene de acotar cada lectura y escritura a tu tenant_id, aplicado en cada petición y no como característica de una pantalla concreta:

  1. Llega una petición con un JWT o una clave de API.

  2. CORE-M extrae tu tenant_id (del claim tid o de la clave de API) y lo adjunta al contexto de la petición.

  3. Cada lectura y escritura se indexa por ese tenant_id, de modo que una petición hecha bajo tu tenant solo direcciona la porción de tus datos.

  4. Las peticiones que nombran explícitamente otro tenant (por ejemplo, una consulta acotada por tenant) se rechazan con PERMISSION_DENIED mediante la comprobación de tenant del handler receptor.

Por eso el claim tid importa tanto: es el único valor que fija una petición entera a la porción de la plataforma de tu tenant.