This post summarizes a recent customer exchange around design principles that guide the development of Katanemo: supporting convenience features only when system features don’t break. I thought it would make for an interesting post for the broader developer community on how we are designed differently.
The short answer is no. The long-answer is “sort of”. Here’s what’s happening underneath the covers. But first a quick primer.
Katanemo is built for developers that are looking to create the next Stripe, Twilio, Figma, etc. Core properties of these successful (cloud-native) apps is that they have rich APIs, which power delightful workflows for users and 3rd party application scenarios. These apps dramatically lower the bar for adoption, and activate more usage through desirable features that meet the highest security standards.
So how does Katanemo help? We match the grooves to the adoption lifecycle of a SaaS app by helping developers build critical on-boarding and security features in minutes. You can build critical authentication capabilities to sign-up users, and effortlessly scale usage within an organization via robust safety, sharing and governance controls (SSO, RBAC/ABAC, Audit logs, etc). Katanemo unifies user, machine and enterprise identity with a fine-grained permissions service - so that you can focus on time to market and features.
While we are different in several ways from others in our space, the one noticeable way is that we don’t support this notion of nested user groups. We support tags - a flat labeling system that resolves at authentication time and enables a more flexible, fast and auditable experience around permissions and access controls.
What are nested user groups? And where did they come from?
User groups as the name suggests is a way to organize users in interesting ways so that administrative tasks can be applied in bulk vs individually- like applying permissions and authorization rules. This idea was popularized by Microsoft Active Directory back in the 90s. And group nesting, simply put, is the process of putting one group inside another group.
Nested groups inherit the permissions and privileges of the group they are put under, and the idea was that this would make privilege access easier. If you update policies at a top-level group, then those permissions would neatly cascade to lower-level groups and with one full swoop the administration of policies around permissions could be made easier. But does it?
While nested groups offer some immediate gratification and convenience benefits - they create for downstream visibility, flexibility, latency, and infrastructure challenges.
To illustrate this via an example, let's look at the following nested group structure. Here the “Built-in Administrator Group” has permissions to all the resources within an application and those permissions don’t traverse to “Brenton” who is a Local user. But If “Brenton” is placed in the “Geeks Local Group” which is part of the “Built-in Administrators Group” then permissions will traverse to Brenton (and Jason) by associative nested memberships.
Naturally, it's convenient to place Brenton in a group where his permissions get elevated so that he can access a particular resource. But here are some key questions:
Modern applications must adapt workflows for today’s dynamic nature of work. Applications are now required to be nimble and adaptable, and this notion that we map users and their memberships in fixed rigid hierarchies doesn’t work anymore. Sure, users and employees will belong to static management hierarchies but their work and collaboration needs are more fluid.
Katanemo support tags - a flat labeling system that resolves at authentication time and enables a more flexible, fast and auditable experience around access controls. Shamelessly, we borrowed the design of our safety and permissions system based on the work we did with AWS IAM during our time there. AWS IAM protects over $100B in cloud workloads at scale and its design principles match to the modern way how people work.
Tags are key and value pairs that act as metadata for organizing users and application resources. Tags can be created to categorize users and resources by purpose, owner, environment, or other criteria. For example our customers (developers) use and enable the use of tags in the following way:
So, let’s borrow from the example above and show how Brenton can be given access to select resources via Katanemo without having to be placed in nested user groups.
Imagine, you’ve built a headless travel app. Your core competency is that you handle all the travel backend infrastructure and separate the presentation layer via Restful APIs. This way your customers can create UI workflows and client side experiences that match to their particular needs. Brenton is designated to manage and operate travel arrangements for executives within an organization. Clearly, Brenton can’t be placed in the “executives” user group - but he can be tagged with appropriate privileges to make changes and view executive bookings.
The above Kataemo policy (an OpenAPI-based permissions language) would grant Breton access to all bookings for executives he manages. The $resourceTags:executive directive tells Katanemo to pull values for the “executive” tag associated with a bookingID, and match all possible values for $principalTags:executives.
$principalTags is a Katanemo directive to pull tags for Brenton. And in this case we want to pull all values for the “executives'' tag so that we can ensure that Brenton only has access to bookings for the executives he supports.
Tags can be used in simple and powerful ways without impacting latencies of authorization workflows. They improve visibility. They match to the more dynamic nature of work, all without compromising security. The trade-off is that resources will need to be appropriately tagged, and users (and other authenticated principals) will also need to be tagged to ensure that safe access controls can be enforced.
At the start of this blog post, I mentioned that Katanemo “sort of” supports nested user groups. Yes, we allow developers to provide their customers self-service tools where upstream attributes (like group memberships) can be mapped to a particular Role. This convenience feature does NOT break system features (latency, auditability, flexibility, etc).
This mapping feature essentially allows a specific group membership to be mapped to a particular role. So if your customers already have user groups established upstream, during SSO workflows those attributes can be used to map to particular roles within your application. What they can’t easily do is use this feature to create unbounded recursive lookups on what a user can and cannot do.
Given that we spent a lot of time at large scale cloud providers like AWS and Azure, our design principles borrow from the work we have done with IAM that protect and power cloud services like AWS Lambda, S3, and DynamoDb. Those approaches scaled, protect over 100B worth of workloads, and fit into the modern vernacular that developers are familiar with.
Of course, like any astute reader you are probably wondering if Katanemo supports nested hierarchies for data models. For example, if an application supports the notion of Folders > Files, then users who have access to a Folder should inherit access to Files within it ? I’ll reserve the deep dive on our resource namespaces and our tag-based index for another blog post. Spoiler alert - we use namespaces available in the API schema, create a tag-index for relationships, and add a caching layer for speed.
Hope you enjoyed this post. I’ll have more engineering deep dives around our design principles in posts to follow.