Skip to main content

· 6 min read
Rushikesh Tote

Introduction

APISIX is a high performance and scalable cloud native API gateway based on Nginx and etcd. It is an open source project by the Apache Software Foundation. Besides that, what makes APISIX so good is the support of many great built in plugins that could be used to implement features like authentication, monitoring, routing, etc. And the fact that plugins in APISIX are hot-reloaded (without restarts) makes it very dynamic.

But while using APISIX, there may be scenarios where you might want to add complex authorization logic in your application. This is where authz-casbin might help you, authz-casbin is an APISIX plugin based on Lua Casbin that enables powerful authorization based on various access control models. Casbin is an authorization library which supports access control models like ACL, RBAC, ABAC. Originally written in Go, it has been ported to many languages and Lua Casbin is the Lua implementation of Casbin. The development of authz-casbin started when we proposed a new plugin for authorization in the APISIX repository (#4674) to which the core members agreed. And after the helpful reviews which led to some major changes and improvements, the PR (#4710) was finally merged.

In this blog, we will use the authz-casbin plugin to show how you can implement an authorization model based on Role Based Access Control (RBAC) in APISIX.

NOTE: You will need to use some other plugin or custom workflow for authenticating the user since Casbin will only do authorization and not authentication.

Creating a model

The plugin uses three parameters for authorizing any request - subject, object and action. Here, subject is the value of the username header, which could be something like [username: alice]. Then, the object is the URL path that is being accessed and the action is request method being used.

Let's say we want to create a model with three resources at the paths - /, /res1 and /res2. And we want to have a model like this:

image

This would mean that all users (*) like for example jack can access the homepage (/). And users with admin permissions like alice and bob can access all the pages and resources (like res1 and res2). Also, let's restrict users without any admin permissions to using only GET request method. For this scenario, we could define the model as:

[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)

Creating a policy

From the above scenario, the policy would be:

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

The matcher from the model means:

  1. (g(r.sub, p.sub) || keyMatch(r.sub, p.sub)): Either the request's subject has a role as the policy's subject or the request's subject matches the policy's subject in keyMatch. keyMatch is built in function in Lua Casbin, you can take a look at the function's description and more such functions that could be useful here.
  2. keyMatch(r.obj, p.obj): The request's object matches the policy's object (URL path here).
  3. keyMatch(r.act, p.act): The request's action matches the policy's action (HTTP request method here).

Enabling the plugin on route

Once you have created the model and policy, you can enable it on a route using the APISIX Admin API. To enable it using model and policy file paths:

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": "/*"
}'

Here, the username field is the header name that you will be using to pass in the subject. For example, if you will be passing the username header as user: alice, you would use "username": "user".

For using model/policy text instead of files, you can use the model and policy fields instead:

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": "/*"
}'

Enabling the plugin using a global model/policy

There may be situations where you might want to use a single model and policy configuration across multiple routes. You can do that by first by sending a PUT request to add the model and policy configuration to the plugin's metadata by:

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"
}'

And then to enable the same configuration on some route, send a request using the Admin API:

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/*"
}'

This will add the plugin metadata configuration to the route. You can also easily update the plugin metadata configuration by resending the request to plugin's metadata with updated model and policy configuration, the plugin will automatically update all the routes using the plugin metadata.

Use Cases

  • The primary use case of this plugin would be in implementing authorization in your APIs. You can easily add this plugin on any API route that you are using with your authorization model and policy configuration.
  • If you want to have a single authorization model for all your APIs, you can use global model/policy method. This makes updating the policy easy for all routes, since you only need to update the metadata in etcd.
  • While if you would like to use a different model for every different route, you can use the route method. This is helpful when different API routes have different sets of user permissions. You can also use this when you are dealing with larger policies, since it will make the authorization faster when filtered into multiple routes.

· One min read
Casbin

Today, we are pleased to announce that Casbin's founder, Yang Luo is awarded the "Google Open Source Peer Bonus winners" for his work on Casbin, Npcap and Nmap in 2019 Q3.

ospb

The original award letter can be accessed here.

The Google Open Source Peer Bonus program is described as:

In the same way that a Google Peer Bonus is used to recognize a fellow Googler who has gone above and beyond, an Open Source Peer Bonus recognizes external people who have made exceptional contributions to open source.

The announcement for the 2019 winners is available at:

https://opensource.googleblog.com/2020/01/announcing-2019-second-cycle-google.html

Yang and Casbin are listed among open source developers and projects that have a relevant impact out there, like Git, TensorFlow, V8, CPython, LLVM, Apache projects, Angular or Jenkins.

We are glad to see Casbin recognized in this way for its contribution to open source and cloud security!

Thanks for flying Casbin!

· One min read
Yang Luo

Today, we migrated Casbin's documentation from GitHub Wiki to Docs of this website, which is powered by Docusaurus. Docusaurus provides lots of awesome features like better Markdown styles, full-text search, versioning, translation.

The documentation is not perfect yet and still needs tuning. The source code is hosted on GitHub: https://github.com/casbin/casbin-website-v2 .

Any contribution or suggestion is welcome!

· One min read
Helong Zhang

Some of our customers ask if Casbin can be used as a service instead of a library. The answer is YES. Today, we launched the Casbin Server project as a concrete solution for Access Control as a Service.

Casbin Server is under active development by our core team. It has several features:

  • Purely developed in Golang.
  • Can manage thousands of Casbin instances, so you can move policy enforcement logic from multiple services into one Casbin Server.
  • gRPC is used to communicated with Casbin Server. We also consider to add the RESTful support in near future.
  • A friendly web administrator portal is provided for non-developer administrators to manage all details like Casbin instances, models, policy storage and load balancing.

The source code is hosted on GitHub: https://github.com/casbin/casbin-server

Any issues or pull requests are welcome :)