OpenID Connect: autorización de aplicaciones internas de genérico a estándar

Hace unos meses, estaba implementando un servidor OpenID Connect para controlar el acceso a cientos de nuestras aplicaciones internas. De nuestros propios desarrollos, convenientes en una escala más pequeña, pasamos al estándar generalmente aceptado. El acceso a través de un servicio central simplifica enormemente las operaciones monótonas, reduce el costo de implementación de autorizaciones, le permite encontrar muchas soluciones preparadas y no romper su cerebro al desarrollar otras nuevas. En este artículo hablaré sobre esta transición y los baches que logramos llenar.

introducción

Érase una vez ... Cómo comenzó todo


Hace unos años, cuando había demasiadas aplicaciones internas para el control manual, escribimos una aplicación para el control de acceso dentro de la empresa. Era una aplicación Rails simple que se conectaba a una base de datos con información sobre empleados, donde se configuraba el acceso a varias funciones. Luego planteamos el primer SSO, que se basó en la verificación de tokens del cliente y el servidor de autorización, el token se transmitió en forma cifrada con varios parámetros y se verificó en el servidor de autorización. Esta no era la opción más conveniente, ya que en cada aplicación interna era necesario describir una capa considerable de lógica, y la base de empleados estaba completamente sincronizada con el servidor de autorización.

Después de un tiempo, decidimos simplificar la tarea de la autorización centralizada. SSO transferido al equilibrador. Usando OpenResty en Lua, agregaron una plantilla que verificaba los tokens, sabían en qué aplicación estaba la solicitud y podían verificar si había acceso allí. Este enfoque simplificó enormemente la tarea de controlar el acceso de las aplicaciones internas: en el código de cada aplicación, ya no era necesario describir una lógica adicional. Como resultado, cerramos el tráfico externamente, y la aplicación en sí no sabía nada sobre la autorización.

Sin embargo, uno de los problemas quedó sin resolver. ¿Qué pasa con las aplicaciones que necesitan información sobre los empleados? Podría escribir una API para el servicio de autorización, pero luego tendría que agregar lógica adicional para cada aplicación. Además, queríamos deshacernos de la dependencia de una de nuestras aplicaciones autoescritas, más orientada hacia la traducción a OpenSource, en nuestro servidor de autorización interno. Hablaremos de él en otro momento. La solución a ambos problemas fue OAuth.

A los estándares generalmente aceptados


OAuth es un estándar de autorización comprensible y generalmente aceptado, pero como su funcionalidad no es suficiente, OpenID Connect (OIDC) comenzó a considerarse inmediatamente. OIDC es la tercera implementación de un estándar de autenticación abierto que se ha extendido al complemento a través del protocolo OAuth 2.0 (protocolo de autorización abierto). Esta solución soluciona el problema de la falta de datos sobre el usuario final y también permite cambiar el proveedor de autorización.

Sin embargo, no elegimos un proveedor específico y decidimos agregar integración con OIDC para nuestro servidor de autorización existente. A favor de tal solución, OIDC es muy flexible en términos de autorizar al usuario final. Por lo tanto, fue posible implementar el soporte OIDC en su servidor de autorización actual.

imagen

Nuestra forma de implementar nuestro propio servidor OIDC


1) Trajeron los datos a la forma deseada


Para integrar OIDC, debe llevar los datos del usuario actual de una manera que sea comprensible para el estándar. En OIDC, esto se llama Reclamaciones. Las marcas son esencialmente campos finales en la base de datos del usuario (nombre, correo electrónico, teléfono, etc.). Hay una lista estándar de marcas , y todo lo que no está incluido en esta lista se considera personalizado. Por lo tanto, el primer punto al que debe prestar atención si desea elegir un proveedor OIDC existente es la capacidad de personalizar convenientemente las nuevas marcas.

El grupo de marcas se combina en el siguiente subconjunto: Alcance. Durante la autorización, se solicita el acceso no a marcas específicas, es decir, a ámbitos, incluso si algunas de las características del alcance no son necesarias.

2) Implementado las subvenciones necesarias


La siguiente parte de la integración de OIDC es la selección e implementación de los tipos de autorización, las llamadas subvenciones. El escenario adicional de la interacción de la aplicación seleccionada con el servidor de autorización dependerá de la concesión seleccionada. En la figura a continuación se presenta un esquema aproximado para elegir la subvención correcta.

imagen

Para nuestra primera solicitud, utilizamos la subvención más común: el Código de autorización. Su diferencia con los demás es que tiene tres pasos, es decir. pasa verificación adicional. Primero, el usuario solicita un permiso de autorización, recibe un Token - Código de autorización, luego con este token, como si fuera un boleto de viaje, solicita un token de acceso. Toda la interacción principal de este escenario de autorización se basa en redirecciones entre la aplicación y el servidor de autorización. Lea más sobre esta subvención aquí .

OAuth se adhiere al concepto de que los tokens de acceso recibidos después de la autorización deben ser temporales y cambiar preferiblemente en promedio cada 10 minutos. La concesión del Código de autorización es una verificación de tres pasos a través de redireccionamientos; hacer este paso cada 10 minutos, francamente, no es una experiencia agradable para los ojos. Para resolver este problema, hay otra subvención: Token de actualización, que también implementamos. Aquí todo es más simple. Durante la prueba, de otra concesión, además del token de acceso principal, se emite uno más: Token de actualización, que puede usarse solo una vez y, como regla, su vida útil es significativamente más larga. Con este token de actualización, cuando finaliza el TTL (Time to Live) del token de acceso principal, una solicitud de un nuevo token de acceso llegará al punto final de otra concesión. El token de actualización usado se restablece inmediatamente.Tal verificación es de dos pasos y se puede realizar en segundo plano, de forma invisible para el usuario.

3) formatos de salida de datos de usuario personalizados


Una vez implementadas las subvenciones seleccionadas, la autorización funciona, vale la pena mencionar la recepción de datos sobre el usuario final. OIDC tiene un punto final separado para esto, en el que puede solicitar datos de usuario con su token de acceso actual y cuando sea relevante. Y si los datos del usuario no cambian con tanta frecuencia, y necesita buscar la actual muchas veces, puede tomar una decisión como los tokens JWT. Estos tokens también son compatibles con el estándar. El token JWT en sí consta de tres partes: encabezado (información sobre el token), carga útil (cualquier dato necesario) y firma (la firma, el token está firmado por el servidor y puede verificar el origen de su firma en el futuro).

En una implementación de OIDC, un token JWT se llama id_token. Se puede solicitar junto con un token de acceso regular, y todo lo que queda es verificar la firma. El servidor de autorización tiene un punto final separado para esto con un montón de claves públicas en formato JWK . Y hablando de esto, vale la pena mencionar que hay otro punto final que, basado en el estándar RFC5785, refleja la configuración actual del servidor OIDC. Contiene todas las direcciones de puntos finales (incluida la dirección del llavero público utilizado para firmar), marcas y ámbitos admitidos, algoritmos de cifrado utilizados, subvenciones admitidas, etc.

Por ejemplo en Google:
{
 "issuer": "https://accounts.google.com",
 "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
 "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
 "token_endpoint": "https://oauth2.googleapis.com/token",
 "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
 "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
 "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
 "response_types_supported": [
  "code",
  "token",
  "id_token",
  "code token",
  "code id_token",
  "token id_token",
  "code token id_token",
  "none"
 ],
 "subject_types_supported": [
  "public"
 ],
 "id_token_signing_alg_values_supported": [
  "RS256"
 ],
 "scopes_supported": [
  "openid",
  "email",
  "profile"
 ],
 "token_endpoint_auth_methods_supported": [
  "client_secret_post",
  "client_secret_basic"
 ],
 "claims_supported": [
  "aud",
  "email",
  "email_verified",
  "exp",
  "family_name",
  "given_name",
  "iat",
  "iss",
  "locale",
  "name",
  "picture",
  "sub"
 ],
 "code_challenge_methods_supported": [
  "plain",
  "S256"
 ],
 "grant_types_supported": [
  "authorization_code",
  "refresh_token",
  "urn:ietf:params:oauth:grant-type:device_code",
  "urn:ietf:params:oauth:grant-type:jwt-bearer"
 ]
}


Por lo tanto, con id_token, puede transferir todas las características necesarias a la carga útil del token y no contactar al servidor de autorización cada vez para solicitar datos sobre el usuario. La desventaja de este enfoque es que cambiar los datos del usuario desde el servidor no se produce de inmediato, sino con un nuevo token de acceso.

Resultados de implementación


Entonces, después de implementar nuestro propio servidor OIDC y configurar las conexiones en el lado de la aplicación, resolvimos el problema de transmitir información del usuario.
Dado que OIDC es un estándar abierto, tenemos la oportunidad de elegir un proveedor o implementación de servidor existente. Probamos Keycloak, que resultó ser muy conveniente de configurar, después de configurar y cambiar las configuraciones de conexión en el lado de la aplicación, está listo para funcionar. En el lado de la aplicación, solo queda cambiar la configuración de la conexión.

Hablando de soluciones existentes


Como parte de nuestra organización, como el primer servidor OIDC, armamos nuestra implementación, que se complementó según fue necesario. Después de una revisión detallada de otras soluciones preparadas, podemos decir que este es un punto discutible. Las inquietudes de los proveedores sobre la falta de funcionalidad necesaria sirvieron como solución para la implementación de su servidor, así como la presencia de un sistema antiguo en el que había varias autorizaciones personalizadas para algunos servicios y se almacenaba una gran cantidad de datos sobre los empleados. Sin embargo, en implementaciones listas para usar, hay conveniencia para la integración. Por ejemplo, Keycloak tiene su propio sistema de gestión de usuarios y los datos se almacenan directamente en él, y no será difícil superar a sus usuarios allí. Para esto, Keycloak tiene una API que le permitirá implementar completamente todos los pasos necesarios para la transferencia.

Otro ejemplo de implementación certificada e interesante, en mi opinión, es Ory Hydra. Es interesante porque consta de diferentes componentes. Para la integración, deberá vincular su servicio de administración de usuarios con su servicio de autorización y expandirse según sea necesario.

Keycloak y Ory Hydra no son las únicas soluciones llave en mano. Es mejor seleccionar una implementación certificada de OpenID Foundation. Típicamente, tales soluciones tienen una insignia de certificación OpenID.

Certificación Openid


Además, no se olvide de los proveedores pagos existentes si no desea conservar su servidor OIDC. Hay muchas buenas opciones hasta la fecha.

Que sigue


En un futuro cercano, vamos a cerrar el tráfico a los servicios internos de otra manera. Planeamos transferir nuestro SSO actual en el equilibrador usando OpenResty a un proxy basado en OAuth. También hay muchas soluciones ya preparadas aquí, por ejemplo:
github.com/bitly/oauth2_proxy
github.com/ory/oathkeeper
github.com/keycloak/keycloak-gatekeeper

Materiales adicionales


jwt.io - un buen servicio para verificar
openid.net/developers/certified JWT tokens - una lista de implementaciones certificadas de OIDC

All Articles