Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PG-1120: Add a new SQL interface pg_tde_alter_principal_key_keyring #357

Merged
merged 2 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 7 additions & 0 deletions pg_tde--1.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,11 @@ RETURNS boolean
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION pg_tde_alter_principal_key_keyring(new_provider_name VARCHAR(255))
RETURNS boolean
AS 'MODULE_PATHNAME'
LANGUAGE C;

CREATE FUNCTION pg_tde_extension_initialize()
RETURNS VOID
AS 'MODULE_PATHNAME'
Expand Down Expand Up @@ -342,6 +347,7 @@ BEGIN
PERFORM pg_tde_grant_execute_privilege_on_function(target_user_or_role, 'pg_tde_add_key_provider_vault_v2', 'varchar, JSON, JSON,JSON,JSON');

PERFORM pg_tde_grant_execute_privilege_on_function(target_user_or_role, 'pg_tde_set_principal_key', 'varchar, varchar, BOOLEAN');
PERFORM pg_tde_grant_execute_privilege_on_function(target_user_or_role, 'pg_tde_alter_principal_key_keyring', 'varchar');

PERFORM pg_tde_grant_execute_privilege_on_function(target_user_or_role, 'pg_tde_rotate_principal_key', 'pg_tde_global, varchar, varchar');
PERFORM pg_tde_grant_execute_privilege_on_function(target_user_or_role, 'pg_tde_rotate_principal_key', 'varchar, varchar');
Expand Down Expand Up @@ -410,6 +416,7 @@ BEGIN
PERFORM pg_tde_revoke_execute_privilege_on_function(target_user_or_role, 'pg_tde_add_key_provider_vault_v2', 'varchar, JSON, JSON,JSON,JSON');

PERFORM pg_tde_revoke_execute_privilege_on_function(target_user_or_role, 'pg_tde_set_principal_key', 'varchar, varchar, BOOLEAN');
PERFORM pg_tde_revoke_execute_privilege_on_function(target_user_or_role, 'pg_tde_alter_principal_key_keyring', 'varchar');

PERFORM pg_tde_revoke_execute_privilege_on_function(target_user_or_role, 'pg_tde_rotate_principal_key', 'pg_tde_global, varchar, varchar');
PERFORM pg_tde_revoke_execute_privilege_on_function(target_user_or_role, 'pg_tde_rotate_principal_key', 'varchar, varchar');
Expand Down
25 changes: 17 additions & 8 deletions src/access/pg_tde_tdemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static int pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore
static int pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read);
static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
static RelKeyData *pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key);
static int pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset);
static int pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool update_header, int fileFlags, bool *is_new_file, off_t *curr_pos);
static RelKeyData *pg_tde_get_key_from_cache(RelFileNumber rel_number, uint32 key_type);

#ifndef FRONTEND
Expand Down Expand Up @@ -279,7 +279,7 @@ pg_tde_delete_tde_files(Oid dbOid)
* The caller must have an EXCLUSIVE LOCK on the files before calling this function.
*/
bool
pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info)
pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info, bool truncate_existing, bool update_header)
{
int map_fd = -1;
int keydata_fd = -1;
Expand All @@ -288,16 +288,23 @@ pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info)
bool is_new_key_data = false;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
int file_flags = O_RDWR | O_CREAT;

/* Set the file paths */
pg_tde_set_db_file_paths(principal_key_info->databaseId,
db_map_path, db_keydata_path);

ereport(LOG, (errmsg("pg_tde_save_principal_key")));
ereport(DEBUG2,
(errmsg("pg_tde_save_principal_key"),
errdetail("truncate_existing:%s update_header:%s", truncate_existing?"YES":"NO", update_header?"YES":"NO")));
/*
* Create or truncate these map and keydata files.
*/
if (truncate_existing)
file_flags |= O_TRUNC;

/* Create or truncate these map and keydata files. */
map_fd = pg_tde_open_file(db_map_path, principal_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_map, &curr_pos);
keydata_fd = pg_tde_open_file(db_keydata_path, principal_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_key_data, &curr_pos);
map_fd = pg_tde_open_file(db_map_path, principal_key_info, update_header, file_flags, &is_new_map, &curr_pos);
keydata_fd = pg_tde_open_file(db_keydata_path, principal_key_info, update_header, file_flags, &is_new_key_data, &curr_pos);

/* Closing files. */
close(map_fd);
Expand Down Expand Up @@ -341,6 +348,8 @@ pg_tde_file_header_write(char *tde_filename, int fd, TDEPrincipalKeyInfo *princi
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", tde_filename)));
}
ereport(DEBUG2,
(errmsg("Wrote the header to %s", tde_filename)));

return fd;
}
Expand Down Expand Up @@ -1124,7 +1133,7 @@ tde_decrypt_rel_key(TDEPrincipalKey *principal_key, RelKeyData *enc_rel_key_data
* or an error is thrown if the file does not exist.
*/
static int
pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *curr_pos)
pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bool update_header, int fileFlags, bool *is_new_file, off_t *curr_pos)
{
int fd = -1;
TDEFileHeader fheader;
Expand All @@ -1141,7 +1150,7 @@ pg_tde_open_file(char *tde_filename, TDEPrincipalKeyInfo *principal_key_info, bo

#ifndef FRONTEND
/* In case it's a new file, let's add the header now. */
if (*is_new_file && principal_key_info)
if ((*is_new_file || update_header) && principal_key_info)
pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written);
#endif /* FRONTEND */

Expand Down
17 changes: 15 additions & 2 deletions src/access/pg_tde_xlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,16 @@ tdeheap_rmgr_redo(XLogReaderState *record)
pg_tde_write_key_map_entry(&xlrec->rlocator, &xlrec->relKey, pk);
LWLockRelease(tde_lwlock_enc_keys());
}
else if (info == XLOG_TDE_ADD_PRINCIPAL_KEY)
else if (info == XLOG_TDE_ADD_PRINCIPAL_KEY || info == XLOG_TDE_UPDATE_PRINCIPAL_KEY)
{
TDEPrincipalKeyInfo *mkey = (TDEPrincipalKeyInfo *) XLogRecGetData(record);

LWLockAcquire(tde_lwlock_enc_keys(), LW_EXCLUSIVE);
save_principal_key_info(mkey);
if (info == XLOG_TDE_ADD_PRINCIPAL_KEY)
save_principal_key_info(mkey);
else
update_principal_key_info(mkey);

LWLockRelease(tde_lwlock_enc_keys());
}
else if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
Expand Down Expand Up @@ -109,6 +113,12 @@ tdeheap_rmgr_desc(StringInfo buf, XLogReaderState *record)

appendStringInfo(buf, "add tde principal key for db %u", xlrec->databaseId);
}
if (info == XLOG_TDE_UPDATE_PRINCIPAL_KEY)
{
TDEPrincipalKeyInfo *xlrec = (TDEPrincipalKeyInfo *) XLogRecGetData(record);

appendStringInfo(buf, "Alter key provider to:%d for tde principal key for db %u", xlrec->keyringId, xlrec->databaseId);
}
if (info == XLOG_TDE_EXTENSION_INSTALL_KEY)
{
XLogExtensionInstall *xlrec = (XLogExtensionInstall *) XLogRecGetData(record);
Expand Down Expand Up @@ -138,6 +148,9 @@ tdeheap_rmgr_identify(uint8 info)
if ((info & ~XLR_INFO_MASK) == XLOG_TDE_ADD_PRINCIPAL_KEY)
return "XLOG_TDE_ADD_PRINCIPAL_KEY";

if ((info & ~XLR_INFO_MASK) == XLOG_TDE_UPDATE_PRINCIPAL_KEY)
return "XLOG_TDE_UPDATE_PRINCIPAL_KEY";

if ((info & ~XLR_INFO_MASK) == XLOG_TDE_EXTENSION_INSTALL_KEY)
return "XLOG_TDE_EXTENSION_INSTALL_KEY";

Expand Down
86 changes: 85 additions & 1 deletion src/catalog/tde_principal_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ static TDEPrincipalKey *set_principal_key_with_keyring(const char *key_name,
GenericKeyring *keyring,
Oid dbOid,
bool ensure_new_key);
static TDEPrincipalKey *alter_keyprovider_for_principal_key(GenericKeyring *newKeyring,Oid dbOid);

static const TDEShmemSetupRoutine principal_key_info_shmem_routine = {
.init_shared_state = initialize_shared_state,
Expand Down Expand Up @@ -213,7 +214,14 @@ save_principal_key_info(TDEPrincipalKeyInfo *principal_key_info)
{
Assert(principal_key_info != NULL);

return pg_tde_save_principal_key(principal_key_info);
return pg_tde_save_principal_key(principal_key_info, true, true);
}

bool
update_principal_key_info(TDEPrincipalKeyInfo *principal_key_info)
{
Assert(principal_key_info != NULL);
return pg_tde_save_principal_key(principal_key_info, false, true);
}

/*
Expand Down Expand Up @@ -296,6 +304,60 @@ set_principal_key_with_keyring(const char *key_name, GenericKeyring *keyring,
return principalKey;
}

/*
* alter_keyprovider_for_principal_key:
*/
TDEPrincipalKey *
alter_keyprovider_for_principal_key(GenericKeyring *newKeyring, Oid dbOid)
{
TDEPrincipalKeyInfo *principalKeyInfo = NULL;
TDEPrincipalKey *principal_key = NULL;

LWLock *lock_files = tde_lwlock_enc_keys();

Assert(newKeyring != NULL);
LWLockAcquire(lock_files, LW_EXCLUSIVE);

principalKeyInfo = pg_tde_get_principal_key_info(dbOid);

if (principalKeyInfo == NULL)
{
LWLockRelease(lock_files);
ereport(ERROR,
(errmsg("Principal key not set for the database"),
errhint("Use set_principal_key interface to set the principal key")));
}

if (newKeyring->key_id == principalKeyInfo->keyringId)
{
LWLockRelease(lock_files);
ereport(ERROR,
(errmsg("New key provider is same as the current key provider")));
}
/* update the key provider in principal key info */

ereport(DEBUG2,
(errmsg("Changing keyprovider ID from :%d to %d", principalKeyInfo->keyringId, newKeyring->key_id)));

principalKeyInfo->keyringId = newKeyring->key_id;

update_principal_key_info(principalKeyInfo);

/* XLog the new key*/
XLogBeginInsert();
XLogRegisterData((char *)principalKeyInfo, sizeof(TDEPrincipalKeyInfo));
XLogInsert(RM_TDERMGR_ID, XLOG_TDE_UPDATE_PRINCIPAL_KEY);

/* clear the cache as well */
clear_principal_key_cache(dbOid);

principal_key = GetPrincipalKey(dbOid, LW_EXCLUSIVE);

LWLockRelease(lock_files);

return principal_key;
}

bool
SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new_key)
{
Expand All @@ -307,6 +369,15 @@ SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new
return (principal_key != NULL);
}

bool
AlterPrincipalKeyKeyring(const char *provider_name)
{
TDEPrincipalKey *principal_key = alter_keyprovider_for_principal_key(GetKeyProviderByName(provider_name, MyDatabaseId),
MyDatabaseId);

return (principal_key != NULL);
}

bool
RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const char *new_provider_name, bool ensure_new_key)
{
Expand Down Expand Up @@ -629,6 +700,19 @@ pg_tde_set_principal_key(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(ret);
}

PG_FUNCTION_INFO_V1(pg_tde_alter_principal_key_keyring);
Datum pg_tde_alter_principal_key_keyring(PG_FUNCTION_ARGS);

Datum pg_tde_alter_principal_key_keyring(PG_FUNCTION_ARGS)
{
char *provider_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
bool ret;

ereport(LOG, (errmsg("Altering principal key provider to \"%s\" for the database", provider_name)));
ret = AlterPrincipalKeyKeyring(provider_name);
PG_RETURN_BOOL(ret);
}

/*
* SQL interface for key rotation
*/
Expand Down
2 changes: 1 addition & 1 deletion src/include/access/pg_tde_tdemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ extern RelKeyData *GetTdeGlobaleRelationKey(RelFileLocator rel);
extern void pg_tde_delete_tde_files(Oid dbOid);

extern TDEPrincipalKeyInfo *pg_tde_get_principal_key_info(Oid dbOid);
extern bool pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info);
extern bool pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info, bool truncate_existing, bool update_header);
extern bool pg_tde_perform_rotate_key(TDEPrincipalKey *principal_key, TDEPrincipalKey *new_principal_key);
extern bool pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_size, char *k_file_data);
extern RelKeyData *tde_create_rel_key(RelFileNumber rel_num, InternalKey *key, TDEPrincipalKeyInfo *principal_key_info);
Expand Down
1 change: 1 addition & 0 deletions src/include/access/pg_tde_xlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define XLOG_TDE_ROTATE_KEY 0x30
#define XLOG_TDE_ADD_KEY_PROVIDER_KEY 0x40
#define XLOG_TDE_FREE_MAP_ENTRY 0x50
#define XLOG_TDE_UPDATE_PRINCIPAL_KEY 0x60

/* ID 140 is registered for Percona TDE extension: https://wiki.postgresql.org/wiki/CustomWALResourceManagers */
#define RM_TDERMGR_ID 140
Expand Down
2 changes: 2 additions & 0 deletions src/include/catalog/tde_principal_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,11 @@ extern TDEPrincipalKey *GetPrincipalKey(Oid dbOid, void *lockMode);
#endif

extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo);
extern bool update_principal_key_info(TDEPrincipalKeyInfo *principal_key_info);

extern Oid GetPrincipalKeyProviderId(void);
extern bool SetPrincipalKey(const char *key_name, const char *provider_name, bool ensure_new_key);
extern bool AlterPrincipalKeyKeyring(const char *provider_name);
extern bool RotatePrincipalKey(TDEPrincipalKey *current_key, const char *new_key_name, const char *new_provider_name, bool ensure_new_key);
extern bool xl_tde_perform_rotate_key(XLogPrincipalKeyRotate *xlrec);

Expand Down
Loading
Loading