From 7a682b01173634ce55aa6b69cc3a7a3f0589693f Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 06:51:35 -0700 Subject: [PATCH 01/11] update to column encryption docs with more explanations of risk/reward and key get/set through API. --- .../guides/database/column-encryption.mdx | 44 +++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index d750f6c33b1..9746544ad09 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -9,9 +9,27 @@ export const meta = { video: 'https://www.youtube.com/v/J9mTPY8rIXE', } -Supabase provides a secure method for encrypting columns using [Vault](/docs/guides/database/vault), our Postgres secrets manager. Vault is a Postgres extension with an integrated UI intended to act as a secure global secrets management for your project. +Supabase provides a secure method for encrypting data using [Vault](/docs/guides/database/vault), our Postgres secrets manager. Vault is a Postgres extension with an integrated UI intended to act as a secure global secrets management for your project. -Vault enables an advanced feature called Transparent Column Encryption (TCE) which provides a safe way to encrypt your data so that it doesn't leak into logs and backups. It can also provide row-level authenticated encryption. +In addition to the Vault secret storage table, Supabase also enables an advanced feature called Transparent Column Encryption (TCE) which provides a safe way to encrypt columns in your own tables so that they doesn't leak into logs and backups. It can also provide row-level authenticated encryption. + +Column Encryption comes with tradeoffs that need to be considered before using it. + + - Encryption and decryption both take time, inserting and selecting encrypted data takes more time than a "plain" column of data. Queries that must load a lot of rows with encrypted columns will be slower than those that are not encrypted. + + - Encrypted columns should never be indexed. This is because the index must store the unencrypted value of a column to be useful, which would defeat the purpose of storing values encrypted. To look up an encrypted column, you must first look up its row by some other unencrypted column, like a primary key. + + - Encrypted columns can be queried in a `WHERE` clause, but this can also have some negative performance consequences, since the value must be decrypted in order to matched to any `WHERE` qualifiers. For small result sets this is not a big deal, but broad queries that match many rows will have to be scanned and each row decrypted in order to check against the `WHERE` clause. Worst case is the entire table must be scanned and decrypted to check against a `WHERE`. + + - While you can encrypt multiple columns in the same table, each column must go through a full encryption cycle, so two columns will take twice the time as one, three columns three time as long, and so on. It is usually better to break up large tables into smaller tables with at most one or two encrypted columns, and associated them with [foreign keys](https://www.postgresql.org/docs/current/tutorial-fk.html) that can be used to JOIN them when necessary. + +In general, it is a bad idea to over-use column encryption for mundane data or data that you need to search against such as names, user or account types, addresses, country codes, etc. Column encryption is intended to be used for very sensitive data that would cause serious issues if it were to leak, such as API keys, payment keys, highly sensitive personal information, etc. + +## Encryption Keys + +Encryption requires keys, but keeping the keys in the same database as the encrypted data doesn't make any sense, it would be like leaving a key in a door lock, a door lock only makes sense when the lock and key can be separated. So similarly, the encryption keys in Supabse are kept separate from the database. + +Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionaly for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to *derive* the encryption keys used by column encryption. These keys are derived from a *Root Key* that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). ## Encrypting columns @@ -23,15 +41,19 @@ Once you've created an encrypted column, you can insert data into the table like ![Encrypted data](/docs/img/guides/database/vault-encrypted-data.png) +Note that, as mentioned above, indexing an encrypted column serves no purpose and has a detrimental effect on performance. Indexing encrypted values is not useful since the index needs to store the unencrypted value to be usable, and that would defeat the purpose of storing encrypted data. Do not create indexes on encrypted columns. + ## Decrypting data Decrypted data is accessed using a special view that is automatically created after adding an encrypted column to a table. This view decrypts the data row-by-row as you access it. By default, this view is called `decrypted_`. In the example below, the decryption view for the `profiles` table is called `decrypted_profiles`. Notice there is a new column in the view called `decrypted_emails` that contains the decrypted email value. ![Decrypted data](/docs/img/guides/database/vault-decrypted-data.png) +As mentioned above, accessing decrypted data is slower than accessing unencrypted data. Any row you query from this view will go through a decryption function, which takes some time and can be a significant performance pentalty if your query loads lots of rows. It's always advisable to look up rows by some indexed unencrypted key first, like a primary key, so that only one row is decrypted at a time. + ## Using an Encrypted Table -Now that you have TCE setup for a table, it's easy to use by simply inserting data into the table, and querying that data by looking at its generated view. The view is named `decrypted_` and by default is in the same schema as your table: +Now that you have column encryption setup for a table, it's easy to use by simply inserting data into the table, and querying that data by looking at its generated view. The view is named `decrypted_` and by default is in the same schema as your table: ```sql insert into secrets @@ -67,6 +89,22 @@ nonce | \x300a14aa721184ff7cf0f6bf088da267 Notice how there is a new column called `decrypted_secret`. This column is not stored in database or on disk at all, it is generated “on-the-fly” as you select from the view. Database dumps do not contain this information, only the view itself, and most importantly, **raw decryption keys are never stored**. +## Granting API Access to encrypted columns + +When you create an encrypted column in the `public` database schema, then that column and the decryption view that is created for it are given *public access via the PostgREST API*. In general it is not recommended to encrypt columns in the public schema, as this adds some additional security considerations that you need to think about, but it is still possible and useful in some cases depending on your level of security comfort. Only you can decide the risks and rewards of making decrypted data available to public API access. It is very strongly recommended that you must protect your public encrypted columns with a Row Level Security (RLS) Policy. + +Even though objects created in the `public` schema default to public access, There is an additional layer of security with pgsodium that must be enabled in order for decryption to work with the PostgREST API. The permissions necessary to call pgsodium functions must be granted to one of the API role that is accessing the public objects. + +There are three roles available for API access with Supabase, The `anon` role represents unauthenticated anonymous users and should *never* be granted access to pgsodium, you do so at your own risk. The `service_role` which is meant to be used by other services in your system, and whose token should never be exposed publicly, and the `authenticated` role which represents authenticated users who present a valid JWT token and are identified by the system as a known user. + +By default, only the `service_user` role is granted access to the column encryption functions. If you wish to make encrypted columns available to your authenticated users, then you must run `GRANT pgsodium_keyiduser TO authenticated;` from the Supabase console or logged in as the `postgres` role. This table shows the default permission settings for API roles accessing the pgsodium encryption functions: + +|Role | pgsodium_keyiduser | pgsodium_keymaker | +|---|---|---| +| anon | X | X | +| authenticated | X | X | +| service_role | Y | X | + ## How Key Derivation Works The current state-of-the-art in encryption libraries is [libsodium](https://doc.libsodium.org/). From 3f0a3dbad604cc57767720ee6bc965410bd0dce6 Mon Sep 17 00:00:00 2001 From: Rodrigo Mansueli Nunes Date: Thu, 10 Aug 2023 11:25:34 -0300 Subject: [PATCH 02/11] Prettier + typo fix --- .../guides/database/column-encryption.mdx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index 9746544ad09..b3873f253f6 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -23,13 +23,13 @@ Column Encryption comes with tradeoffs that need to be considered before using i - While you can encrypt multiple columns in the same table, each column must go through a full encryption cycle, so two columns will take twice the time as one, three columns three time as long, and so on. It is usually better to break up large tables into smaller tables with at most one or two encrypted columns, and associated them with [foreign keys](https://www.postgresql.org/docs/current/tutorial-fk.html) that can be used to JOIN them when necessary. -In general, it is a bad idea to over-use column encryption for mundane data or data that you need to search against such as names, user or account types, addresses, country codes, etc. Column encryption is intended to be used for very sensitive data that would cause serious issues if it were to leak, such as API keys, payment keys, highly sensitive personal information, etc. +In general, it is a bad idea to over-use column encryption for mundane data or data that you need to search against such as names, user or account types, addresses, country codes, etc. Column encryption is intended to be used for very sensitive data that would cause serious issues if it were to leak, such as API keys, payment keys, highly sensitive personal information, etc. ## Encryption Keys Encryption requires keys, but keeping the keys in the same database as the encrypted data doesn't make any sense, it would be like leaving a key in a door lock, a door lock only makes sense when the lock and key can be separated. So similarly, the encryption keys in Supabse are kept separate from the database. -Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionaly for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to *derive* the encryption keys used by column encryption. These keys are derived from a *Root Key* that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). +Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionaly for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to _derive_ the encryption keys used by column encryption. These keys are derived from a _Root Key_ that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). ## Encrypting columns @@ -41,7 +41,7 @@ Once you've created an encrypted column, you can insert data into the table like ![Encrypted data](/docs/img/guides/database/vault-encrypted-data.png) -Note that, as mentioned above, indexing an encrypted column serves no purpose and has a detrimental effect on performance. Indexing encrypted values is not useful since the index needs to store the unencrypted value to be usable, and that would defeat the purpose of storing encrypted data. Do not create indexes on encrypted columns. +Note that, as mentioned above, indexing an encrypted column serves no purpose and has a detrimental effect on performance. Indexing encrypted values is not useful since the index needs to store the unencrypted value to be usable, and that would defeat the purpose of storing encrypted data. Do not create indexes on encrypted columns. ## Decrypting data @@ -49,7 +49,7 @@ Decrypted data is accessed using a special view that is automatically created af ![Decrypted data](/docs/img/guides/database/vault-decrypted-data.png) -As mentioned above, accessing decrypted data is slower than accessing unencrypted data. Any row you query from this view will go through a decryption function, which takes some time and can be a significant performance pentalty if your query loads lots of rows. It's always advisable to look up rows by some indexed unencrypted key first, like a primary key, so that only one row is decrypted at a time. +As mentioned above, accessing decrypted data is slower than accessing unencrypted data. Any row you query from this view will go through a decryption function, which takes some time and can be a significant performance pentalty if your query loads lots of rows. It's always advisable to look up rows by some indexed unencrypted key first, like a primary key, so that only one row is decrypted at a time. ## Using an Encrypted Table @@ -91,19 +91,19 @@ Notice how there is a new column called `decrypted_secret`. This column is not s ## Granting API Access to encrypted columns -When you create an encrypted column in the `public` database schema, then that column and the decryption view that is created for it are given *public access via the PostgREST API*. In general it is not recommended to encrypt columns in the public schema, as this adds some additional security considerations that you need to think about, but it is still possible and useful in some cases depending on your level of security comfort. Only you can decide the risks and rewards of making decrypted data available to public API access. It is very strongly recommended that you must protect your public encrypted columns with a Row Level Security (RLS) Policy. +When you create an encrypted column in the `public` database schema, then that column and the decryption view that is created for it are given _public access via the PostgREST API_. In general it is not recommended to encrypt columns in the public schema, as this adds some additional security considerations that you need to think about, but it is still possible and useful in some cases depending on your level of security comfort. Only you can decide the risks and rewards of making decrypted data available to public API access. It is very strongly recommended that you must protect your public encrypted columns with a Row Level Security (RLS) Policy. -Even though objects created in the `public` schema default to public access, There is an additional layer of security with pgsodium that must be enabled in order for decryption to work with the PostgREST API. The permissions necessary to call pgsodium functions must be granted to one of the API role that is accessing the public objects. +Even though objects created in the `public` schema default to public access, There is an additional layer of security with pgsodium that must be enabled in order for decryption to work with the PostgREST API. The permissions necessary to call pgsodium functions must be granted to one of the API role that is accessing the public objects. -There are three roles available for API access with Supabase, The `anon` role represents unauthenticated anonymous users and should *never* be granted access to pgsodium, you do so at your own risk. The `service_role` which is meant to be used by other services in your system, and whose token should never be exposed publicly, and the `authenticated` role which represents authenticated users who present a valid JWT token and are identified by the system as a known user. +There are three roles available for API access with Supabase, The `anon` role represents unauthenticated anonymous users and should _never_ be granted access to pgsodium, you do so at your own risk. The `service_role` which is meant to be used by other services in your system, and whose token should never be exposed publicly, and the `authenticated` role which represents authenticated users who present a valid JWT token and are identified by the system as a known user. -By default, only the `service_user` role is granted access to the column encryption functions. If you wish to make encrypted columns available to your authenticated users, then you must run `GRANT pgsodium_keyiduser TO authenticated;` from the Supabase console or logged in as the `postgres` role. This table shows the default permission settings for API roles accessing the pgsodium encryption functions: +By default, only the `service_user` role is granted access to the column encryption functions. If you wish to make encrypted columns available to your authenticated users, then you must run `GRANT pgsodium_keyiduser TO authenticated;` from the Supabase console or logged in as the `postgres` role. This table shows the default permission settings for API roles accessing the pgsodium encryption functions: -|Role | pgsodium_keyiduser | pgsodium_keymaker | -|---|---|---| -| anon | X | X | -| authenticated | X | X | -| service_role | Y | X | +| Role | pgsodium_keyiduser | pgsodium_keymaker | +| ------------- | ------------------ | ----------------- | +| anon | X | X | +| authenticated | X | X | +| service_role | Y | X | ## How Key Derivation Works From 70f2e46040b959bdfdf0dac40783bd57d65ba531 Mon Sep 17 00:00:00 2001 From: Rodrigo Mansueli Nunes Date: Thu, 10 Aug 2023 11:27:40 -0300 Subject: [PATCH 03/11] Update column-encryption.mdx --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index b3873f253f6..30b803b7572 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -29,7 +29,7 @@ In general, it is a bad idea to over-use column encryption for mundane data or d Encryption requires keys, but keeping the keys in the same database as the encrypted data doesn't make any sense, it would be like leaving a key in a door lock, a door lock only makes sense when the lock and key can be separated. So similarly, the encryption keys in Supabse are kept separate from the database. -Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionaly for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to _derive_ the encryption keys used by column encryption. These keys are derived from a _Root Key_ that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). +Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionally for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to _derive_ the encryption keys used by column encryption. These keys are derived from a _Root Key_ that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). ## Encrypting columns From 9bebecc2b09efa4c93e32bc83f35ce81526456ec Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:42:57 -0700 Subject: [PATCH 04/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index 30b803b7572..2ed12615f4a 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -9,7 +9,7 @@ export const meta = { video: 'https://www.youtube.com/v/J9mTPY8rIXE', } -Supabase provides a secure method for encrypting data using [Vault](/docs/guides/database/vault), our Postgres secrets manager. Vault is a Postgres extension with an integrated UI intended to act as a secure global secrets management for your project. +Supabase provides a secure method for encrypting data using [Vault](/docs/guides/database/vault), our Postgres secrets manager. Vault is a Postgres extension with an [integrated UI](https://app.supabase.com/project/_/settings/vault/secrets) intended to act as a secure global secrets management for your project. In addition to the Vault secret storage table, Supabase also enables an advanced feature called Transparent Column Encryption (TCE) which provides a safe way to encrypt columns in your own tables so that they doesn't leak into logs and backups. It can also provide row-level authenticated encryption. From 697d48ac1beab96574d255b0432470f2cc4f0742 Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:45:31 -0700 Subject: [PATCH 05/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index 2ed12615f4a..cb944f48d6d 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -17,7 +17,7 @@ Column Encryption comes with tradeoffs that need to be considered before using i - Encryption and decryption both take time, inserting and selecting encrypted data takes more time than a "plain" column of data. Queries that must load a lot of rows with encrypted columns will be slower than those that are not encrypted. - - Encrypted columns should never be indexed. This is because the index must store the unencrypted value of a column to be useful, which would defeat the purpose of storing values encrypted. To look up an encrypted column, you must first look up its row by some other unencrypted column, like a primary key. + - Encrypted columns should never be indexed. This is because the index will store the encrypted value of a column, which would not be useful. To look up an encrypted column, you must first look up its row by some other unencrypted column, like a primary key. - Encrypted columns can be queried in a `WHERE` clause, but this can also have some negative performance consequences, since the value must be decrypted in order to matched to any `WHERE` qualifiers. For small result sets this is not a big deal, but broad queries that match many rows will have to be scanned and each row decrypted in order to check against the `WHERE` clause. Worst case is the entire table must be scanned and decrypted to check against a `WHERE`. From 35552848e08afac97c3a8171180bbce6f1b14f4c Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:46:12 -0700 Subject: [PATCH 06/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index cb944f48d6d..fc817569f90 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -19,7 +19,7 @@ Column Encryption comes with tradeoffs that need to be considered before using i - Encrypted columns should never be indexed. This is because the index will store the encrypted value of a column, which would not be useful. To look up an encrypted column, you must first look up its row by some other unencrypted column, like a primary key. - - Encrypted columns can be queried in a `WHERE` clause, but this can also have some negative performance consequences, since the value must be decrypted in order to matched to any `WHERE` qualifiers. For small result sets this is not a big deal, but broad queries that match many rows will have to be scanned and each row decrypted in order to check against the `WHERE` clause. Worst case is the entire table must be scanned and decrypted to check against a `WHERE`. + - Encrypted columns can be queried in a `WHERE` clause, but this can also have some negative performance consequences, since the value must be decrypted in order to matched to any `WHERE` qualifiers. For small result sets the impact is small, but queries that match many rows will cause each row to be decrypted in order to check against the `WHERE` clause. In the worst case, the entire table must be scanned and decrypted to check against a `WHERE` clause. - While you can encrypt multiple columns in the same table, each column must go through a full encryption cycle, so two columns will take twice the time as one, three columns three time as long, and so on. It is usually better to break up large tables into smaller tables with at most one or two encrypted columns, and associated them with [foreign keys](https://www.postgresql.org/docs/current/tutorial-fk.html) that can be used to JOIN them when necessary. From b7e1d97e8a78c9375a4c18daaf143e072d5f4e1c Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:46:46 -0700 Subject: [PATCH 07/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index fc817569f90..fc2ac5c8480 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -27,7 +27,7 @@ In general, it is a bad idea to over-use column encryption for mundane data or d ## Encryption Keys -Encryption requires keys, but keeping the keys in the same database as the encrypted data doesn't make any sense, it would be like leaving a key in a door lock, a door lock only makes sense when the lock and key can be separated. So similarly, the encryption keys in Supabse are kept separate from the database. +Encryption requires keys. Keeping the keys in the same database as the encrypted data would be unsafe. It would be like leaving a key in a door lock. For that reason, encryption keys are kept separate from the database. Supabase column encryption and the Vault both use a low level Postgres extension library called [pgsodium](https://github.com/michelp/pgsodium/). This library in turn wraps a very popular encryption library called [libsodium](https://doc.libsodium.org/). These libraries provide functionally for doing something called [Key Derivation](https://libsodium.gitbook.io/doc/key_derivation). Supabase uses key derivation to _derive_ the encryption keys used by column encryption. These keys are derived from a _Root Key_ that is stored by Supabase, outside the database. If you need to migrate encrypted data from one system to another, you must ensure that this root key is copied over as well. There is a [REST API for getting the root key for a project](https://supabase.com/docs/reference/api/gets-projects-pgsodium-config). From d62a7fb9c4d6ff047679825f5fa86f28edf654e9 Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:47:02 -0700 Subject: [PATCH 08/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index fc2ac5c8480..938ed2ff736 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -49,7 +49,7 @@ Decrypted data is accessed using a special view that is automatically created af ![Decrypted data](/docs/img/guides/database/vault-decrypted-data.png) -As mentioned above, accessing decrypted data is slower than accessing unencrypted data. Any row you query from this view will go through a decryption function, which takes some time and can be a significant performance pentalty if your query loads lots of rows. It's always advisable to look up rows by some indexed unencrypted key first, like a primary key, so that only one row is decrypted at a time. +Accessing decrypted data is slower than accessing unencrypted data. Any row you query from this view will go through a decryption function, which takes some time and can be a significant performance pentalty if your query loads lots of rows. It's always advisable to look up rows by some indexed unencrypted key first, like a primary key, so that only one row is decrypted at a time. ## Using an Encrypted Table From 307fc3ad0a574ed602375f7aad4760832e63c80b Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:47:28 -0700 Subject: [PATCH 09/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index 938ed2ff736..6f4b3a58dc1 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -41,7 +41,7 @@ Once you've created an encrypted column, you can insert data into the table like ![Encrypted data](/docs/img/guides/database/vault-encrypted-data.png) -Note that, as mentioned above, indexing an encrypted column serves no purpose and has a detrimental effect on performance. Indexing encrypted values is not useful since the index needs to store the unencrypted value to be usable, and that would defeat the purpose of storing encrypted data. Do not create indexes on encrypted columns. +As mentioned above, indexing an encrypted column serves no purpose and has a detrimental effect on performance. Indexing encrypted values is not useful since the index needs to store the unencrypted value to be usable, and that would defeat the purpose of storing encrypted data. Do not create indexes on encrypted columns. ## Decrypting data From 4734ac6a52a19ae19608fdc6e9b9963c0435cbdb Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:47:44 -0700 Subject: [PATCH 10/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index 6f4b3a58dc1..d36b9685473 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -91,7 +91,7 @@ Notice how there is a new column called `decrypted_secret`. This column is not s ## Granting API Access to encrypted columns -When you create an encrypted column in the `public` database schema, then that column and the decryption view that is created for it are given _public access via the PostgREST API_. In general it is not recommended to encrypt columns in the public schema, as this adds some additional security considerations that you need to think about, but it is still possible and useful in some cases depending on your level of security comfort. Only you can decide the risks and rewards of making decrypted data available to public API access. It is very strongly recommended that you must protect your public encrypted columns with a Row Level Security (RLS) Policy. +When you create an encrypted column in the `public` database schema, then that column and the decryption view that is created for it are given _public access via the PostgREST API_. In general it is not recommended to encrypt columns in the public schema, as this adds some additional security considerations that you need to think about, but it is still possible and useful in some cases depending on your level of security comfort. Only you can decide the risks and rewards of making decrypted data available to public API access. It is very strongly recommended that you must protect your public encrypted columns with a [Row Level Security (RLS) Policy](docs/guides/auth/row-level-security). Even though objects created in the `public` schema default to public access, There is an additional layer of security with pgsodium that must be enabled in order for decryption to work with the PostgREST API. The permissions necessary to call pgsodium functions must be granted to one of the API role that is accessing the public objects. From 1292cd29dc20179475c97e6a77378835312076c2 Mon Sep 17 00:00:00 2001 From: Michel Pelletier Date: Thu, 10 Aug 2023 09:48:47 -0700 Subject: [PATCH 11/11] Update apps/docs/pages/guides/database/column-encryption.mdx Co-authored-by: Oliver Rice --- apps/docs/pages/guides/database/column-encryption.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/database/column-encryption.mdx b/apps/docs/pages/guides/database/column-encryption.mdx index d36b9685473..1734d88a6af 100644 --- a/apps/docs/pages/guides/database/column-encryption.mdx +++ b/apps/docs/pages/guides/database/column-encryption.mdx @@ -95,7 +95,7 @@ When you create an encrypted column in the `public` database schema, then that c Even though objects created in the `public` schema default to public access, There is an additional layer of security with pgsodium that must be enabled in order for decryption to work with the PostgREST API. The permissions necessary to call pgsodium functions must be granted to one of the API role that is accessing the public objects. -There are three roles available for API access with Supabase, The `anon` role represents unauthenticated anonymous users and should _never_ be granted access to pgsodium, you do so at your own risk. The `service_role` which is meant to be used by other services in your system, and whose token should never be exposed publicly, and the `authenticated` role which represents authenticated users who present a valid JWT token and are identified by the system as a known user. +There are three roles available for API access with Supabase, The `anon` role represents unauthenticated anonymous users and should _never_ be granted access to pgsodium. The `service_role` which is meant to be used by other services in your system, and whose token should never be exposed publicly, and the `authenticated` role which represents authenticated users who present a valid JWT token and are identified by the system as a known user. By default, only the `service_user` role is granted access to the column encryption functions. If you wish to make encrypted columns available to your authenticated users, then you must run `GRANT pgsodium_keyiduser TO authenticated;` from the Supabase console or logged in as the `postgres` role. This table shows the default permission settings for API roles accessing the pgsodium encryption functions: