An appeal for baking security into the platform
Maybe this should have just been a message in #general, but I thought I'd drop it here since it sort of falls into the feature requests category.
I've been on board with keeping a lot of things out of core, but the further I go in my current backend refactor, whether using middleware or something else, I miss the certainty that I would get from true system level RLS and RBAC (and simple niceties like
updatedAt
timestamps).
To wit, my main concern is that any of the currently discussed approaches to authz require continual developer vigilance to work.
This is a problem. I can have RLS middleware, but if an engineer forgets to use it, and it manages to slip through the PR review, we're baked.
It would be amazing to have a formal implementation of configurable authz within convex, similar to how schemas work, fully enforced at the system level. I'm sure this kind of approach has been discussed internally, just wanted to make an appeal for it, and ask if you can share any more on whether it's in the realm of possibility, or else how the team is thinking about enforcement and developer confidence.19 Replies
having seen a million reasonable ways to do authz, I believe very strongly now there is no One True Religion for authz. usually RLS gets swapped for something more custom and more specific to a project as projects grow. it's too much of a blunt instrument for mature projects
ergo, convex will solve this with the (soon to be shipped) component system and e.g. a first party RLS component. we may go so far as to recommend using this first party RLS components in the docs in a new "security" section, and maaaybe so far as to introduce this component as part of a deeper tutorial flow as the recommended way for projects to get started with authz
but if the implied question is: will we make it impossible to access the low-level APIs available now, the answer is: that is very unlikely
we do view our current API as sort of the "LLVM " of databases, and these APIs will remain available for those that want to do something more custom in their own middleware/components etc
most of what's "built in" in the future will be first-party components and our mainline platform documentation recommending using those components for the initial solution to any given application need
over time, if third parties (you all) produce even better components, we'll be happy to switch the docs to recommend ecosystem components as well if we deem it appropriate, and have our developers contribute to your projects (assuming you accept our PRs 😄 )
whether this is "built in" enough or not probably gets down to the semantics of what built in means, I suppose, but happy to go deeper on that if I understand what level of primacy constitutes "built-in" enough
Good callout on the implied question - I meant to add that this should be opt-in because it definitely won’t fit all needs. I love and agree with the llvm concept. My hope is for centrally defined, system enforced authz. That’s the part I’m still not clear will be enabled through the components, but if so, I’m all for it!
I don’t actually want built in necessarily, just system enforced.
I think I said the quiet part loud - this isn't about built-in at all, actually. It's about having the mechanism available to enforce constraints centrally, rather than per-function. And I expect at the LLVM level some things need to be added/exposed to make that possible for the ecosystem, which is where the "built in" part comes from.
Just to write out how I'd go about adding in some form of access control if I were building a Convex app -- I'd wrap the "raw"
query
and mutation
from convex/_generated/server
with something that applies RLS (or whatever I want to use for access control). I'd export these as query
and mutation
and lint against use of the "raw" query
and mutation
in my codebase.
This isn't quite system enforced (a developer could ignore the lint rule and bypass this access control completely), but IMO reduces the requirement for all of your developers to be constantly vigilant since they're more or less forced into using the version of query
and mutation
with the proper access controlYeah barring use of raw query/mutation is a fair approach, agree. It does feel thin for security purposes, though.
eslint as a critical, lone link in the security chain feels like something I never want to have to write down for SOC2 😅
fwiw, at Dropbox part of the soc2 for authz was like "any code that matches a regex
auth.*
(i.e. the linter) triggers a code review from the security team", so it's not unreasonable 😛we really need an lolsob emoji
actually that's super sensible as part of the whole picture
Yeah this is a really common way to do it. Certain paths in a PR trigger mandatory review by specialized teams.
(at Asana, we had a
queryBypassingAccessControl(reasonThisIsSafe: string, ...rest)
function that I believe also triggered code review from the security team)Yeah I don't disagree on those at all as ancillary security measures
I think my core point got a bit lost here, and another message brought me back to it: https://discord.com/channels/1019350475847499849/1019350478817079338/1183119745235570788
I think folks will expect a mechanism for system level enforcement of constraints. In postgres I can set a field as unique and never think about it again, or I can limit access to write to a field for public users, and never think about it again, and have absolute certainty that those constraints will not be violated or bypassed because they're enforced by the db itself.
This may be moot if you're already enabling something like this with components, it's just not clear whether that's the case.
Basically, the read/modify concept from RLS middleware, except maybe in a specific file that convex reads and ensures the functions run at read/write time. Enforcing uniqueness, RBAC, and RLS would all work fine with a system like that, and it's opt-in so users who have more complex needs that it somehow doesn't serve don't have to use it.
I may not be thinking about this correctly, and I know the team has put a ton of time and consideration into the current direction, so this isn't an expression of doubt or uncertainty. I just want to reconcile the expectations that I and others have expressed, and hopefully refine a lot of feedback we've seen down to a fine point or two.
I think the need for this mechanism is one such point.
I’m about to jump on a flight, but I’ll write something up on this in transit.
Thanks Jamie, I appreciate it. Feel free to put off until a more convenient time too, I just post this stuff when I'm thinking about it.
@erquhart thanks for the patience. (a) I honestly needed a little downtime with family this weekend, and (b) I'm now working on this as a longer-form stack post because I think it's a question that deserves it. will have it out ASAP
I'm seriously glad you chose your family and yourself this weekend. No problem at all, can't wait to read it.
Convex had our holiday party Friday night. and while it was great, we were all a little raw and tired on Saturday 😄
@erquhart sorry for the huge delay, but finally following up on this: https://stack.convex.dev/the-software-defined-database
Convex: The Software-Defined Database
Which to choose, the expressive power of code, or the robustness of built-in database features? With Convex, you can have both. By eliminating the bou...
On the reading list 👍
"Built in database security features don't actually scale" is a really solid answer to my OP here. Really love the components concept, and this post gives great context and vision for that approach.
For others who haven't seen it yet, I can also plug https://labs.convex.dev/convex-ents which do include an RLS implementation and enforce its use through abstraction (to then fully secure the DB, you can add lint warnings against built-in function wrappers).
Convex Ents - Convex Ents
Relations, default values, unique fields and more for Convex
@erquhart I outlined how to use ESLint to prevent using the "raw" query/mutation/action here: https://stack.convex.dev/eslint-setup
Set up ESLint for best practices
ESLint is a powerful tool that goes beyond simply type checking. We go over how to set it up and implement some basic workflows with the
I saw that! Great tips in there