Una biblioteca de autorizaciones compatible con RBAC (control de acceso basado en roles) distribuido
Nuestro proyecto KFC usa una arquitectura de microservicios, con componentes escritos en distintos idiomas y entornos de ejecución, como .NET, Ruby y Go. Muchos de estos componentes deben tomar decisiones basándose en el estado de autorización de los usuarios: quiénes son, a qué roles pertenecen, qué acciones pueden realizar y con qué finalidad.
Necesitábamos una forma coherente de usar el control de acceso basado en roles entre varios lenguajes independientes, y también necesitábamos una forma de administrar los permisos y las listas de control de acceso (ACL).
Al desarrollar aplicaciones en marcos de trabajo comunes con lenguajes como Ruby, Python, PHP o Go, el control de acceso basado en roles tiende a pertenecer al marco de trabajo y está disponible para su uso. Pero esto no sirve al desarrollar una aplicación como parte de un sistema mucho más grande que no usa los mismos marcos de trabajo a gran escala.
Investigamos las diferentes alternativas, y rápidamente descubrimos que teníamos una opción. Un método sería usar un servicio centralizado (como Keycloak), que actuaría como un agente de autorizaciones común para todos los microservicios. El claro inconveniente es que el agente centralizado se convierte en un único punto de error y un posible cuello de botella. Cualquier error aquí podría causar que se perdieran al instante todas las ventajas de una arquitectura de microservicios distribuida.
En su lugar, nos interesamos por los métodos descentralizados; en concreto, queríamos encontrar una forma coherente de representar y procesar listas de control de acceso en distintos lenguajes; entonces descubrimos Casbin, una biblioteca de autorizaciones que hace exactamente eso y se ha implementado en una amplia variedad de lenguajes.
Teníamos nuestra implementación de RBAC, pero había un problema: necesitamos una implementación de Ruby, y Casbin aún no se había portado a Ruby. Por lo tanto, decidimos hacerlo nosotros, y el resultado es Casbin-Ruby. Como Casbin se había migrado a muchos lenguajes anteriormente, tenía un completo conjunto de pruebas que podíamos usar para verificar que nuestra implementación se comportaba de forma similar a sus homólogos.
¿Cómo funciona?
Básicamente, cada microservicio tiene acceso a dos archivos, que se distribuyen en el sistema. El primero contiene una lista de los usuarios, grupos, roles, etc. Es decir, definen los principios de autorización. El segundo contiene las asignaciones entre las entidades de seguridad: en términos prácticos, es una combinación de todas las listas de control de acceso usadas por el sistema.
Esto proporciona la solución para el aspecto central de nuestro reto: la administración descentralizada (o distribuida) de usuarios, roles y funciones.
Esto es lo que Casbin permite:
- Exigir la política en la forma clásica
{subject, object, action}
o bien una forma personalizada definida, y ambas permiten y deniegan autorizaciones. - Gestionar el almacenamiento del modelo de control de acceso y su política.
- Administrar las asignaciones de rol-usuario y rol-rol (es decir, jerarquía de roles en RBAC).
- Admitir el superusuario integrado, como
root
oadministrator
. Un superusuario puede realizar cualquier acción sin permisos explícitos. - Varios operadores integrados para admitir la coincidencia de reglas. Por ejemplo,
keyMatch
puede asignar una clave de recurso/foo/bar
al patrón/foo*
.
Esto es lo que Casbin NO puede hacer:
- Autenticación (es decir, verificar el
username
lapassword
cuando un usuario intenta iniciar la sesión). - Administrar la lista de usuarios o roles. Resulta más práctico que el proyecto en sí administre estas entidades. Los usuarios suelen tener sus contraseñas, y Casbin no se ha diseñado como un contenedor de contraseñas. Sin embargo, Casbin almacena la asignación de rol-usuario para el escenario de RBAC.
Instalar Casbin con:
to use latest version:
gem 'casbin-ruby', github: 'CasbinRuby/casbin-ruby'
to use specific version:
gem 'casbin-ruby', '1.0.5'
Desarrollo futuro
Tardamos más o menos un mes en desarrollar nuestra implementación de Casbin en Ruby; al usar pruebas de implementaciones existentes en distintos lenguajes, empezamos con una base completa de cobertura de pruebas, y hemos continuado con un exhaustivo método que da preferencia al desarrollo basado en pruebas.
Desde que desarrollamos la implementación de Ruby principal, hemos continuado creando almacenes y notificaciones. También tenemos previsto admitir administradores de roles, y queremos añadir puentes a distintos marcos de Ruby, como Ruby on Rails, Hanami y Roda.
Casbin-Ruby está disponible en Github, y puede obtener más información sobre Casbin en su sitio web.