[HN Gopher] Aserto: Developer API for permissions and RBAC
       ___________________________________________________________________
        
       Aserto: Developer API for permissions and RBAC
        
       Author : vklmn
       Score  : 97 points
       Date   : 2022-02-16 15:33 UTC (7 hours ago)
        
 (HTM) web link (www.aserto.com)
 (TXT) w3m dump (www.aserto.com)
        
       | fabian2k wrote:
       | 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?
        
         | samjs wrote:
         | 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...
        
           | ogazitt wrote:
           | 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.
        
             | samjs wrote:
             | Indeed ;) https://news.ycombinator.com/item?id=28559608
        
         | lmeyerov wrote:
         | 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 wrote:
           | 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.
        
         | ogazitt wrote:
         | 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.
        
         | jzelinskie wrote:
         | 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 wrote:
           | 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?
        
         | rad_gruchalski wrote:
         | If you are using Postgres (or YugabyteDB) then you can use row
         | level security for that.
        
           | ogazitt wrote:
           | 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 wrote:
             | 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.
        
       | claytongulick wrote:
       | 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.
        
         | sizediterable wrote:
         | 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 wrote:
           | 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 wrote:
           | 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 wrote:
         | 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 wrote:
           | 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.
        
         | ogazitt wrote:
         | 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
        
       | dew2105 wrote:
       | Auth is a major challenge and pain point... and Aserto is really
       | impressive. Love the open source vs. completely walled garden
       | approach.
        
       | eatonphil wrote:
       | 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.
        
         | kache_ wrote:
         | 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 wrote:
           | 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 wrote:
         | 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 wrote:
           | 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.
        
         | ogazitt wrote:
         | 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 wrote:
           | 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 wrote:
             | 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.
        
               | eatonphil wrote:
               | Thanks for clarifying!
        
       | sparsely wrote:
       | 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 wrote:
         | 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 wrote:
         | 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.
        
       | bradhe wrote:
       | 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!
        
         | ogazitt wrote:
         | Thanks Brad! We're big fans of both Auth0 and OPA.
        
       | rschwabco wrote:
       | Can't I just use Auth0 for authorization?
        
         | ogazitt wrote:
         | 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...
        
         | kache_ wrote:
         | Auth0 is building something pretty cool akin to Zanzibar
         | 
         | https://play.fga.dev/
        
           | wereHamster wrote:
           | 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 wrote:
             | 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 wrote:
               | 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_ wrote:
               | Reading the Zanzibar paper is actually how I learned
               | about how powerful of an optimization technique
               | denormalization could be
        
         | janczukt wrote:
         | 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 wrote:
           | Thanks for the kind words! Maybe next time you look at
           | evolving your authorization model, we can chat :)
        
       | apoland wrote:
       | I've built my own authz too many times. The prospect of having a
       | standard framework to do this is encouraging.
        
       ___________________________________________________________________
       (page generated 2022-02-16 23:02 UTC)