diff --git a/contrib/pg_tde/expected/delete_principal_key.out b/contrib/pg_tde/expected/delete_principal_key.out index 550bcc217b2dd..92b8299c2b725 100644 --- a/contrib/pg_tde/expected/delete_principal_key.out +++ b/contrib/pg_tde/expected/delete_principal_key.out @@ -134,6 +134,46 @@ SELECT pg_tde_delete_key(); (1 row) +-- Delete default key even if it's configured for a database or server key, as +-- long as it's unused. Regardless how the key was set, we unset it if it's the +-- same key as is used as a default key. This is probably a bug. +SELECT pg_tde_set_default_key_using_global_key_provider('test-db-key','file-provider'); + pg_tde_set_default_key_using_global_key_provider +-------------------------------------------------- + +(1 row) + +SELECT pg_tde_set_key_using_global_key_provider('test-db-key','file-provider'); + pg_tde_set_key_using_global_key_provider +------------------------------------------ + +(1 row) + +SELECT pg_tde_set_server_key_using_global_key_provider('test-db-key','file-provider'); +WARNING: The WAL encryption feature is currently in beta and may be unstable. Do not use it in production environments! + pg_tde_set_server_key_using_global_key_provider +------------------------------------------------- + +(1 row) + +SELECT pg_tde_delete_default_key(); + pg_tde_delete_default_key +--------------------------- + +(1 row) + +SELECT pg_tde_key_info(); -- No key configured + pg_tde_key_info +----------------- + (,,,) +(1 row) + +SELECT pg_tde_server_key_info(); -- No key configured + pg_tde_server_key_info +------------------------ + (,,,) +(1 row) + SELECT pg_tde_delete_global_key_provider('file-provider'); pg_tde_delete_global_key_provider ----------------------------------- diff --git a/contrib/pg_tde/sql/delete_principal_key.sql b/contrib/pg_tde/sql/delete_principal_key.sql index abc4c574b5616..142eedde0a56d 100644 --- a/contrib/pg_tde/sql/delete_principal_key.sql +++ b/contrib/pg_tde/sql/delete_principal_key.sql @@ -53,5 +53,16 @@ SELECT pg_tde_delete_default_key(); DROP TABLE test_table; SELECT pg_tde_delete_key(); + +-- Delete default key even if it's configured for a database or server key, as +-- long as it's unused. Regardless how the key was set, we unset it if it's the +-- same key as is used as a default key. This is probably a bug. +SELECT pg_tde_set_default_key_using_global_key_provider('test-db-key','file-provider'); +SELECT pg_tde_set_key_using_global_key_provider('test-db-key','file-provider'); +SELECT pg_tde_set_server_key_using_global_key_provider('test-db-key','file-provider'); +SELECT pg_tde_delete_default_key(); +SELECT pg_tde_key_info(); -- No key configured +SELECT pg_tde_server_key_info(); -- No key configured + SELECT pg_tde_delete_global_key_provider('file-provider'); DROP EXTENSION pg_tde; diff --git a/contrib/pg_tde/src/access/pg_tde_tdemap.c b/contrib/pg_tde/src/access/pg_tde_tdemap.c index f285f2e24a0a8..6c1f146e306d3 100644 --- a/contrib/pg_tde/src/access/pg_tde_tdemap.c +++ b/contrib/pg_tde/src/access/pg_tde_tdemap.c @@ -529,7 +529,7 @@ pg_tde_delete_principal_key(Oid dbOid) char path[MAXPGPATH]; Assert(LWLockHeldByMeInMode(tde_lwlock_enc_keys(), LW_EXCLUSIVE)); - Assert(pg_tde_count_relations(dbOid) == 0); + Assert(pg_tde_count_encryption_keys(dbOid) == 0); pg_tde_set_db_file_path(dbOid, path); @@ -672,17 +672,15 @@ pg_tde_find_map_entry(const RelFileLocator *rlocator, TDEMapEntryType key_type, } /* - * Counts number of encrypted objects in a database. + * Counts number of encryption keys in a key file. * * Does not check if objects actually exist but just that they have keys in - * the map file. For the only current caller, checking if we can use - * FILE_COPY, this is good enough but for other workloads where a false - * positive is more harmful this might not be. + * the key file. * - * Works even if the database has no map file. + * Works even if the database has no key file. */ int -pg_tde_count_relations(Oid dbOid) +pg_tde_count_encryption_keys(Oid dbOid) { char db_map_path[MAXPGPATH]; File map_fd; diff --git a/contrib/pg_tde/src/catalog/tde_principal_key.c b/contrib/pg_tde/src/catalog/tde_principal_key.c index 38f962b4794f2..d795eb014ee61 100644 --- a/contrib/pg_tde/src/catalog/tde_principal_key.c +++ b/contrib/pg_tde/src/catalog/tde_principal_key.c @@ -700,7 +700,7 @@ pg_tde_delete_key(PG_FUNCTION_ARGS) * If database has something encryted, we can try to fallback to the * default principal key */ - if (pg_tde_count_relations(MyDatabaseId) != 0) + if (pg_tde_count_encryption_keys(MyDatabaseId) != 0) { default_principal_key = GetPrincipalKeyNoDefault(DEFAULT_DATA_TDE_OID, LW_EXCLUSIVE); if (default_principal_key == NULL) @@ -785,7 +785,7 @@ pg_tde_delete_default_key(PG_FUNCTION_ARGS) * delete default principal key if there are encrypted tables in * the database. */ - if (pg_tde_count_relations(dbOid) != 0) + if (pg_tde_count_encryption_keys(dbOid) != 0) { ereport(ERROR, errmsg("cannot delete default principal key"), @@ -798,8 +798,22 @@ pg_tde_delete_default_key(PG_FUNCTION_ARGS) } /* - * Remove empty key map files for databases that has no encrypted tables - * as we cannot leave reference to the default principal key. + * The default key may have been used as server key, check if there are + * any WAL encryption keys that uses it. + */ + principal_key = GetPrincipalKeyNoDefault(GLOBAL_DATA_TDE_OID, LW_EXCLUSIVE); + if (pg_tde_is_same_principal_key(default_principal_key, principal_key)) + { + if (pg_tde_count_encryption_keys(GLOBAL_DATA_TDE_OID) != 0) + ereport(ERROR, + errmsg("cannot delete default principal key"), + errhint("There are WAL encryption keys.")); + dbs = lappend_oid(dbs, GLOBAL_DATA_TDE_OID); + } + + /* + * Remove empty key files for OIDs that have no encryption keys as we + * cannot leave references to the default principal key. */ foreach_oid(dbOid, dbs) { diff --git a/contrib/pg_tde/src/include/access/pg_tde_tdemap.h b/contrib/pg_tde/src/include/access/pg_tde_tdemap.h index f3177544cf551..e6d6d982404ec 100644 --- a/contrib/pg_tde/src/include/access/pg_tde_tdemap.h +++ b/contrib/pg_tde/src/include/access/pg_tde_tdemap.h @@ -92,7 +92,7 @@ extern bool pg_tde_has_smgr_key(RelFileLocator rel); extern InternalKey *pg_tde_get_smgr_key(RelFileLocator rel); extern void pg_tde_free_key_map_entry(RelFileLocator rel); -extern int pg_tde_count_relations(Oid dbOid); +extern int pg_tde_count_encryption_keys(Oid dbOid); extern void pg_tde_delete_tde_files(Oid dbOid); diff --git a/contrib/pg_tde/src/pg_tde_event_capture.c b/contrib/pg_tde/src/pg_tde_event_capture.c index 9f089f5c36eee..3dcb787c7dd87 100644 --- a/contrib/pg_tde/src/pg_tde_event_capture.c +++ b/contrib/pg_tde/src/pg_tde_event_capture.c @@ -643,7 +643,7 @@ pg_tde_proccess_utility(PlannedStmt *pstmt, int count; LWLockAcquire(tde_lwlock_enc_keys(), LW_SHARED); - count = pg_tde_count_relations(dbOid); + count = pg_tde_count_encryption_keys(dbOid); LWLockRelease(tde_lwlock_enc_keys()); if (count > 0)