I’ve written a proof of concept for an idea that’s been banging around in my head for a while. I didn’t write it with an existing production use case in mind, but I think the code is reasonably easy to read regardless.
The idea is that FDB today doesn’t provide any access control at the KV layer, which means you need something between your end user / end developer to mediate access and prevent a rogue user from issuing tn.clear_range("\x00", "\xFF")
and causing a very bad day for everyone else.
If you could write another layer that as transparently as possible spoke the FDB API (not necessarily network protocol), you could shim in this access control layer along with a few other features. My first version of as transparently as possible
is to use the Redis protocol, as there is an implementation in every popular language and it provides enough features to model the FDB API on top off.
So I call this the Gateway, since Proxy is already taken as a component name in the FDB architecture. You connect using the Redis protocol, issue a chroot
command to put your client into a directory using the directory layer, and then can transparently issue commands as if you own the entire instance. You can’t access the system keyspace (such as the metadata version key), but I could provide an escape hatch for that later using some kind of ACLs system.
To use it, you first set a tuple in the directory sys-tenant-authorization
in the formation of ["chroot_name", "username", "password"] => password
. This can be re-evaluated, but I just copied Redis’ design for the authorization system coming in Redis 6 where you have any number of users and passwords and can rotate passwords by having two passwords for the same user for a period of time.
The commands you can issue are named after the FDB API, but I didn’t implement everything yet. Just the basic ones like get
, set
, get_range
, clear_range
, clear
. To do any operations at all, you must chroot
into a directory and start a transaction. This is to prevent you from doing something wrong if you disconnect and reconnect to a different Gateway and attempt to start issuing commands again as if you’re in the same transaction as from before you disconnected. You’ll receive an error saying there isn’t any active transaction if you try. Same thing if you forget to chroot
, you’re denied.
Other than obvious stuff like more features, does this interest anyone here?
It could fulfill 3 roles:
- Provide a basic security boundary in a multi-tenant environment without sacrificing expressive power on the part of the tenants using the FDB API. This is useful for environments where an entire FDB cluster for each tenant is cost prohibitive or undesirable from a management perspective.
- Provide an interface for an existing Redis-using application to replace Redis. This is more useful if additional Redis commands were added, but
GET
andSET
are the same AFAIK. - Provide a generic platform for community investment in features not in core FDB today, such as predicate pushdown. One could imagine the Gateway coordinating with other Gateways deployed on storage servers using the boundary key API to match predicates of keys or values in large scans before returning them to the client. Another idea I had is this is a safe place to implement scripting like Redis has today with Lua. Instead of deploying an entire application with client bindings and managing all that, you could write a Lua script that does the transactional bit of your interaction with FDB entirely on the Gateway and returns and entire fully formed result, like a stored procedure. An example stored procedure is the high-contention queue pattern could be implemented in Lua.
There are a few negatives to using this. You do not get the current behavior of zero-latency set
because to you have to send the data to the Gateway for it to call the real set
on the transaction. I think this is tolerable given you would be deploying the Gateway in the same datacenter as your application and you can pipeline multiple set
commands as you can with Redis today. The second and more serious concern is maintaining correctness. My testing strategy (which I haven’t started yet, just thought about) would be to write a workload like the existing binding tester which does some operations and compares them to the operations of a regular API client. Past that, I think the regular guarantees of FDB would still apply to the Gateway.
Please poke holes, request features, and express your positive (or negative) feelings!
I’m not super invested in this conceptually, so I would prefer to hear why this wouldn’t work well, is not possible to make safe, or is not desired by anyone now before I write any more code.