diff --git a/contrib/pg_tde/meson.build b/contrib/pg_tde/meson.build index 6cf1a43994629..200894ece1c0f 100644 --- a/contrib/pg_tde/meson.build +++ b/contrib/pg_tde/meson.build @@ -114,6 +114,7 @@ tap_tests = [ 't/010_change_key_provider.pl', 't/011_unlogged_tables.pl', 't/012_replication.pl', + 't/013_crash_recovery.pl', ] tests += { diff --git a/contrib/pg_tde/src/access/pg_tde_tdemap.c b/contrib/pg_tde/src/access/pg_tde_tdemap.c index 715c9a8d1eaf8..7994b5cfaf105 100644 --- a/contrib/pg_tde/src/access/pg_tde_tdemap.c +++ b/contrib/pg_tde/src/access/pg_tde_tdemap.c @@ -309,7 +309,7 @@ pg_tde_save_principal_key_redo(const TDESignedPrincipalKeyInfo *signed_key_info) LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE); - map_fd = pg_tde_open_file_write(db_map_path, signed_key_info, true, &curr_pos); + map_fd = pg_tde_open_file_write(db_map_path, signed_key_info, false, &curr_pos); close(map_fd); LWLockRelease(tde_lwlock_enc_keys()); diff --git a/contrib/pg_tde/t/013_crash_recovery.pl b/contrib/pg_tde/t/013_crash_recovery.pl new file mode 100644 index 0000000000000..7163cfc9ead35 --- /dev/null +++ b/contrib/pg_tde/t/013_crash_recovery.pl @@ -0,0 +1,94 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use File::Basename; +use Test::More; +use lib 't'; +use pgtde; + +PGTDE::setup_files_dir(basename($0)); + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->append_conf( + 'postgresql.conf', q{ +checkpoint_timeout = 1h +shared_preload_libraries = 'pg_tde' +}); +$node->start; + +PGTDE::psql($node, 'postgres', 'CREATE EXTENSION IF NOT EXISTS pg_tde;'); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_add_global_key_provider_file('global_keyring', '/tmp/crash_recovery.per');" +); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key', 'global_keyring');" +); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_add_database_key_provider_file('db_keyring', '/tmp/crash_recovery.per');" +); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_key_using_database_key_provider('db_key', 'db_keyring');" +); + +PGTDE::psql($node, 'postgres', + "CREATE TABLE test_enc (x int PRIMARY KEY) USING tde_heap;"); +PGTDE::psql($node, 'postgres', "INSERT INTO test_enc (x) VALUES (1), (2);"); + +PGTDE::psql($node, 'postgres', + "CREATE TABLE test_plain (x int PRIMARY KEY) USING heap;"); +PGTDE::psql($node, 'postgres', "INSERT INTO test_plain (x) VALUES (3), (4);"); + +PGTDE::psql($node, 'postgres', "ALTER SYSTEM SET pg_tde.wal_encrypt = 'on';"); + +PGTDE::append_to_result_file("-- kill -9"); +$node->kill9; + +PGTDE::append_to_result_file("-- server start"); +$node->start; + +PGTDE::append_to_result_file("-- rotate wal key"); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key_1', 'global_keyring', true);" +); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_key_using_database_key_provider('db_key_1', 'db_keyring');" +); +PGTDE::psql($node, 'postgres', "INSERT INTO test_enc (x) VALUES (3), (4);"); +PGTDE::append_to_result_file("-- kill -9"); +$node->kill9; +PGTDE::append_to_result_file("-- server start"); +PGTDE::append_to_result_file( + "-- check that pg_tde_save_principal_key_redo hasn't destroyed a WAL key created during the server start" +); +$node->start; + +PGTDE::append_to_result_file("-- rotate wal key"); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key_2', 'global_keyring', true);" +); +PGTDE::psql($node, 'postgres', + "SELECT pg_tde_set_key_using_database_key_provider('db_key_2', 'db_keyring');" +); +PGTDE::psql($node, 'postgres', "INSERT INTO test_enc (x) VALUES (5), (6);"); +PGTDE::append_to_result_file("-- kill -9"); +$node->kill9; +PGTDE::append_to_result_file("-- server start"); +PGTDE::append_to_result_file( + "-- check that the key rotation hasn't destroyed a WAL key created during the server start" +); +$node->start; + +PGTDE::psql($node, 'postgres', "TABLE test_enc;"); + +$node->stop; + +# Compare the expected and out file +my $compare = PGTDE->compare_results(); + +is($compare, 0, + "Compare Files: $PGTDE::expected_filename_with_path and $PGTDE::out_filename_with_path files." +); + +done_testing(); diff --git a/contrib/pg_tde/t/expected/013_crash_recovery.out b/contrib/pg_tde/t/expected/013_crash_recovery.out new file mode 100644 index 0000000000000..3ec79d59e35bf --- /dev/null +++ b/contrib/pg_tde/t/expected/013_crash_recovery.out @@ -0,0 +1,77 @@ +CREATE EXTENSION IF NOT EXISTS pg_tde; +SELECT pg_tde_add_global_key_provider_file('global_keyring', '/tmp/crash_recovery.per'); + pg_tde_add_global_key_provider_file +------------------------------------- + -1 +(1 row) + +SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key', 'global_keyring'); + pg_tde_set_server_key_using_global_key_provider +------------------------------------------------- + +(1 row) + +SELECT pg_tde_add_database_key_provider_file('db_keyring', '/tmp/crash_recovery.per'); + pg_tde_add_database_key_provider_file +--------------------------------------- + 1 +(1 row) + +SELECT pg_tde_set_key_using_database_key_provider('db_key', 'db_keyring'); + pg_tde_set_key_using_database_key_provider +-------------------------------------------- + +(1 row) + +CREATE TABLE test_enc (x int PRIMARY KEY) USING tde_heap; +INSERT INTO test_enc (x) VALUES (1), (2); +CREATE TABLE test_plain (x int PRIMARY KEY) USING heap; +INSERT INTO test_plain (x) VALUES (3), (4); +ALTER SYSTEM SET pg_tde.wal_encrypt = 'on'; +-- kill -9 +-- server start +-- rotate wal key +SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key_1', 'global_keyring', true); + pg_tde_set_server_key_using_global_key_provider +------------------------------------------------- + +(1 row) + +SELECT pg_tde_set_key_using_database_key_provider('db_key_1', 'db_keyring'); + pg_tde_set_key_using_database_key_provider +-------------------------------------------- + +(1 row) + +INSERT INTO test_enc (x) VALUES (3), (4); +-- kill -9 +-- server start +-- check that pg_tde_save_principal_key_redo hasn't destroyed a WAL key created during the server start +-- rotate wal key +SELECT pg_tde_set_server_key_using_global_key_provider('wal_encryption_key_2', 'global_keyring', true); + pg_tde_set_server_key_using_global_key_provider +------------------------------------------------- + +(1 row) + +SELECT pg_tde_set_key_using_database_key_provider('db_key_2', 'db_keyring'); + pg_tde_set_key_using_database_key_provider +-------------------------------------------- + +(1 row) + +INSERT INTO test_enc (x) VALUES (5), (6); +-- kill -9 +-- server start +-- check that the key rotation hasn't destroyed a WAL key created during the server start +TABLE test_enc; + x +--- + 1 + 2 + 3 + 4 + 5 + 6 +(6 rows) +