Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion menu/navigation.json
Original file line number Diff line number Diff line change
Expand Up @@ -3949,6 +3949,10 @@
"label": "Manage user permissions for Serverless SQL Databases",
"slug": "manage-permissions"
},
{
"label": "Use Row Level Security on a database",
"slug": "use-row-level-security"
},
{
"label": "Edit a Serverless SQL Database's autoscaling",
"slug": "configure-autoscaling"
Expand Down Expand Up @@ -3978,6 +3982,10 @@
{
"label": "Securing connections using SSL/TLS",
"slug": "secure-connection-ssl-tls"
},
{
"label": "Using Row Level Security with PostgREST",
"slug": "postgrest-row-level-security"
}
],
"label": "API/CLI",
Expand Down Expand Up @@ -5333,4 +5341,4 @@
],
"label": "Additional Services"
}
]
]
84 changes: 84 additions & 0 deletions serverless/sql-databases/api-cli/postgrest-row-level-security.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
---
meta:
title: How to use Row Level Security with PostgREST for Serverless SQL Databases
description: This page provides the steps to use Row Level Security with PostGREST for Serverless SQL Databases
content:
h1: How to use Row Level Security with PostgREST for Serverless SQL Databases
paragraph: This page provides the steps to use Row Level Security with PostGREST for Serverless SQL Databases
tags: sql-databases serverless database row-level-security postgresql postgrest
dates:
validation: 2024-09-24
posted: 2024-09-24
categories:
- serverless
---

- A Scaleway account logged into the [console](https://console.scaleway.com)
- [Owner](/identity-and-access-management/iam/concepts/#owner) status or [IAM permissions](/identity-and-access-management/iam/concepts/#permission) allowing you to perform actions in the intended Organization
- [Created a Serverless SQL Database](/serverless/sql-databases/how-to/create-a-database/)
- [Created two applications](/identity-and-access-management/iam/how-to/create-application/) in IAM

## Use Row Level Security with PostgREST

PostgREST built-in Row Level Security based on users JWT relies either on [role impersonation](https://docs.postgrest.org/en/v12/references/auth.html#user-impersonation) or [transaction-scoped settings](https://docs.postgrest.org/en/v12/references/transactions.html#tx-settings). Due to connection pooling, Serverless SQL Database currently only support transaction-scoped settings and requires using a single PostgreSQL role for all queries (the internal `role_readwrite` in PostgreSQL).

1. [Install PostgREST](https://docs.postgrest.org/en/v12/tutorials/tut0.html#step-1-install-postgresql)

2. Create a `tutorial.conf` file with the following content:
```
db-uri = "postgres://[user-or-application-id]:[api-secret-key]@[database-hostname]:5432/[database-name]?sslmode=require"
db-schemas = "[your database schema]"
jwt-secret = "[your jwt secret]"
```
where:
- `db-uri` should use credentials with an application having **ServerlessSQLDatabaseDataReadWrite** permissions (and not **ServerlessSQLDatabaseDataReadWrite** neither **ServerlessSQLDatabaseFullAccess**)
- `db-schemas` is your database schema. You can use `"public"` as a default value.
- `jwt-secret` can be generated using the command `openssl rand -base64 32`

3. Run PostgREST:
```bash
postgrest tutorial.conf
```
You can check that your are able to query your database by [generating a JWT](https://docs.postgrest.org/en/v12/tutorials/tut1.html#step-3-sign-a-token) with the payload data `{"role": "role_readwrite"}`:
```bash
curl http://localhost:3000/pets \
-H "Authorization: Bearer $TOKEN"
```
where `$TOKEN` is your generated JWT.
A pet list should display.

4. Connect to your Serverless SQL Database with **ServerlessSQLDatabaseFullAccess** permissions, and delete the existing policy on the `pets` table:
```sql
DROP POLICY pets_keeper ON pets;
```

5. Create a new policy on the `pets` table:
```sql
CREATE POLICY pets_keeper ON pets TO role_readwrite
USING (keeper = current_setting('request.jwt.claims', true)::json->>'user_type');
```
This policy will use `current_settings` instead on `current_user` and thus check for additional fields contained by the JWT instead of only the `"role"` field.

6. Generate a JWT with the following payload data:
```json
{
"role": "role_readwrite",
"user_type": "role_readwrite"
}
```
<Message type="tip">
In this configuration, `user_type` value from JWT will be checked against `keeper` column value in your database to authorize access. You can replace `"user_type": "role_readwrite"` by any alternative field name or value depending on your use case. However you need to keep `"role": "role_readwrite"` for any kind of users you want to authenticate through PostgREST, because alternative roles (such as `role_admin`) will already have too much privileges and be able to see any data.
</Message>

7. Query your database using this JWT through PostgREST:
```bash
curl http://localhost:3000/pets \
-H "Authorization: Bearer $TOKEN"
```
You should only see pets with a `keeper` column value of `role_readwrite`.

Your new application can now only access a specific subset of rows based on its permissions using transaction-scoped settings.

<Message type="tip">
You can change your JWT payload data with `"user_type": "role_admin"` and see that only another set of rows will be displayed. You can go further by adding any additional fields or values to filter, and edit your policy to filter on a more complex set of rules.
</Message>
90 changes: 90 additions & 0 deletions serverless/sql-databases/how-to/use-row-level-security.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
meta:
title: How to use Row Level Security with Serverless SQL Database
description: This page explains how to use Row Level Security with Serverless SQL Databases
content:
h1: How to use Row Level Security with Serverless SQL Database
paragraph: This page explains how to use Row Level Security with Serverless SQL Databases
tags: sql-databases serverless database row-level-security postgresql postgrest
dates:
validation: 2024-09-24
posted: 2024-09-24
categories:
- serverless
---

Row-Level Security is a database security mechanism that allows access only to specific rows of a table based on a user's role or permissions.

Row Level Security can be actived with Serverless SQL Databases for a maximum of two different roles, having both read and write permissions. This can be used to restrict access to a subset of users with frameworks or tools such as [PostgREST](https://docs.postgrest.org/en/v12/).

This requires setting up different [IAM permissions sets](/identity-and-access-management/iam/reference-content/permission-sets/) for each role (**ServerlessSQLDatabaseFullAccess** or **ServerlessSQLDatabaseReadWrite** for one role, and **ServerlessSQLDatabaseDataReadWrite** for the other).

<Macro id="requirements" />

- A Scaleway account logged into the [console](https://console.scaleway.com)
- [Owner](/identity-and-access-management/iam/concepts/#owner) status or [IAM permissions](/identity-and-access-management/iam/concepts/#permission) allowing you to perform actions in the intended Organization
- [Created a Serverless SQL Database](/serverless/sql-databases/how-to/create-a-database/)

## Add sample data and create PostgreSQL Row Level Security

1. [Connect to your Serverless SQL Database](/serverless/sql-databases/quickstart/#how-to-connect-to-a-database) with a PostgreSQL client such as `psql`:
```bash
psql "postgres://[user-or-application-id]:[api-secret-key]@[database-hostname]:5432/[database-name]?sslmode=require"
```

2. Add sample data to the database using the following command:
```sql
CREATE TABLE pets (name varchar, keeper varchar, id int);
INSERT INTO pets VALUES ('Stuart','role_admin',1),('Nemo','role_admin',2),('Alfie','role_readwrite',3),('Peanut','role_readwrite',4);
```

3. Run the command below to enable **Row Level Security**:
```sql
ALTER TABLE pets ENABLE row level security;
```

4. Run the command below to create a PostgreSQL policy so that users or applications connecting with `role_readwrite` can access a `pet` row only if its `keeper` column value is `role_readwrite`:
```sql
CREATE POLICY pets_keeper ON pets TO role_readwrite USING (keeper = current_user);
```

5. (Optional) Run the command below to check that you can see all the data with your current connection:
```sql
SELECT * FROM pets;
```
All the data contained in the database displays, as you are connected with `role_admin`.

<Message type="tip">
You can verify the current role your are connected with using the following command:
```sql
SELECT current_user;
```
</Message>

## Create an IAM application with Row Level Security enabled

1. Create a new [IAM application](/identity-and-access-management/iam/how-to/create-application/).

2. Create a new [IAM policy](/identity-and-access-management/iam/how-to/create-policy/), and add the **ServerlessSQLDatabaseDataReadWrite** permission set to the application you just created.

<Message type="note">
You must provide **ServerlessSQLDatabaseDataReadWrite** permission set and not **ServerlessSQLDatabaseReadWrite** permission set. Indeed, all connections to your database performed with the former permissions set will use `role_readwrite` in PostgreSQL, whereas all connections performed with the latter, or **ServerlessSQLDatabaseFullAccess** will use `role_admin` in PostgreSQL.
</Message>

3. Create an [API Key](/identity-and-access-management/iam/how-to/create-api-keys/) for this application, and connect to your Serverless SQL Database with this application.
```bash
psql "postgres://[new-application-id]:[new-api-secret-key]@[database-hostname]:5432/[database-name]?sslmode=require"
```

4. Run the following command to list the `pets` this application has access to:
```sql
SELECT * FROM pets;
```
Only the pets with a `keeper` column value of `role_readwrite` display. Your new application can now only access a specific subset of rows based on its permissions.

<Message type="tip">
Row level security and policies can be created or deleted by a table owner. In this example, you can check table owner with the following command:
```sql
select * from pg_tables where tablename = 'pets';
```
</Message>