Launch HN: Fortress (YC S24) – Database platform for multi-tenant SaaS
There’s a demo here: https://www.loom.com/share/761cac3090ba4db8b2ce9d713873333a?..., as well as a walkthrough of our Python SDK: https://www.loom.com/share/c4b3f95235e24d99a7ea571c4564602b
YC initially funded us for AI web-scraping, but early in the batch we realized we wanted to pivot to something in data privacy - in some ways the opposite of web-scraping…
From talking with SaaS developers, we learned tenant isolation (making sure one customer’s data is not shown to another) is often considered in development but rarely a core competency. Many developers struggled setting up Row-Level-Security (RLS) correctly on Postgres, some are enforcing application level access controls with none at the database-level at all, and many didn’t know which multi-tenant db architecture to start with and just decided to deal with it later. However, with increasing data sensitivity and compliance requirements, they’ve seen growing customer demand for stricter data requirements, including more demands for dedicated database instances or even databases deployed on the customer’s private cloud.
We also learned that SaaS developers prefer to have databases on their own cloud, and many who start on a 3rd party DBaaS eventually move infrastructure to their own cloud later. Having things on your own cloud makes it easier for SaaS to offer on-prem/full-siloed deployments and meet compliance requirements for larger customers. So we pivoted into being a BYOC platform and made Fortress integratable with cloud-native databases.
Our goal with Fortress is to give SaaS developers the ease of use of a managed DBaaS, native isolation for tenants, and the ability to programmatically provision and access database instances on any cloud.
Fortress provides SaaS developers an abstraction at the tenant level, allowing them to enforce tenant isolation through a function without having to set up RLS themselves or use WHERE statements in every query. Currently, on the Fortress platform, this is simple as every tenant in a shared database is given a logical db in a Postgres Cluster and we handle routing (We are currently working on a solution that provides native tenant isolation for tenants stored in shared tables).
Through our SDKs, developers only need to handle one connection to the Fortress client and we'll route requests and handle connection caching to ensure minimal latency to the right tenant’s data. We are working on creating more SDKs and simplifying existing ones. We currently support Postgres via AWS Aurora with plans to support other cloud-native databases and open-sourced databases via Kubernetes.
If you want to try it out, we’ve opened up self-serve to spin up new databases on your AWS cloud. You will need to create an account with Fortress (https://fortress.build/auth/sign-up) to connect it to your own AWS account - that’s what BYOC (Bring Your Own Cloud) means! But if you are uncomfortable with granting us IAM permissions, we are offering a free db on the managed Fortress cloud for you to test out our SDKs (just cancel out of the Integrations page, create a database on the Database page, and select managed as the option, you will have a limit of 1). Note: AWS takes a while to spin up new clusters, adding tenants to existing clusters should be fairly instantaneous.
To provide you something basic to pl...
86 comments
[ 3.6 ms ] story [ 152 ms ] threadHere's my two cents: your FTUX has so many steps and so many tour popups, and IMHO these are overwhelm your value prop. You have an opportunity to focus more on your value prop first and foremost. If you like, I can give you my actual use cases.
I use AWS, and I use multi-tenant Postgres such as with a tenant_id row, as well as multi-region setups, and for some projects one database per end organization tenant.
On AWS I use Aurora and also some self-managed Postgres. Some of the Postgres extensions I use are for geofencing, trigramming, etc. and these ideally could/should have tenant-specific instantiations. I code using Go & Rust. I work in regulated industries that use SOX, HIPAA, FERPA, etc.
Can you speak to if/how the Fortress value prop can help me, and if/how/when to get the API in Go and Rust?
We've seen most SaaS companies use some sort of tenant_id column and this is definitely the most popular method that developers currently use.
We want to provide a few things for SaaS developers. For one, many SaaS companies will face the need to create a completely new isolated database instance and may need to deploy this instance on a specific cloud (we know that Azure is really popular for healthcare).
Further, we want to spare the dev-experience of using WHERE clauses and/or setting up RLS. We aim to provide a seamless DX that abstracts over where the tenant data actually is and provide a unified platform that developers can trust to provide native isolation. We are pretty early but want to hear whether these resonate with you!
When talking to a specific customer, in my experience, it's better to not use phrases like "we know that many companies JUST LIKE YOU do X and Y". That seems unpersonal and frankly, a bit like a smartass.
Better:
- Reply directly to their concerns and questions without any fluff.
- Ask the customer about their problems, wants, and needs. Maximize your understanding of their problem space.
- And: Throw out the jargon. [0] It sucks.
[0] "provide a unified platform that developers can trust to provide native isolation"
We still definitely need to work on our language to best communicate this; we'll work on keeping it more concise and straightforward to best highlight what we offer.
That sounds like an AT&T customer service chatbot.
Do you speak like this to other people, in day-to-day life?
This goes against any of the main items that @jph closed with: COMPLIANCE.
So - abstracting the implementation complexity is difference than abstracting the "where data lives" - especially with Compliant requirements such as SOX and HIPAA, wtc. -- Its been a while but I've done some significant sized HIPAA and SOX, SAS70 and other compliance audits - and one of those reqs is "data retention for ~7 years" in many compliance laws... and so abstracting where data resides no beuno. (Surely you didnt mean that literally?)
I am currently working on am 10DLC compliant SMS routing platform... and so I get to dive back into compliance - and I know already I have to know where all my flows tick KPIs in a way I can visibly and empirically document life-of-a-data
And "Secure, Multi-tenant DB Routing as a Service." might be a better DNA for the tag-line.
--
Also, I think I recall youre previous HN announcement for the AI scraping?
But - in conjunction with this, it would be great to have a PWA-DB that is my own RLS multi-tenant for my personal data that I own all my records and companies have to subscribe to RLS access to my PII and blacklist all databrokers and scrape for who has my PII so I can actively manage who is accessing any of it - (Using both of your AI Scraper/Crawler tool and some-version of this seems like that could be a reality)
(I love what youre doing - as other HNers said, Got to get the right CorpoSpeak bolted on here for BigBanko :-)
That is a super interesting idea. We have also been really tickled with the idea of owning our own data, and that is somewhat of the mission that drives us to make data security and privacy more accessible for developers. I love the connection to scraping.
The example is that this can apply smart DB insertion into tables where youre using RLS as the route-ing rule that says "Any [fields of [this_type] from [urls] go [DB.schema.table.row]" and then provide views to these based on whatever presentation you want a component to view that data, like a structured form dynamically screaped into view with a RLS view rule...
(Just look at all the recent posts to HN where all these legos have basically been put up in the last 3-months.
Al Erector-Sets are currently being assembled and the amount of tool-age is mind-blowing awesome)
This prompting post on reddit was really interesting:
https://i.imgur.com/xJALx30.png
https://old.reddit.com/r/ClaudeAI/comments/1exy6re/the_peopl...
A laudable goal, but one which is easily solved at library level, or at the "infrastructure code" level. I've been doing this across a range of databases for several years.
We initially targeted startups at the moment that they are moving from a 3rd party DBaaS to databases on their own cloud. However, we just realized this was super tough to time. We experimented a bit with enterprise actually too but many of them already have huge systems in place.
We are shifting our focus to SaaS developers. We know that often, thinking about data isolation is a factor on SaaS developers' minds. We want to build a platform where they can have an incredibly simple DX while also trusting that their customer data will be isolated.
We're still thinking about this a lot. We're using AWS Aurora currently which auto-scales compute and storage, and are looking into other options such as distributed databases (Cockroach, etc.) and Kubernetes operators.
I have worked on bigger data sharing stuff, and the smaller clients have no interest in paying the single tenant tax, and the huge folks wont hear anything but.
Always try to find ways to remove an entire class of problem.
Maybe... but don't I trade that for your risks and vulnerabilities? And you're a small startup so it's tough for you to play the obvious "expert-specialist" card at this point. I think you need a strong value prop at this stage.
IMO the tagline should be a "Postgres platform for multi-tenant SaaS"
I think most companies aren’t really working to appeal the higher end of the market when trying to be “Planetscale for Postgres” - the focus seems to mainly be easy developer experience and faster iterations for startups
Prior to doing queries, you do a SQL query that sets a “Postgres environment variable”.
In very simplified terms, after that, queries automatically have a WHERE clause applied which ensures only rows with the value of the env variable are returned.
This is a good thing because it means you do not have to write WHERE customer = ‘blah’ anywhere.
Note that a Postgres environment variable is not an operating system environment variable.
[0] https://www.postgresql.org/docs/current/ddl-rowsecurity.html
EDIT: That page doesn't cover session vars, but this one does:https://www.crunchydata.com/blog/row-level-security-for-tena...
After configuring it as the parent post says, you set the environment variable like so:
SET myapp.manager = '123e4567-e89b-12d3-a456-426614174000';
Then you can just query the database and it will only return records where manager = '123e4567-e89b-12d3-a456-426614174000'
It's something like that anyway - you have to do lots of reading the docs and fiddling to make sure all the bits and pieces are set up right for it to work - which is why these folks are creating a SAAS to do all the thinking for you.
The real benefit of RLS is developers don't have to put "WHERE company_id=whatevere" on all queries, along with the risk that leaving it out or writing it wrong will reveal one client's data in another clients user interface.
I think most people think of environment variables as being for a whole process. For RLS this can be any GUC variable so it can be per-session, per transaction, etc.
Usually you would set it per transaction (and start a transaction for each request) and I think the important part you are missing to say is they are applied to any joins, CTE's, functions and views (as of the latest-1 version with the right flag).
So you write your schema, write your access (RLS) rules and can then write your queries as if you had access to the whole DB but the only parts you will see is what that user can access.
Like "we protect / monitor / audit / lock your Supabase instance".
RLS is an easy pitfall there, and it's a database used by a lot of SaaS products.
You wouldn't get the pain of managing clusters, and at the same time, you get the good role, and companies who care about data safety can use it as additional security assurance.
So in theory you could have only 'local' as a host in your .env.development file, and enable Fortress for production mode
While we hope to share similar DXs, our fundamental difference is that we are focused on a BYOC-first platform instead of a serverless Postgres platform. We realized that developers who were doing strict tenant-isolation were only doing it as a means to meet their customer's demands to close deals. Often, database isolation is not the only requirement; there are requirements on which cloud a database can be hosted on, or even asks to host the database on a private cloud. For these reasons, we thought that the BYOC angle gave us more flexibility to solve these problems as well as providing a easy-to-use interface.
What I'm guessing is that if you have a isolation=shared tenant you add a database to an existing postgresql cluster and if it is set to isolation=dedicated you setup a separate cluster? The clusters are setup with normal postgresql hosted solutions like AWS aurora and billed in the same way, right?
If so I don't understand why I'd use your product over any traditional IaC like CDK or terraform where I have done similar stuff (spin up multiple instances/clusters/databases based on tenants) and seems to integrate better with existing devops tooling or a workflow on top of CDK/terraform scripts that creates databases/schemas.
How is this defined? What is considered separated?
I dot see the value proposition here. Let's take couple of examples
If I need to have my totally separate infra for each tenant I'm going to go for terraform
If I need separate database on the same db infra, I'm Goin to either have a db initialization script that creates a usable db or clones a template database already present
So why do I need your sdk? To avoid a call to postgres to execute a script or a terraform script?
How does that work with the need for prefilled data?
Maybe I'm missing something, but I do not understand this service.
The cloud counterpart had 600+ mongodb databases split amongst 3 Mongo clusters.
The integration team took usually 2 weeks to setup the on premises software, and the cloud stuff took about a minute. The entire setup for the cloud was a single form that the integration team filled in with data.
The point I'm trying to make, is that if your customers require separate infra, they can wait a bisuness day to be setup. Meanwhile they can play on a sandbox environment.
It's also doable in fully automated fashion, but you will have to have strong identity and payment verifications, to avoid DoS, and in those cases usually contracts fly around.
That's for the b2b side.
For b2c, usually you rely on a single db and filter by column ID or similar, which can easily be abstracted away.
I think you aren't the target market. The target market is probably people who are new to coding or even self-taught indie hackers who aren't too technical but oriented towards building a product as quickly as possible
1) In any financial regulated environment your regulator will usually specifically require this (at least in jurisdictions I'm familiar with). Am I prepared to go to battle with my regulator on behalf of a vendor? Most definitely not.
2) Even if I'm not in that situation, do I trust the vendor to have tech protections that work well enough that my customer data won't leak if there's some sort of problem, leading to a GDPR/data protection nightmare? No. No I don't trust anyone that much. I wouldn't even trust code that I myself had written that much (ie when I have built b2b saas solutions I have insisted on single tenant shared nothing). I've actually used (a demo of) a multi-tenant saas where the vendor has insisted on the security of their multitenant solution and been shown another customer's data on more than one occasion.
3) Even if I did trust the vendor and wasn't in a regulated environment which required single tenant, would I be prepared to go to war with my internal legal counsel over the data protection implications of multitenant? No. I want to keep a good working relationship with them and their life is hard enough as it is. They want single tenant shared nothing that's good enough for me.
4) Even if none of the above applies a lot of big corporates will want the option to host a solution in a cloud subaccount that they own. That's clearly not on the cards with something like this.
[1] https://isae3402.co.uk/isae-3402-and-iso-27001
[2] Going for them will suck up a lot of energy, focus and time and you can't really tell which ones your clients are going to ask for in what order so there is the danger that you get the priorities wrong which would be a bad mistake in the early stage of a saas startup. So what I would recommend is you read through those and whatever nist guidelines and stuff like that and bear them in mind as you build your product, then start researching who you will get to do your ISAE/ISO27001/SOC1/SOC2 audit when you need one, then when the first client says have you got ISAE3402 (or whichever other one) you say "we're working towards it" (which is true) and as soon as you get off the call with your client call your preferred audit vendor and start the process. "We're working towards it" is an acceptable answer for most big corps because they know the process is slow (iirc it takes a minimum of 6 months for any of those because you have to demonstrate the process over time) and they are slow anyway so they don't mind it taking a minute for you to get it done. Then once you have one, the next time a client asks you for that one you have it, and if they ask you for a different one you say "we have <x> already and are working towards <y>" and rinse and repeat. It's going to be easier this time because you'll be able to repurpose some of the stuff you produced for the first one for the second and so on.
The only webapps that I've released commercially were all intended for internal use by a single customer, running on their private hardware, with usually only a single login, so I'm about as far from this space as you can get and still be a dev...
I was always under the impression that most SaaS was multitenant, with the individual tenants sharing tables, but being disambiguated by customer ID. Am I that far off?
Also any system which could notionally be multitenant but the customer is a tech-savvy large enterprise and wants to bring their own cloud. That's de facto single tenant because they're not going to host anyone else's instance are they? So where I work there are a few saas vendors we deal with where we have set up AWS subaccounts where they have some access and they host an instance of their thing in there just for us. Saas vendors will frequently do this if the contract /client is valuable enough, so it's pretty common in an enterprise context.
[1] Mambu, Thought Machine etc
Not to say that effort is or isn't worth it, but Rails companies will have to _really want_ what you offer to build on it, and your call if it's worth investing that effort on your side or not.
Also, is there any compliance that requires it to be in different Postgresql servers? I assume most companies just use some sort of isolation (tenant_id column or dedicated tenant database/table) so I wonder if this problem could better be solved as a proxy layer.
Some regional regulations (GDPR, etc.) require local and/or isolated hosting. Most companies indeed solve this with either a tenant id column, dedicated tenant databases or both. We want to simplify those architectures, and a proxy layer is exactly our idea there - we're working on a solution that handles connection pooling and routing to remove the need to cache connections on the client.
I just wish postgres on AWS had better ability to separate compute and storage.
Do you provide any per-tenant resource limits or prioritization (storage, memory, network [rates plus total], CPU)? Anything to limit the impact of noisy neighbors?
Do you provide per-tenant accounting (for billing) capabilities?
https://zenstack.dev/blog/multi-tenant#innovative-approach
What's the comparison with citus?