Techconative Logo

Authorization Woes :

  KETO way of solving

Wed Aug 09 2023

Access_Control  |  Authorization  |  Keto  |  RBAC  
Authorization Woes - KETO way of solvingimage

Introduction

This is the third part of our Authorization series. In the previous blogs, we discussed typical challenges when implementing an authorization solution and how OPA helps to solve some of them. In this section we will examine authorization woes with respect to keto access control server. Keto is based on Google’s authorization solution Zanzibar, whose details have been published by google in 2019. Ory Keto is primarily designed to provide flexible and scalable access control for microservices and modern applications. It aims to be a complete access control solution for complex, distributed systems. Lets leverage the build blocks of keto and see some of the building blocks necessary and see how we can leverage it to implement the access control server using Keto.

Keto building blocks

Object: Typically represents the resource on which the access control has to be enforced. Keto recommends using UUIDs as they provide a high entropy and therefore are unique identifiers.

Subject: Represents something that tries to access the resource.

Subject Set: Set of all subjects that have a specific relation on an object. Subject sets within the context of Ory Keto can exhibit recursion by indirectly referencing other subject sets. Subject sets possess the ability to refer to an object by utilizing the empty relation, which essentially translates to "any relation, including the absence of one."

Namespace: Represents a category of resource. There would typically be a namespace for each type of resource that you would need to define access for. In the Ory Permission Language, namespaces are represented as TypeScript classes and should be named using the singular form of the type they describe. The naming convention for namespaces follows the upper camel case style.

Relation: Represents the relationship of any of the entities like Object with Subject_id , Subject Set.

Relationship: Relationships in the context of Ory Permissions serve to encode connections between objects (the resources intended for management) and subjects (the individuals or entities seeking access to these resources). Each relationship is associated with a designated namespace, where its specific relation must be defined and configured.

A sample representation of building blocks.

'keto flow-chart'

Ory Permission Language

The Ory Permission Language is a syntactical subset of TypeScript. Along with type definitions for the syntax elements of the language (such as Namespace or Context), users can get context help from their IDE while writing the configuration.

ORY Keto is based on a permission language called ORY Access Control Policy Language or simply 'OPL' language.

The Ory Permission Language(OPL) is a declarative language used to define access control policies. It allows developers to specify fine-grained access control rules and conditions for resources, actions, and subjects (users, groups, etc.).

The OPL language is designed to be flexible and expressive, making it suitable for a wide range of access control use cases.

the following would be the OPL for example that we have represented in the above diagram.

class User implements Namespace { related: { manager: User[] } } class Group implements Namespace { related: { members: (User | Group)[] } } class Folder implements Namespace { related: { parents: File[] viewers: (User | SubjectSet<Group, "members">)[] } permits = { view: (ctx: Context): boolean => this.related.viewers.includes(ctx.subject), } } class File implements Namespace { related: { parents: (File | Folder)[] viewers: (User | SubjectSet<Group, "members">)[] owners: (User | SubjectSet<Group, "members">)[] siblings: File[] } permits = { view: (ctx: Context): boolean => this.related.parents.traverse((p) => p.related.viewers.includes(ctx.subject)) || this.related.parents.traverse((p) => p.permits.view(ctx)) || this.related.viewers.includes(ctx.subject) || this.related.owners.includes(ctx.subject), edit: (ctx: Context) => this.related.owners.includes(ctx.subject), rename: (ctx: Context) => this.related.siblings.traverse((s) => s.permits.edit(ctx)), } }

User, Group, Folder, and File are classes that implement the Namespace interface. Each class has a related property, which contains various relationships or associations with other entities.Folder and File classes have additional properties like permits, which define access control rules for different actions like view, edit, and rename. Access control regulations make use of a Context object (ctx), which contains attributes for portraying the current user or subject aiming to carry out actions on the namespaces. The permits property in the File class defines access control logic based onviewers, owners, parents permissions, and sibling file permissions. The permits property in the Folder class defines access control logic based on viewers and parent folder permissions.

ORY Keto - Implementation details

Having seen the OPL and building blocks of keto , we can now go ahead and figure out how to implement the keto access control server using their sdk and API endpoints.

  • Ory Keto exposes two APIs for integration : gRPC and REST.
  • It basically runs on two port 4466 for read apis and 4467 for write apis.

Write APIs

The Write API's offer multiple ways to insert and delete relationships.

Create or Delete Relationships: This API allows you to create or delete a relationship using Http and Grpc endpoints.

Example

When a relationship need to be created/deleted between a main folder and a sub-folder or a sub-folder and a file , a tuple with relation parents is created using this write API.

Read APIs

The Read API's offer ways to query relationships and permission checks.

List relationships: This API allows you to query relationships by providing a partial relationship using Http and Grpc endpoints. If we provide no relationship it returns all the relationship in db.

Example

To retrieve a list of relationships involving a specific user. They can do this by providing a partial relationship in the API call. For instance, they might want to find all the relationships where User A is connected.

Check relationships: The Check API enables you to verify whether a subject possesses a relation to an object. It handles subject sets and relationships by resolving them. When making a check request, you have the option to specify the maximum depth of the search tree. If the provided value is less than 1 or exceeds the global max-depth limit, the global max-depth value will be applied to maintain low latency and control resource usage per request. This API's primary purpose is to assess permissions and enforce action restrictions. The endpoint supports both HTTP and gRPC protocols.

Example

To check if User A has permission to read File X. They would make a request to the Check API endpoint, specifying the subject, object, and the desired action (read).

Sample Implementation

So far we have seem way to implement the keto server. Lets check how keto solves Role based access control with some extra workarounds.

Hierarchical Role Based Access Control (H-RBAC)

Role-based access control assign roles to subjects based on their responsibilities and functions and then associate those roles with the appropriate permissions or access rights. The objective of Hierarchical Role-Based Access Control (H-RBAC) is to simplify permission management by organizing subjects into roles and assigning permissions to those roles. This hierarchical approach allows for more structured and efficient access control in various systems and applications.

Let's look at a small example to understand how this H-RBAC works.

For example , If we have roles in hierarchy order from top to bottom are create ,edit and view roles respectively. If a subject has role view , then the subject can just view the file cannot edit or create one. Whereas if a subject has role edit , then that subject can have all permissions of role view provided by this hierarchy. Same way, if a subject has role create , then that subject can have all permissions of edit and view role.

Keto’s way of rescuing Authorization woes

Solving inconsistent implementation

As mentioned in the previous blog of the series, having a centralized service with standard permission endpoints solves the problem of inconsistencies in the definitions.

Policy testing and validation

Unlike rego’s test framework in OPA, we don’t have a dedicated toolkit that allows us to test the authorization policies. So any tests that you might have to write will be at your application layer.

Cost of development

Being a pre-packaged solution, ORY Keto certainly reduces the cost of development in the aspect that you don’t have to work on framework, definition and implementation of authorization.

There is also a chain of services such as ORY Hydra(OIDC), Kratos(for user management), which would work well together among themselves would help us to get a quick start.

There could be a minimal cost that you might have to pay for the learning curve, to get yourself comfortable with the Zanzibar concepts and fit in your requirement to the framework, which should be ok considering the gains.

Performance and Scalability

gRPC

Keto gets a bit of a boost by exposing its APIs as gRPC. Thus reducing the transit overhead to some extent.

Operational performance

  • With our little experiment that we ran on the c3-highcpu-8 (8 CPUs , 16 GB RAM). In which both the DB(MySQL) and the Keto server were running in the same instances.
  • And for 100 users and 200 resources, ”list resources for a given user” call had a 80th, 85th, 90th and 95th percentile of 3.73s, 3.76s, 7.7s and 15.7s respectively.

We haven’t pushed the limits of Keto further. And neither do we have any benchmarks available outside. We are happy to know if there are any extensive studies done here.

Limitations and Challenges

Implementation of dynamic resource types would be challenging, as there is no straightforward way to get it done. The performance is not so great as discussed in the Operational Performance section. But there could be an option for improvement by throwing more hardware. The Permission language is still maturing and there is a lot of scope for improvement and optimization.

  • When your permission model is logic heavy and not data heavy. I.e., You will be able to decide your permission without having to track/maintain permit/deny list(ACL) for each resource, Keto might not be the best.
  • There is no concept of tenants by OPL so we have to rely on code to maintain multi-tenancy.
  • Keto doesn't support time based access controls to allow network access on the basis of time period.
  • No scope of dynamicity in OPL. Roles and permission cannot be created or written at run time and it has to statically given through file.

Conclusion

When considering ORY Keto as an access control solution, it is essential to recognize its benefits, including a centralized service with standard permission endpoints, reduced development cost, and performance improvements through gRPC. However, it is crucial to acknowledge its limitations, such as the lack of support for dynamic resource types, time-based access controls, and dynamicity in OPL.

In this context, it’s also important to note that the claims in Zanzibar paper like having a 99.9th percentile of 100ms cannot be expected from Zanzibar based implementations for 2 reasons, Google is running 1000s of servers for their authorization and none of the Zanzibar based implementations are 100% Zanzibar yet. For example, additional indexing servers like Leopard, Request hedging and many other optimizations are part of Zanzibar which are costly to get it done in the open source implementations.

We would love to hear from you! Reach us @

info@techconative.com

Techconative Logo

More than software development, our product engineering services goes beyond backlog and emphasizes best outcomes and experiences.