Tema representativo de entrevista

Entrevista de diseño de sistemas: Construir un servicio centralizado de decisión de autorización

Diseño de sistemasDifícil
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Diseña un servicio centralizado de decisión de autorización utilizado por múltiples servicios internos: dado un sujeto, una acción, un recurso y el contexto de la solicitud, devuelve permitir (allow) o denegar (deny) y explica cómo entran en vigor los cambios de políticas.

Planteamiento y contexto

Varios servicios de negocio necesitan responder a la misma pregunta: ¿quién puede realizar qué acción sobre qué recurso? Diseña un servicio de decisión compartido que acepte un sujeto, una acción, un recurso y un contexto, devuelva ALLOW o DENY, y admita usuarios, cuentas de servicio, recursos jerárquicos, límites de inquilinos y cambios de políticas.

Utiliza estos supuestos para la entrevista: 100,000 verificaciones de autorización por segundo como base, un pico de 3 veces el promedio, un objetivo de latencia p99 de 20 ms, escrituras de políticas mucho menos frecuentes que las lecturas, y clientes que deben distinguir una denegación explícita de la indisponibilidad temporal del servicio de autorización. Estos son supuestos del problema, no puntos de referencia de la industria. El procesamiento de pagos, la emisión de claves y las escrituras en bases de datos de negocio quedan fuera de este servicio.

Qué está evaluando el entrevistador

Las respuestas sólidas convierten la autorización en una tupla de cuatro elementos y un contrato de consistencia en lugar de limitarse a decir “agrega un servicio de RBAC”:

  • modelar límites para sujeto, recurso, acción, contexto, jerarquía y referencias entre inquilinos;
  • cuándo encajan las políticas basadas en ACL, RBAC, ABAC o en relaciones, y cómo evitar que la lógica de políticas diverja entre servicios;
  • cómo interactúan la ruta de lectura de decisiones, la ruta de escritura de políticas, la caché y los eventos de invalidación;
  • cuándo se vuelve visible un cambio de política y si una caché obsoleta aún puede permitir el acceso;
  • si una interrupción (outage) aplica fail-open o fail-closed para cada clase de riesgo;
  • cómo los registros, las explicaciones, la reproducción (replay) y la inyección de fallas demuestran una denegación correcta sin filtraciones entre inquilinos.

Preguntas de clarificación que debes hacer

Pregunta sobre restricciones que cambien el diseño:

  1. ¿Cuál es la ventana de consistencia? Si una revocación debe surtir efecto en menos de 5 segundos, los arrendamientos (leases) de caché y los tokens de versión deben cumplir con esos 5 segundos; una tolerancia a escala de minutos permite un TTL más largo.
  2. ¿La verificación es una búsqueda de un solo recurso o una consulta de relaciones? “¿Puede este usuario leer un documento?” puede depender de la membresía, la herencia de grupos y los recursos superiores; eso determina si se necesita un grafo de relaciones o verificaciones por lotes.
  3. ¿Qué se permite durante una interrupción? Se puede permitir que el contenido público falle en modo fail-open, mientras que los pagos, los datos personales y la administración suelen fallar en modo fail-closed. Elige según el riesgo, no por costumbre.
  4. ¿Quién escribe y revisa las políticas? La publicación directa por parte de los equipos de negocio requiere versiones, aprobación, comprobaciones estáticas y reversión (rollback); un flujo de escritura exclusivo para seguridad puede reducir la superficie de control.
  5. ¿Los clientes necesitan explicaciones? La depuración puede requerir el ID de la regla coincidente, pero una explicación orientada al cliente no debe revelar los recursos o políticas de otro inquilino.

Un marco de respuesta de 30 segundos

Comienza con esta estructura:

“Modelo una solicitud como (principal, action, resource, context). Un motor de políticas devuelve permitir, denegar, una versión de política y un ID de regla interno cuando una depuración controlada lo necesita. Un plano de control administra los datos de políticas y relaciones delimitados por inquilino; un plano de datos evalúa instantáneas (snapshots) versionadas e inmutables en una caché local de solo lectura. La publicación emite eventos de invalidación reproducibles, y los clientes envían una versión mínima de política para que las instantáneas obsoletas no puedan anular silenciosamente una decisión más reciente. Las rutas sensibles aplican fail-closed cuando la autorización no está disponible; las lecturas de bajo riesgo se degradan solo bajo una política explícita de producto. Valido la propagación de revocaciones, los límites entre inquilinos, las carreras de caché y las fallas de dependencias mediante inyección de fallas y reproducción.”

Esto proporciona el modelo, el flujo de datos, la consistencia y el comportamiento ante fallas antes de que una pregunta de seguimiento seleccione un área para profundizar.

Análisis detallado paso a paso

Define primero la semántica de las políticas. Un sujeto puede ser un usuario, una cuenta de servicio o un grupo. Un recurso puede ser un inquilino, un proyecto o un documento dentro de una jerarquía. Las acciones deben ser un vocabulario acotado como read, write y share. El contexto puede incluir el estado del dispositivo, el origen o la hora, pero un campo no verificado del cliente no es un hecho confiable. La guía de ABAC del NIST trata los atributos del sujeto, el objeto y el entorno como entradas de decisión; las políticas basadas en relaciones representan la membresía como aristas transitables.

Separa los planos de control y de datos. El plano de control edita, valida, aprueba, versiona y revierte políticas. El plano de datos carga únicamente instantáneas inmutables publicadas y responde a las verificaciones. Los servicios de negocio no deberían implementar cada uno un analizador sintáctico (parser) de políticas diferente. Una publicación genera una versión monótona y un evento de invalidación; el plano de datos intercambia la instantánea de forma atómica para que un conjunto de reglas a medio publicar nunca sea visible.

Diseña la API de verificación. Una interfaz interna podría ser:

text
Check(principal, action, resource, context, min_policy_version)
  -> decision, policy_version, rule_id, expires_at
BatchCheck(principal, [(action, resource, context)...])
  -> decisions[]

rule_id sirve para registros controlados y depuración. Un cliente de otro inquilino no debe descubrir la existencia de un recurso a través de detalles de error. Las verificaciones por lotes reducen los viajes de ida y vuelta (round trips), pero necesitan límites en el tamaño del lote y en el costo de evaluación.

Gestiona la consistencia y el almacenamiento en caché. Una caché local puede alcanzar un objetivo de 20 ms, pero la revocación no puede depender únicamente del TTL. Un cliente puede enviar la última versión de política que observó; si la versión local está desactualizada, el servicio lee una réplica compartida o devuelve “indecidible temporalmente”. Los eventos de invalidación necesitan un cursor de reproducción y reconciliación periódica para que una notificación perdida no deje permisos obsoletos activos. Para recursos altamente sensibles, incluye una versión del recurso o un arrendamiento corto para que las versiones de permisos y de objetos se verifiquen juntas.

Elige el comportamiento ante interrupciones. Si el plano de datos no puede comunicarse con el plano de control, una instantánea cargada no expirada puede continuar prestando servicio. Después de que expire, las acciones de pago, datos personales y administrativas deben fallar en modo fail-closed; el contenido estático público puede fallar en modo fail-open solo bajo una regla de producto aprobada. Un tiempo de espera (timeout) debe ser un UNAVAILABLE explícito, no un DENY disfrazado, o la lógica de negocio confundirá una falla de infraestructura con una denegación de permisos del usuario.

Aísla a los inquilinos y el abuso. Cada objeto de política y clave de caché incluye un ID de inquilino. El servidor deriva el inquilino a partir de la identidad verificada en lugar de confiar en un campo arbitrario del cuerpo de la solicitud. Aplica cuotas por sujeto, inquilino y lote; limita la profundidad de relaciones y la complejidad de las políticas para que un solo inquilino no agote los recursos de evaluación.

Audita y verifica. Registra un hash de la solicitud, sujeto, acción, tipo de recurso, decisión, versión de la política, latencia y clase de falla; mantén los valores sensibles como identificadores irreversibles. Prueba la caché obsoleta tras una revocación, ciclos en la herencia de grupos, IDs de recursos idénticos entre diferentes inquilinos, caídas durante la publicación, eventos de invalidación duplicados o perdidos, reinicios del plano de datos y tiempos de espera de dependencias. La aceptación requiere reproducir una versión de política y explicar una decisión, no simplemente devolver DENY.

Estima el cuello de botella. Con una base de 100,000 verificaciones por segundo y un pico de 300,000, 2 KB por solicitud implican cerca de 600 MB/s de entrada (ingress) en el pico. Enviar una política completa en cada solicitud amplifica la latencia y el ancho de banda, por lo que es preferible utilizar instantáneas locales, verificaciones por lotes y réplicas de lectura. Si el recorrido de relaciones se convierte en el cuello de botella, aplica fragmentación (sharding) por inquilino o recurso y limita la profundidad y la dispersión (fan-out). Explica cómo las pruebas de carga reemplazarían estos supuestos.

Respuesta de muestra de alta calidad

“Primero confirmaría el objetivo de revocación y el límite de seguridad durante fallas. Supongamos 300,000 verificaciones por segundo en el pico, un objetivo p99 de 20 ms y una revocación efectiva en 5 segundos. Separaría los planos de control y de datos. El plano de control almacena ACLs delimitadas por inquilino, relaciones de grupo y condiciones ABAC; antes de publicar, verifica sintaxis, ciclos y referencias entre inquilinos, y luego crea una instantánea inmutable y una versión monótona. El plano de datos de cada región evalúa (subject, action, resource, context) desde una caché local de solo lectura. Los eventos de invalidación llevan un cursor y son reproducibles; un cliente puede enviar min_policy_version, de modo que una caché retrasada lee una réplica compartida o devuelve UNAVAILABLE.

Para pagos, datos personales y acciones administrativas, una instantánea expirada o una dependencia no disponible falla en modo fail-closed; la degradación para contenido público requiere aprobación explícita de producto. Los resultados incluyen la versión de la política y un ID de regla interno. Los registros almacenan decisiones, latencia y clase de error sin exponer datos de otro inquilino. Las versiones de recursos o los arrendamientos cortos protegen a los objetos más sensibles frente a un permiso antiguo tras una revocación. Las pruebas de carga cubren el tráfico pico y el recorrido de relaciones más profundo; la inyección de fallas cubre invalidaciones perdidas, condiciones de carrera en revocaciones, IDs entre inquilinos y reinicios regionales. La reconciliación y la reproducción versionada deben demostrar que no existen permisos no explicados.”

Esto conecta supuestos, modelo, consistencia, manejo de fallas y verificación. En la entrevista, ajusta los detalles a medida que cambien las restricciones; 300,000 verificaciones por segundo y 5 segundos no son hechos universales de producción.

Errores comunes

  • Reducir cada caso a RBAC. Los roles no expresan de forma natural la jerarquía, las relaciones heredadas ni las condiciones del entorno. Define la semántica de permisos antes de elegir el modelo.
  • Usar un TTL fijo como mecanismo de revocación. El TTL mitiga un caso de obsolescencia, pero no resuelve notificaciones perdidas ni carreras de versiones. Agrega versiones, invalidación reproducible y reconciliación.
  • Aplicar siempre fail-open o siempre fail-closed. El riesgo del recurso varía. Define el comportamiento a partir de la base de seguridad mínima, la frescura de la instantánea y la reversibilidad del negocio.
  • Copiar la lógica de políticas en cada servicio. Múltiples analizadores sintácticos divergen y producen denegaciones dispares. Versiona la política e invoca una única interfaz de decisión.
  • Devolver “recurso no encontrado” o reglas detalladas. Eso filtra información entre inquilinos. Utiliza errores externos estables e IDs de reglas internos controlados.
  • Probar solo la ruta de permiso habitual. La revocación, la reproducción, los ciclos y los límites de inquilinos son donde fallan los sistemas de autorización. Utiliza inyección de fallas y reproducción versionada.

Preguntas de seguimiento y respuestas

¿Puede mantenerse una caché local si la revocación debe ser inmediata?

Sí, pero la caché no puede decidir por sí sola. La revocación debe generar una versión observable globalmente o una invalidación de arrendamiento. Las solicitudes sensibles envían la versión mínima de la política; una caché retrasada omite los datos locales o espera confirmación. Si la confirmación no cabe en el presupuesto de tiempo, devuelve UNAVAILABLE o deniega en lugar de utilizar silenciosamente un permiso antiguo.

¿Qué ocurre si el recorrido de relaciones encuentra un ciclo a través de grupos superiores?

Rechaza los ciclos durante la publicación y, aun así, aplica un límite máximo de profundidad, número de nodos y presupuesto de tiempo en tiempo de ejecución. El evaluador rastrea los nodos visitados, detiene la rama repetida y devuelve un error interno diagnosticable. Un ciclo nunca debe convertir una verificación en un trabajo ilimitado.

¿Cómo demuestras que no hay autorización cruzada entre inquilinos?

Haz obligatorio el alcance del inquilino en los espacios de nombres de políticas y prefijos de claves de caché, y deriva el inquilino del sujeto a partir de la identidad del lado del servidor. Genera IDs de recursos idénticos bajo diferentes inquilinos mediante pruebas basadas en propiedades; cada autorización debe satisfacer la igualdad de inquilino entre sujeto, recurso y política. Añade muestreo de registros y reproducción de rutas de denegación.

¿Es obligatorio copiar el modelo de consistencia externa de Zanzibar?

No. Elige tokens de versión, arrendamientos o una consistencia más fuerte en función del objetivo de revocación y el riesgo de negocio. Si un producto garantiza que un miembro recién eliminado no puede seguir leyendo un objeto antiguo, el orden causal y las versiones de objetos están justificados. Para contenido público de bajo riesgo, una consistencia más débil y un almacenamiento en caché más prolongado pueden resultar más simples. Declara la promesa y su costo.

Fuentes públicas

Preguntas relacionadas

Herramienta de entrevista relacionada

Usa Resolver para una respuesta de diseño de sistemas

Aclara primero los requisitos y luego avanza a través de la escala, la arquitectura, la elección de componentes y las compensaciones (trade-offs).

Ver la herramienta