Skip to content

Instantly share code, notes, and snippets.

@StevenACoffman
Last active April 7, 2024 02:43
Show Gist options
  • Star 45 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save StevenACoffman/1644ec1157a793eb7d868aa22b260e91 to your computer and use it in GitHub Desktop.
Save StevenACoffman/1644ec1157a793eb7d868aa22b260e91 to your computer and use it in GitHub Desktop.
OPA vs Casbin

Information in this Gist originally from this github issue, which is outdated.

As @RomanMinkin mentioned, you can also consider Casbin (https://github.com/casbin/casbin). It is the most starred authorization library in Golang. There are several differences between Casbin and OPA.

Feature Casbin OPA
Library or service? Library/Service Library/Service
How to write policy? Two parts: model and policy. Model is general authorization logic. Policy is concrete policy rule. A single part: Rego
RBAC hierarchy Casbin supports role hierarchy (a role can have a sub-role) Role hierarchies can be encoded in data. Also with the new graph.reachable() built-in function queries over those hierarchies are much more feasible now.
RBAC separation of duties Not supported Supported: two roles cannot be assigned together
ABAC Casbin supports to directly retrieve Golang struct's members as attributes OPA needs to be provided with an attribute list (JSON) or Golang struct
Built-in functions RESTful match, IP match, regex are supported. You can also write your own Golang function and let Casbin use it Functions like regex, max, min, count, type conversion are supported. You can write your own built-in functions.
Policy storage All common databases are supported by dozens of middlewares, like SQL, NoSQL, Key-Value, AWS S3, etc. Not supported, you need to write your own code if you want to use DB like MySQL.
Conflict resolution Allow-override, Deny-override, Allow-and-no-Deny, Priority are built-in supported. You can also write your own Effector logic (in code) to have a custom conflict resolution Allow-override, Deny-override, Priority (but grammar is a little long). You can also resolve conflicts inside Rego itself.
Distributed authorization You can use multiple Casbin instances together. Sharding and policy change notification are supported One single OPA service
Other programming languages Golang, Java, PHP, Node.JS, Python, .NET, Delphi, Rust and others are supported (> 8) Golang, WASM (NodeJS in progress)
Adopters Intel, VMware, Docker, Cisco, Banzai Cloud, Orange, Tencent Cloud, Microsoft Netflix, Chef, SolarWinds, Cisco, Cloudflare, Pinterest, State Street Corporation

(let me know if the above table is not accurate)

Metric casbin OPA
Page rank 6.756345697844901e-05 2.1407964930428962e-05
Stars 6783 3413
Order by page rank 246 744
Order by page rank in github repos 133 583
Order by stars 166 436
Imported by 73 repos 23 repos
Imports 16 repos 71 repos

OPA

OPA is primarily developed by Styra Inc. Styra is building "authorization as a service" which is backed by OPA. The marketing is slicker, and it appears a little more focussed on commercial service integrations.

Casbin

Casbin's originator works for Microsoft Research, it doesn't have a group of sales people, but it appears more popular at a grassroots level.

@hsluoyz
Copy link

hsluoyz commented May 28, 2020

Golang, Java, PHP, Node.JS, Python, .NET, Delphi, Rust are supported

Casbin now supports > 8 languages: https://casbin.org/en/

But once you want to do something exotic, I'm not sure if that would work with casbin as the project (casbin) itself may has to be modified. Personally, I find the DSL a bit easier to read than rego, but it comes at the cost of flexibility.

Casbin supports many models and custom functions to support best flexibility. Please name a scenario that Casbin cannot do.

I am quite sure that we can't implement conditions with casbin, the DSL is too simple for that.

This is not true. See an issue about conditions: casbin/casbin#441

@srenatus
Copy link

I don't claim that this is the only wrong bit wrt OPA, but

One single OPA service

for Distributed authorization surely isn't accurate. You can have a sidecar per service, you can use it as a library, there's a bundles mechanism (now), styra's offering covers the distributed authz scenario....

@StevenACoffman
Copy link
Author

StevenACoffman commented May 29, 2020

Reply from @tsandall OPA slack:

  • RE: RBAC Hierarchies. Role hierarchies can be encoded in data. Also with the new graph.reachable() built-in function queries over those hierarchies are much more feasible now.
  • RE: ABAC. I'm not sure what Casbin supports here but you can pass arbitrary data (Go structs, JSON, etc.) into OPA.
  • RE: Built-in functions. OPA supports the examples that were mentioned in the Casbin sentence. There are many, many more here: https://www.openpolicyagent.org/docs/latest/policy-reference/#built-in-functions
  • RE: Policy Storage. OPA does not act as a source of truth for policies--by design. It's makes decisions based on policies & data but where that policy & data comes from differs from use case to use case. OPA has APIs that let you load policies & data into memory synchronously or asynchronously. We typically recommend starting with OPA bundles. That means you can point OPA at any HTTP server (e.g., an nginx process will even do the job) to fetch policies & data from a central location. Users often use S3 or other cloud provider storage systems. You can write your own like that comparison says.
  • RE: Conflict resolution. OPA does not have any built-in conflict resolution mechanisms. The policy defines how conflicts should be resolved in logic. You can implement allow-overrides, deny-overrides, allow-and-no-deny, priority, etc.
  • RE: Distributed Authorization. This is a bit of a naming nit, but I'd argue that if your running multiple instances of some software in a sharded/replicated manner, it's probably less distributed than what you get out of the box with OPA (because you probably have to deal with the care and feeding of that service cluster). OTOH, OPA enables distributed enforcement. Policy decision making should happen as close to the software that enforces the decision as possible. We recommend you run OPA on the same machine as the software querying OPA. OPA enables this by being as lightweight as possible (e.g., no database dependency, above)
  • RE: Other Languages. OPA policies can be compiled into Wasm and executed inside any language with a Wasm runtime available. We're working on support for NodeJS right now. More coming.
  • RE: Adopters. https://github.com/open-policy-agent/opa/blob/master/ADOPTERS.md

@SPopenko
Copy link

@hsluoyz

Please name a scenario that Casbin cannot do.

Do you have any suggestions how to implement reverse db query case with Casbin like it was described here: https://blog.openpolicyagent.org/write-policy-in-opa-enforce-policy-in-sql-d9d24db93bf4

The problem is with collection endpoint and DB queries. Like you have sql db table with pets and api v1/pets that should return all pets that you have access to. That are the pets you own and for example any pet that you treat as a veterinarian.

The classical issue is how to apply policy without fetching all table data and then evaluating each record individually. Basically auth service should answer a question: “what pets user Bob could see?” and then convert this response into the query. I was failed to find solution with casbin :( I would appreciate if someone could share the ideas how to solve this pretty common task.

@Kingside88
Copy link

@hsluoyz

Please name a scenario that Casbin cannot do.

Do you have any suggestions how to implement reverse db query case with Casbin like it was described here: https://blog.openpolicyagent.org/write-policy-in-opa-enforce-policy-in-sql-d9d24db93bf4

The problem is with collection endpoint and DB queries. Like you have sql db table with pets and api v1/pets that should return all pets that you have access to. That are the pets you own and for example any pet that you treat as a veterinarian.

The classical issue is how to apply policy without fetching all table data and then evaluating each record individually. Basically auth service should answer a question: “what pets user Bob could see?” and then convert this response into the query. I was failed to find solution with casbin :( I would appreciate if someone could share the ideas how to solve this pretty common task.

I troubled also with this issue and solved it this way:

  1. I read out the permissions the user has: enforcer.GetImplicitPermissionsForUser(userId)
  2. Iterate these permissions and filter which of the permission types you need to filter your data itself. This data I stored in a seperate List of strings.
  3. Join all the result by String.Join(','myList) to a comma seperated string
  4. Query the Database by manipulating the Where clause: SELECT * FROM pets WHERE PetId IN (MyCommaSeperatedString).

I hope to see this feature further included in Casbi.

@vtolstov
Copy link

@hsluoyz

Please name a scenario that Casbin cannot do.

Do you have any suggestions how to implement reverse db query case with Casbin like it was described here: https://blog.openpolicyagent.org/write-policy-in-opa-enforce-policy-in-sql-d9d24db93bf4
The problem is with collection endpoint and DB queries. Like you have sql db table with pets and api v1/pets that should return all pets that you have access to. That are the pets you own and for example any pet that you treat as a veterinarian.
The classical issue is how to apply policy without fetching all table data and then evaluating each record individually. Basically auth service should answer a question: “what pets user Bob could see?” and then convert this response into the query. I was failed to find solution with casbin :( I would appreciate if someone could share the ideas how to solve this pretty common task.

I troubled also with this issue and solved it this way:

  1. I read out the permissions the user has: enforcer.GetImplicitPermissionsForUser(userId)
  2. Iterate these permissions and filter which of the permission types you need to filter your data itself. This data I stored in a seperate List of strings.
  3. Join all the result by String.Join(','myList) to a comma seperated string
  4. Query the Database by manipulating the Where clause: SELECT * FROM pets WHERE PetId IN (MyCommaSeperatedString).

I hope to see this feature further included in Casbi.

If you have 10000 pets, i think in clause and store this array before query is not good

@IceQub3
Copy link

IceQub3 commented Jan 14, 2022

I belive that knowing what animals you own isnt the responsibility of the auth service nor policy. The database itself shoud keep record on pet ownership and policy should be use to istruct service over joining the tables and filtering results. (Should user read only his own animals? Then use specific implementation. Shoud user get access to other animals, lets say Georges animals, than querying shoud be performed as all animals owned by george and the user.
The db dont understand why this user is allowed to query Georges animals. It is in the policy that user can query animals of direct employees.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment