Merge pull request #214 from dAdAbird/xlog_key_mgmt

Add key management for WAL

Make the *.map *.dat processing code aware of custom databases and
table spaces

Add XLog GUC and init the keyring based on that. Only FS for now

Make the internal/external key infrastructure work with custom
(not stored in the database) keyrings.

Check and create an internal key for XLog during the server start.
If the key is created (not the first start with the EncryptWAL), then
upload it into the cache. We can't read the key from files while
writing the XLog to the disk as it happens in the critical section and
no palloc is allowed.

Create a custom cache for the global catalog external key as we can't
use PG's hashmap during the (again, no pallocs in critical section).

During the server start, when pg_tde module is loading and it needs to
read *.map, *.dat file, InitFileAccess is yet to be called, hence Vfd
isn't ready to use. The same gonna happen during recovery. So use raw
pread/pwrite calls istead.
pull/209/head
Andrew Pogrebnoi 1 year ago committed by GitHub
commit a670e46eac
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      Makefile.in
  2. 1
      meson.build
  3. 438
      src/access/pg_tde_tdemap.c
  4. 44
      src/access/pg_tde_xlog.c
  5. 248
      src/catalog/tde_global_catalog.c
  6. 3
      src/catalog/tde_keyring.c
  7. 82
      src/catalog/tde_master_key.c
  8. 14
      src/include/access/pg_tde_tdemap.h
  9. 9
      src/include/access/pg_tde_xlog.h
  10. 41
      src/include/catalog/tde_global_catalog.h
  11. 7
      src/include/catalog/tde_keyring.h
  12. 10
      src/include/catalog/tde_master_key.h
  13. BIN
      src/keyring/.keyring_api.c.swp
  14. 39
      src/keyring/keyring_file.c
  15. 13
      src/pg_tde.c
  16. 2
      src/smgr/pg_tde_smgr.c
  17. 2
      src/transam/pg_tde_xact_handler.c

@ -40,6 +40,7 @@ src/keyring/keyring_curl.o \
src/keyring/keyring_file.o \
src/keyring/keyring_vault.o \
src/keyring/keyring_api.o \
src/catalog/tde_global_catalog.o \
src/catalog/tde_keyring.o \
src/catalog/tde_master_key.o \
src/common/pg_tde_shmem.o \

@ -40,6 +40,7 @@ pg_tde_sources = files(
'src/smgr/pg_tde_smgr.c',
'src/catalog/tde_global_catalog.c',
'src/catalog/tde_keyring.c',
'src/catalog/tde_master_key.c',
'src/common/pg_tde_shmem.c',

@ -73,36 +73,30 @@ typedef struct TDEMapEntry
int32 key_index;
} TDEMapEntry;
/* Global variables */
static char db_path[MAXPGPATH] = {0};
static char db_map_path[MAXPGPATH] = {0};
static char db_keydata_path[MAXPGPATH] = {0};
static void put_key_into_map(Oid rel_id, RelKeyData *key);
static File pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing);
static File pg_tde_file_header_write(char *tde_filename, File tde_file, TDEMasterKeyInfo *master_key_info, off_t *bytes_written);
static File pg_tde_file_header_read(char *tde_filename, File tde_file, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read);
typedef struct TDEMapFilePath
{
char map_path[MAXPGPATH];
char keydata_path[MAXPGPATH];
} TDEMapFilePath;
static RelKeyData* tde_create_rel_key(const RelFileLocator *rlocator, InternalKey *key, TDEMasterKeyInfo *master_key_info);
static RelKeyData *tde_encrypt_rel_key(TDEMasterKey *master_key, RelKeyData *rel_key_data, const RelFileLocator *rlocator);
static RelKeyData *tde_decrypt_rel_key(TDEMasterKey *master_key, RelKeyData *enc_rel_key_data, const RelFileLocator *rlocator);
static int pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing);
static int pg_tde_file_header_write(char *tde_filename, int fd, TDEMasterKeyInfo *master_key_info, off_t *bytes_written);
static int pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read);
static void pg_tde_set_db_file_paths(Oid dbOid);
static File pg_tde_open_file(char *tde_filename, TDEMasterKeyInfo *master_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset);
static int pg_tde_open_file(char *tde_filename, TDEMasterKeyInfo *master_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *offset);
static int32 pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMasterKeyInfo *master_key_info);
static off_t pg_tde_write_one_map_entry(File map_file, const RelFileLocator *rlocator, int flags, int32 key_index, TDEMapEntry *map_entry, off_t *offset);
static off_t pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, int32 key_index, TDEMapEntry *map_entry, off_t *offset);
static int32 pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t *offset, bool should_delete);
static bool pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
static bool pg_tde_read_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset);
static void pg_tde_write_keydata(char *db_keydata_path, TDEMasterKeyInfo *master_key_info, int32 key_index, RelKeyData *enc_rel_key_data);
static void pg_tde_write_one_keydata(File keydata_file, int32 key_index, RelKeyData *enc_rel_key_data);
static RelKeyData* pg_tde_get_key_from_file(const RelFileLocator *rlocator);
static void pg_tde_write_one_keydata(int keydata_fd, int32 key_index, RelKeyData *enc_rel_key_data);
static RelKeyData* pg_tde_get_key_from_file(const RelFileLocator *rlocator, GenericKeyring *keyring);
static RelKeyData* pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEMasterKey *master_key);
static RelKeyData* pg_tde_read_one_keydata(File keydata_file, int32 key_index, TDEMasterKey *master_key);
static RelKeyData* pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEMasterKey *master_key);
static File keyrotation_init_file(TDEMasterKeyInfo *new_master_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos);
static int keyrotation_init_file(TDEMasterKeyInfo *new_master_key_info, char *rotated_filename, char *filename, bool *is_new_file, off_t *curr_pos);
static void finalize_key_rotation(char *m_path_old, char *k_path_old, char *m_path_new, char *k_path_new);
/*
@ -117,8 +111,7 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator)
TDEMasterKey *master_key;
XLogRelKey xlrec;
pg_tde_set_db_file_paths(newrlocator->dbOid);
master_key = GetMasterKey(newrlocator->dbOid);
master_key = GetMasterKey(newrlocator->dbOid, newrlocator->spcOid, NULL);
if (master_key == NULL)
{
ereport(ERROR,
@ -140,7 +133,7 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator)
}
/* Encrypt the key */
rel_key_data = tde_create_rel_key(newrlocator, &int_key, &master_key->keyInfo);
rel_key_data = tde_create_rel_key(newrlocator->relNumber, &int_key, &master_key->keyInfo);
enc_rel_key_data = tde_encrypt_rel_key(master_key, rel_key_data, newrlocator);
/*
@ -171,6 +164,12 @@ RelKey *tde_rel_key_map = NULL;
*/
RelKeyData *
GetRelationKey(RelFileLocator rel)
{
return GetRelationKeyWithKeyring(rel, NULL);
}
RelKeyData *
GetRelationKeyWithKeyring(RelFileLocator rel, GenericKeyring *keyring)
{
RelKey *curr;
RelKeyData *key;
@ -184,18 +183,18 @@ GetRelationKey(RelFileLocator rel)
}
}
key = pg_tde_get_key_from_file(&rel);
key = pg_tde_get_key_from_file(&rel, keyring);
if (key != NULL)
{
put_key_into_map(rel.relNumber, key);
pg_tde_put_key_into_map(rel.relNumber, key);
}
return key;
}
static void
put_key_into_map(Oid rel_id, RelKeyData *key) {
void
pg_tde_put_key_into_map(Oid rel_id, RelKeyData *key) {
RelKey *new;
RelKey *prev = NULL;
@ -226,8 +225,8 @@ tde_sprint_key(InternalKey *k)
* Creates a key for a relation identified by rlocator. Returns the newly
* created key.
*/
static RelKeyData *
tde_create_rel_key(const RelFileLocator *rlocator, InternalKey *key, TDEMasterKeyInfo *master_key_info)
RelKeyData *
tde_create_rel_key(Oid rel_id, InternalKey *key, TDEMasterKeyInfo *master_key_info)
{
RelKeyData *rel_key_data;
@ -238,7 +237,7 @@ tde_create_rel_key(const RelFileLocator *rlocator, InternalKey *key, TDEMasterKe
rel_key_data->internal_key.ctx = NULL;
/* Add to the decrypted key to cache */
put_key_into_map(rlocator->relNumber, rel_key_data);
pg_tde_put_key_into_map(rel_id, rel_key_data);
return rel_key_data;
}
@ -246,7 +245,7 @@ tde_create_rel_key(const RelFileLocator *rlocator, InternalKey *key, TDEMasterKe
/*
* Encrypts a given key and returns the encrypted one.
*/
static RelKeyData *
RelKeyData *
tde_encrypt_rel_key(TDEMasterKey *master_key, RelKeyData *rel_key_data, const RelFileLocator *rlocator)
{
RelKeyData *enc_rel_key_data;
@ -260,7 +259,7 @@ tde_encrypt_rel_key(TDEMasterKey *master_key, RelKeyData *rel_key_data, const Re
/*
* Decrypts a given key and returns the decrypted one.
*/
static RelKeyData *
RelKeyData *
tde_decrypt_rel_key(TDEMasterKey *master_key, RelKeyData *enc_rel_key_data, const RelFileLocator *rlocator)
{
RelKeyData *rel_key_data = NULL;
@ -271,33 +270,24 @@ tde_decrypt_rel_key(TDEMasterKey *master_key, RelKeyData *enc_rel_key_data, cons
return rel_key_data;
}
/*
* Sets the global variables so that we don't have to do this again for this
* backend lifetime.
*/
static void
pg_tde_set_db_file_paths(Oid dbOid)
inline void
pg_tde_set_db_file_paths(const RelFileLocator *rlocator, char *map_path, char *keydata_path)
{
/* Return if the values are already set */
// TODO: remove this entire global state thing
//if (*db_path && *db_map_path && *db_keydata_path)
// return;
char *db_path;
/* Fill in the values */
snprintf(db_path, MAXPGPATH, "%s", GetDatabasePath(dbOid, DEFAULTTABLESPACE_OID));
/* If this is a global space, than the call might be in a critial section
* (during XLog write) so we can't do GetDatabasePath as it calls palloc()
*/
if (rlocator->spcOid == GLOBALTABLESPACE_OID)
db_path = "global";
else
db_path = GetDatabasePath(rlocator->dbOid, rlocator->spcOid);
/* Set the file nanes for map and keydata */
join_path_components(db_map_path, db_path, PG_TDE_MAP_FILENAME);
join_path_components(db_keydata_path, db_path, PG_TDE_KEYDATA_FILENAME);
}
/*
* Path data clean up once the transaction is done.
*/
void
pg_tde_cleanup_path_vars(void)
{
*db_path = *db_map_path = *db_keydata_path = 0;
if (map_path)
join_path_components(map_path, db_path, PG_TDE_MAP_FILENAME);
if (keydata_path)
join_path_components(keydata_path, db_path, PG_TDE_KEYDATA_FILENAME);
}
/*
@ -305,10 +295,17 @@ pg_tde_cleanup_path_vars(void)
* Returns true if both map and key data files are created.
*/
void
pg_tde_delete_tde_files(Oid dbOid)
pg_tde_delete_tde_files(Oid dbOid, Oid spcOid)
{
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(dbOid);
pg_tde_set_db_file_paths(&(RelFileLocator) {
spcOid,
dbOid,
0},
db_map_path, db_keydata_path);
/* Remove these files without emitting any error */
PathNameDeleteTemporaryFile(db_map_path, false);
@ -327,24 +324,30 @@ pg_tde_delete_tde_files(Oid dbOid)
bool
pg_tde_save_master_key(TDEMasterKeyInfo *master_key_info)
{
File map_file = -1;
File keydata_file = -1;
int map_fd = -1;
int keydata_fd = -1;
off_t curr_pos = 0;
bool is_new_map = false;
bool is_new_key_data = false;
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(master_key_info->databaseId);
pg_tde_set_db_file_paths(&(RelFileLocator) {
master_key_info->tablespaceId,
master_key_info->databaseId,
0},
db_map_path, db_keydata_path);
ereport(LOG, (errmsg("pg_tde_save_master_key")));
/* Create or truncate these map and keydata files. */
map_file = pg_tde_open_file(db_map_path, master_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_map, &curr_pos);
keydata_file = pg_tde_open_file(db_keydata_path, master_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_key_data, &curr_pos);
map_fd = pg_tde_open_file(db_map_path, master_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_map, &curr_pos);
keydata_fd = pg_tde_open_file(db_keydata_path, master_key_info, false, O_RDWR | O_CREAT | O_TRUNC, &is_new_key_data, &curr_pos);
/* Closing files. */
FileClose(map_file);
FileClose(keydata_file);
close(map_fd);
close(keydata_fd);
return (is_new_map && is_new_key_data);
}
@ -354,30 +357,35 @@ pg_tde_save_master_key(TDEMasterKeyInfo *master_key_info)
* a LW_SHARED or higher lock on files before calling this function.
*/
TDEMasterKeyInfo *
pg_tde_get_master_key(Oid dbOid)
pg_tde_get_master_key(Oid dbOid, Oid spcOid)
{
File tde_file = -1;
int fd = -1;
TDEFileHeader fheader;
TDEMasterKeyInfo *master_key_info = NULL;
bool is_new_file = false;
off_t bytes_read = 0;
char db_map_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(dbOid);
pg_tde_set_db_file_paths(&(RelFileLocator) {
spcOid,
dbOid,
0},
db_map_path, NULL);
/*
* Ensuring that we always open the file in binary mode. The caller must
* specify other flags for reading, writing or creating the file.
*/
tde_file = pg_tde_open_file_basic(db_map_path, O_RDONLY, true);
fd = pg_tde_open_file_basic(db_map_path, O_RDONLY, true);
/* The file does not exist. */
if (tde_file < 0)
if (fd < 0)
return NULL;
pg_tde_file_header_read(db_map_path, tde_file, &fheader, &is_new_file, &bytes_read);
pg_tde_file_header_read(db_map_path, fd, &fheader, &is_new_file, &bytes_read);
FileClose(tde_file);
close(fd);
/* It's not a new file. So we can memcpy the master key info from the header */
if (!is_new_file)
@ -397,32 +405,32 @@ pg_tde_get_master_key(Oid dbOid)
* Returns the file descriptor in case of a success. Otherwise, fatal error
* is raised except when ignore_missing is true and the file does not exit.
*/
static File
static int
pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing)
{
File tde_file = -1;
int fd = -1;
/*
* Ensuring that we always open the file in binary mode. The caller must
* specify other flags for reading, writing or creating the file.
*/
tde_file = PathNameOpenFile(tde_filename, fileFlags | PG_BINARY);
if (tde_file < 0 && !(errno == ENOENT && ignore_missing == true))
fd = BasicOpenFile(tde_filename, fileFlags | PG_BINARY);
if (fd < 0 && !(errno == ENOENT && ignore_missing == true))
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("Could not open tde file \"%s\": %m",
errmsg("could not open tde file \"%s\": %m",
tde_filename)));
}
return tde_file;
return fd;
}
/*
* Write TDE file header to a TDE file.
*/
static File
pg_tde_file_header_write(char *tde_filename, File tde_file, TDEMasterKeyInfo *master_key_info, off_t *bytes_written)
static int
pg_tde_file_header_write(char *tde_filename, int fd, TDEMasterKeyInfo *master_key_info, off_t *bytes_written)
{
TDEFileHeader fheader;
size_t sz = sizeof(TDEMasterKeyInfo);
@ -436,33 +444,42 @@ pg_tde_file_header_write(char *tde_filename, File tde_file, TDEMasterKeyInfo *ma
memset(&fheader.master_key_info, 0, sz);
memcpy(&fheader.master_key_info, master_key_info, sz);
*bytes_written = FileWrite(tde_file, &fheader, TDE_FILE_HEADER_SIZE, 0, WAIT_EVENT_DATA_FILE_WRITE);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
*bytes_written = pg_pwrite(fd, &fheader, TDE_FILE_HEADER_SIZE, 0);
if (*bytes_written != TDE_FILE_HEADER_SIZE)
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("Could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
tde_filename)));
}
return tde_file;
if (pg_fsync(fd) != 0)
{
ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", tde_filename)));
}
return fd;
}
/*
* Read TDE file header from a TDE file and fill in the fheader data structure.
*/
static File
pg_tde_file_header_read(char *tde_filename, File tde_file, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read)
static int
pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read)
{
Assert(fheader);
*bytes_read = FileRead(tde_file, fheader, TDE_FILE_HEADER_SIZE, 0, WAIT_EVENT_DATA_FILE_READ);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
*bytes_read = pg_pread(fd, fheader, TDE_FILE_HEADER_SIZE, 0);
*is_new_file = (*bytes_read == 0);
/* File doesn't exist */
if (*bytes_read == 0)
return tde_file;
return fd;
if (*bytes_read != TDE_FILE_HEADER_SIZE
|| fheader->file_version != PG_TDE_FILEMAGIC)
@ -474,7 +491,7 @@ pg_tde_file_header_read(char *tde_filename, File tde_file, TDEFileHeader *fheade
tde_filename)));
}
return tde_file;
return fd;
}
/*
@ -494,10 +511,10 @@ pg_tde_file_header_read(char *tde_filename, File tde_file, TDEFileHeader *fheade
* The caller can pass the required flags to ensure that file is created
* or an error is thrown if the file does not exist.
*/
File
int
pg_tde_open_file(char *tde_filename, TDEMasterKeyInfo *master_key_info, bool should_fill_info, int fileFlags, bool *is_new_file, off_t *curr_pos)
{
File tde_file = -1;
int fd = -1;
TDEFileHeader fheader;
off_t bytes_read = 0;
off_t bytes_written = 0;
@ -506,16 +523,16 @@ pg_tde_open_file(char *tde_filename, TDEMasterKeyInfo *master_key_info, bool sho
* Ensuring that we always open the file in binary mode. The caller must
* specify other flags for reading, writing or creating the file.
*/
tde_file = pg_tde_open_file_basic(tde_filename, fileFlags, false);
fd = pg_tde_open_file_basic(tde_filename, fileFlags, false);
pg_tde_file_header_read(tde_filename, tde_file, &fheader, is_new_file, &bytes_read);
pg_tde_file_header_read(tde_filename, fd, &fheader, is_new_file, &bytes_read);
/* In case it's a new file, let's add the header now. */
if (*is_new_file && master_key_info)
pg_tde_file_header_write(tde_filename, tde_file, master_key_info, &bytes_written);
pg_tde_file_header_write(tde_filename, fd, master_key_info, &bytes_written);
*curr_pos = bytes_read + bytes_written;
return tde_file;
return fd;
}
/*
@ -530,7 +547,7 @@ pg_tde_open_file(char *tde_filename, TDEMasterKeyInfo *master_key_info, bool sho
static int32
pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMasterKeyInfo *master_key_info)
{
File map_file = -1;
int map_fd = -1;
int32 key_index = 0;
TDEMapEntry map_entry;
bool is_new_file;
@ -539,7 +556,7 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMas
bool found = false;
/* Open and vaidate file for basic correctness. */
map_file = pg_tde_open_file(db_map_path, master_key_info, false, O_RDWR | O_CREAT, &is_new_file, &curr_pos);
map_fd = pg_tde_open_file(db_map_path, master_key_info, false, O_RDWR | O_CREAT, &is_new_file, &curr_pos);
prev_pos = curr_pos;
/*
@ -550,7 +567,7 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMas
while(1)
{
prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_file, NULL, MAP_ENTRY_FREE, &map_entry, &curr_pos);
found = pg_tde_read_one_map_entry(map_fd, NULL, MAP_ENTRY_FREE, &map_entry, &curr_pos);
/* We either reach EOF or found an empty slot in the middle of the file */
if (prev_pos == curr_pos || found)
@ -562,10 +579,10 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMas
/* Write the given entry at the location pointed by prev_pos; i.e. the free entry */
curr_pos = prev_pos;
pg_tde_write_one_map_entry(map_file, rlocator, MAP_ENTRY_VALID, key_index, &map_entry, &prev_pos);
pg_tde_write_one_map_entry(map_fd, rlocator, MAP_ENTRY_VALID, key_index, &map_entry, &prev_pos);
/* Let's close the file. */
FileClose(map_file);
close(map_fd);
/* Register the entry to be freed in case the transaction aborts */
RegisterEntryForDeletion(rlocator, curr_pos, false);
@ -578,7 +595,7 @@ pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEMas
* map file.
*/
static off_t
pg_tde_write_one_map_entry(File map_file, const RelFileLocator *rlocator, int flags, int32 key_index, TDEMapEntry *map_entry, off_t *offset)
pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, int32 key_index, TDEMapEntry *map_entry, off_t *offset)
{
int bytes_written = 0;
@ -589,16 +606,27 @@ pg_tde_write_one_map_entry(File map_file, const RelFileLocator *rlocator, int fl
map_entry->flags = flags;
map_entry->key_index = key_index;
bytes_written = FileWrite(map_file, map_entry, MAP_ENTRY_SIZE, *offset, WAIT_EVENT_DATA_FILE_WRITE);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
bytes_written = pg_pwrite(fd, map_entry, MAP_ENTRY_SIZE, *offset);
/* Add the entry to the file */
if (bytes_written != MAP_ENTRY_SIZE)
{
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator, db_map_path, NULL);
ereport(FATAL,
(errcode_for_file_access(),
errmsg("Could not write tde map file \"%s\": %m",
errmsg("could not write tde map file \"%s\": %m",
db_map_path)));
}
if (pg_fsync(fd) != 0)
{
char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(rlocator, db_map_path, NULL);
ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", db_map_path)));
}
return (*offset + bytes_written);
}
@ -615,7 +643,7 @@ pg_tde_write_one_map_entry(File map_file, const RelFileLocator *rlocator, int fl
static int32
pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t *offset, bool should_delete)
{
File map_file = -1;
File map_fd = -1;
int32 key_index = 0;
TDEMapEntry map_entry;
bool is_new_file;
@ -629,7 +657,7 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_
* Open and validate file for basic correctness. DO NOT create it.
* The file should pre-exist otherwise we should never be here.
*/
map_file = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos);
map_fd = pg_tde_open_file(db_map_path, NULL, false, O_RDWR, &is_new_file, &curr_pos);
/*
* If we need to delete an entry, we expect an offset value to the start
@ -638,13 +666,13 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_
*/
if (should_delete == true && *offset > 0)
{
curr_pos = lseek(map_file, *offset, SEEK_SET);
curr_pos = lseek(map_fd, *offset, SEEK_SET);
if (curr_pos == -1)
{
ereport(FATAL,
(errcode_for_file_access(),
errmsg("Could not seek in tde map file \"%s\": %m",
errmsg("could not seek in tde map file \"%s\": %m",
db_map_path)));
}
}
@ -662,7 +690,7 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_
while(1)
{
prev_pos = curr_pos;
found = pg_tde_read_one_map_entry(map_file, rlocator, MAP_ENTRY_VALID, &map_entry, &curr_pos);
found = pg_tde_read_one_map_entry(map_fd, rlocator, MAP_ENTRY_VALID, &map_entry, &curr_pos);
/* We've reached EOF */
if (curr_pos == prev_pos)
@ -674,7 +702,7 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_
/* Mark the entry pointed by prev_pos as free */
if (should_delete)
{
pg_tde_write_one_map_entry(map_file, NULL, MAP_ENTRY_FREE, 0, &map_entry, &prev_pos);
pg_tde_write_one_map_entry(map_fd, NULL, MAP_ENTRY_FREE, 0, &map_entry, &prev_pos);
}
break;
@ -685,7 +713,7 @@ pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_
}
/* Let's close the file. */
FileClose(map_file);
close(map_fd);
/* Return -1 indicating that no entry was removed */
return ((found) ? key_index : -1);
@ -712,7 +740,8 @@ pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int fla
Assert(offset);
/* Read the entry at the given offset */
bytes_read = FileRead(map_file, map_entry, MAP_ENTRY_SIZE, *offset, WAIT_EVENT_DATA_FILE_READ);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
bytes_read = pg_pread(map_file, map_entry, MAP_ENTRY_SIZE, *offset);
/* We've reached the end of the file. */
if (bytes_read != MAP_ENTRY_SIZE)
@ -741,39 +770,46 @@ pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int fla
static void
pg_tde_write_keydata(char *db_keydata_path, TDEMasterKeyInfo *master_key_info, int32 key_index, RelKeyData *enc_rel_key_data)
{
File keydata_file = -1;
File fd = -1;
bool is_new_file;
off_t curr_pos = 0;
/* Open and validate file for basic correctness. */
keydata_file = pg_tde_open_file(db_keydata_path, master_key_info, false, O_RDWR | O_CREAT, &is_new_file, &curr_pos);
fd = pg_tde_open_file(db_keydata_path, master_key_info, false, O_RDWR | O_CREAT, &is_new_file, &curr_pos);
/* Write a single key data */
pg_tde_write_one_keydata(keydata_file, key_index, enc_rel_key_data);
pg_tde_write_one_keydata(fd, key_index, enc_rel_key_data);
/* Let's close the file. */
FileClose(keydata_file);
close(fd);
}
/*
* Function writes a single RelKeyData into the file at the given index.
*/
static void
pg_tde_write_one_keydata(File keydata_file, int32 key_index, RelKeyData *enc_rel_key_data)
pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data)
{
off_t curr_pos;
Assert(keydata_file != -1);
Assert(fd != -1);
/* Calculate the writing position in the file. */
curr_pos = (key_index * INTERNAL_KEY_LEN) + TDE_FILE_HEADER_SIZE;
if (FileWrite(keydata_file, &enc_rel_key_data->internal_key, INTERNAL_KEY_LEN, curr_pos, WAIT_EVENT_DATA_FILE_WRITE) != INTERNAL_KEY_LEN)
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pwrite(fd, &enc_rel_key_data->internal_key, INTERNAL_KEY_LEN, curr_pos) != INTERNAL_KEY_LEN)
{
ereport(FATAL,
(errcode_for_file_access(),
errmsg("Could not write tde key data file \"%s\": %m",
db_keydata_path)));
errmsg("could not write tde key data file: %m")));
}
if (pg_fsync(fd) != 0)
{
ereport(data_sync_elevel(ERROR),
(errcode_for_file_access(),
errmsg("could not fsync file: %m")));
}
}
@ -783,7 +819,7 @@ pg_tde_write_one_keydata(File keydata_file, int32 key_index, RelKeyData *enc_rel
static RelKeyData *
pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEMasterKey *master_key)
{
File keydata_file = -1;
int fd = -1;
RelKeyData *enc_rel_key_data;
off_t read_pos = 0;
bool is_new_file;
@ -791,13 +827,13 @@ pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEMasterKey *master
/* Open and validate file for basic correctness. */
LWLockAcquire(lock_files, LW_SHARED);
keydata_file = pg_tde_open_file(db_keydata_path, &master_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos);
fd = pg_tde_open_file(db_keydata_path, &master_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos);
/* Read the encrypted key from file */
enc_rel_key_data = pg_tde_read_one_keydata(keydata_file, key_index, master_key);
enc_rel_key_data = pg_tde_read_one_keydata(fd, key_index, master_key);
/* Let's close the file. */
FileClose(keydata_file);
close(fd);
LWLockRelease(lock_files);
return enc_rel_key_data;
@ -807,7 +843,7 @@ pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEMasterKey *master
* Reads a single keydata from the file.
*/
static RelKeyData *
pg_tde_read_one_keydata(File keydata_file, int32 key_index, TDEMasterKey *master_key)
pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEMasterKey *master_key)
{
RelKeyData *enc_rel_key_data;
off_t read_pos = 0;
@ -821,21 +857,34 @@ pg_tde_read_one_keydata(File keydata_file, int32 key_index, TDEMasterKey *master
read_pos += (key_index * INTERNAL_KEY_LEN) + TDE_FILE_HEADER_SIZE;
/* Check if the file has a valid key */
if ((read_pos + INTERNAL_KEY_LEN) > FileSize(keydata_file))
if ((read_pos + INTERNAL_KEY_LEN) > lseek(keydata_fd, 0, SEEK_END))
{
char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(&(RelFileLocator) {
master_key->keyInfo.tablespaceId,
master_key->keyInfo.databaseId,
0},
NULL, db_keydata_path);
ereport(FATAL,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("Could not find the required key at index %d in tde data file \"%s\": %m",
errmsg("could not find the required key at index %d in tde data file \"%s\": %m",
key_index,
db_keydata_path)));
}
/* Read the encrypted key */
if (FileRead(keydata_file, &(enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, read_pos, WAIT_EVENT_DATA_FILE_READ) != INTERNAL_KEY_LEN)
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pread(keydata_fd, &(enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, read_pos) != INTERNAL_KEY_LEN)
{
char db_keydata_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(&(RelFileLocator) {
master_key->keyInfo.tablespaceId,
master_key->keyInfo.databaseId,
0},
NULL, db_keydata_path);
ereport(FATAL,
(errcode_for_file_access(),
errmsg("Could not read key at index %d in tde key data file \"%s\": %m",
errmsg("could not read key at index %d in tde key data file \"%s\": %m",
key_index,
db_keydata_path)));
}
@ -855,11 +904,13 @@ pg_tde_write_key_map_entry(const RelFileLocator *rlocator, RelKeyData *enc_rel_k
{
int32 key_index = 0;
LWLock *lock_files = tde_lwlock_mk_files();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
/* Set the file paths */
pg_tde_set_db_file_paths(rlocator->dbOid);
pg_tde_set_db_file_paths(rlocator, db_map_path, db_keydata_path);
/* Create the map entry and then add the encrypted key to the data file */
LWLockAcquire(lock_files, LW_EXCLUSIVE);
@ -880,11 +931,13 @@ pg_tde_delete_key_map_entry(const RelFileLocator *rlocator)
int32 key_index = 0;
off_t offset = 0;
LWLock *lock_files = tde_lwlock_mk_files();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
/* Get the file paths */
pg_tde_set_db_file_paths(rlocator->dbOid);
pg_tde_set_db_file_paths(rlocator, db_map_path, db_keydata_path);
/* Remove the map entry if found */
LWLockAcquire(lock_files, LW_EXCLUSIVE);
@ -895,7 +948,7 @@ pg_tde_delete_key_map_entry(const RelFileLocator *rlocator)
{
ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("Could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber,
db_map_path)));
@ -922,11 +975,13 @@ pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset)
{
int32 key_index = 0;
LWLock *lock_files = tde_lwlock_mk_files();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
/* Get the file paths */
pg_tde_set_db_file_paths(rlocator->dbOid);
pg_tde_set_db_file_paths(rlocator, db_map_path, db_keydata_path);
/* Remove the map entry if found */
LWLockAcquire(lock_files, LW_EXCLUSIVE);
@ -937,7 +992,7 @@ pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset)
{
ereport(WARNING,
(errcode(ERRCODE_NO_DATA_FOUND),
errmsg("Could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
errmsg("could not find the required map entry for deletion of relation %d in tde map file \"%s\": %m",
rlocator->relNumber,
db_map_path)));
@ -950,7 +1005,7 @@ pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset)
* reads the key data from the keydata file.
*/
static RelKeyData *
pg_tde_get_key_from_file(const RelFileLocator *rlocator)
pg_tde_get_key_from_file(const RelFileLocator *rlocator, GenericKeyring *keyring)
{
int32 key_index = 0;
TDEMasterKey *master_key;
@ -958,14 +1013,15 @@ pg_tde_get_key_from_file(const RelFileLocator *rlocator)
RelKeyData *enc_rel_key_data;
off_t offset = 0;
LWLock *lock_files = tde_lwlock_mk_files();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
Assert(rlocator);
LWLockAcquire(lock_files, LW_SHARED);
/* Get/generate a master, create the key for relation and get the encrypted key with bytes to write */
pg_tde_set_db_file_paths(rlocator->dbOid);
master_key = GetMasterKey(rlocator->dbOid);
master_key = GetMasterKey(rlocator->dbOid, rlocator->spcOid, keyring);
if (master_key == NULL)
{
LWLockRelease(lock_files);
@ -973,6 +1029,9 @@ pg_tde_get_key_from_file(const RelFileLocator *rlocator)
(errmsg("failed to retrieve master key")));
}
/* Get the file paths */
pg_tde_set_db_file_paths(rlocator, db_map_path, db_keydata_path);
/* Read the map entry and get the index of the relation key */
key_index = pg_tde_process_map_entry(rlocator, db_map_path, &offset, false);
@ -1037,8 +1096,8 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
int32 key_index[MASTER_KEY_COUNT] = {0};
RelKeyData *rel_key_data[MASTER_KEY_COUNT];
RelKeyData *enc_rel_key_data[MASTER_KEY_COUNT];
File m_file[MASTER_KEY_COUNT] = {-1};
File k_file[MASTER_KEY_COUNT] = {-1};
int m_fd[MASTER_KEY_COUNT] = {-1};
int k_fd[MASTER_KEY_COUNT] = {-1};
char m_path[MASTER_KEY_COUNT][MAXPGPATH];
char k_path[MASTER_KEY_COUNT][MAXPGPATH];
TDEMapEntry map_entry;
@ -1052,9 +1111,15 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
off_t xlrec_size;
LWLock *lock_files = tde_lwlock_mk_files();
LWLock *lock_cache = tde_lwlock_mk_cache();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
/* Set the file paths */
pg_tde_set_db_file_paths(master_key->keyInfo.databaseId);
pg_tde_set_db_file_paths(&(RelFileLocator) {
master_key->keyInfo.tablespaceId,
master_key->keyInfo.databaseId,
0},
db_map_path, db_keydata_path);
/* Let's update the pathnames in the local variable for ease of use/readability */
strncpy(m_path[OLD_MASTER_KEY], db_map_path, MAXPGPATH);
@ -1064,17 +1129,17 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
LWLockAcquire(lock_cache, LW_EXCLUSIVE);
/* Open both files in read only mode. We don't need to track the current position of the keydata file. We always use the key index */
m_file[OLD_MASTER_KEY] = pg_tde_open_file(m_path[OLD_MASTER_KEY], &master_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_MASTER_KEY]);
k_file[OLD_MASTER_KEY] = pg_tde_open_file(k_path[OLD_MASTER_KEY], &master_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp);
m_fd[OLD_MASTER_KEY] = pg_tde_open_file(m_path[OLD_MASTER_KEY], &master_key->keyInfo, false, O_RDONLY, &is_new_file, &curr_pos[OLD_MASTER_KEY]);
k_fd[OLD_MASTER_KEY] = pg_tde_open_file(k_path[OLD_MASTER_KEY], &master_key->keyInfo, false, O_RDONLY, &is_new_file, &read_pos_tmp);
m_file[NEW_MASTER_KEY] = keyrotation_init_file(&new_master_key->keyInfo, m_path[NEW_MASTER_KEY], m_path[OLD_MASTER_KEY], &is_new_file, &curr_pos[NEW_MASTER_KEY]);
k_file[NEW_MASTER_KEY] = keyrotation_init_file(&new_master_key->keyInfo, k_path[NEW_MASTER_KEY], k_path[OLD_MASTER_KEY], &is_new_file, &read_pos_tmp);
m_fd[NEW_MASTER_KEY] = keyrotation_init_file(&new_master_key->keyInfo, m_path[NEW_MASTER_KEY], m_path[OLD_MASTER_KEY], &is_new_file, &curr_pos[NEW_MASTER_KEY]);
k_fd[NEW_MASTER_KEY] = keyrotation_init_file(&new_master_key->keyInfo, k_path[NEW_MASTER_KEY], k_path[OLD_MASTER_KEY], &is_new_file, &read_pos_tmp);
/* Read all entries until EOF */
for(key_index[OLD_MASTER_KEY] = 0; ; key_index[OLD_MASTER_KEY]++)
{
prev_pos[OLD_MASTER_KEY] = curr_pos[OLD_MASTER_KEY];
found = pg_tde_read_one_map_entry(m_file[OLD_MASTER_KEY], NULL, MAP_ENTRY_VALID, &map_entry, &curr_pos[OLD_MASTER_KEY]);
found = pg_tde_read_one_map_entry(m_fd[OLD_MASTER_KEY], NULL, MAP_ENTRY_VALID, &map_entry, &curr_pos[OLD_MASTER_KEY]);
/* We either reach EOF */
if (prev_pos[OLD_MASTER_KEY] == curr_pos[OLD_MASTER_KEY])
@ -1090,7 +1155,7 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
rloc.spcOid = DEFAULTTABLESPACE_OID;
/* Let's get the decrypted key and re-encrypt it with the new key. */
enc_rel_key_data[OLD_MASTER_KEY] = pg_tde_read_one_keydata(k_file[OLD_MASTER_KEY], key_index[OLD_MASTER_KEY], master_key);
enc_rel_key_data[OLD_MASTER_KEY] = pg_tde_read_one_keydata(k_fd[OLD_MASTER_KEY], key_index[OLD_MASTER_KEY], master_key);
/* Decrypt and re-encrypt keys */
rel_key_data[OLD_MASTER_KEY] = tde_decrypt_rel_key(master_key, enc_rel_key_data[OLD_MASTER_KEY], &rloc);
@ -1098,20 +1163,20 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
/* Write the given entry at the location pointed by prev_pos */
prev_pos[NEW_MASTER_KEY] = curr_pos[NEW_MASTER_KEY];
curr_pos[NEW_MASTER_KEY] = pg_tde_write_one_map_entry(m_file[NEW_MASTER_KEY], &rloc, MAP_ENTRY_VALID, key_index[NEW_MASTER_KEY], &map_entry, &prev_pos[NEW_MASTER_KEY]);
pg_tde_write_one_keydata(k_file[NEW_MASTER_KEY], key_index[NEW_MASTER_KEY], enc_rel_key_data[NEW_MASTER_KEY]);
curr_pos[NEW_MASTER_KEY] = pg_tde_write_one_map_entry(m_fd[NEW_MASTER_KEY], &rloc, MAP_ENTRY_VALID, key_index[NEW_MASTER_KEY], &map_entry, &prev_pos[NEW_MASTER_KEY]);
pg_tde_write_one_keydata(k_fd[NEW_MASTER_KEY], key_index[NEW_MASTER_KEY], enc_rel_key_data[NEW_MASTER_KEY]);
/* Increment the key index for the new master key */
key_index[NEW_MASTER_KEY]++;
}
/* Close unrotated files */
FileClose(m_file[OLD_MASTER_KEY]);
FileClose(k_file[OLD_MASTER_KEY]);
close(m_fd[OLD_MASTER_KEY]);
close(k_fd[OLD_MASTER_KEY]);
/* Let's calculate sizes */
map_size = FileSize(m_file[NEW_MASTER_KEY]);
keydata_size = FileSize(k_file[NEW_MASTER_KEY]);
map_size = lseek(m_fd[NEW_MASTER_KEY], 0, SEEK_END);
keydata_size = lseek(k_fd[NEW_MASTER_KEY], 0, SEEK_END);
xlrec_size = map_size + keydata_size + SizeoOfXLogMasterKeyRotate;
/* palloc and fill in the structure */
@ -1121,12 +1186,13 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
xlrec->map_size = map_size;
xlrec->keydata_size = keydata_size;
FileRead(m_file[NEW_MASTER_KEY], xlrec->buff, xlrec->map_size, 0, WAIT_EVENT_DATA_FILE_READ);
FileRead(k_file[NEW_MASTER_KEY], &xlrec->buff[xlrec->map_size], xlrec->keydata_size, 0, WAIT_EVENT_DATA_FILE_READ);
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
pg_pread(m_fd[NEW_MASTER_KEY], xlrec->buff, xlrec->map_size, 0);
pg_pread(k_fd[NEW_MASTER_KEY], &xlrec->buff[xlrec->map_size], xlrec->keydata_size, 0);
/* Close the files */
FileClose(m_file[NEW_MASTER_KEY]);
FileClose(k_file[NEW_MASTER_KEY]);
close(m_fd[NEW_MASTER_KEY]);
close(k_fd[NEW_MASTER_KEY]);
/* Insert the XLog record */
XLogBeginInsert();
@ -1143,7 +1209,6 @@ pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_key
/* Free up the palloc'ed data */
pfree(xlrec);
/* TODO: Remove the existing ones from cache etc. */
return true;
#undef OLD_MASTER_KEY
@ -1160,56 +1225,81 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_
TDEFileHeader *fheader;
char m_path_new[MAXPGPATH];
char k_path_new[MAXPGPATH];
File m_file_new;
File k_file_new;
int m_fd_new;
int k_fd_new;
bool is_new_file;
off_t curr_pos = 0;
off_t read_pos_tmp = 0;
LWLock *lock_files = tde_lwlock_mk_files();
LWLock *lock_cache = tde_lwlock_mk_cache();
char db_map_path[MAXPGPATH] = {0};
char db_keydata_path[MAXPGPATH] = {0};
bool is_err = false;
/* Let's get the header. Buff should start with the map file header. */
fheader = (TDEFileHeader *) m_file_data;
/* Set the file paths */
pg_tde_set_db_file_paths(fheader->master_key_info.databaseId);
pg_tde_set_db_file_paths(&(RelFileLocator) {
fheader->master_key_info.tablespaceId,
fheader->master_key_info.databaseId,
0},
db_map_path, db_keydata_path);
LWLockAcquire(lock_files, LW_EXCLUSIVE);
LWLockAcquire(lock_cache, LW_EXCLUSIVE);
/* Initialize the new files and set the names */
m_file_new = keyrotation_init_file(&fheader->master_key_info, m_path_new, db_map_path, &is_new_file, &curr_pos);
k_file_new = keyrotation_init_file(&fheader->master_key_info, k_path_new, db_keydata_path, &is_new_file, &read_pos_tmp);
m_fd_new = keyrotation_init_file(&fheader->master_key_info, m_path_new, db_map_path, &is_new_file, &curr_pos);
k_fd_new = keyrotation_init_file(&fheader->master_key_info, k_path_new, db_keydata_path, &is_new_file, &read_pos_tmp);
if (FileWrite(m_file_new, m_file_data, map_size, 0, WAIT_EVENT_DATA_FILE_WRITE) != map_size)
/* TODO: pgstat_report_wait_start / pgstat_report_wait_end */
if (pg_pwrite(m_fd_new, m_file_data, map_size, 0) != map_size)
{
LWLockRelease(lock_cache);
LWLockRelease(lock_files);
ereport(WARNING,
(errcode_for_file_access(),
errmsg("Could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
m_path_new)));
is_err = true;
goto FINALIZE;
}
if (FileWrite(k_file_new, k_file_data, keydata_size, 0, WAIT_EVENT_DATA_FILE_WRITE) != keydata_size)
if (pg_fsync(m_fd_new) != 0)
{
LWLockRelease(lock_cache);
LWLockRelease(lock_files);
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", m_path_new)));
is_err = true;
goto FINALIZE;
}
if (pg_pwrite(k_fd_new, k_file_data, keydata_size, 0) != keydata_size)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("Could not write tde file \"%s\": %m",
errmsg("could not write tde file \"%s\": %m",
k_path_new)));
is_err = true;
goto FINALIZE;
}
if (pg_fsync(k_fd_new) != 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m", k_path_new)));
is_err = true;
goto FINALIZE;
}
FileClose(m_file_new);
FileClose(k_file_new);
FINALIZE:
close(m_fd_new);
close(k_fd_new);
if (!is_err)
finalize_key_rotation(db_map_path, db_keydata_path, m_path_new, k_path_new);
LWLockRelease(lock_cache);
LWLockRelease(lock_files);
return true;
return !is_err;
}

@ -16,6 +16,7 @@
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xloginsert.h"
#include "catalog/pg_tablespace_d.h"
#include "storage/bufmgr.h"
#include "storage/shmem.h"
#include "utils/guc.h"
@ -23,12 +24,14 @@
#include "access/pg_tde_tdemap.h"
#include "access/pg_tde_xlog.h"
#include "catalog/tde_master_key.h"
#include "encryption/enc_tde.h"
#ifdef PERCONA_FORK
#include "catalog/tde_global_catalog.h"
static char *TDEXLogEncryptBuf = NULL;
bool EncryptXLog = false;
/* GUC */
static bool EncryptXLog = false;
static XLogPageHeaderData EncryptCurrentPageHrd;
static XLogPageHeaderData DecryptCurrentPageHrd;
@ -36,6 +39,8 @@ static XLogPageHeaderData DecryptCurrentPageHrd;
static ssize_t TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset);
static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix);
static int XLOGChooseNumBuffers(void);
#endif
/*
* TDE fork XLog
*/
@ -123,18 +128,12 @@ pg_tde_rmgr_identify(uint8 info)
#ifdef PERCONA_FORK
/*
* -------------------------
* XLog Storage Manager
* TODO:
* - Should be a config option "on/off"?
* - Currently it encrypts WAL XLog Pages, should we encrypt whole Segments? `initdb` for
* example generates a write of 312 pages - so 312 "gen IV" and "encrypt" runs instead of one.
* Would require though an extra read() during recovery/was_send etc to check `XLogPageHeader`
* if segment is encrypted.
* We could also encrypt Records while adding them to the XLog Buf but it'll be the slowest (?).
*/
void
xlogInitGUC(void)
XLogInitGUC(void)
{
DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */
"Enable/Disable encryption of WAL.", /* short_desc */
@ -166,7 +165,7 @@ XLOGChooseNumBuffers(void)
* Defines the size of the XLog encryption buffer
*/
Size
TDEXLogEncryptBuffSize()
TDEXLogEncryptBuffSize(void)
{
int xbuffers;
@ -187,10 +186,10 @@ TDEXLogEncryptBuffSize()
void
TDEXLogShmemInit(void)
{
if (EncryptXLog)
{
bool foundBuf;
if (EncryptXLog)
{
TDEXLogEncryptBuf = (char *)
TYPEALIGN(PG_IO_ALIGN_SIZE,
ShmemInitStruct("TDE XLog Encryption Buffer",
@ -202,17 +201,11 @@ TDEXLogShmemInit(void)
}
void
TDEInitXLogSmgr(void)
TDEXLogSmgrInit(void)
{
SetXLogSmgr(&tde_xlog_smgr);
}
/*
* TODO: proper key management
* where to store refs to the master and internal keys?
*/
static InternalKey XLogInternalKey = {.key = {0xD,}};
ssize_t
pg_tde_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset)
{
@ -232,12 +225,11 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd;
XLogPageHeader enc_buf_page;
RelKeyData key = {.internal_key = XLogInternalKey};
RelKeyData *key = GetGlCatInternalKey(XLOG_TDE_OID);
off_t enc_off;
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
uint32 iv_ctr = 0;
#ifdef TDE_XLOG_DEBUG
elog(DEBUG1, "write encrypted WAL, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset);
#endif
@ -300,7 +292,7 @@ TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset)
{
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_ENCRYPT_DATA(iv_prefix, iv_ctr, (char *) buf + enc_off, data_size,
TDEXLogEncryptBuf + enc_off, &key);
TDEXLogEncryptBuf + enc_off, key);
}
page_size = XLOG_BLCKSZ;
@ -320,7 +312,7 @@ pg_tde_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
char iv_prefix[16] = {0,};
size_t data_size = 0;
XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd;
RelKeyData key = {.internal_key = XLogInternalKey};
RelKeyData *key = GetGlCatInternalKey(XLOG_TDE_OID);
size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ;
off_t dec_off;
uint32 iv_ctr = 0;
@ -373,7 +365,7 @@ pg_tde_xlog_seg_read(int fd, void *buf, size_t count, off_t offset)
SetXLogPageIVPrefix(curr_page_hdr->xlp_tli, curr_page_hdr->xlp_pageaddr, iv_prefix);
PG_TDE_DECRYPT_DATA(
iv_prefix, iv_ctr,
(char *) buf + dec_off, data_size, (char *) buf + dec_off, &key);
(char *) buf + dec_off, data_size, (char *) buf + dec_off, key);
}
page_size = XLOG_BLCKSZ;

@ -0,0 +1,248 @@
/*-------------------------------------------------------------------------
*
* tde_global_catalog.c
* Global catalog key management
*
*
* IDENTIFICATION
* src/catalog/tde_global_catalog.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#ifdef PERCONA_FORK
#include "storage/shmem.h"
#include "utils/guc.h"
#include "access/pg_tde_tdemap.h"
#include "catalog/tde_global_catalog.h"
#include "catalog/tde_keyring.h"
#include "catalog/tde_master_key.h"
#include <openssl/rand.h>
#include <openssl/err.h>
#include <sys/time.h>
#define MASTER_KEY_DEFAULT_NAME "tde-global-catalog-key"
/* TODO: not sure if we need an option of multiple master keys for the global catalog */
typedef enum
{
TDE_GCAT_XLOG_KEY,
/* must be last */
TDE_GCAT_KEYS_COUNT
} GlobalCatalogKeyTypes;
typedef struct EncryptionStateData
{
GenericKeyring *keyring;
TDEMasterKey master_keys[TDE_GCAT_KEYS_COUNT];
} EncryptionStateData;
static EncryptionStateData * EncryptionState = NULL;
/* GUC */
static char *KRingProviderType = NULL;
static char *KRingProviderFilePath = NULL;
static void init_gl_catalog_keys(void);
static void init_keyring(void);
static TDEMasterKey * create_master_key(const char *key_name,
GenericKeyring * keyring, Oid dbOid, Oid spcOid,
bool ensure_new_key);
void
TDEGlCatInitGUC(void)
{
DefineCustomStringVariable("pg_tde.global_keyring_type",
"Keyring type for global catalog",
NULL,
&KRingProviderType,
NULL,
PGC_POSTMASTER,
0, /* no flags required */
NULL,
NULL,
NULL
);
DefineCustomStringVariable("pg_tde.global_keyring_file_path",
"Keyring file options for global catalog",
NULL,
&KRingProviderFilePath,
NULL,
PGC_POSTMASTER,
0, /* no flags required */
NULL,
NULL,
NULL
);
}
Size
TDEGlCatEncStateSize(void)
{
Size size;
size = sizeof(EncryptionStateData);
size = add_size(size, sizeof(KeyringProviders));
return MAXALIGN(size);
}
void
TDEGlCatShmemInit(void)
{
bool foundBuf;
char *allocptr;
EncryptionState = (EncryptionStateData *)
ShmemInitStruct("TDE XLog Encryption State",
TDEGlCatEncStateSize(), &foundBuf);
allocptr = ((char *) EncryptionState) + MAXALIGN(sizeof(EncryptionStateData));
EncryptionState->keyring = (GenericKeyring *) allocptr;
memset(EncryptionState->keyring, 0, sizeof(KeyringProviders));
memset(EncryptionState->master_keys, 0, sizeof(TDEMasterKey) * TDE_GCAT_KEYS_COUNT);
}
void
TDEGlCatKeyInit(void)
{
char db_map_path[MAXPGPATH] = {0};
init_keyring();
pg_tde_set_db_file_paths(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID),
db_map_path, NULL);
if (access(db_map_path, F_OK) == -1)
{
init_gl_catalog_keys();
}
else
{
/* put an internal key into the cache */
GetGlCatInternalKey(XLOG_TDE_OID);
}
}
TDEMasterKey *
TDEGetGlCatKeyFromCache(void)
{
TDEMasterKey *mkey;
mkey = &EncryptionState->master_keys[TDE_GCAT_XLOG_KEY];
if (mkey->keyLength == 0)
return NULL;
return mkey;
}
void
TDEPutGlCatKeyInCache(TDEMasterKey * mkey)
{
memcpy(EncryptionState->master_keys + TDE_GCAT_XLOG_KEY, mkey, sizeof(TDEMasterKey));
}
RelKeyData *
GetGlCatInternalKey(Oid obj_id)
{
return GetRelationKeyWithKeyring(GLOBAL_SPACE_RLOCATOR(obj_id), EncryptionState->keyring);
}
/*
* TODO: should be aligned with the rest of the keyring_provider code after its
* refactoring
*
* TODO: add Vault
*/
static void
init_keyring(void)
{
EncryptionState->keyring->type = get_keyring_provider_from_typename(KRingProviderType);
switch (EncryptionState->keyring->type)
{
case FILE_KEY_PROVIDER:
FileKeyring * kring = (FileKeyring *) EncryptionState->keyring;
strncpy(kring->file_name, KRingProviderFilePath, sizeof(kring->file_name));
break;
}
}
/*
* Keys are created during the cluster start only, so no locks needed here.
*/
static void
init_gl_catalog_keys(void)
{
InternalKey int_key;
RelKeyData *rel_key_data;
RelKeyData *enc_rel_key_data;
RelFileLocator *rlocator;
TDEMasterKey *mkey;
mkey = create_master_key(MASTER_KEY_DEFAULT_NAME,
EncryptionState->keyring,
GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID, false);
memset(&int_key, 0, sizeof(InternalKey));
/* Create and store an internal key for XLog */
if (!RAND_bytes(int_key.key, INTERNAL_KEY_LEN))
{
ereport(FATAL,
(errcode(ERRCODE_INTERNAL_ERROR),
errmsg("could not generate internal key for \"WAL\": %s",
ERR_error_string(ERR_get_error(), NULL))));
}
rlocator = &GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID);
rel_key_data = tde_create_rel_key(rlocator->relNumber, &int_key, &mkey->keyInfo);
enc_rel_key_data = tde_encrypt_rel_key(mkey, rel_key_data, rlocator);
pg_tde_write_key_map_entry(rlocator, enc_rel_key_data, &mkey->keyInfo);
/*
* TODO: move global catalog internal keys into own cache. This cache should
* be in the TopMemmoryContext because of SSL contexts
* (see https://github.com/Percona-Lab/pg_tde/pull/214#discussion_r1648998317)
*/
pg_tde_put_key_into_map(rlocator->relNumber, rel_key_data);
TDEPutGlCatKeyInCache(mkey);
}
static TDEMasterKey *
create_master_key(const char *key_name, GenericKeyring * keyring,
Oid dbOid, Oid spcOid, bool ensure_new_key)
{
TDEMasterKey *masterKey;
keyInfo *keyInfo = NULL;
masterKey = palloc(sizeof(TDEMasterKey));
masterKey->keyInfo.databaseId = dbOid;
masterKey->keyInfo.tablespaceId = spcOid;
masterKey->keyInfo.keyId.version = DEFAULT_MASTER_KEY_VERSION;
masterKey->keyInfo.keyringId = keyring->key_id;
strncpy(masterKey->keyInfo.keyId.name, key_name, TDE_KEY_NAME_LEN);
gettimeofday(&masterKey->keyInfo.creationTime, NULL);
keyInfo = load_latest_versioned_key_name(&masterKey->keyInfo, keyring, ensure_new_key);
if (keyInfo == NULL)
keyInfo = KeyringGenerateNewKeyAndStore(keyring, masterKey->keyInfo.keyId.versioned_name, INTERNAL_KEY_LEN, false);
if (keyInfo == NULL)
{
ereport(ERROR,
(errmsg("failed to retrieve master key")));
}
masterKey->keyLength = keyInfo->data.len;
memcpy(masterKey->keyData, keyInfo->data.data, keyInfo->data.len);
return masterKey;
}
#endif /* PERCONA_FORK */

@ -50,13 +50,12 @@ PG_FUNCTION_INFO_V1(keyring_delete_dependency_check_trigger);
#define FILE_KEYRING_TYPE_KEY "type"
static FileKeyring *load_file_keyring_provider_options(Datum keyring_options);
static ProviderType get_keyring_provider_from_typename(char *provider_type);
static GenericKeyring *load_keyring_provider_options(ProviderType provider_type, Datum keyring_options);
static VaultV2Keyring *load_vaultV2_keyring_provider_options(Datum keyring_options);
static void debug_print_kerying(GenericKeyring *keyring);
static GenericKeyring *load_keyring_provider_from_tuple(HeapTuple tuple, TupleDesc tupDesc);
static ProviderType
ProviderType
get_keyring_provider_from_typename(char *provider_type)
{
if (provider_type == NULL)

@ -29,8 +29,9 @@
#include <sys/time.h>
#include "access/pg_tde_tdemap.h"
#define DEFAULT_MASTER_KEY_VERSION 1
#ifdef PERCONA_FORK
#include "catalog/tde_global_catalog.h"
#endif
typedef struct TdeMasterKeySharedState
{
@ -67,12 +68,10 @@ static Size required_shared_mem_size(void);
static int required_locks_count(void);
static void shared_memory_shutdown(int code, Datum arg);
static void master_key_startup_cleanup(int tde_tbl_count, void *arg);
static keyInfo *load_latest_versioned_key_name(TDEMasterKeyInfo *mastere_key_info, GenericKeyring *keyring, bool ensure_new_key);
static void clear_master_key_cache(Oid databaseId, Oid tablespaceId) ;
static void clear_master_key_cache(Oid databaseId) ;
static inline dshash_table *get_master_key_Hash(void);
static TDEMasterKey *get_master_key_from_cache(Oid dbOid);
static void push_master_key_to_cache(TDEMasterKey *masterKey);
static TDEMasterKey *set_master_key_with_keyring(const char *key_name, GenericKeyring *keyring, bool ensure_new_key);
static const TDEShmemSetupRoutine master_key_info_shmem_routine = {
.init_shared_state = initialize_shared_state,
@ -214,11 +213,10 @@ save_master_key_info(TDEMasterKeyInfo *master_key_info)
* throws an error.
*/
TDEMasterKey *
GetMasterKey(Oid dbOid)
GetMasterKey(Oid dbOid, Oid spcOid, GenericKeyring *keyring)
{
TDEMasterKey *masterKey = NULL;
TDEMasterKeyInfo *masterKeyInfo = NULL;
GenericKeyring *keyring = NULL;
const keyInfo *keyInfo = NULL;
KeyringReturnCodes keyring_ret;
LWLock *lock_files = tde_lwlock_mk_files();
@ -236,6 +234,12 @@ GetMasterKey(Oid dbOid)
recursion++;
LWLockAcquire(lock_cache, LW_SHARED);
#ifdef PERCONA_FORK
/* Global catalog has its own cache */
if (spcOid == GLOBALTABLESPACE_OID)
masterKey = TDEGetGlCatKeyFromCache();
else
#endif
masterKey = get_master_key_from_cache(dbOid);
LWLockRelease(lock_cache);
@ -252,6 +256,12 @@ GetMasterKey(Oid dbOid)
LWLockAcquire(lock_files, LW_SHARED);
LWLockAcquire(lock_cache, LW_EXCLUSIVE);
#ifdef PERCONA_FORK
/* Global catalog has its own cache */
if (spcOid == GLOBALTABLESPACE_OID)
masterKey = TDEGetGlCatKeyFromCache();
else
#endif
masterKey = get_master_key_from_cache(dbOid);
if (masterKey)
@ -263,7 +273,7 @@ GetMasterKey(Oid dbOid)
}
/* Master key not present in cache. Load from the keyring */
masterKeyInfo = pg_tde_get_master_key(dbOid);
masterKeyInfo = pg_tde_get_master_key(dbOid, spcOid);
if (masterKeyInfo == NULL)
{
LWLockRelease(lock_cache);
@ -273,7 +283,8 @@ GetMasterKey(Oid dbOid)
return NULL;
}
/* Load the master key from keyring and store it in cache */
if (keyring == NULL)
{
keyring = GetKeyProviderByID(masterKeyInfo->keyringId);
if (keyring == NULL)
{
@ -283,6 +294,7 @@ GetMasterKey(Oid dbOid)
recursion--;
return NULL;
}
}
keyInfo = KeyringGetKey(keyring, masterKeyInfo->keyId.versioned_name, false, &keyring_ret);
if (keyInfo == NULL)
@ -300,7 +312,12 @@ GetMasterKey(Oid dbOid)
memcpy(masterKey->keyData, keyInfo->data.data, keyInfo->data.len);
masterKey->keyLength = keyInfo->data.len;
Assert(MyDatabaseId == masterKey->keyInfo.databaseId);
Assert(dbOid == masterKey->keyInfo.databaseId);
#ifdef PERCONA_FORK
if (spcOid == GLOBALTABLESPACE_OID)
TDEPutGlCatKeyInCache(masterKey);
else
#endif
push_master_key_to_cache(masterKey);
/* Release the exclusive locks here */
@ -324,12 +341,11 @@ GetMasterKey(Oid dbOid)
* to make sure if some other caller has not added a master key for
* same database while we were waiting for the lock.
*/
static TDEMasterKey *
set_master_key_with_keyring(const char *key_name, GenericKeyring *keyring, bool ensure_new_key)
TDEMasterKey *
set_master_key_with_keyring(const char *key_name, GenericKeyring *keyring,
Oid dbOid, Oid spcOid, bool ensure_new_key)
{
TDEMasterKey *masterKey = NULL;
Oid dbOid = MyDatabaseId;
LWLock *lock_files = tde_lwlock_mk_files();
LWLock *lock_cache = tde_lwlock_mk_cache();
bool is_dup_key = false;
@ -345,14 +361,15 @@ set_master_key_with_keyring(const char *key_name, GenericKeyring *keyring, bool
/* TODO: Add the key in the cache? */
if (is_dup_key == false)
is_dup_key = (pg_tde_get_master_key(dbOid) != NULL);
is_dup_key = (pg_tde_get_master_key(dbOid, spcOid) != NULL);
if (is_dup_key == false)
{
const keyInfo *keyInfo = NULL;
masterKey = palloc(sizeof(TDEMasterKey));
masterKey->keyInfo.databaseId = MyDatabaseId;
masterKey->keyInfo.databaseId = dbOid;
masterKey->keyInfo.tablespaceId = spcOid;
masterKey->keyInfo.keyId.version = DEFAULT_MASTER_KEY_VERSION;
masterKey->keyInfo.keyringId = keyring->key_id;
strncpy(masterKey->keyInfo.keyId.name, key_name, TDE_KEY_NAME_LEN);
@ -407,7 +424,10 @@ set_master_key_with_keyring(const char *key_name, GenericKeyring *keyring, bool
bool
SetMasterKey(const char *key_name, const char *provider_name, bool ensure_new_key)
{
TDEMasterKey *master_key = set_master_key_with_keyring(key_name, GetKeyProviderByName(provider_name), ensure_new_key);
TDEMasterKey *master_key = set_master_key_with_keyring(key_name,
GetKeyProviderByName(provider_name),
MyDatabaseId, MyDatabaseTableSpace,
ensure_new_key);
return (master_key != NULL);
}
@ -415,10 +435,11 @@ SetMasterKey(const char *key_name, const char *provider_name, bool ensure_new_ke
bool
RotateMasterKey(const char *new_key_name, const char *new_provider_name, bool ensure_new_key)
{
TDEMasterKey *master_key = GetMasterKey(MyDatabaseId);
TDEMasterKey *master_key = GetMasterKey(MyDatabaseId, MyDatabaseTableSpace, NULL);
TDEMasterKey new_master_key;
const keyInfo *keyInfo = NULL;
GenericKeyring *keyring;
bool is_rotated;
/*
* Let's set everything the same as the older master key and
@ -457,8 +478,13 @@ RotateMasterKey(const char *new_key_name, const char *new_provider_name, bool en
new_master_key.keyLength = keyInfo->data.len;
memcpy(new_master_key.keyData, keyInfo->data.data, keyInfo->data.len);
clear_master_key_cache(MyDatabaseId, MyDatabaseTableSpace);
return pg_tde_perform_rotate_key(master_key, &new_master_key);
is_rotated = pg_tde_perform_rotate_key(master_key, &new_master_key);
if (is_rotated) {
clear_master_key_cache(master_key->keyInfo.databaseId);
push_master_key_to_cache(&new_master_key);
}
return is_rotated;
}
/*
@ -470,7 +496,7 @@ xl_tde_perform_rotate_key(XLogMasterKeyRotate *xlrec)
bool ret;
ret = pg_tde_write_map_keydata_files(xlrec->map_size, xlrec->buff, xlrec->keydata_size, &xlrec->buff[xlrec->map_size]);
clear_master_key_cache(MyDatabaseId, MyDatabaseTableSpace);
clear_master_key_cache(MyDatabaseId);
return ret;
}
@ -480,7 +506,7 @@ xl_tde_perform_rotate_key(XLogMasterKeyRotate *xlrec)
* If ensure_new_key is true, then we will keep on incrementing the version number
* till we get a key name that is not present in the keyring
*/
static keyInfo *
keyInfo *
load_latest_versioned_key_name(TDEMasterKeyInfo *mastere_key_info, GenericKeyring *keyring, bool ensure_new_key)
{
KeyringReturnCodes kr_ret;
@ -564,7 +590,7 @@ GetMasterKeyProviderId(void)
}
{
/* Master key not present in cache. Try Loading it from the info file */
masterKeyInfo = pg_tde_get_master_key(dbOid);
masterKeyInfo = pg_tde_get_master_key(dbOid, MyDatabaseTableSpace);
if (masterKeyInfo)
{
keyringId = masterKeyInfo->keyringId;
@ -620,7 +646,7 @@ static void
push_master_key_to_cache(TDEMasterKey *masterKey)
{
TDEMasterKey *cacheEntry = NULL;
Oid databaseId = MyDatabaseId;
Oid databaseId = masterKey->keyInfo.databaseId;
bool found = false;
cacheEntry = dshash_find_or_insert(get_master_key_Hash(),
&databaseId, &found);
@ -664,18 +690,18 @@ master_key_startup_cleanup(int tde_tbl_count, void* arg)
void
cleanup_master_key_info(Oid databaseId, Oid tablespaceId)
{
clear_master_key_cache(databaseId, tablespaceId);
clear_master_key_cache(databaseId);
/*
* TODO: Although should never happen. Still verify if any table in the
* database is using tde
*/
/* Remove the tde files */
pg_tde_delete_tde_files(databaseId);
pg_tde_delete_tde_files(databaseId, tablespaceId);
}
static void
clear_master_key_cache(Oid databaseId, Oid tablespaceId)
clear_master_key_cache(Oid databaseId)
{
TDEMasterKey *cache_entry;
@ -748,7 +774,7 @@ Datum pg_tde_master_key_info(PG_FUNCTION_ARGS)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context that cannot accept type record")));
master_key = GetMasterKey(MyDatabaseId);
master_key = GetMasterKey(MyDatabaseId, MyDatabaseTableSpace, NULL);
if (master_key == NULL)
{
ereport(ERROR,

@ -10,6 +10,7 @@
#include "utils/rel.h"
#include "access/xlog_internal.h"
#include "catalog/pg_tablespace_d.h"
#include "catalog/tde_master_key.h"
#include "storage/fd.h"
#include "storage/relfilelocator.h"
@ -52,15 +53,22 @@ extern void pg_tde_delete_key_map_entry(const RelFileLocator *rlocator);
extern void pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset);
extern RelKeyData *GetRelationKey(RelFileLocator rel);
extern RelKeyData *GetRelationKeyWithKeyring(RelFileLocator rel, GenericKeyring *keyring);
extern void pg_tde_cleanup_path_vars(void);
extern void pg_tde_delete_tde_files(Oid dbOid);
extern void pg_tde_delete_tde_files(Oid dbOid, Oid spcOid);
extern TDEMasterKeyInfo *pg_tde_get_master_key(Oid dbOid);
extern TDEMasterKeyInfo *pg_tde_get_master_key(Oid dbOid, Oid spcOid);
extern bool pg_tde_save_master_key(TDEMasterKeyInfo *master_key_info);
extern bool pg_tde_perform_rotate_key(TDEMasterKey *master_key, TDEMasterKey *new_master_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(Oid rel_id, InternalKey *key, TDEMasterKeyInfo *master_key_info);
extern RelKeyData *tde_encrypt_rel_key(TDEMasterKey *master_key, RelKeyData *rel_key_data, const RelFileLocator *rlocator);
extern RelKeyData *tde_decrypt_rel_key(TDEMasterKey *master_key, RelKeyData *enc_rel_key_data, const RelFileLocator *rlocator);
extern void pg_tde_set_db_file_paths(const RelFileLocator *rlocator, char *map_path, char *keydata_path);
const char * tde_sprint_key(InternalKey *k);
extern void pg_tde_put_key_into_map(Oid rel_id, RelKeyData *key);
#endif /*PG_TDE_MAP_H*/

@ -41,10 +41,7 @@ static const RmgrData pg_tde_rmgr = {
/* XLog encryption staff */
/* GUC */
extern bool EncryptXLog;
extern Size TDEXLogEncryptBuffSize();
extern Size TDEXLogEncryptBuffSize(void);
#define XLOG_TDE_ENC_BUFF_ALIGNED_SIZE add_size(TDEXLogEncryptBuffSize(), PG_IO_ALIGN_SIZE)
@ -58,9 +55,9 @@ static const XLogSmgr tde_xlog_smgr = {
.seg_write = pg_tde_xlog_seg_write,
};
extern void TDEInitXLogSmgr(void);
extern void TDEXLogSmgrInit(void);
extern void xlogInitGUC(void);
extern void XLogInitGUC(void);
#endif

@ -0,0 +1,41 @@
/*-------------------------------------------------------------------------
*
* tde_global_catalog.h
* Global catalog key management
*
* src/include/catalog/tde_global_catalog.h
*
*-------------------------------------------------------------------------
*/
#ifndef TDE_GLOBAL_CATALOG_H
#define TDE_GLOBAL_CATALOG_H
#include "postgres.h"
#include "catalog/tde_master_key.h"
/*
* Needed for glogbal data (WAL etc) keys identification in caches and storage.
* We take IDs the oid type operators, so there is no overlap with the "real"
* catalog object possible.
*/
#define GLOBAL_DATA_TDE_OID 607 /* Global objects fake "db" */
#define XLOG_TDE_OID 608
#define GLOBAL_SPACE_RLOCATOR(_obj_oid) (RelFileLocator) { \
GLOBALTABLESPACE_OID, \
GLOBAL_DATA_TDE_OID, \
_obj_oid \
}
extern void TDEGlCatInitGUC(void);
extern Size TDEGlCatEncStateSize(void);
extern void TDEGlCatShmemInit(void);
extern void TDEGlCatKeyInit(void);
extern TDEMasterKey *TDEGetGlCatKeyFromCache(void);
extern void TDEPutGlCatKeyInCache(TDEMasterKey *mkey);
extern RelKeyData *GetGlCatInternalKey(Oid obj_id);
#endif /*TDE_GLOBAL_CATALOG_H*/

@ -54,8 +54,15 @@ typedef struct VaultV2Keyring
char vault_mount_path[MAXPGPATH];
} VaultV2Keyring;
typedef union KeyringProviders
{
FileKeyring file;
VaultV2Keyring vault;
} KeyringProviders;
extern List *GetAllKeyringProviders(void);
extern GenericKeyring *GetKeyProviderByName(const char *provider_name);
extern GenericKeyring *GetKeyProviderByID(int provider_id);
extern ProviderType get_keyring_provider_from_typename(char *provider_type);
#endif /*TDE_KEYRING_H*/

@ -17,6 +17,7 @@
#include "nodes/pg_list.h"
#include "storage/lwlock.h"
#define DEFAULT_MASTER_KEY_VERSION 1
#define MASTER_KEY_NAME_LEN TDE_KEY_NAME_LEN
#define MAX_MASTER_KEY_VERSION_NUM 100000
@ -68,9 +69,16 @@ extern LWLock *tde_lwlock_mk_cache(void);
extern bool save_master_key_info(TDEMasterKeyInfo *masterKeyInfo);
extern Oid GetMasterKeyProviderId(void);
extern TDEMasterKey* GetMasterKey(Oid);
extern TDEMasterKey* GetMasterKey(Oid dbOid, Oid spcOid, GenericKeyring *keyring);
extern bool SetMasterKey(const char *key_name, const char *provider_name, bool ensure_new_key);
extern bool RotateMasterKey(const char *new_key_name, const char *new_provider_name, bool ensure_new_key);
extern bool xl_tde_perform_rotate_key(XLogMasterKeyRotate *xlrec);
extern TDEMasterKey *set_master_key_with_keyring(const char *key_name,
GenericKeyring *keyring,
Oid dbOid, Oid spcOid,
bool ensure_new_key);
extern keyInfo *load_latest_versioned_key_name(TDEMasterKeyInfo *mastere_key_info,
GenericKeyring *keyring,
bool ensure_new_key);
#endif /*PG_TDE_MASTER_KEY_H*/

Binary file not shown.

@ -40,21 +40,21 @@ static keyInfo*
get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error, KeyringReturnCodes *return_code)
{
keyInfo* key = NULL;
File file = -1;
int fd = -1;
FileKeyring* file_keyring = (FileKeyring*)keyring;
off_t bytes_read = 0;
off_t curr_pos = 0;
*return_code = KEYRING_CODE_SUCCESS;
file = PathNameOpenFile(file_keyring->file_name, PG_BINARY);
if (file < 0)
fd = BasicOpenFile(file_keyring->file_name, PG_BINARY);
if (fd < 0)
return NULL;
key = palloc(sizeof(keyInfo));
while(true)
{
bytes_read = FileRead(file, key, sizeof(keyInfo), curr_pos, WAIT_EVENT_DATA_FILE_READ);
bytes_read = pg_pread(fd, key, sizeof(keyInfo), curr_pos);
curr_pos += bytes_read;
if (bytes_read == 0 )
@ -62,13 +62,13 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
/*
* Empty keyring file is considered as a valid keyring file that has no keys
*/
FileClose(file);
close(fd);
pfree(key);
return NULL;
}
if (bytes_read != sizeof(keyInfo))
{
FileClose(file);
close(fd);
pfree(key);
/* Corrupt file */
*return_code = KEYRING_CODE_DATA_CORRUPTED;
@ -81,11 +81,11 @@ get_key_by_name(GenericKeyring* keyring, const char* key_name, bool throw_error,
}
if (strncasecmp(key->name.name, key_name, sizeof(key->name.name)) == 0)
{
FileClose(file);
close(fd);
return key;
}
}
FileClose(file);
close(fd);
pfree(key);
return NULL;
}
@ -95,7 +95,7 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
{
off_t bytes_written = 0;
off_t curr_pos = 0;
File file;
int fd;
FileKeyring* file_keyring = (FileKeyring*)keyring;
keyInfo *existing_key;
KeyringReturnCodes return_code = KEYRING_CODE_SUCCESS;
@ -111,8 +111,8 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
return KEYRING_CODE_INVALID_OPERATION;
}
file = PathNameOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY);
if (file < 0)
fd = BasicOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY);
if (fd < 0)
{
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
@ -120,17 +120,26 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
/* Write key to the end of file */
curr_pos = FileSize(file);
bytes_written = FileWrite(file, key, sizeof(keyInfo), curr_pos, WAIT_EVENT_DATA_FILE_WRITE);
curr_pos = lseek(fd, 0, SEEK_END);
bytes_written = pg_pwrite(fd, key, sizeof(keyInfo), curr_pos);
if (bytes_written != sizeof(keyInfo))
{
FileClose(file);
close(fd);
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
errmsg("keyring file \"%s\" can't be written: %m",
file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
FileClose(file);
if (pg_fsync(fd) != 0)
{
close(fd);
ereport(throw_error?ERROR:WARNING,
(errcode_for_file_access(),
errmsg("could not fsync file \"%s\": %m",
file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
}
close(fd);
return KEYRING_CODE_SUCCESS;
}

@ -32,6 +32,9 @@
#include "utils/builtins.h"
#include "pg_tde_defs.h"
#include "smgr/pg_tde_smgr.h"
#ifdef PERCONA_FORK
#include "catalog/tde_global_catalog.h"
#endif
#define MAX_ON_INSTALLS 5
@ -80,9 +83,13 @@ tde_shmem_startup(void)
TdeShmemInit();
AesInit();
#ifdef PERCONA_FORK
TDEGlCatShmemInit();
TDEGlCatKeyInit();
TDEXLogShmemInit();
TDEInitXLogSmgr();
TDEXLogSmgrInit();
#endif
}
@ -97,9 +104,9 @@ _PG_init(void)
keyringRegisterVariables();
InitializeMasterKeyInfo();
#ifdef PERCONA_FORK
xlogInitGUC();
XLogInitGUC();
TDEGlCatInitGUC();
#endif
prev_shmem_request_hook = shmem_request_hook;
shmem_request_hook = tde_shmem_request;
prev_shmem_startup_hook = shmem_startup_hook;

@ -35,7 +35,7 @@ tde_smgr_get_key(SMgrRelation reln)
recursion++;
if(GetMasterKey(reln->smgr_rlocator.locator.relNumber)==NULL)
if(GetMasterKey(reln->smgr_rlocator.locator.relNumber, reln->smgr_rlocator.locator.spcOid, NULL)==NULL)
{
recursion--;
return NULL;

@ -52,8 +52,6 @@ pg_tde_xact_callback(XactEvent event, void *arg)
{
pending_delete_cleanup();
}
pg_tde_cleanup_path_vars();
}
void

Loading…
Cancel
Save