mirror of https://github.com/postgres/postgres
This commit changes the approach to WAL encryption. Instead of encrypting each WAL page and keeping its header unencrypted with a special encrypted flag, this change moves encrypted/unencrypted bookkeeping to WAL internal keys. Now every [WAL] internal key has an additional field `start_lsn`. The field indicates the first WAL record that was encrypted with this key. This means everything starting from that LSN is encrypted with the key until the next or the end of the WAL. In order to have unencrypted WAL (when the user sets `pg_tde.wal_encrypt = off`), we insert a special key with the flag `TDE_KEY_TYPE_WAL_UNENCRYPTED`. The user can turn WAL encryption on and off, which will generate a new WAL key with the respective state (`TDE_KEY_TYPE_WAL_ENCRYPTED` or `TDE_KEY_TYPE_WAL_UNENCRYPTED `). If GUC pg_tde.wal_encrypt was changed, the server will generate a new WAL key with `start_lsn` set to `InvalidXLogRecPtr` on start. WAL writer, in turn, will update `start_lsn` with the actual LSN on the first write since the key creation. We use the current key _map and _dat files infrastructure along with the Internal key cache but with some special cases. There might be multiple internal keys for WAL but only one for the SMGR (relations, indexes etc). Creating a new WAL key, we write it the same as the SMGR key, so key rotation, for example, doesn't require any changes. But reads and start_lsn happen directly from/in _dat file (omitting _map). This needs revision and refactoring (along with _map, _dat files in general). As well as WAL keys cache, which is currently a simple linked list referencing the actual internal key case. That allows WAL key changing.pull/209/head
parent
8a7a951db4
commit
d352e5af41
@ -1,36 +0,0 @@ |
||||
-- basic tests for pg_tde_create_wal_key |
||||
-- doesn't test actual wal encryption, as that requires a server restart, |
||||
-- only sanity checks for the key creation |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
SELECT pg_tde_add_global_key_provider_file('file-keyring','/tmp/pg_tde_test_keyring.per'); |
||||
pg_tde_add_global_key_provider_file |
||||
------------------------------------- |
||||
-3 |
||||
(1 row) |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
-- db local principal key with global provider |
||||
SELECT pg_tde_set_global_principal_key('test-db-principal-key', 'file-keyring', true); |
||||
ERROR: failed to create principal key: already exists |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
SELECT pg_tde_set_server_principal_key('test-db-principal-key', 'file-keyring'); |
||||
pg_tde_set_server_principal_key |
||||
--------------------------------- |
||||
t |
||||
(1 row) |
||||
|
||||
-- and now it should work! |
||||
SELECT pg_tde_create_wal_key(); |
||||
pg_tde_create_wal_key |
||||
----------------------- |
||||
t |
||||
(1 row) |
||||
|
||||
-- and now it shouldn't create a new one! |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
DROP EXTENSION pg_tde; |
@ -1,36 +0,0 @@ |
||||
-- basic tests for pg_tde_create_wal_key |
||||
-- doesn't test actual wal encryption, as that requires a server restart, |
||||
-- only sanity checks for the key creation |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
SELECT pg_tde_add_global_key_provider_file('file-keyring','/tmp/pg_tde_test_keyring.per'); |
||||
pg_tde_add_global_key_provider_file |
||||
------------------------------------- |
||||
-1 |
||||
(1 row) |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
-- db local principal key with global provider |
||||
SELECT pg_tde_set_global_principal_key('test-db-principal-key', 'file-keyring', true); |
||||
ERROR: failed to create principal key: already exists |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: failed to retrieve principal key. Create one using pg_tde_set_principal_key before using encrypted tables. |
||||
SELECT pg_tde_set_server_principal_key('test-db-principal-key', 'file-keyring'); |
||||
pg_tde_set_server_principal_key |
||||
--------------------------------- |
||||
t |
||||
(1 row) |
||||
|
||||
-- and now it should work! |
||||
SELECT pg_tde_create_wal_key(); |
||||
pg_tde_create_wal_key |
||||
----------------------- |
||||
t |
||||
(1 row) |
||||
|
||||
-- and now it shouldn't create a new one! |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
DROP EXTENSION pg_tde; |
@ -1,32 +0,0 @@ |
||||
-- basic tests for pg_tde_create_wal_key |
||||
-- doesn't test actual wal encryption, as that requires a server restart, |
||||
-- only sanity checks for the key creation |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
SELECT pg_tde_add_global_key_provider_file('file-keyring','/tmp/pg_tde_test_keyring.per'); |
||||
pg_tde_add_global_key_provider_file |
||||
------------------------------------- |
||||
-2 |
||||
(1 row) |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
-- db local principal key with global provider |
||||
SELECT pg_tde_set_global_principal_key('test-db-principal-key', 'file-keyring', true); |
||||
ERROR: failed to create principal key: already exists |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
SELECT pg_tde_set_server_principal_key('test-db-principal-key', 'file-keyring'); |
||||
pg_tde_set_server_principal_key |
||||
--------------------------------- |
||||
t |
||||
(1 row) |
||||
|
||||
-- and now it should work! |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
-- and now it shouldn't create a new one! |
||||
SELECT pg_tde_create_wal_key(); |
||||
ERROR: WAL key already exists. |
||||
DROP EXTENSION pg_tde; |
@ -1,25 +0,0 @@ |
||||
-- basic tests for pg_tde_create_wal_key |
||||
-- doesn't test actual wal encryption, as that requires a server restart, |
||||
-- only sanity checks for the key creation |
||||
CREATE EXTENSION IF NOT EXISTS pg_tde; |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
|
||||
SELECT pg_tde_add_global_key_provider_file('file-keyring','/tmp/pg_tde_test_keyring.per'); |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
|
||||
-- db local principal key with global provider |
||||
SELECT pg_tde_set_global_principal_key('test-db-principal-key', 'file-keyring', true); |
||||
|
||||
SELECT pg_tde_create_wal_key(); |
||||
|
||||
SELECT pg_tde_set_server_principal_key('test-db-principal-key', 'file-keyring'); |
||||
|
||||
-- and now it should work! |
||||
SELECT pg_tde_create_wal_key(); |
||||
|
||||
-- and now it shouldn't create a new one! |
||||
SELECT pg_tde_create_wal_key(); |
||||
|
||||
DROP EXTENSION pg_tde; |
@ -1,54 +0,0 @@ |
||||
/*-------------------------------------------------------------------------
|
||||
* |
||||
* tde_global_space.c |
||||
* Global catalog key management |
||||
* |
||||
* |
||||
* IDENTIFICATION |
||||
* src/catalog/tde_global_space.c |
||||
* |
||||
*------------------------------------------------------------------------- |
||||
*/ |
||||
|
||||
#include "postgres.h" |
||||
|
||||
#ifdef PERCONA_EXT |
||||
|
||||
#include "utils/memutils.h" |
||||
|
||||
#include "access/pg_tde_tdemap.h" |
||||
#include "catalog/tde_global_space.h" |
||||
#include "catalog/tde_keyring.h" |
||||
#include "common/pg_tde_utils.h" |
||||
|
||||
#ifdef FRONTEND |
||||
#include "pg_tde_fe.h" |
||||
#endif |
||||
|
||||
#include <unistd.h> |
||||
#include <openssl/rand.h> |
||||
#include <openssl/err.h> |
||||
#include <sys/time.h> |
||||
|
||||
void |
||||
TDEInitGlobalKeys(void) |
||||
{ |
||||
InternalKey *key; |
||||
|
||||
key = pg_tde_get_key_from_file(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID), TDE_KEY_TYPE_GLOBAL, true); |
||||
|
||||
/*
|
||||
* Internal Key should be in the TopMemmoryContext because of SSL |
||||
* contexts. This context is being initialized by OpenSSL with the pointer |
||||
* to the encryption context which is valid only for the current backend. |
||||
* So new backends have to inherit a cached key with NULL SSL connext and |
||||
* any changes to it have to remain local ot the backend. (see |
||||
* https://github.com/percona-Lab/pg_tde/pull/214#discussion_r1648998317)
|
||||
*/ |
||||
if (key != NULL) |
||||
{ |
||||
pg_tde_put_key_into_cache(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID), key); |
||||
} |
||||
} |
||||
|
||||
#endif /* PERCONA_EXT */ |
Loading…
Reference in new issue