Settings

Theme

Aserto: Developer API for permissions and RBAC

aserto.com

114 points by vklmn 4 years ago · 52 comments

Reader

fabian2k 4 years ago

This is probably a pretty stupid question, or at least based on some misconception of mine about this space. But I don't really understand how permissions as a service or API can work efficiently.

If I request a single resource, of course this can work if I ask a second API on whether the request is allowed or not. But if I query a database for a list of items, to add access control I need to modify the database query. I can't just filter after the fact, it's too easy to cause pathological performance issues there e.g. if the user has only access to a very small subset of a large list of results. How does this work with a separate access control API that can't directly modify the database query?

  • emreb 4 years ago

    Disclaimer, I am a founder of Cerbos. At Cerbos, rather than writing policies in Rego, you can write them in a much simpler YAML/JSON (much more like AWS IAM)

    (a bit late to the party)

    Hi Fabian, At Cerbos we had to handle this issue as well and wrote a blog post about [1] how we can convert a policy into a generic AST that you can use in your data filtering logic on your data storage. This way you can empower your data storage queries to only fetch the relevant records.

    To showcase how this works, we have released a Prisma ORM plugin [2] that converts our AST to Prisma filters - you can see a demo on Prisma’s YouTube channel[3]

    [1]: https://cerbos.dev/blog/filtering-data-using-authorization-l...

    [2]: https://cerbos.dev/blog/fully-featured-authorization-for-you...

    [3]: https://youtu.be/lqiGj02WVqo?t=3616

  • jzelinskie 4 years ago

    Disclaimer: I am a founder of Authzed (W21).

    Generally, this problem is called ACL-Filtering[0][1] and can be done in two ways: "pre-filter" and "post-filter". Sometimes you might even have to do both.

    If you decide to use a service/database for permissions, similar to SpiceDB[2], there are often specialized APIs for directly listing the entities a subject has access to in various ways. You can take these results and feed them into a database query to select only the authorized content. This doesn't have to just be a list of IDs, but can also be datastructures like bitmaps, effectively providing your database with a custom index for your query. Systems that implement some of the novel parts of the Zanzibar paper[3] can also enable you to cache these values in your database until your application performs an operation that invalidates the results.

    Filtering once you've queried all possible results from your database can also be more performant than you'd think, because you can amortize performance by lazy loading and performing permission checks in parallel. We have some pretty large systems that are purely using this strategy. The code for filtering can also be made extremely elegant because it can be hidden behind the iterator interface in whatever programming language you're using.

    [0]: https://docs.authzed.com/reference/glossary#acl-filtering

    [1]: https://authzed.com/blog/acl-filtering-in-authzed/

    [2]: https://github.com/authzed/spicedb

    [3]: https://authzed.com/blog/what-is-zanzibar/

    • gertd 4 years ago

      So the idea is that you create a candidate set of resource keys from the permission system and join that with the external database and / or use it as a post filter?

      • gertd 4 years ago

        @jzelinskie care to respond, I am really interested in the answer?

        • jzelinskie 4 years ago

          You're correct. The only thing I'd add is that post filters can also be done without a candidate set of resources by performing individual permission checks for each potential resource. This is slower, but, as I mentioned, it can actually be perform better than you'd think with some tricks.

          Apologies for the delayed response.

  • lmeyerov 4 years ago

    We've passed on most of the google-pointing technologies in this thread precisely because of that architectural footgun

    Instead, we went with Casbin (microsoft research) because it can push to your DB (including multi-tenant-sharing if you scale) and a legit modern policy engine - A(R)BAC, ACL, etc. Definitely warts, but pretty close to what I'd hope architecturally, meaning a clear path to prettier UIs, plugging into automatic SMT solvers/verifiers, etc, and till then, pretty easy from whatever backend lang + SQL DB you use.

    Long-term, stuff like row-level security in your SQL / metadata store makes a lot of sense (people pointing that out in the thread below), but RLS is still awkward in practice for even basic enterprise RBAC/ACL policies. Until then, Casbin-style architectures are the equivalent of a flexible external policy decision point with the actual compute still being pushdown to wherever you want, including the DB: win/win.

    I wish the VC money went this way instead, but I see why $ goes to simpler "google for everyone else" pitches, so here we are :(

    • ogazitt 4 years ago

      You bring up a good point with respect to the "Google for everyone else" technologies. The fact is that very few organizations are the size of Google (or have the SRE team / expertise that Google does). Zanzibar works at Google because they have a geo-scale private fiber investment, and an SRE team that can operate many global instances. The cache consistency elements of Zanzibar are the hard problem here.

      We chose a more pragmatic approach with Aserto. We believe that most authorization problems can be expressed as a combination of rules and data. A system that is 100% rules or 100% data isn't pragmatic.

  • samjs 4 years ago

    It's actually a pretty great question!

    As others have mentioned, authorization often requires both a single method to authorize "can the user perform this action on this resource" as well as more flexible versions like "what are all the resources this user can perform this action on". That's one part of why authorization is hard, I wrote an article on this a little while ago [1]. At Oso (disclaimer: I'm the CTO), we solve this by turning authorization logic into SQL [2].

    Supporting those APIs in a generic service definitely turns up the difficulty level -- you no longer have a single database to query.

    The thing is, if you have multiple services, you might already be in that situation. If I need to query another service to ,e.g., find what projects a user belongs to, and then need to go combine that with data in my database, I'm going to need to start worrying about how to do that efficiently. In those situations starting to centralize that data + logic starts making sense -- we talk about this in [3]. So now there's a bunch of companies with different takes on how to best solve this, including Oso.

    ---

    I feel bad about self-promoting so many links here... but we're passionate about this subject so we've been writing a lot about it!

    [1]: https://www.osohq.com/post/why-authorization-is-hard

    [2]: https://www.osohq.com/post/authorization-logic-into-sql

    [3]: https://www.osohq.com/post/microservices-authorization-patte...

    • DandyDev 4 years ago

      Hey samjs, we've been using Oso at Source.ag for a month or so, and we're really happy with it! Precisely the fact that you solve authorization on a resource level and implement filtering on the DB level, makes it super useful!

      The biggest gripe we have, is lack of support for SQLAlchemy 2.0 style queries and lack of support for DB & Python enums as role names

      We had a chat with Graham who told us about your upcoming cloud offering. Looking forward to that!

      • samjs 4 years ago

        Thank you! We're looking forward to sharing more about Oso cloud too :)

    • ogazitt 4 years ago

      Welp, you know you're solving a hard problem when two other founders drop links in your HN thread :)

      More seriously, I agree that there are a number of challenges, and different use-cases tend to require different approaches. Over time, we think there will be a set of common patterns that emerge, which will help the industry move towards a more consistent set of authorization experiences. And that will be great for everyone.

  • ogazitt 4 years ago

    Great question. There are two scenarios that are relevant for authorization:

    1. Gating the operation (whether it's retrieving a single resource, or creating / updating / deleting a resource). In this scenario, the application does need to call the authorizer before performing the operation on the resource, but the relationship between the authorizer and the application is at "arms length".

    2. Filtering a list of resources. In this scenario, the authorization system can help you by running what in OPA is known as a "partial evaluation", which returns an abstract syntax tree. Your code would then walk that tree and insert the proper where clauses (if you're talking to a SQL back-end). As you mentioned, by necessity, your application needs to work more closely with the authorizer.

  • rad_gruchalski 4 years ago

    If you are using Postgres (or YugabyteDB) then you can use row level security for that.

    • ogazitt 4 years ago

      Authorization is really about "defense in depth". In a ZTA model, your access proxy, authentication system, API gateway, application middleware, and data layer all provide additional levels of protection [0].

      Using your DB's row-level security for data filtering is definitely complementary to API authorization.

      [0] https://www.aserto.com/blog/modern-authorization-requires-de...

      • rad_gruchalski 4 years ago

        Yup, and I'd use Keycloak with a PostgreSQL extension to drive both together. I'd drive RLS from Keycloak if I was going to go that way.

eatonphil 4 years ago

There are a lot of new-ish products in the last 5 years in the auth/identity space. I have been meaning to dig into them: Kanadm, Keycloak, Ory, SuperTokens, Oso, FusionAuth, CAS, maybe Authzed. I hadn't heard of Aserto yet, adding them to the list. Although I'm most interested in OSS products and Aserto looks like it is hosted-only.

If anyone has already done an independent study of the ecosystem I'd love a link.

  • ogazitt 4 years ago

    Aserto is based on a few open source projects: OPA [1], policy CLI [2], and Open Policy Registry [3].

    Architecturally, the Aserto authorizer is packaged up as a docker container and deployed as a sidecar or microservice in a customer environment. The control plane typically runs in Aserto's cloud (although you could run it on your own if you needed full control of the end-to-end solution).

    [1] https://www.openpolicyagent.org/

    [2] https://github.com/opcr-io/policy

    [3] https://www.openpolicyregistry.io/

    • eatonphil 4 years ago

      Being based on open source projects doesn't mean too much (Youtube is written in Python, so it's based on open-source). Having a consistent language (OPA) does mean something.

      But fundamentally I meant that it doesn't seem like you can run your entire system self-hosted and the code for it is entirely OSS. Do I have that right?

      • ogazitt 4 years ago

        You're right that the control plane currently is not OSS. Most people we talked to when we first embarked on the journey said that it was critical for the authorizer to run locally (and be OSS), but they preferred to not have to operate the control plane.

        With that said, our intent is to create the option to run the entire system self-hosted.

  • kache_ 4 years ago

    The biggest competitor in this space: build your own

    Hard to develop a SaaS service when the integration needs to have such close locality to your customers' systems.

    • ogazitt 4 years ago

      Hi, this is Omri, co-founder of Aserto.

      Your comment is spot on - that's exactly what we've found. Authorization needs to be deployed right next to the application - no one is going to take a dependency on a SaaS developer API that is "the internet away", when authorization is in the critical path of every application request. That's why Aserto is packaged as a sidecar that you deploy right next to your application. The sidecar synchronizes state with the control plane, so authorization decisions are made with data that is locally cached.

      It's also the case that authorization has to be done in the context of users that come from an identity provider. Aserto automatically syncs users from identity providers / directories (Okta, Auth0, etc).

  • itsronenh 4 years ago

    Aserto takes a hybrid approach. It runs a hosted control plane where you configure your user-directory, authorization policies, etc. But the authorization logic itself can run alongside the application that uses it, ensuring high availability and low latency.

    • rad_gruchalski 4 years ago

      This can be done with Keycloak Authorization Services and custom logger. Keycloak loggers can be essentially anything, and they can listen and react to any kind of event happening inside. For example: policy create, update, delete. Those events can be forwarded to whatever needs to build your OPA policies.

      Keycloak is a very solid product. The main aspect speaking in favor of Keycloak is its extensibility. Nothing beats it.

      The problem with Keycloak is that people generally don't want to invest too much into learning it.

claytongulick 4 years ago

So much of authorization is context / application dependent, I'm struggling with this a bit.

For example, I have a cluster of services. I allow access to some of them, for certain actions, based on whether the user is part of a patient's care team.

That's very dynamic, I need to do a FHIR query to one of my services to determine that. Then there's a lot more logic, like what servicer / organization affiliation the user is part of, this is also a runtime lookup in a shared session state thing, etc...

I just list all that as a basic example, there are so many things that are application specific that require runtime evaluation, it's hard for me to understand the benefit of writing all that in a different language, in a different place, where I can't use the libraries and utilities that are already part of the application.

  • ogazitt 4 years ago

    That's indeed why authorization is a harder problem than authentication - because much of it is domain-specific.

    Still, there are many things an authorization system can help with. For example, the service/organization affiliation of the user is easily expressed as a set of attributes / properties / roles on the user. If that's stored in a central directory, and the authorizer has a cached copy, you can use this context as part of your policy for making authorization decisions.

    Lifting the authorization policy into a central repo allows you to consolidate authorization logic, and also enables separation of concerns. SecOps can evolve the authorization policy of the application without having to ask developers to revisit the logic in all the places it exists. In fact, we have customers that have their secops team deploy new versions of the authorization policy without having to redeploy the application.

    Another example is having front-end code that can dynamically render component state (visible or enabled) based on the same authorization rules that the back-end / API uses. We have nice examples of this in our "peoplefinder" demo [0], which you can launch as a quickstart [1].

    [0] https://github.com/aserto-demo/peoplefinder

    [1] https://www.aserto.com/quickstarts

  • sizediterable 4 years ago

    But what if your services are written in different languages from each other and they need to perform similar authz checks? Sure, each service might need be responsible for its own data fetching, but the actual logic over the data can be written in one common language (Rego) and have one single source of truth.

    • claytongulick 4 years ago

      Well, I'm in exactly this situation right now.

      The approach I've taken is to implement my own application gateway using node-http-proxy.

      I use npm workspaces to share common functionality between all the node parts of the application, including the api gateway / reverse proxy.

      I configure the other services to trust a HTTP header that's injected in the api gateway (and explicitly deleted from incoming requests) that includes details about the user. For example, Apache Superset (and several other services) support the REMOTE_USER header.

      Honestly, doing this in a high-level language like NodeJS with node-http-proxy is even simpler to do and easier to read / audit than what I've seen in Rego, plus I get to use all the common utilities for dynamic service access, database access, etc...

      This borders on a "NIH" thing, but I think if you saw the actual implementation, it's even less complex than what I'm seeing from these examples. It took me a couple hours to throw together, it's easy to extend, and supports a multitude of authentication scenarios, including shared-session (which would be tough with Rego).

      • ogazitt 4 years ago

        That approach could definitely work if all you need for authorization is context about the user. Sometimes that context does get large, and it's hard to put it all in an HTTP header. This is a common problem for SaaS products that bake a bunch of scopes into their JWT and put it into the HTTP Authorization header. We've helped some of our customers unroll that approach and create an explicit authorization service that the app calls.

        Also, once you start incorporating resource-specific information in your authorization decisions, this approach starts to break down. The gateway could be made to understand resource-specific information, but then you're essentially moving the problem from the application to the gateway. And typically you want your API gateway to make forward/block decisions quickly.

        Happy to chat about your use case! You can find me at @omrig / omri at aserto dot com.

    • ogazitt 4 years ago

      This is indeed one of the benefits of the policy-as-code approach.

      And Rego syntax is much easier to grok than other "-as-code" approaches (read: wall-of-yaml)

  • itsronenh 4 years ago

    This goes straight to the core of what makes authorization in complex applications such a challenge. You hit the nail on the head when you say that authorization in inseparable from each application's unique circumstances.

    At the most abstract level, an authorization decision is an answer to the question "is an identity (user, service, computer, etc.) allowed to perform an action on a resource?".

    Each one of these constituents (identity, action, and resource) may include contextual information that is unique to the application at hand. Aserto gives you the ability to imbue each one with the necessary information.

    Identities are stored in a directory where they can be enriched with arbitrary data. Roles, teams, attributes, and anything else that is directly tied to an identity whose actions need to be authorized.

    Relevant information about the resource being accessed is collected by the application and sent as part of the authorization call.

    Then there are the authorization policies that receive identity and resource information and make decisions.

    There can be multiple ways to model an application's authorization scheme. In your example it sounds like the user (identity) is a care giver and the "resource" is patient data. If users belong to numerous care teams and their membership in them is highly dynamic, your application may perform the FHIR query to retrieve the identities of the the patient's care team prior to the authorization call and include that information in the resource context.

    The policy can then make decision based on whether or not the acting identity is a member of the team, as well as any other relevant information (e.g. are they the patient's primary care giver or a specialist?).

    There are many advantages to keeping authorization policies separate from application logic. Change management, provenance, and testability are a few.

    Having a single place where all authorization policies are defined allows us to reason more deeply about the behavior of our applications.

    • claytongulick 4 years ago

      I totally get the benefits, the part I'm struggling with is the real-world details.

      Like, the amount of effort it would be to put in application logic in order to determine attributes that would then be put on to the profile would be more than that which would be required to just have auth native in the code.

      Then there's the problem of keeping those attributes in sync with the application as things change.

      Then there's the problem of debugging when things go wrong - instead of being able to inspect the application state and determine the issue, now I have two places and different processes for issue resolution.

      I'm not talking about this in a hypothetical sense - I've tried this before. All sort of declarative rule based systems, and integration with Auth0 with attributes stored as part of the Auth0 profile, etc...

      After doing it and balancing the benefits, I've found that having well-architected code base with auth as a separate concern, but embedded within the native code (as a separate class/service/module/etc... is more effective and less work with better performance characteristics.

      Obviously this doesn't apply to every situation, I can think of several scenarios where third-part auth would work very well, I just don't run into them a lot.

sparsely 4 years ago

This looks so cool. I've always wanted something like this, especially being able to write the policies in Rego. I can't work out if it supports delegation though, i.e. service A temporarily allows service B to access a resource which normally only A has access to.

  • viovanov 4 years ago

    If the caller can authenticate with the services, I think you can write some rego that does something like this. I'm interested in what the flow looks like. Does the caller talk to A first to initiate this delegation?

  • gertd 4 years ago

    You can create rules which take in to account that there is a temporary grant, you do need to account for that somewhere in the form of accessible state. This could be achieved using the tenant level resource state, which is immediately updated and can be referenced from the rego rule.

rschwabco 4 years ago

Can't I just use Auth0 for authorization?

  • ogazitt 4 years ago

    Auth0 is a great developer API for authentication, and Aserto picks up where Auth0 leaves off. The "contract" between the authentication system (Auth0) and the authorization system (Aserto) is a signed JWT.

    You can get away with very simple access control using scopes embedded in a JWT token, but that approach runs out of room pretty quickly [0]

    With Aserto, you can write authorization rules that are evaluated for every application request, and reason about the user attributes, the operation, and any resource context that is involved in the authorization decision.

    [0] https://www.aserto.com/blog/oauth2-scopes-are-not-permission...

  • janczukt 4 years ago

    As an ex-Auth0 I was watching Aserto for a while - it is indeed elegantly designed to naturally pick up where Auth0 leaves you. I wish this was available when we were adding authorization to Fusebit APIs. But well, next startup...

    • ogazitt 4 years ago

      Thanks for the kind words! Maybe next time you look at evolving your authorization model, we can chat :)

  • kache_ 4 years ago

    Auth0 is building something pretty cool akin to Zanzibar

    https://play.fga.dev/

    • wereHamster 4 years ago

      There are at least two startups which are re-implementing something like zanzibar. In my experience, RBAC is too simplistic for even not so advanced apps. For example, with RBAC alone you can't express «User X can edit object Y», if object Y is one of many objects in a collection. Zanzibar – and any system building on top of tuples (subject, relation, object) – can express that quite intuitively.

      • ogazitt 4 years ago

        RBAC is simple to get started with, but indeed pretty limited. We tend to use the term because it's more recognizable than ABAC or ReBAC.

        The {subject,relation,object} tuples do provide a convenient way to express an ACL-based system.

        Most real-world systems we've encountered tend to have a combination of user-centric and resource-centric aspects to them. With an ABAC-style policy, you can easily enforce relationships like "user X can edit objects in project Y, and can read objects in project Z". In fact, the Aserto policy for Aserto [1] uses this style of authorization, without going "full-tuple".

        In fact, for many use-cases, the prospect of creating an ACL for every resource feels like a management nightmare for the folks we've talked to, and they typically have a "resource group" construct or hierarchy that they want to treat the same from an authorization perspective.

        Finally, in addition to the user model, Aserto has a resource model, and we're exploring evolving it more towards the tuple approach.

        [1] https://github.com/aserto-dev/policy-aona

        • wereHamster 4 years ago

          Zanzibar has a notion of «User sets» to allow expressing conditions such as «File X can be viewed by (all users who can view Folder Y)» to avoid too much duplication in the rule sets. One challenge they had was to make resolving these rules not too slow, since that forms basically a graph (= graph traversal)

          • kache_ 4 years ago

            Reading the Zanzibar paper is actually how I learned about how powerful of an optimization technique denormalization could be

            • ogazitt 4 years ago

              It's definitely a good paper :)

              Denormalization has been around since Date/Codd invented 6NF and relational databases, and then we all realized that most applications have to precompute some joins in order to execute in a performant fashion. In SQL Server we used to call them "materialized views".

          • ogazitt 4 years ago

            Yes, flattening the graph is essential to getting reasonable performance.

            A separate (difficult) problem is to keep all the tuple data consistent with the data in your store (often these contain duplicate info).

bradhe 4 years ago

I've been following Aserto for a while actually, really excited to see this development. Makes a great compliment to Auth0. Also the stuff they're doing for the OPA ecosystem is awesome!

dew2105 4 years ago

Auth is a major challenge and pain point... and Aserto is really impressive. Love the open source vs. completely walled garden approach.

apoland 4 years ago

I've built my own authz too many times. The prospect of having a standard framework to do this is encouraging.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection