RBAC Complexity in Internal Tools

RBAC Complexity in Internal Tools

Some outside-the-box ways of looking at an old problem

RBAC is hard. UI is rigid.

And I think that’s been the case for, what, 50 years? So I doubt there’s a silver bullet solution.

However, I’ve come across a few outside-the-box ideas when it comes to RBAC and internal tools, specifically:

  1. Build less UI by simplifying the problem

  2. Do more work (and then automate it) to simplify RBAC

  3. Build more UI to get visibility into RBAC

Why is RBAC a hard problem?

1. Hidden state

Simple question: “Who has access to this tool?”

Hahahahaha okay. Get ready to embark on an adventure through Okta, your database, AWS Secrets Manager, your source code, and CI/CD config files, and put this giant map together in your head. 🚃🏜️🐪🚢🌊⛰️🚠🧗🏊‍♂️📍🗺️

2. UI is rigid

Did you see the OpenAI demo where the man drew a website on a napkin with a pen and then the computer turned it into a REAL WEBSITE? And was that not the most amazing thing you’ve ever seen a computer do, because you’re a human who has experience with both: 1) drawing boxes with a pen and 2) drawing boxes with a computer; and you know that (1) is a something that people do for pleasure and (2) is something that is so terrible that companies will pay you hundreds of thousands of dollars to do it for them?

3. RBAC is hard to name

We have these concepts of “groups” and “roles”, but the problem isn’t modeling the people versus the things they do — the problem is that you don’t know what the future looks like. So you prematurely optimize, or you repeat yourself.

How often do you need to give one permission to a developer? Do you…

  1. … add the dev to a new group? (You’ll give that one person too much access!)

  2. … add that one permission to a role? (You’ll give other devs too much access!)

  3. … attach a single permission to that single person? (Fine, but now you’ve thrown away the idea of “groups” and “roles”, and you’re back at square one 🙃🙂🙃)

(This pattern shows up in CSS as well, which is why I personally ❤️ Tailwind)

4. RBAC is hard to isolate

From Chris O’Neill:

RBAC is a solution for AuthZ, but it isn’t the only solution. How granular does your authorization model need to be? Does it need to interact with multiple services or just a single stack? Does it need to span across multiple companies or just your own? Answering those questions is the hardest part of building AuthZ and where you need to align stakeholders first before building AuthZ, either with RBAC or something else.

Sam Scott, from Oso, boils it down in Why Authorization is Hard:

  1. It’s hard to enforce, because you have to enforce it all sorts of places

  2. It’s hard to isolate, because it’s entangled with app state

  3. It’s hard to model, because there are always edge cases to your pretty little role field

Where do you take your medicine? 💉

Okay, so it’s a hard problem with trade offs. Now where do developers take their lumps and accept those trade offs?

You’re a Human Run Button

In some orgs, the business people treat their devs like Human Run Buttons. “Hey can you run that query again? Thx” 📞👩‍💻🕹️

Free Access in the Summer of Love

Other orgs just give everyone access to everything 🌈🌻☮️✌️

Conditionally rendering components

If you’re in this role, you can see this button, if you’re in that role you can see that button.

This is really difficult to test. 🍝

It also leads to Frankenstein UIs. 🧟‍♂️

Making lots of apps

If you can tie your RBAC to a URL, then you can pull all those nasty conditionals out of your code.

Only problem — each new app has a fixed cost. 🏋️‍♂️

And, god help you if you ever need to move functionality between them. 🚛🚛🚛

Mapping API permissions onto UIs

It’s much easier to test RBAC when it’s implemented at the API level. Small problem — internal tool users interact with UIs, not your API.

That’s fine if the API roles cleanly map onto apps/pages, but that’s never actually the case. So one of two things happens:

  1. All the API permissions get reimplemented on the frontend anyway 🥳

  2. The frontend has buttons and inputs that mysteriously don’t work for certain users, as they silently return 401 errors 🤫

Thinking outside the box

1. Simplify the problem

What if you could get away with a simpler UI? What if that UI were so simple that it could be automatically generated from backend code?

If you’ve ever used SwaggerUI or Postman or one of the GraphQL visualizers, you’re already familiar with this approach.

This is the approach we’ve taken with Flank. Airplane and Windmill are similar. Slackbots are even simpler — a CLI for business people, to complement our 21st century IRC.

This approach scales really well from an RBAC point of view. The tradeoff is that there’s a ceiling on the functionality. If you need sophisticated UI, you have to boot out into a more sophisticated tool / framework. (Having said that, I think 80% of internal tools never reach the point that they need a sophisticated UI)

2. Automate frontend drudgery

Sometimes the fastest path through the track is the longest distance 🏎️

What if you simplified RBAC by creating a different app for each role… but then you made it easy to make lots of apps!

DraftKings home-rolled something like this. Their RBAC was controlled at the URL-level — simple to configure, no messy conditionals in code. Then, they automated the creation of boilerplate infrastructure and code, and spun up dozens of little apps.

Similarly, Retool has eliminated the fixed cost of creating different apps. Also — and this is really important — Retool has made it easy to copy + paste components between apps. This means that you can reshape your tools around the important dimension, “apps”. That’s the dimension along which Retool controls RBAC.

3. Build a little app to manage the RBAC complexity of your main app

This example from Tristan Cartledge is really interesting. He built a simple version of the AWS IAM page for his GraphQL API in Retool. Permissions map to groups. Groups map to users. It’s all editable.

Similarly, this example from Anil Vaitla is cool (scroll down to third case). He sets up a sidecar database in Retool for managing permissions. This gives his app visibility into the permissions of not just the logged-in user, but the all users in his org.

I like these examples because they’re quick and dirty. The main constraint is creativity. I myself don’t have any creativity, but I respect it when I see it ✊

Thanks to Anil Vaitla, Tristan Cartledge, Will Hester, and Chris O’Neill for providing input/feedback.