Ir al contenido principal

Autorización en APISIX usando Casbin

· Lectura de 6 min
Rushikesh Tote

Introducción

APISIX es una puerta de enlace API nativa de la nube de alto rendimiento y escalable basada en Nginx y etcd. Es un proyecto de código abierto de la Apache Software Foundation. Además, lo que hace que APISIX sea tan bueno es el soporte de muchos excelentes complementos integrados que se podrían usar para implementar características como autenticación, monitoreo, enrutamiento, etc. Y el hecho de que los complementos en APISIX se recargan en caliente (sin reinicios) lo hace muy dinámico.

Pero al usar APISIX, puede haber escenarios en los que desees agregar lógica de autorización compleja en tu aplicación. Aquí es donde authz-casbin podría ayudarte, authz-casbin es un complemento de APISIX basado en Lua Casbin que permite una autorización poderosa basada en varios modelos de control de acceso. Casbin es una biblioteca de autorización que soporta modelos de control de acceso como ACL, RBAC, ABAC. Originalmente escrito en Go, ha sido portado a muchos idiomas y Lua Casbin es la implementación en Lua de Casbin. El desarrollo de authz-casbin comenzó cuando propusimos un nuevo complemento para la autorización en el repositorio de APISIX (#4674) al cual los miembros principales estuvieron de acuerdo. Y después de las útiles revisiones que llevaron a algunos cambios importantes y mejoras, el PR (#4710) finalmente se fusionó.

En este blog, usaremos el complemento authz-casbin para mostrar cómo puedes implementar un modelo de autorización basado en el Control de Acceso Basado en Roles (RBAC) en APISIX.

NOTA: Necesitarás usar algún otro complemento o flujo de trabajo personalizado para autenticar al usuario, ya que Casbin solo hará autorización y no autenticación.

Creando un modelo

El complemento utiliza tres parámetros para autorizar cualquier solicitud: sujeto, objeto y acción. Aquí, sujeto es el valor del encabezado de nombre de usuario, que podría ser algo como [username: alice]. Luego, el objeto es la ruta URL que se está accediendo y la acción es el método de solicitud que se está utilizando.

Digamos que queremos crear un modelo con tres recursos en las rutas - /, /res1 y /res2. Y queremos tener un modelo así:

imagen

Esto significaría que todos los usuarios (*) como por ejemplo jack pueden acceder a la página de inicio (/). Y los usuarios con permisos de admin como alice y bob pueden acceder a todas las páginas y recursos (como res1 y res2). Además, restrinjamos a los usuarios sin ningún permiso de administrador a usar solo el método de solicitud GET. Para este escenario, podríamos definir el modelo como:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)

Creando una política

Del escenario anterior, la política sería:

p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin

El comparador del modelo significa:

  1. (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)): O bien el sujeto de la solicitud tiene un rol como el sujeto de la política o el sujeto de la solicitud coincide con el sujeto de la política en keyMatch. keyMatch es una función integrada en Lua Casbin, puedes echar un vistazo a la descripción de la función y más funciones que podrían ser útiles aquí.
  2. keyMatch(r.obj, p.obj): El objeto de la solicitud coincide con el objeto de la política (ruta URL aquí).
  3. keyMatch(r.act, p.act): La acción de la solicitud coincide con la acción de la política (método de solicitud HTTP aquí).

Habilitando el complemento en la ruta

Una vez que hayas creado el modelo y la política, puedes habilitarlo en una ruta utilizando la API de administración de APISIX. Para habilitarlo usando rutas de archivos de modelo y política:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model_path": "/path/to/model.conf",
"policy_path": "/path/to/policy.csv",
"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'

Aquí, el campo de nombre de usuario es el nombre del encabezado que usarás para pasar el sujeto. Por ejemplo, si pasarás el encabezado de nombre de usuario como user: alice, usarías "username": "user".

Para usar texto de modelo/política en lugar de archivos, puedes usar los campos model y policy en su lugar:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"model": "[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",

"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin",

"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/*"
}'

Habilitando el complemento usando un modelo/política global

Puede haber situaciones en las que desees usar una única configuración de modelo y política en múltiples rutas. Puedes hacerlo primero enviando una solicitud PUT para agregar la configuración de modelo y política a los metadatos del complemento por:

curl http://127.0.0.1:9080/apisix/admin/plugin_metadata/authz-casbin -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -i -X PUT -d '
{
"model": "[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)) && keyMatch(r.obj, p.obj) && keyMatch(r.act, p.act)",

"policy": "p, *, /, GET
p, admin, *, *
g, alice, admin
g, bob, admin"
}'

Y luego para habilitar la misma configuración en alguna ruta, envía una solicitud usando la API de administración:

curl http://127.0.0.1:9080/apisix/admin/routes/1 -H 'X-API-KEY: edd1c9f034335f136f87ad84b625c8f1' -X PUT -d '
{
"plugins": {
"authz-casbin": {
"username": "username"
}
},
"upstream": {
"nodes": {
"127.0.0.1:1980": 1
},
"type": "roundrobin"
},
"uri": "/route1/*"
}'

Esto agregará la configuración de metadatos del complemento a la ruta. También puedes actualizar fácilmente la configuración de metadatos del complemento reenviando la solicitud a los metadatos del complemento con la configuración de modelo y política actualizada, el complemento actualizará automáticamente todas las rutas que usan la configuración de metadatos del complemento.

Casos de uso

  • El caso de uso principal de este complemento sería en la implementación de autorización en tus API. Puedes agregar fácilmente este complemento en cualquier ruta de API que estés utilizando con tu modelo de autorización y configuración de política.
  • Si deseas tener un único modelo de autorización para todas tus API, puedes usar el método de modelo/política global. Esto facilita la actualización de la política para todas las rutas, ya que solo necesitas actualizar los metadatos en etcd.
  • Mientras que si te gustaría usar un modelo diferente para cada ruta diferente, puedes usar el método de ruta. Esto es útil cuando diferentes rutas de la API tienen diferentes conjuntos de permisos de usuario. También puedes usar esto cuando estás tratando con políticas más grandes, ya que hará que la autorización sea más rápida cuando se filtre en múltiples rutas.