From 161ba3da325d5ae2b2ff09cf3497988c99135246 Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Wed, 3 Jul 2024 08:32:16 -0400 Subject: [PATCH] docs: document more ways to secure the data api (#27756) Document ways to increase the security of Data API, including: - Disabling it entirely - Exposing a custom schema instead of the `public` schema Also found a duplicated link in the nav for CLS, so removed it. --- .../NavigationMenu.constants.ts | 8 +-- .../guides/database/hardening-data-api.mdx | 57 +++++++++++++++++++ .../content/guides/database/secure-data.mdx | 2 + 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 apps/docs/content/guides/database/hardening-data-api.mdx diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index e6bf73bdf40..05fa4fce8cc 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -734,6 +734,10 @@ export const database: NavMenuConstant = { name: 'Column Level Security', url: '/guides/database/postgres/column-level-security', }, + { + name: 'Hardening the Data API', + url: '/guides/database/hardening-data-api', + }, { name: 'Custom Claims & RBAC', url: '/guides/database/postgres/custom-claims-and-role-based-access-control-rbac', @@ -747,10 +751,6 @@ export const database: NavMenuConstant = { name: 'Superuser Access and Unsupported Operations', url: '/guides/database/postgres/roles-superuser', }, - { - name: 'Column level privileges', - url: '/guides/database/postgres/column-level-security', - }, ], }, { diff --git a/apps/docs/content/guides/database/hardening-data-api.mdx b/apps/docs/content/guides/database/hardening-data-api.mdx new file mode 100644 index 00000000000..64258cf784a --- /dev/null +++ b/apps/docs/content/guides/database/hardening-data-api.mdx @@ -0,0 +1,57 @@ +--- +title: 'Hardening the Data API' +--- + +Your database's automatically generated Data API exposes the `public` schema by default. If your `public` schema is used by other tools as a default space, you might want to lock down this schema. This helps prevent accidental exposure of data that's automatically added to `public`. + +There are two levels of security hardening for the Data API: + +- Disabling the Data API entirely. This is recommended if you _never_ need to access your database via Supabase client libraries or the REST and GraphQL endpoints. +- Removing the `public` schema from the Data API and replacing it with a custom schema (such as `api`). + +## Disabling the Data API + +You can disable the Data API entirely if you never intend to use the Supabase client libraries or the REST and GraphQL data endpoints. For example, if you only access your database via a direct connection on the server, disabling the Data API gives you the greatest layer of protection. + +1. Go to [API Settings](/dashboard/project/_/settings/api) in the Supabase Dashboard. +1. Under **Data API Settings**, toggle **Enable Data API** off. + +## Exposing a custom schema instead of `public` + +If you want to use the Data API but with increased security, you can expose a custom schema instead of `public`. By not using `public`, which is often used as a default space and has laxer default permissions, you get more conscious control over your exposed data. + +Any data, views, or functions that should be exposed need to be deliberately put within your custom schema (which we will call `api`), rather than ending up there by default. + +### Step 1: Remove `public` from exposed schemas + +1. Go to [**API Settings**](/dashboard/project/_/settings/api) in the Supabase Dashboard. +1. Under **Data API Settings**, remove `public` from **Exposed schemas**. Also remove `public` from **Extra search path**. +1. Click **Save**. +1. Go to [**Database Extensions**](/dashboard/project/_/database/extensions) and disable the `pg_graphql` extension. + +### Step 2: Create an `api` schema and expose it + +1. Connect to your database. You can use `psql`, the [Supabase SQL Editor](/dashboard/project/_/sql), or the Postgres client of your choice. + +1. Create a new schema named `api`: + + ```sql + create schema if not exists api; + ``` + +1. Grant the `anon` and `authenticated` roles usage on this schema. + + ```sql + grant usage on schema api to anon, authenticated; + ``` + +1. Go to [API Settings](/dashboard/project/_/settings/api) in the Supabase Dashboard. + +1. Under **Data API Settings**, add `api` to **Exposed schemas**. Make sure it is the first schema in the list, so that it will be searched first by default. + +1. Under these new settings, `anon` and `authenticated` can execute functions defined in the `api` schema, but they have no automatic permissions on any tables. On a table-by-table basis, you can grant them permissions. For example: + + ```sql + grant select on table api. to anon; + grant select, insert, update, delete on table api. to authenticated; + ``` diff --git a/apps/docs/content/guides/database/secure-data.mdx b/apps/docs/content/guides/database/secure-data.mdx index 61f636ea2fd..e42a13b2d9b 100644 --- a/apps/docs/content/guides/database/secure-data.mdx +++ b/apps/docs/content/guides/database/secure-data.mdx @@ -27,5 +27,7 @@ Unlike your anon key, your **service role key** is **never** safe to expose beca Supabase and Postgres provide you with multiple ways to manage security, including but not limited to Row Level Security. See the Access and Security pages for more information: - [Row Level Security](/docs/guides/database/postgres/row-level-security) +- [Column Level Security](/docs/guides/database/postgres/column-level-security) +- [Hardening the Data API](/docs/guides/database/hardening-data-api) - [Managing Postgres roles](/docs/guides/database/postgres/roles) - [Managing secrets with Vault](/docs/guides/database/vault)