`spacetime start` allows restricting who can create new databases
Objective
In an effort to improve the self-hosting user experience we need to be able to restrict publishing to only certain identities. Ideally the UX would look like this:
spacetime start -l 0.0.0.0:3000 \
--publish="restricted"
--publish-allow-list "\
c20093cd8df79879ae6d2b058650ca5112d6bb11334b5003f443cc0776da3d15,\
c20093cd824532bc5748afb2648f236de3164546275271823452354234f2f2f2,
c20093cd8df79879ae6d2bc058650ca5112d6bb11334b5003f443cc0776da3d5,"
This adds 2 new arguments to start:
--publish
- Can either be set to
openorrestricted. The default isopen.
--publish-allow-list
- This is a comma-separated list of SpacetimeDB identities that are allowed to create new databases. This does not allow you to publish to any database it only gives you the ability to create new databases.
Rationale
A huge part of why many users use SpacetimeDB is the user experience, and the current self-hosting user experience is quite bad.
Right now our documentation shows users how to install SpacetimeDB + nginx and gives them the option to block all routes except for the /v1/<database>/subscribe route for remote clients. The problem with this is then they are not able to publish remotely. There are 2 solutions to this:
- We tell the users that they have to upload their module to the remote host via sftp and then publish locally. This is a super clunky user experience. You also need to install all of the dependencies for building your module on the remote machine (including dotnet/cargo, etc.).
- We could tell them what we do with BitCraft which is restricting publish to only tailscale but this requires everyone who follows the guide to use tailscale which is also sub-optimal. I also do not want this guide to have a dependency on tailscale in order to be considered "secure".
I would like to be able to change the guide to not use tailscale and not block custom routes via nginx so that the documentation is a lot simpler and the user experience is what I would consider "optimal" which means users can just publish to their self-hosted instance like any other server.
Seems doable. A few questions:
- Why have two separate command line flags? Would it be simpler to just be in "restricted" mode if an allowlist is supplied, and "open" mode if no list is supplied?
- Do we want to, and can we from a SemVer perspective, make it so that "restricted" mode is the default?
- Would it be better for the allowlist to go in a config file someplace?
- How does this compare to
--listen-addr? Is that only a command line flag, or is it also configurable via a config file?
- How does this compare to
- Are there any other operations we want/need to restrict?
Why have two separate command line flags? Would it be simpler to just be in "restricted" mode if an allowlist is supplied, and "open" mode if no list is supplied?
I want it to be possible to say that nobody can publish, which would be essentially just using --publish-mode=restricted and then not supplying any allowed identities. For a first iteration on this I would be fine with saying that you can't "lockdown" a server. So essentially either everyone can publish or only the list of allowed identities can publish.
Do we want to, and can we from a SemVer perspective, make it so that "restricted" mode is the default?
I am open to this and I actually think in general this would be good because clearly it is more "secure" to have the server locked down by default, although there are 2 cases to consider here:
Development Users
This is the group of users who are just starting SpacetimeDB locally using:
spacetime start
In this mode, anyone should be able to publish from localhost. Our default -l 127.0.0.1:3000 does the heavy-lifting here to deny outside users from publishing to this instance. In this mode I don't think the "restricted" publish mode should be the default.
Self-Hosted Users
This is the group of users where they want to host their own version of SpacetimeDB and they want to "lock it down" where only they can publish.
I think the standalone usage flow is like this:
- Use
spacetime login showto get your identity - Install SpacetimeDB on the standalone server
- Start SpacetimeDB using
spacetime start -l 0.0.0.0:3000 --publish-allow-list <1,2,3>
Then we can warn the user that if they don't supply a --publish-allow-list then anyone can publish. But to your point, we could enforce that if your listen address isn't localhost or in 127.0.0.0/24 then we by default enable the "restricted" mode.
Would it be better for the allowlist to go in a config file someplace?
I think this should be the same as the -l 0.0.0.0:3000 flag, which I believe is only a command line flag.
Are there any other operations we want/need to restrict?
I would do this as follow-up tickets after do this first pass. I think the answer is likely yes but restricting the publish route is the highest value goal right now.
I would be nice to be able to supply the list of allowed identities using an environnent variable, it's easier for people that use Docker