From 2d2208bdb572ba190b24e280d0d3ede37b71cb80 Mon Sep 17 00:00:00 2001 From: Andrew Pogrebnoy Date: Mon, 26 Aug 2024 19:04:58 +0300 Subject: [PATCH 1/4] Make related code compilable with frontend This commit makes the code around keyring, principal keys and WAL encryption compilable with frontend tools. Namely: - Hide everything that isn't compatible and of no use behind '#ifndef FRONTEND' - Redefine code that is needed in both versions but should have different code. E.g. error handling, file descriptors and locks - Make use of frontend lists instead of backend ones where needed. For https://perconadev.atlassian.net/browse/PG-857 --- Makefile.in | 2 +- meson.build | 2 +- src/access/pg_tde_tdemap.c | 1011 +++++++++++----------- src/access/pg_tde_xlog.c | 287 ------ src/access/pg_tde_xlog_encrypt.c | 310 +++++++ src/catalog/tde_global_space.c | 20 +- src/catalog/tde_keyring.c | 548 ++++++------ src/catalog/tde_keyring_parse_opts.c | 5 + src/catalog/tde_principal_key.c | 262 +++--- src/common/pg_tde_utils.c | 9 +- src/encryption/enc_tde.c | 17 +- src/include/access/pg_tde_xlog.h | 30 +- src/include/access/pg_tde_xlog_encrypt.h | 35 + src/include/catalog/tde_principal_key.h | 8 + src/include/common/pg_tde_utils.h | 3 + src/include/keyring/keyring.h | 4 - src/include/keyring/keyring_config.h | 18 - src/include/pg_tde_fe.h | 77 ++ src/keyring/keyring.c | 10 - src/keyring/keyring_api.c | 37 +- src/keyring/keyring_config.c | 17 - src/keyring/keyring_curl.c | 3 +- src/keyring/keyring_file.c | 8 +- src/keyring/keyring_vault.c | 5 +- src/pg_tde.c | 3 +- 25 files changed, 1492 insertions(+), 1239 deletions(-) create mode 100644 src/access/pg_tde_xlog_encrypt.c create mode 100644 src/include/access/pg_tde_xlog_encrypt.h delete mode 100644 src/include/keyring/keyring.h delete mode 100644 src/include/keyring/keyring_config.h create mode 100644 src/include/pg_tde_fe.h delete mode 100644 src/keyring/keyring.c delete mode 100644 src/keyring/keyring_config.c diff --git a/Makefile.in b/Makefile.in index b3d38487..21ede5e2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -36,8 +36,8 @@ src$(MAJORVERSION)/access/pg_tde_rewrite.o \ src$(MAJORVERSION)/access/pg_tdeam_handler.o \ src/access/pg_tde_ddl.o \ src/access/pg_tde_xlog.o \ +src/access/pg_tde_xlog_encrypt.o \ src/transam/pg_tde_xact_handler.o \ -src/keyring/keyring_config.o \ src/keyring/keyring_curl.o \ src/keyring/keyring_file.o \ src/keyring/keyring_vault.o \ diff --git a/meson.build b/meson.build index 7dca74f5..7479bfca 100644 --- a/meson.build +++ b/meson.build @@ -32,11 +32,11 @@ pg_tde_sources = files( src_version / 'access/pg_tde_visibilitymap.c', 'src/access/pg_tde_ddl.c', 'src/access/pg_tde_xlog.c', + 'src/access/pg_tde_xlog_encrypt.c', 'src/encryption/enc_tde.c', 'src/encryption/enc_aes.c', - 'src/keyring/keyring_config.c', 'src/keyring/keyring_curl.c', 'src/keyring/keyring_file.c', 'src/keyring/keyring_vault.c', diff --git a/src/access/pg_tde_tdemap.c b/src/access/pg_tde_tdemap.c index 2254c0d4..8bd145db 100644 --- a/src/access/pg_tde_tdemap.c +++ b/src/access/pg_tde_tdemap.c @@ -12,6 +12,7 @@ #include "postgres.h" #include "access/pg_tde_tdemap.h" +#include "common/file_perm.h" #include "transam/pg_tde_xact_handler.h" #include "storage/fd.h" #include "utils/wait_event.h" @@ -36,6 +37,10 @@ #include "pg_tde_defines.h" +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif + /* A useful macro when debugging key encryption/decryption */ #ifdef DEBUG #define ELOG_KEY(_msg, _key) \ @@ -96,22 +101,21 @@ typedef struct RelKey /* Head of the key cache (linked list) */ RelKey *tde_rel_key_map = NULL; +static int32 pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t *offset, bool should_delete); +static RelKeyData* pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key); 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, TDEPrincipalKeyInfo *principal_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 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); +#ifndef FRONTEND + +static int pg_tde_file_header_write(char *tde_filename, int fd, TDEPrincipalKeyInfo *principal_key_info, off_t *bytes_written); static int32 pg_tde_write_map_entry(const RelFileLocator *rlocator, char *db_map_path, TDEPrincipalKeyInfo *principal_key_info); 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(int fd, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset); - static void pg_tde_write_keydata(char *db_keydata_path, TDEPrincipalKeyInfo *principal_key_info, int32 key_index, RelKeyData *enc_rel_key_data); static void pg_tde_write_one_keydata(int keydata_fd, int32 key_index, RelKeyData *enc_rel_key_data); -static RelKeyData* pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key); -static RelKeyData* pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key); - static int keyrotation_init_file(TDEPrincipalKeyInfo *new_principal_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); @@ -170,57 +174,6 @@ pg_tde_create_key_map_entry(const RelFileLocator *newrlocator) return rel_key_data; } - -/* - * Returns TDE key for a given relation. - * First it looks in a cache. If nothing found in the cache, it reads data from - * the tde fork file and populates cache. - */ -RelKeyData * -GetRelationKey(RelFileLocator rel) -{ - RelKey *curr; - RelKeyData *key; - Oid rel_id = rel.relNumber; - - for (curr = tde_rel_key_map; curr != NULL; curr = curr->next) - { - if (curr->rel_id == rel_id) - { - return &curr->key; - } - } - - key = pg_tde_get_key_from_file(&rel); - - if (key != NULL) - { - RelKeyData* cached_key = pg_tde_put_key_into_map(rel.relNumber, key); - pfree(key); - return cached_key; - } - - return key; /* returning NULL key */ -} - -RelKeyData * -pg_tde_put_key_into_map(Oid rel_id, RelKeyData *key) -{ - RelKey *new = (RelKey *) MemoryContextAlloc(TopMemoryContext, sizeof(RelKey)); - new->rel_id = rel_id; - memcpy(&new->key, key, sizeof(RelKeyData)); - new->next = NULL; - - if (tde_rel_key_map == NULL) - tde_rel_key_map = new; - else - { - new->next = tde_rel_key_map; - tde_rel_key_map = new; - } - return &new->key; -} - const char * tde_sprint_key(InternalKey *k) { @@ -262,32 +215,6 @@ tde_encrypt_rel_key(TDEPrincipalKey *principal_key, RelKeyData *rel_key_data, co return enc_rel_key_data; } -/* - * Decrypts a given key and returns the decrypted one. - */ -RelKeyData * -tde_decrypt_rel_key(TDEPrincipalKey *principal_key, RelKeyData *enc_rel_key_data, const RelFileLocator *rlocator) -{ - RelKeyData *rel_key_data = NULL; - size_t key_bytes; - - AesDecryptKey(principal_key, rlocator, &rel_key_data, enc_rel_key_data, &key_bytes); - - return rel_key_data; -} - -inline void -pg_tde_set_db_file_paths(const RelFileLocator *rlocator, char *map_path, char *keydata_path) -{ - char *db_path = pg_tde_get_tde_file_dir(rlocator->dbOid, rlocator->spcOid); - - 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); - pfree(db_path); -} - /* * Creates the pair of map and key data file and save the principal key information. * Returns true if both map and key data files are created. @@ -350,80 +277,6 @@ pg_tde_save_principal_key(TDEPrincipalKeyInfo *principal_key_info) return (is_new_map && is_new_key_data); } -/* - * Get the principal key from the map file. The caller must hold - * a LW_SHARED or higher lock on files before calling this function. - */ -TDEPrincipalKeyInfo * -pg_tde_get_principal_key(Oid dbOid, Oid spcOid) -{ - int fd = -1; - TDEFileHeader fheader; - TDEPrincipalKeyInfo *principal_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(&(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. - */ - fd = pg_tde_open_file_basic(db_map_path, O_RDONLY, true); - - /* The file does not exist. */ - if (fd < 0) - return NULL; - - pg_tde_file_header_read(db_map_path, fd, &fheader, &is_new_file, &bytes_read); - - close(fd); - - /* It's not a new file. So we can memcpy the principal key info from the header */ - if (!is_new_file) - { - size_t sz = sizeof(TDEPrincipalKeyInfo); - - principal_key_info = (TDEPrincipalKeyInfo *) palloc(sz); - memcpy(principal_key_info, &fheader.principal_key_info, sz); - } - - return principal_key_info; -} - -/* - * Open a TDE file [pg_tde.*]: - * - * 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 int -pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing) -{ - 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. - */ - 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", - tde_filename))); - } - - return fd; -} - /* * Write TDE file header to a TDE file. */ @@ -463,76 +316,6 @@ pg_tde_file_header_write(char *tde_filename, int fd, TDEPrincipalKeyInfo *princi return fd; } -/* - * Read TDE file header from a TDE file and fill in the fheader data structure. - */ -static int -pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read) -{ - Assert(fheader); - - /* 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 fd; - - if (*bytes_read != TDE_FILE_HEADER_SIZE - || fheader->file_version != PG_TDE_FILEMAGIC) - { - /* Corrupt file */ - ereport(FATAL, - (errcode_for_file_access(), - errmsg("TDE map file \"%s\" is corrupted: %m", - tde_filename))); - } - - return fd; -} - -/* - * Open and Validate File Header [pg_tde.*]: - * header: {Format Version, Principal Key Name} - * - * Returns the file descriptor in case of a success. Otherwise, fatal error - * is raised. - * - * Also, it sets the is_new_file to true if the file is just created. This is - * useful to know when reading a file so that we can skip further processing. - * - * Plus, there is nothing wrong with a create even if we are going to read - * data. This will save the creation overhead the next time. Ideally, this - * should never happen for a read operation as it indicates a missing file. - * - * The caller can pass the required flags to ensure that file is created - * or an error is thrown if the file does not exist. - */ -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) -{ - int fd = -1; - TDEFileHeader fheader; - off_t bytes_read = 0; - off_t bytes_written = 0; - - /* - * Ensuring that we always open the file in binary mode. The caller must - * specify other flags for reading, writing or creating the file. - */ - fd = pg_tde_open_file_basic(tde_filename, fileFlags, false); - - 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 && principal_key_info) - pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written); - - *curr_pos = bytes_read + bytes_written; - return fd; -} - /* * Key Map Table [pg_tde.map]: * header: {Format Version, Principal Key Name} @@ -630,145 +413,18 @@ pg_tde_write_one_map_entry(int fd, const RelFileLocator *rlocator, int flags, in } /* - * Returns the index of the read map if we find a valid match; i.e. - * - flags is set to MAP_ENTRY_VALID and the relNumber matches the one - * provided in rlocator. - * - If should_delete is true, we delete the entry. An offset value may - * be passed to speed up the file reading operation. + * Key Data [pg_tde.dat]: + * header: {Format Version: x} + * data: {Encrypted Key} * - * The function expects that the offset points to a valid map start location. + * Requires a valid index of the key to be written. The function with seek to + * the required location in the file. Any holes will be filled when another + * job finds an empty index. */ -static int32 -pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t *offset, bool should_delete) +static void +pg_tde_write_keydata(char *db_keydata_path, TDEPrincipalKeyInfo *principal_key_info, int32 key_index, RelKeyData *enc_rel_key_data) { - File map_fd = -1; - int32 key_index = 0; - TDEMapEntry map_entry; - bool is_new_file; - bool found = false; - off_t prev_pos = 0; - off_t curr_pos = 0; - - Assert(offset); - - /* - * Open and validate file for basic correctness. DO NOT create it. - * The file should pre-exist otherwise we should never be here. - */ - 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 - * of the entry to speed up the operation. Otherwise, we'd be sequntially - * scanning the entire map file. - */ - if (should_delete == true && *offset > 0) - { - 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", - db_map_path))); - } - } - else - { - /* Otherwise, let's just offset to zero */ - *offset = 0; - } - - /* - * Read until we find an empty slot. Otherwise, read until end. This seems - * to be less frequent than vacuum. So let's keep this function here rather - * than overloading the vacuum process. - */ - while(1) - { - prev_pos = 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) - break; - - /* We found a valid entry for the relNumber */ - if (found) - { - /* Mark the entry pointed by prev_pos as free */ - if (should_delete) - { - pg_tde_write_one_map_entry(map_fd, NULL, MAP_ENTRY_FREE, 0, &map_entry, &prev_pos); - } - - break; - } - - /* Increment the offset and the key index */ - key_index++; - } - - /* Let's close the file. */ - close(map_fd); - - /* Return -1 indicating that no entry was removed */ - return ((found) ? key_index : -1); -} - -/* - * Returns true if a valid map entry if found. Otherwise, it only increments - * the offset and returns false. If the same offset value is set, it indicates - * to the caller that nothing was read. - * - * If a non-NULL rlocator is provided, the function compares the read value - * against the relNumber of rlocator. It sets found accordingly. - * - * The caller is reponsible for identifying that we have reached EOF by - * comparing old and new value of the offset. - */ -static bool -pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset) -{ - bool found; - off_t bytes_read = 0; - - Assert(map_entry); - Assert(offset); - - /* Read the entry at the given offset */ - /* 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) - return false; - - *offset += bytes_read; - - /* We found a valid entry for the relNumber */ - found = (map_entry->flags == flags); - - /* If a valid rlocator is provided, let's compare and set found value */ - found &= (rlocator == NULL) ? true : (map_entry->relNumber == rlocator->relNumber); - - return found; -} - -/* - * Key Data [pg_tde.dat]: - * header: {Format Version: x} - * data: {Encrypted Key} - * - * Requires a valid index of the key to be written. The function with seek to - * the required location in the file. Any holes will be filled when another - * job finds an empty index. - */ -static void -pg_tde_write_keydata(char *db_keydata_path, TDEPrincipalKeyInfo *principal_key_info, int32 key_index, RelKeyData *enc_rel_key_data) -{ - File fd = -1; + File fd = -1; bool is_new_file; off_t curr_pos = 0; @@ -811,85 +467,6 @@ pg_tde_write_one_keydata(int fd, int32 key_index, RelKeyData *enc_rel_key_data) } } -/* - * Open the file and read the required key data from file and return encrypted key. - */ -static RelKeyData * -pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key) -{ - int fd = -1; - RelKeyData *enc_rel_key_data; - off_t read_pos = 0; - bool is_new_file; - LWLock *lock_files = tde_lwlock_mk_files(); - - /* Open and validate file for basic correctness. */ - LWLockAcquire(lock_files, LW_SHARED); - fd = pg_tde_open_file(db_keydata_path, &principal_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(fd, key_index, principal_key); - - /* Let's close the file. */ - close(fd); - LWLockRelease(lock_files); - - return enc_rel_key_data; -} - -/* - * Reads a single keydata from the file. - */ -static RelKeyData * -pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key) -{ - RelKeyData *enc_rel_key_data; - off_t read_pos = 0; - - /* Allocate and fill in the structure */ - enc_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData)); - - strncpy(enc_rel_key_data->principal_key_id.name, principal_key->keyInfo.keyId.name, PRINCIPAL_KEY_NAME_LEN); - - /* Calculate the reading position in the file. */ - 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) > lseek(keydata_fd, 0, SEEK_END)) - { - char db_keydata_path[MAXPGPATH] = {0}; - pg_tde_set_db_file_paths(&(RelFileLocator) { - principal_key->keyInfo.tablespaceId, - principal_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", - key_index, - db_keydata_path))); - } - - /* Read the encrypted key */ - /* 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) { - principal_key->keyInfo.tablespaceId, - principal_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", - key_index, - db_keydata_path))); - } - - return enc_rel_key_data; -} - /* * Calls the create map entry function to get an index into the keydata. This * The keydata function will then write the encrypted key on the desired @@ -998,55 +575,6 @@ pg_tde_free_key_map_entry(const RelFileLocator *rlocator, off_t offset) } } -/* - * Reads the key of the required relation. It identifies its map entry and then simply - * reads the key data from the keydata file. - */ -RelKeyData * -pg_tde_get_key_from_file(const RelFileLocator *rlocator) -{ - int32 key_index = 0; - TDEPrincipalKey *principal_key; - RelKeyData *rel_key_data; - 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 principal key, create the key for relation and get the encrypted key with bytes to write */ - principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid); - if (principal_key == NULL) - { - LWLockRelease(lock_files); - ereport(ERROR, - (errmsg("failed to retrieve principal 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); - - if (key_index == -1) - { - LWLockRelease(lock_files); - return NULL; - } - - enc_rel_key_data = pg_tde_read_keydata(db_keydata_path, key_index, principal_key); - LWLockRelease(lock_files); - - rel_key_data = tde_decrypt_rel_key(principal_key, enc_rel_key_data, rlocator); - pfree(enc_rel_key_data); - return rel_key_data; -} - /* * Accepts the unrotated filename and returns the rotation temp * filename. Both the strings are expected to be of the size @@ -1302,3 +830,500 @@ pg_tde_write_map_keydata_files(off_t map_size, char *m_file_data, off_t keydata_ return !is_err; } + +#endif /* !FRONTEND */ + +/* + * Reads the key of the required relation. It identifies its map entry and then simply + * reads the key data from the keydata file. + */ +RelKeyData * +pg_tde_get_key_from_file(const RelFileLocator *rlocator) +{ + int32 key_index = 0; + TDEPrincipalKey *principal_key; + RelKeyData *rel_key_data; + 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 principal key, create the key for relation and get the encrypted key with bytes to write */ + principal_key = GetPrincipalKey(rlocator->dbOid, rlocator->spcOid); + if (principal_key == NULL) + { + LWLockRelease(lock_files); + ereport(ERROR, + (errmsg("failed to retrieve principal 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); + + if (key_index == -1) + { + LWLockRelease(lock_files); + return NULL; + } + + enc_rel_key_data = pg_tde_read_keydata(db_keydata_path, key_index, principal_key); + LWLockRelease(lock_files); + + rel_key_data = tde_decrypt_rel_key(principal_key, enc_rel_key_data, rlocator); + + return rel_key_data; +} + +inline void +pg_tde_set_db_file_paths(const RelFileLocator *rlocator, char *map_path, char *keydata_path) +{ + char *db_path = pg_tde_get_tde_file_dir(rlocator->dbOid, rlocator->spcOid); + + 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); + pfree(db_path); +} + +/* + * Returns the index of the read map if we find a valid match; i.e. + * - flags is set to MAP_ENTRY_VALID and the relNumber matches the one + * provided in rlocator. + * - If should_delete is true, we delete the entry. An offset value may + * be passed to speed up the file reading operation. + * + * The function expects that the offset points to a valid map start location. + */ +static int32 +pg_tde_process_map_entry(const RelFileLocator *rlocator, char *db_map_path, off_t *offset, bool should_delete) +{ + File map_fd = -1; + int32 key_index = 0; + TDEMapEntry map_entry; + bool is_new_file; + bool found = false; + off_t prev_pos = 0; + off_t curr_pos = 0; + + Assert(offset); + + /* + * Open and validate file for basic correctness. DO NOT create it. + * The file should pre-exist otherwise we should never be here. + */ + 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 + * of the entry to speed up the operation. Otherwise, we'd be sequntially + * scanning the entire map file. + */ + if (should_delete == true && *offset > 0) + { + 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", + db_map_path))); + } + } + else + { + /* Otherwise, let's just offset to zero */ + *offset = 0; + } + + /* + * Read until we find an empty slot. Otherwise, read until end. This seems + * to be less frequent than vacuum. So let's keep this function here rather + * than overloading the vacuum process. + */ + while(1) + { + prev_pos = 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) + break; + + /* We found a valid entry for the relNumber */ + if (found) + { +#ifndef FRONTEND + /* Mark the entry pointed by prev_pos as free */ + if (should_delete) + { + pg_tde_write_one_map_entry(map_fd, NULL, MAP_ENTRY_FREE, 0, &map_entry, &prev_pos); + } +#endif + break; + } + + /* Increment the offset and the key index */ + key_index++; + } + + /* Let's close the file. */ + close(map_fd); + + /* Return -1 indicating that no entry was removed */ + return ((found) ? key_index : -1); +} + + +/* + * Open the file and read the required key data from file and return encrypted key. + */ +static RelKeyData * +pg_tde_read_keydata(char *db_keydata_path, int32 key_index, TDEPrincipalKey *principal_key) +{ + int fd = -1; + RelKeyData *enc_rel_key_data; + off_t read_pos = 0; + bool is_new_file; + LWLock *lock_files = tde_lwlock_mk_files(); + + /* Open and validate file for basic correctness. */ + LWLockAcquire(lock_files, LW_SHARED); + fd = pg_tde_open_file(db_keydata_path, &principal_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(fd, key_index, principal_key); + + /* Let's close the file. */ + close(fd); + LWLockRelease(lock_files); + + return enc_rel_key_data; +} + + +/* + * Decrypts a given key and returns the decrypted one. + */ +RelKeyData * +tde_decrypt_rel_key(TDEPrincipalKey *principal_key, RelKeyData *enc_rel_key_data, const RelFileLocator *rlocator) +{ + RelKeyData *rel_key_data = NULL; + size_t key_bytes; + + AesDecryptKey(principal_key, rlocator, &rel_key_data, enc_rel_key_data, &key_bytes); + + return rel_key_data; +} + + +/* + * Open and Validate File Header [pg_tde.*]: + * header: {Format Version, Principal Key Name} + * + * Returns the file descriptor in case of a success. Otherwise, fatal error + * is raised. + * + * Also, it sets the is_new_file to true if the file is just created. This is + * useful to know when reading a file so that we can skip further processing. + * + * Plus, there is nothing wrong with a create even if we are going to read + * data. This will save the creation overhead the next time. Ideally, this + * should never happen for a read operation as it indicates a missing file. + * + * The caller can pass the required flags to ensure that file is created + * 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) +{ + int fd = -1; + TDEFileHeader fheader; + off_t bytes_read = 0; + off_t bytes_written = 0; + + /* + * Ensuring that we always open the file in binary mode. The caller must + * specify other flags for reading, writing or creating the file. + */ + fd = pg_tde_open_file_basic(tde_filename, fileFlags, false); + + pg_tde_file_header_read(tde_filename, fd, &fheader, is_new_file, &bytes_read); + +#ifndef FRONTEND + /* In case it's a new file, let's add the header now. */ + if (*is_new_file && principal_key_info) + pg_tde_file_header_write(tde_filename, fd, principal_key_info, &bytes_written); +#endif /* FRONTEND */ + + *curr_pos = bytes_read + bytes_written; + return fd; +} + + +/* + * Open a TDE file [pg_tde.*]: + * + * 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 int +pg_tde_open_file_basic(char *tde_filename, int fileFlags, bool ignore_missing) +{ + 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. + */ + 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", + tde_filename))); + } + + return fd; +} + + +/* + * Read TDE file header from a TDE file and fill in the fheader data structure. + */ +static int +pg_tde_file_header_read(char *tde_filename, int fd, TDEFileHeader *fheader, bool *is_new_file, off_t *bytes_read) +{ + Assert(fheader); + + /* 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 fd; + + if (*bytes_read != TDE_FILE_HEADER_SIZE + || fheader->file_version != PG_TDE_FILEMAGIC) + { + /* Corrupt file */ + ereport(FATAL, + (errcode_for_file_access(), + errmsg("TDE map file \"%s\" is corrupted: %m", + tde_filename))); + } + + return fd; +} + + +/* + * Returns true if a valid map entry if found. Otherwise, it only increments + * the offset and returns false. If the same offset value is set, it indicates + * to the caller that nothing was read. + * + * If a non-NULL rlocator is provided, the function compares the read value + * against the relNumber of rlocator. It sets found accordingly. + * + * The caller is reponsible for identifying that we have reached EOF by + * comparing old and new value of the offset. + */ +static bool +pg_tde_read_one_map_entry(File map_file, const RelFileLocator *rlocator, int flags, TDEMapEntry *map_entry, off_t *offset) +{ + bool found; + off_t bytes_read = 0; + + Assert(map_entry); + Assert(offset); + + /* Read the entry at the given offset */ + /* 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) + return false; + + *offset += bytes_read; + + /* We found a valid entry for the relNumber */ + found = (map_entry->flags == flags); + + /* If a valid rlocator is provided, let's compare and set found value */ + found &= (rlocator == NULL) ? true : (map_entry->relNumber == rlocator->relNumber); + + return found; +} + + +/* + * Reads a single keydata from the file. + */ +static RelKeyData * +pg_tde_read_one_keydata(int keydata_fd, int32 key_index, TDEPrincipalKey *principal_key) +{ + RelKeyData *enc_rel_key_data; + off_t read_pos = 0; + + /* Allocate and fill in the structure */ + enc_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData)); + + strncpy(enc_rel_key_data->principal_key_id.name, principal_key->keyInfo.keyId.name, PRINCIPAL_KEY_NAME_LEN); + + /* Calculate the reading position in the file. */ + 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) > lseek(keydata_fd, 0, SEEK_END)) + { + char db_keydata_path[MAXPGPATH] = {0}; + pg_tde_set_db_file_paths(&(RelFileLocator) { + principal_key->keyInfo.tablespaceId, + principal_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", + key_index, + db_keydata_path))); + } + + /* Read the encrypted key */ + /* 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) { + principal_key->keyInfo.tablespaceId, + principal_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", + key_index, + db_keydata_path))); + } + + return enc_rel_key_data; +} + + +/* + * Get the principal key from the map file. The caller must hold + * a LW_SHARED or higher lock on files before calling this function. + */ +TDEPrincipalKeyInfo * +pg_tde_get_principal_key(Oid dbOid, Oid spcOid) +{ + int fd = -1; + TDEFileHeader fheader; + TDEPrincipalKeyInfo *principal_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(&(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. + */ + fd = pg_tde_open_file_basic(db_map_path, O_RDONLY, true); + + /* The file does not exist. */ + if (fd < 0) + return NULL; + + pg_tde_file_header_read(db_map_path, fd, &fheader, &is_new_file, &bytes_read); + + close(fd); + + /* It's not a new file. So we can memcpy the principal key info from the header */ + if (!is_new_file) + { + size_t sz = sizeof(TDEPrincipalKeyInfo); + + principal_key_info = (TDEPrincipalKeyInfo *) palloc(sz); + memcpy(principal_key_info, &fheader.principal_key_info, sz); + } + + return principal_key_info; +} + +RelKeyData * +pg_tde_put_key_into_map(Oid rel_id, RelKeyData *key) +{ + RelKey *new; + +#ifndef FRONTEND + MemoryContext oldctx; + oldctx = MemoryContextSwitchTo(TopMemoryContext); +#endif + new = (RelKey *) palloc(sizeof(RelKey)); +#ifndef FRONTEND + MemoryContextSwitchTo(oldctx); +#endif + new->rel_id = rel_id; + memcpy(&new->key, key, sizeof(RelKeyData)); + new->next = NULL; + + if (tde_rel_key_map == NULL) + tde_rel_key_map = new; + else + { + new->next = tde_rel_key_map; + tde_rel_key_map = new; + } + return &new->key; +} + +/* + * Returns TDE key for a given relation. + * First it looks in a cache. If nothing found in the cache, it reads data from + * the tde fork file and populates cache. + */ +RelKeyData * +GetRelationKey(RelFileLocator rel) +{ + RelKey *curr; + RelKeyData *key; + Oid rel_id = rel.relNumber; + + for (curr = tde_rel_key_map; curr != NULL; curr = curr->next) + { + if (curr->rel_id == rel_id) + { + return &curr->key; + } + } + + key = pg_tde_get_key_from_file(&rel); + + if (key != NULL) + { + RelKeyData* cached_key = pg_tde_put_key_into_map(rel.relNumber, key); + pfree(key); + return cached_key; + } + + return key; /* returning NULL key */ +} diff --git a/src/access/pg_tde_xlog.c b/src/access/pg_tde_xlog.c index eefef365..05b8cae2 100644 --- a/src/access/pg_tde_xlog.c +++ b/src/access/pg_tde_xlog.c @@ -24,24 +24,8 @@ #include "utils/guc.h" #include "utils/memutils.h" -#include "access/pg_tde_tdemap.h" #include "access/pg_tde_xlog.h" #include "encryption/enc_tde.h" -#ifdef PERCONA_EXT -#include "catalog/tde_global_space.h" - -static char *TDEXLogEncryptBuf = NULL; - -/* GUC */ -static bool EncryptXLog = false; - -static XLogPageHeaderData EncryptCurrentPageHrd; -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 @@ -139,274 +123,3 @@ tdeheap_rmgr_identify(uint8 info) return NULL; } - -#ifdef PERCONA_EXT - -/* - * ------------------------- - * XLog Storage Manager - */ - -void -XLogInitGUC(void) -{ - DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */ - "Enable/Disable encryption of WAL.", /* short_desc */ - NULL, /* long_desc */ - &EncryptXLog, /* value address */ - false, /* boot value */ - PGC_POSTMASTER, /* context */ - 0, /* flags */ - NULL, /* check_hook */ - NULL, /* assign_hook */ - NULL /* show_hook */ - ); -} - -static int -XLOGChooseNumBuffers(void) -{ - int xbuffers; - - xbuffers = NBuffers / 32; - if (xbuffers > (wal_segment_size / XLOG_BLCKSZ)) - xbuffers = (wal_segment_size / XLOG_BLCKSZ); - if (xbuffers < 8) - xbuffers = 8; - return xbuffers; -} - -/* - * Defines the size of the XLog encryption buffer - */ -Size -TDEXLogEncryptBuffSize(void) -{ - int xbuffers; - - xbuffers = (XLOGbuffers == -1) ? XLOGChooseNumBuffers() : XLOGbuffers; - return (Size) XLOG_BLCKSZ * xbuffers; -} - -/* - * Alloc memory for the encryption buffer. - * - * It should fit XLog buffers (XLOG_BLCKSZ * wal_buffers). We can't - * (re)alloc this buf in tdeheap_xlog_seg_write() based on the write size as - * it's called in the CRIT section, hence no allocations are allowed. - * - * Access to this buffer happens during XLogWrite() call which should - * be called with WALWriteLock held, hence no need in extra locks. - */ -void -TDEXLogShmemInit(void) -{ - bool foundBuf; - - if (EncryptXLog) - { - TDEXLogEncryptBuf = (char *) - TYPEALIGN(PG_IO_ALIGN_SIZE, - ShmemInitStruct("TDE XLog Encryption Buffer", - XLOG_TDE_ENC_BUFF_ALIGNED_SIZE, - &foundBuf)); - - elog(DEBUG1, "pg_tde: initialized encryption buffer %lu bytes", XLOG_TDE_ENC_BUFF_ALIGNED_SIZE); - } -} - -void -TDEXLogSmgrInit(void) -{ - SetXLogSmgr(&tde_xlog_smgr); -} - -ssize_t -tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset) -{ - if (EncryptXLog) - return TDEXLogWriteEncryptedPages(fd, buf, count, offset); - else - return pg_pwrite(fd, buf, count, offset); -} - -/* - * Encrypt XLog page(s) from the buf and write to the segment file. - */ -static ssize_t -TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset) -{ - char iv_prefix[16] = {0,}; - size_t data_size = 0; - XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd; - XLogPageHeader enc_buf_page; - RelKeyData *key = GetRelationKey(GLOBAL_SPACE_RLOCATOR(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 - - /* - * Go through the buf page-by-page and encrypt them. - * We may start or finish writing from/in the middle of the page - * (walsender or `full_page_writes = off`). So preserve a page header - * for the IV init data. - * - * TODO: check if walsender restarts form the beggining of the page - * in case of the crash. - */ - for (enc_off = 0; enc_off < count;) - { - data_size = Min(page_size, count); - - if (page_size == XLOG_BLCKSZ) - { - memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD); - - /* - * Need to use a separate buf for the encryption so the page remains non-crypted - * in the XLog buf (XLogInsert has to have access to records' lsn). - */ - enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off); - memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr)); - enc_buf_page->xlp_info |= XLP_ENCRYPTED; - - enc_off += XLogPageHeaderSize(curr_page_hdr); - data_size -= XLogPageHeaderSize(curr_page_hdr); - /* it's a beginning of the page */ - iv_ctr = 0; - } - else - { - /* we're in the middle of the page */ - iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); - } - - if (data_size + enc_off > count) - { - data_size = count - enc_off; - } - - /* - * The page is zeroed (no data), no sense to enctypt. - * This may happen when base_backup or other requests XLOG SWITCH and - * some pages in XLog buffer still not used. - */ - if (curr_page_hdr->xlp_magic == 0) - { - /* ensure all the page is {0} */ - Assert((*((char *) buf + enc_off) == 0) && - memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0); - - memcpy((char *) enc_buf_page, (char *) buf + enc_off, data_size); - } - else - { - 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); - } - - page_size = XLOG_BLCKSZ; - enc_off += data_size; - } - - return pg_pwrite(fd, TDEXLogEncryptBuf, count, offset); -} - -/* - * Read the XLog pages from the segment file and dectypt if need. - */ -ssize_t -tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset) -{ - ssize_t readsz; - char iv_prefix[16] = {0,}; - size_t data_size = 0; - XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd; - RelKeyData *key = GetRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); - size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ; - off_t dec_off; - uint32 iv_ctr = 0; - -#ifdef TDE_XLOG_DEBUG - elog(DEBUG1, "read from a WAL segment, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset); -#endif - - readsz = pg_pread(fd, buf, count, offset); - - /* - * Read the buf page by page and decypt ecnrypted pages. - * We may start or fihish reading from/in the middle of the page (walreceiver) - * in such a case we should preserve the last read page header for - * the IV data and the encryption state. - * - * TODO: check if walsender/receiver restarts form the beggining of the page - * in case of the crash. - */ - for (dec_off = 0; dec_off < readsz;) - { - data_size = Min(page_size, readsz); - - if (page_size == XLOG_BLCKSZ) - { - memcpy((char *) curr_page_hdr, (char *) buf + dec_off, SizeOfXLogShortPHD); - - /* set the flag to "not encrypted" for the walreceiver */ - ((XLogPageHeader) ((char *) buf + dec_off))->xlp_info &= ~XLP_ENCRYPTED; - - Assert(curr_page_hdr->xlp_magic == XLOG_PAGE_MAGIC || curr_page_hdr->xlp_magic == 0); - dec_off += XLogPageHeaderSize(curr_page_hdr); - data_size -= XLogPageHeaderSize(curr_page_hdr); - /* it's a beginning of the page */ - iv_ctr = 0; - } - else - { - /* we're in the middle of the page */ - iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); - } - - if ((data_size + dec_off) > readsz) - { - data_size = readsz - dec_off; - } - - if (curr_page_hdr->xlp_info & XLP_ENCRYPTED) - { - 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); - } - - page_size = XLOG_BLCKSZ; - dec_off += data_size; - } - - return readsz; -} - -/* IV: TLI(uint32) + XLogRecPtr(uint64)*/ -static void -SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix) -{ - iv_prefix[0] = (tli >> 24); - iv_prefix[1] = ((tli >> 16) & 0xFF); - iv_prefix[2] = ((tli >> 8) & 0xFF); - iv_prefix[3] = (tli & 0xFF); - - iv_prefix[4] = (lsn >> 56); - iv_prefix[5] = ((lsn >> 48) & 0xFF); - iv_prefix[6] = ((lsn >> 40) & 0xFF); - iv_prefix[7] = ((lsn >> 32) & 0xFF); - iv_prefix[8] = ((lsn >> 24) & 0xFF); - iv_prefix[9] = ((lsn >> 16) & 0xFF); - iv_prefix[10] = ((lsn >> 8) & 0xFF); - iv_prefix[11] = (lsn & 0xFF); -} - -#endif diff --git a/src/access/pg_tde_xlog_encrypt.c b/src/access/pg_tde_xlog_encrypt.c new file mode 100644 index 00000000..9016698e --- /dev/null +++ b/src/access/pg_tde_xlog_encrypt.c @@ -0,0 +1,310 @@ +/*------------------------------------------------------------------------- + * + * pg_tde_xlog_encrypt.c + * Encrypted XLog storage manager + * + * + * IDENTIFICATION + * src/access/pg_tde_xlog_encrypt.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#ifdef PERCONA_FORK +#include "pg_tde.h" +#include "pg_tde_defines.h" +#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" +#include "utils/memutils.h" + +#include "access/pg_tde_xlog_encrypt.h" +#include "catalog/tde_global_space.h" +#include "encryption/enc_tde.h" + +static XLogPageHeaderData DecryptCurrentPageHrd; + +static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix); + +#ifndef FRONTEND +/* GUC */ +static bool EncryptXLog = false; + +static XLogPageHeaderData EncryptCurrentPageHrd; + +static ssize_t TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset); +static char *TDEXLogEncryptBuf = NULL; +static int XLOGChooseNumBuffers(void); + +void +XLogInitGUC(void) +{ + DefineCustomBoolVariable("pg_tde.wal_encrypt", /* name */ + "Enable/Disable encryption of WAL.", /* short_desc */ + NULL, /* long_desc */ + &EncryptXLog, /* value address */ + false, /* boot value */ + PGC_POSTMASTER, /* context */ + 0, /* flags */ + NULL, /* check_hook */ + NULL, /* assign_hook */ + NULL /* show_hook */ + ); +} + +static int +XLOGChooseNumBuffers(void) +{ + int xbuffers; + + xbuffers = NBuffers / 32; + if (xbuffers > (wal_segment_size / XLOG_BLCKSZ)) + xbuffers = (wal_segment_size / XLOG_BLCKSZ); + if (xbuffers < 8) + xbuffers = 8; + return xbuffers; +} + +/* + * Defines the size of the XLog encryption buffer + */ +Size +TDEXLogEncryptBuffSize(void) +{ + int xbuffers; + + xbuffers = (XLOGbuffers == -1) ? XLOGChooseNumBuffers() : XLOGbuffers; + return (Size) XLOG_BLCKSZ * xbuffers; +} + +/* + * Alloc memory for the encryption buffer. + * + * It should fit XLog buffers (XLOG_BLCKSZ * wal_buffers). We can't + * (re)alloc this buf in tdeheap_xlog_seg_write() based on the write size as + * it's called in the CRIT section, hence no allocations are allowed. + * + * Access to this buffer happens during XLogWrite() call which should + * be called with WALWriteLock held, hence no need in extra locks. + */ +void +TDEXLogShmemInit(void) +{ + bool foundBuf; + + if (EncryptXLog) + { + TDEXLogEncryptBuf = (char *) + TYPEALIGN(PG_IO_ALIGN_SIZE, + ShmemInitStruct("TDE XLog Encryption Buffer", + XLOG_TDE_ENC_BUFF_ALIGNED_SIZE, + &foundBuf)); + + elog(DEBUG1, "pg_tde: initialized encryption buffer %lu bytes", XLOG_TDE_ENC_BUFF_ALIGNED_SIZE); + } +} + +/* + * Encrypt XLog page(s) from the buf and write to the segment file. + */ +static ssize_t +TDEXLogWriteEncryptedPages(int fd, const void *buf, size_t count, off_t offset) +{ + char iv_prefix[16] = {0,}; + size_t data_size = 0; + XLogPageHeader curr_page_hdr = &EncryptCurrentPageHrd; + XLogPageHeader enc_buf_page; + RelKeyData *key = GetRelationKey(GLOBAL_SPACE_RLOCATOR(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 + + /* + * Go through the buf page-by-page and encrypt them. + * We may start or finish writing from/in the middle of the page + * (walsender or `full_page_writes = off`). So preserve a page header + * for the IV init data. + * + * TODO: check if walsender restarts form the beggining of the page + * in case of the crash. + */ + for (enc_off = 0; enc_off < count;) + { + data_size = Min(page_size, count); + + if (page_size == XLOG_BLCKSZ) + { + memcpy((char *) curr_page_hdr, (char *) buf + enc_off, SizeOfXLogShortPHD); + + /* + * Need to use a separate buf for the encryption so the page remains non-crypted + * in the XLog buf (XLogInsert has to have access to records' lsn). + */ + enc_buf_page = (XLogPageHeader) (TDEXLogEncryptBuf + enc_off); + memcpy((char *) enc_buf_page, (char *) buf + enc_off, (Size) XLogPageHeaderSize(curr_page_hdr)); + enc_buf_page->xlp_info |= XLP_ENCRYPTED; + + enc_off += XLogPageHeaderSize(curr_page_hdr); + data_size -= XLogPageHeaderSize(curr_page_hdr); + /* it's a beginning of the page */ + iv_ctr = 0; + } + else + { + /* we're in the middle of the page */ + iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); + } + + if (data_size + enc_off > count) + { + data_size = count - enc_off; + } + + /* + * The page is zeroed (no data), no sense to enctypt. + * This may happen when base_backup or other requests XLOG SWITCH and + * some pages in XLog buffer still not used. + */ + if (curr_page_hdr->xlp_magic == 0) + { + /* ensure all the page is {0} */ + Assert((*((char *) buf + enc_off) == 0) && + memcmp((char *) buf + enc_off, (char *) buf + enc_off + 1, data_size - 1) == 0); + + memcpy((char *) enc_buf_page, (char *) buf + enc_off, data_size); + } + else + { + 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); + } + + page_size = XLOG_BLCKSZ; + enc_off += data_size; + } + + return pg_pwrite(fd, TDEXLogEncryptBuf, count, offset); +} +#endif /* !FRONTEND */ + +void +TDEXLogSmgrInit(void) +{ + SetXLogSmgr(&tde_xlog_smgr); +} + +ssize_t +tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset) +{ +#ifndef FRONTEND + if (EncryptXLog) + return TDEXLogWriteEncryptedPages(fd, buf, count, offset); + else +#endif + return pg_pwrite(fd, buf, count, offset); +} + +/* + * Read the XLog pages from the segment file and dectypt if need. + */ +ssize_t +tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset) +{ + ssize_t readsz; + char iv_prefix[16] = {0,}; + size_t data_size = 0; + XLogPageHeader curr_page_hdr = &DecryptCurrentPageHrd; + RelKeyData *key = GetRelationKey(GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); + size_t page_size = XLOG_BLCKSZ - offset % XLOG_BLCKSZ; + off_t dec_off; + uint32 iv_ctr = 0; + +#ifdef TDE_XLOG_DEBUG + elog(DEBUG1, "read from a WAL segment, pages amount: %d, size: %lu offset: %ld", count / (Size) XLOG_BLCKSZ, count, offset); +#endif + + readsz = pg_pread(fd, buf, count, offset); + + /* + * Read the buf page by page and decypt ecnrypted pages. + * We may start or fihish reading from/in the middle of the page (walreceiver) + * in such a case we should preserve the last read page header for + * the IV data and the encryption state. + * + * TODO: check if walsender/receiver restarts form the beggining of the page + * in case of the crash. + */ + for (dec_off = 0; dec_off < readsz;) + { + data_size = Min(page_size, readsz); + + if (page_size == XLOG_BLCKSZ) + { + memcpy((char *) curr_page_hdr, (char *) buf + dec_off, SizeOfXLogShortPHD); + + /* set the flag to "not encrypted" for the walreceiver */ + ((XLogPageHeader) ((char *) buf + dec_off))->xlp_info &= ~XLP_ENCRYPTED; + + Assert(curr_page_hdr->xlp_magic == XLOG_PAGE_MAGIC || curr_page_hdr->xlp_magic == 0); + dec_off += XLogPageHeaderSize(curr_page_hdr); + data_size -= XLogPageHeaderSize(curr_page_hdr); + /* it's a beginning of the page */ + iv_ctr = 0; + } + else + { + /* we're in the middle of the page */ + iv_ctr = (offset % XLOG_BLCKSZ) - XLogPageHeaderSize(curr_page_hdr); + } + + if ((data_size + dec_off) > readsz) + { + data_size = readsz - dec_off; + } + + if (curr_page_hdr->xlp_info & XLP_ENCRYPTED) + { + 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); + } + + page_size = XLOG_BLCKSZ; + dec_off += data_size; + } + + return readsz; +} + +/* IV: TLI(uint32) + XLogRecPtr(uint64)*/ +static void +SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix) +{ + iv_prefix[0] = (tli >> 24); + iv_prefix[1] = ((tli >> 16) & 0xFF); + iv_prefix[2] = ((tli >> 8) & 0xFF); + iv_prefix[3] = (tli & 0xFF); + + iv_prefix[4] = (lsn >> 56); + iv_prefix[5] = ((lsn >> 48) & 0xFF); + iv_prefix[6] = ((lsn >> 40) & 0xFF); + iv_prefix[7] = ((lsn >> 32) & 0xFF); + iv_prefix[8] = ((lsn >> 24) & 0xFF); + iv_prefix[9] = ((lsn >> 16) & 0xFF); + iv_prefix[10] = ((lsn >> 8) & 0xFF); + iv_prefix[11] = (lsn & 0xFF); +} + +#endif /* PERCONA_FORK */ \ No newline at end of file diff --git a/src/catalog/tde_global_space.c b/src/catalog/tde_global_space.c index 88e395da..529e74d9 100644 --- a/src/catalog/tde_global_space.c +++ b/src/catalog/tde_global_space.c @@ -15,15 +15,16 @@ #ifdef PERCONA_EXT #include "catalog/pg_tablespace_d.h" -#include "nodes/pg_list.h" -#include "storage/shmem.h" -#include "utils/guc.h" #include "utils/memutils.h" #include "access/pg_tde_tdemap.h" #include "catalog/tde_global_space.h" #include "catalog/tde_keyring.h" -#include "catalog/tde_principal_key.h" +#include "common/pg_tde_utils.h" + +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif #include #include @@ -35,15 +36,19 @@ #define DefaultKeyProvider GetKeyProviderByName(KEYRING_DEFAULT_NAME, \ GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) +#ifndef FRONTEND static void init_keys(void); static void init_default_keyring(void); static TDEPrincipalKey * create_principal_key(const char *key_name, GenericKeyring * keyring, Oid dbOid, Oid spcOid); +#endif /* !FRONTEND */ + void -TDEInitGlobalKeys(void) +TDEInitGlobalKeys() { +#ifndef FRONTEND char db_map_path[MAXPGPATH] = {0}; pg_tde_set_db_file_paths(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID), @@ -54,6 +59,7 @@ TDEInitGlobalKeys(void) init_keys(); } else +#endif /* !FRONTEND */ { RelKeyData *ikey; @@ -71,6 +77,8 @@ TDEInitGlobalKeys(void) } } +#ifndef FRONTEND + static void init_default_keyring(void) { @@ -181,4 +189,6 @@ create_principal_key(const char *key_name, GenericKeyring * keyring, return principalKey; } +#endif /* FRONTEND */ + #endif /* PERCONA_EXT */ diff --git a/src/catalog/tde_keyring.c b/src/catalog/tde_keyring.c index 4b014f3f..01d3254a 100644 --- a/src/catalog/tde_keyring.c +++ b/src/catalog/tde_keyring.c @@ -10,7 +10,6 @@ *------------------------------------------------------------------------- */ #include "postgres.h" -#include "funcapi.h" #include "access/xlog.h" #include "access/xloginsert.h" #include "access/pg_tde_xlog.h" @@ -18,29 +17,27 @@ #include "catalog/tde_keyring.h" #include "catalog/tde_principal_key.h" #include "access/skey.h" -#include "access/relscan.h" -#include "access/relation.h" -#include "catalog/namespace.h" #include "utils/lsyscache.h" -#include "access/heapam.h" #include "utils/snapmgr.h" #include "utils/fmgroids.h" #include "common/pg_tde_utils.h" -#include "common/pg_tde_shmem.h" -#include "executor/spi.h" #include "miscadmin.h" #include "unistd.h" #include "utils/builtins.h" #include "pg_tde.h" -PG_FUNCTION_INFO_V1(pg_tde_add_key_provider_internal); -Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS); - -PG_FUNCTION_INFO_V1(pg_tde_list_all_key_providers); -Datum pg_tde_list_all_key_providers(PG_FUNCTION_ARGS); - -#define PG_TDE_KEYRING_FILENAME "pg_tde_keyrings" -#define PG_TDE_LIST_PROVIDERS_COLS 4 +#ifndef FRONTEND +#include "access/heapam.h" +#include "common/pg_tde_shmem.h" +#include "funcapi.h" +#include "access/relscan.h" +#include "access/relation.h" +#include "catalog/namespace.h" +#include "executor/spi.h" +#else +#include "fe_utils/simple_list.h" +#include "pg_tde_fe.h" +#endif /* !FRONTEND */ typedef enum ProviderScanType { @@ -50,13 +47,33 @@ typedef enum ProviderScanType PROVIDER_SCAN_ALL } ProviderScanType; -static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid spcOid); +#define PG_TDE_KEYRING_FILENAME "pg_tde_keyrings" static FileKeyring *load_file_keyring_provider_options(char *keyring_options); static GenericKeyring *load_keyring_provider_options(ProviderType provider_type, char *keyring_options); static VaultV2Keyring *load_vaultV2_keyring_provider_options(char *keyring_options); static void debug_print_kerying(GenericKeyring *keyring); +static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider); static char *get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid); +static bool fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider); + +#ifdef FRONTEND + +static SimplePtrList *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid spcOid); +static void simple_list_free(SimplePtrList *list); + +#else + +static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid spcOid); + +PG_FUNCTION_INFO_V1(pg_tde_add_key_provider_internal); +Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS); + +PG_FUNCTION_INFO_V1(pg_tde_list_all_key_providers); +Datum pg_tde_list_all_key_providers(PG_FUNCTION_ARGS); + +#define PG_TDE_LIST_PROVIDERS_COLS 4 + static void key_provider_startup_cleanup(int tde_tbl_count, XLogExtensionInstall *ext_info, bool redo, void *arg); static const char *get_keyring_provider_typename(ProviderType p_type); static uint32 write_key_provider_info(KeyringProvideRecord *provider, @@ -148,22 +165,6 @@ get_keyring_provider_typename(ProviderType p_type) return NULL; } -static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider) -{ - GenericKeyring *keyring = NULL; - - keyring = load_keyring_provider_options(provider->provider_type, provider->options); - if (keyring) - { - keyring->key_id = provider->provider_id; - strncpy(keyring->provider_name, provider->provider_name, sizeof(keyring->provider_name)); - keyring->type = provider->provider_type; - strncpy(keyring->options, provider->options, sizeof(keyring->options)); - debug_print_kerying(keyring); - } - return keyring; -} - List * GetAllKeyringProviders(Oid dbOid, Oid spcOid) { @@ -190,140 +191,6 @@ GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid) return keyring; } -GenericKeyring * -GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid) -{ - GenericKeyring *keyring = NULL; - List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); - if (providers != NIL) - { - keyring = (GenericKeyring *)linitial(providers); - list_free(providers); - } - return keyring; -} - -static GenericKeyring * -load_keyring_provider_options(ProviderType provider_type, char *keyring_options) -{ - switch (provider_type) - { - case FILE_KEY_PROVIDER: - return (GenericKeyring *)load_file_keyring_provider_options(keyring_options); - break; - case VAULT_V2_KEY_PROVIDER: - return (GenericKeyring *)load_vaultV2_keyring_provider_options(keyring_options); - break; - default: - break; - } - return NULL; -} - -static FileKeyring * -load_file_keyring_provider_options(char *keyring_options) -{ - FileKeyring *file_keyring = palloc0(sizeof(FileKeyring)); - - file_keyring->keyring.type = FILE_KEY_PROVIDER; - - if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring, - keyring_options, strlen(keyring_options))) - { - return NULL; - } - - if(strlen(file_keyring->file_name) == 0) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("file path is missing in the keyring options"))); - return NULL; - } - - return file_keyring; -} - -static VaultV2Keyring * -load_vaultV2_keyring_provider_options(char *keyring_options) -{ - VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring)); - - vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER; - - if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring, - keyring_options, strlen(keyring_options))) - { - return NULL; - } - - if(strlen(vaultV2_keyring->vault_token) == 0 || - strlen(vaultV2_keyring->vault_url) == 0 || - strlen(vaultV2_keyring->vault_mount_path) == 0) - { - ereport(WARNING, - (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("missing in the keyring options:%s%s%s", - !vaultV2_keyring->vault_token ? " token" : "", - !vaultV2_keyring->vault_url ? " url" : "", - !vaultV2_keyring->vault_mount_path ? " mountPath" : ""))); - return NULL; - } - - return vaultV2_keyring; -} - -static void -debug_print_kerying(GenericKeyring *keyring) -{ - int debug_level = DEBUG2; - elog(debug_level, "Keyring type: %d", keyring->type); - elog(debug_level, "Keyring name: %s", keyring->provider_name); - elog(debug_level, "Keyring id: %d", keyring->key_id); - switch (keyring->type) - { - case FILE_KEY_PROVIDER: - elog(debug_level, "File Keyring Path: %s", ((FileKeyring *)keyring)->file_name); - break; - case VAULT_V2_KEY_PROVIDER: - elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *)keyring)->vault_token); - elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *)keyring)->vault_url); - elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *)keyring)->vault_mount_path); - elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *)keyring)->vault_ca_path); - break; - case UNKNOWN_KEY_PROVIDER: - elog(debug_level, "Unknown Keyring "); - break; - } -} - -/* - * Fetch the next key provider from the file and update the curr_pos -*/ -static bool -fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider) -{ - off_t bytes_read = 0; - - Assert(provider != NULL); - Assert(fd >= 0); - - bytes_read = pg_pread(fd, provider, sizeof(KeyringProvideRecord), *curr_pos); - *curr_pos += bytes_read; - - if (bytes_read == 0) - return false; - if (bytes_read != sizeof(KeyringProvideRecord)) - { - close(fd); - /* Corrupt file */ - ereport(ERROR, - (errcode_for_file_access(), - errmsg("key provider info file is corrupted: %m"), - errdetail("invalid key provider record size %lld expected %lu", bytes_read, sizeof(KeyringProvideRecord) ))); - } - return true; -} static uint32 write_key_provider_info(KeyringProvideRecord *provider, Oid database_id, @@ -436,71 +303,6 @@ redo_key_provider_info(KeyringProviderXLRecord* xlrec) return write_key_provider_info(&xlrec->provider, xlrec->database_id, xlrec->tablespace_id, xlrec->offset_in_file, true, false); } -/* - * Scan the key provider info file and can also apply filter based on scanType - */ -static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid spcOid) -{ - off_t curr_pos = 0; - int fd; - char kp_info_path[MAXPGPATH] = {0}; - KeyringProvideRecord provider; - List *providers_list = NIL; - - if (scanType != PROVIDER_SCAN_ALL) - Assert(scanKey != NULL); - - get_keyring_infofile_path(kp_info_path, dbOid, spcOid); - - LWLockAcquire(tde_provider_info_lock(), LW_SHARED); - - fd = BasicOpenFile(kp_info_path, PG_BINARY); - if (fd < 0) - { - LWLockRelease(tde_provider_info_lock()); - ereport(DEBUG2, - (errcode_for_file_access(), - errmsg("could not open tde file \"%s\": %m", kp_info_path))); - return NIL; - } - while (fetch_next_key_provider(fd, &curr_pos, &provider)) - { - bool match = false; - ereport(DEBUG2, - (errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name))); - - if (scanType == PROVIDER_SCAN_BY_NAME) - { - if (strcasecmp(provider.provider_name, (char*)scanKey) == 0) - match = true; - } - else if (scanType == PROVIDER_SCAN_BY_ID) - { - if (provider.provider_id == *(int *)scanKey) - match = true; - } - else if (scanType == PROVIDER_SCAN_BY_TYPE) - { - if (provider.provider_type == *(ProviderType*)scanKey) - match = true; - } - else if (scanType == PROVIDER_SCAN_ALL) - match = true; - - if (match) - { - GenericKeyring *keyring = load_keyring_provider_from_record(&provider); - if (keyring) - { - providers_list = lappend(providers_list, keyring); - } - } - } - close(fd); - LWLockRelease(tde_provider_info_lock()); - return providers_list; -} - void cleanup_key_provider_info(Oid databaseId, Oid tablespaceId) { @@ -511,16 +313,6 @@ cleanup_key_provider_info(Oid databaseId, Oid tablespaceId) PathNameDeleteTemporaryFile(kp_info_path, false); } -static char* -get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid) -{ - char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid); - Assert(db_path != NULL); - join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME); - pfree(db_path); - return resPath; -} - Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS) { @@ -599,3 +391,277 @@ pg_tde_list_all_key_providers(PG_FUNCTION_ARGS) list_free_deep(all_providers); return (Datum)0; } + +GenericKeyring * +GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid) +{ + GenericKeyring *keyring = NULL; + List *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); + if (providers != NIL) + { + keyring = (GenericKeyring *)linitial(providers); + list_free(providers); + } + return keyring; +} + +#endif /* !FRONTEND */ + +#ifdef FRONTEND +GenericKeyring * +GetKeyProviderByID(int provider_id, Oid dbOid, Oid spcOid) +{ + GenericKeyring *keyring = NULL; + SimplePtrList *providers = scan_key_provider_file(PROVIDER_SCAN_BY_ID, &provider_id, dbOid, spcOid); + if (providers != NULL) + { + keyring = (GenericKeyring *) providers->head->ptr; + simple_list_free(providers); + } + return keyring; +} + +static void +simple_list_free(SimplePtrList *list) +{ + SimplePtrListCell *cell; + + cell = list->head; + while (cell != NULL) + { + SimplePtrListCell *next; + + next = cell->next; + pfree(cell); + cell = next; + } +} +#endif /* FRONTEND */ + +/* + * Scan the key provider info file and can also apply filter based on scanType + */ +#ifndef FRONTEND +static List * +#else +static SimplePtrList * +#endif +scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid spcOid) +{ + off_t curr_pos = 0; + int fd; + char kp_info_path[MAXPGPATH] = {0}; + KeyringProvideRecord provider; +#ifndef FRONTEND + List *providers_list = NIL; +#else + SimplePtrList *providers_list = NULL; +#endif + + if (scanType != PROVIDER_SCAN_ALL) + Assert(scanKey != NULL); + + get_keyring_infofile_path(kp_info_path, dbOid, spcOid); + + LWLockAcquire(tde_provider_info_lock(), LW_SHARED); + + fd = BasicOpenFile(kp_info_path, PG_BINARY); + if (fd < 0) + { + LWLockRelease(tde_provider_info_lock()); + ereport(DEBUG2, + (errcode_for_file_access(), + errmsg("could not open tde file \"%s\": %m", kp_info_path))); + return providers_list; + } + while (fetch_next_key_provider(fd, &curr_pos, &provider)) + { + bool match = false; + ereport(DEBUG2, + (errmsg("read key provider ID=%d %s", provider.provider_id, provider.provider_name))); + + if (scanType == PROVIDER_SCAN_BY_NAME) + { + if (strcasecmp(provider.provider_name, (char*)scanKey) == 0) + match = true; + } + else if (scanType == PROVIDER_SCAN_BY_ID) + { + if (provider.provider_id == *(int *)scanKey) + match = true; + } + else if (scanType == PROVIDER_SCAN_BY_TYPE) + { + if (provider.provider_type == *(ProviderType*)scanKey) + match = true; + } + else if (scanType == PROVIDER_SCAN_ALL) + match = true; + + if (match) + { + GenericKeyring *keyring = load_keyring_provider_from_record(&provider); + if (keyring) + { +#ifndef FRONTEND + providers_list = lappend(providers_list, keyring); +#else + simple_ptr_list_append(providers_list, keyring); +#endif + } + } + } + close(fd); + LWLockRelease(tde_provider_info_lock()); + return providers_list; +} + +static GenericKeyring * +load_keyring_provider_from_record(KeyringProvideRecord *provider) +{ + GenericKeyring *keyring = NULL; + + keyring = load_keyring_provider_options(provider->provider_type, provider->options); + if (keyring) + { + keyring->key_id = provider->provider_id; + strncpy(keyring->provider_name, provider->provider_name, sizeof(keyring->provider_name)); + keyring->type = provider->provider_type; + strncpy(keyring->options, provider->options, sizeof(keyring->options)); + debug_print_kerying(keyring); + } + return keyring; +} + + +static GenericKeyring * +load_keyring_provider_options(ProviderType provider_type, char *keyring_options) +{ + switch (provider_type) + { + case FILE_KEY_PROVIDER: + return (GenericKeyring *)load_file_keyring_provider_options(keyring_options); + break; + case VAULT_V2_KEY_PROVIDER: + return (GenericKeyring *)load_vaultV2_keyring_provider_options(keyring_options); + break; + default: + break; + } + return NULL; +} + +static FileKeyring * +load_file_keyring_provider_options(char *keyring_options) +{ + FileKeyring *file_keyring = palloc0(sizeof(FileKeyring)); + + file_keyring->keyring.type = FILE_KEY_PROVIDER; + + if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring, + keyring_options, strlen(keyring_options))) + { + return NULL; + } + + if(strlen(file_keyring->file_name) == 0) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("file path is missing in the keyring options"))); + return NULL; + } + + return file_keyring; +} + +static VaultV2Keyring * +load_vaultV2_keyring_provider_options(char *keyring_options) +{ + VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring)); + + vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER; + + if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring, + keyring_options, strlen(keyring_options))) + { + return NULL; + } + + if(strlen(vaultV2_keyring->vault_token) == 0 || + strlen(vaultV2_keyring->vault_url) == 0 || + strlen(vaultV2_keyring->vault_mount_path) == 0) + { + ereport(WARNING, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("missing in the keyring options:%s%s%s", + !vaultV2_keyring->vault_token ? " token" : "", + !vaultV2_keyring->vault_url ? " url" : "", + !vaultV2_keyring->vault_mount_path ? " mountPath" : ""))); + return NULL; + } + + return vaultV2_keyring; +} + +static void +debug_print_kerying(GenericKeyring *keyring) +{ + int debug_level = DEBUG2; + elog(debug_level, "Keyring type: %d", keyring->type); + elog(debug_level, "Keyring name: %s", keyring->provider_name); + elog(debug_level, "Keyring id: %d", keyring->key_id); + switch (keyring->type) + { + case FILE_KEY_PROVIDER: + elog(debug_level, "File Keyring Path: %s", ((FileKeyring *)keyring)->file_name); + break; + case VAULT_V2_KEY_PROVIDER: + elog(debug_level, "Vault Keyring Token: %s", ((VaultV2Keyring *)keyring)->vault_token); + elog(debug_level, "Vault Keyring URL: %s", ((VaultV2Keyring *)keyring)->vault_url); + elog(debug_level, "Vault Keyring Mount Path: %s", ((VaultV2Keyring *)keyring)->vault_mount_path); + elog(debug_level, "Vault Keyring CA Path: %s", ((VaultV2Keyring *)keyring)->vault_ca_path); + break; + case UNKNOWN_KEY_PROVIDER: + elog(debug_level, "Unknown Keyring "); + break; + } +} + +static char* +get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid) +{ + char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid); + Assert(db_path != NULL); + join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME); + pfree(db_path); + return resPath; +} + +/* + * Fetch the next key provider from the file and update the curr_pos +*/ +static bool +fetch_next_key_provider(int fd, off_t* curr_pos, KeyringProvideRecord *provider) +{ + off_t bytes_read = 0; + + Assert(provider != NULL); + Assert(fd >= 0); + + bytes_read = pg_pread(fd, provider, sizeof(KeyringProvideRecord), *curr_pos); + *curr_pos += bytes_read; + + if (bytes_read == 0) + return false; + if (bytes_read != sizeof(KeyringProvideRecord)) + { + close(fd); + /* Corrupt file */ + ereport(ERROR, + (errcode_for_file_access(), + errmsg("key provider info file is corrupted: %m"), + errdetail("invalid key provider record size %ld expected %lu", bytes_read, sizeof(KeyringProvideRecord) ))); + } + return true; +} \ No newline at end of file diff --git a/src/catalog/tde_keyring_parse_opts.c b/src/catalog/tde_keyring_parse_opts.c index d09fec94..9c095a87 100644 --- a/src/catalog/tde_keyring_parse_opts.c +++ b/src/catalog/tde_keyring_parse_opts.c @@ -23,6 +23,7 @@ */ #include "postgres.h" +#include "common/file_perm.h" #include "common/jsonapi.h" #include "mb/pg_wchar.h" #include "storage/fd.h" @@ -30,6 +31,10 @@ #include "catalog/tde_keyring.h" #include "keyring/keyring_curl.h" +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif + #include #define MAX_CONFIG_FILE_DATA_LENGTH 1024 diff --git a/src/catalog/tde_principal_key.c b/src/catalog/tde_principal_key.c index 111955df..a20e11bd 100644 --- a/src/catalog/tde_principal_key.c +++ b/src/catalog/tde_principal_key.c @@ -13,8 +13,6 @@ #include "access/xlog.h" #include "access/xloginsert.h" #include "catalog/tde_principal_key.h" -#include "common/pg_tde_shmem.h" -#include "storage/lwlock.h" #include "storage/fd.h" #include "utils/palloc.h" #include "utils/memutils.h" @@ -22,14 +20,22 @@ #include "utils/timestamp.h" #include "common/relpath.h" #include "miscadmin.h" -#include "funcapi.h" #include "utils/builtins.h" #include "pg_tde.h" #include "access/pg_tde_xlog.h" -#include - #include "access/pg_tde_tdemap.h" #include "catalog/tde_global_space.h" +#ifndef FRONTEND +#include "common/pg_tde_shmem.h" +#include "funcapi.h" +#include "storage/lwlock.h" +#else +#include "pg_tde_fe.h" +#endif + +#include + +#ifndef FRONTEND typedef struct TdePrincipalKeySharedState { @@ -206,125 +212,6 @@ save_principal_key_info(TDEPrincipalKeyInfo *principal_key_info) return pg_tde_save_principal_key(principal_key_info); } -/* - * Public interface to get the principal key for the current database - * If the principal key is not present in the cache, it is loaded from - * the keyring and stored in the cache. - * When the principal key is not set for the database. The function returns - * throws an error. - */ -TDEPrincipalKey * -GetPrincipalKey(Oid dbOid, Oid spcOid) -{ - GenericKeyring *keyring; - TDEPrincipalKey *principalKey = NULL; - TDEPrincipalKeyInfo *principalKeyInfo = NULL; - const keyInfo *keyInfo = NULL; - KeyringReturnCodes keyring_ret; - LWLock *lock_files = tde_lwlock_mk_files(); - LWLock *lock_cache = tde_lwlock_mk_cache(); - - // TODO: This recursion counter is a dirty hack until the metadata is in the catalog - // As otherwise we would call GetPrincipalKey recursively and deadlock - static int recursion = 0; - - if(recursion > 0) - { - return NULL; - } - - recursion++; - - /* We don't store global space key in cache */ - if (spcOid != GLOBALTABLESPACE_OID) - { - LWLockAcquire(lock_cache, LW_SHARED); - principalKey = get_principal_key_from_cache(dbOid); - LWLockRelease(lock_cache); - } - - if (principalKey) - { - recursion--; - return principalKey; - } - - /* - * We should hold an exclusive lock here to ensure that a valid principal key, if found, is added - * to the cache without any interference. - */ - LWLockAcquire(lock_files, LW_SHARED); - LWLockAcquire(lock_cache, LW_EXCLUSIVE); - - /* We don't store global space key in cache */ - if (spcOid != GLOBALTABLESPACE_OID) - { - principalKey = get_principal_key_from_cache(dbOid); - } - - if (principalKey) - { - LWLockRelease(lock_cache); - LWLockRelease(lock_files); - recursion--; - return principalKey; - } - - /* Principal key not present in cache. Load from the keyring */ - principalKeyInfo = pg_tde_get_principal_key(dbOid, spcOid); - if (principalKeyInfo == NULL) - { - LWLockRelease(lock_cache); - LWLockRelease(lock_files); - - recursion--; - return NULL; - } - - keyring = GetKeyProviderByID(principalKeyInfo->keyringId, dbOid, spcOid); - if (keyring == NULL) - { - LWLockRelease(lock_cache); - LWLockRelease(lock_files); - - recursion--; - return NULL; - } - - keyInfo = KeyringGetKey(keyring, principalKeyInfo->keyId.versioned_name, false, &keyring_ret); - if (keyInfo == NULL) - { - LWLockRelease(lock_cache); - LWLockRelease(lock_files); - - recursion--; - return NULL; - } - - principalKey = palloc(sizeof(TDEPrincipalKey)); - - memcpy(&principalKey->keyInfo, principalKeyInfo, sizeof(principalKey->keyInfo)); - memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); - principalKey->keyLength = keyInfo->data.len; - - Assert(dbOid == principalKey->keyInfo.databaseId); - /* We don't store global space key in cache */ - if (spcOid != GLOBALTABLESPACE_OID) - { - push_principal_key_to_cache(principalKey); - } - - /* Release the exclusive locks here */ - LWLockRelease(lock_cache); - LWLockRelease(lock_files); - - if (principalKeyInfo) - pfree(principalKeyInfo); - - recursion--; - return principalKey; -} - /* * SetPrincipalkey: * We need to ensure that only one principal key is set for a database. @@ -855,3 +742,130 @@ pg_tde_get_key_info(PG_FUNCTION_ARGS, Oid dbOid, Oid spcOid) PG_RETURN_DATUM(result); } +#endif /* FRONTEND */ + +/* + * Public interface to get the principal key for the current database + * If the principal key is not present in the cache, it is loaded from + * the keyring and stored in the cache. + * When the principal key is not set for the database. The function returns + * throws an error. + */ +TDEPrincipalKey * +GetPrincipalKey(Oid dbOid, Oid spcOid) +{ + GenericKeyring *keyring; + TDEPrincipalKey *principalKey = NULL; + TDEPrincipalKeyInfo *principalKeyInfo = NULL; + const keyInfo *keyInfo = NULL; + KeyringReturnCodes keyring_ret; + LWLock *lock_files = tde_lwlock_mk_files(); + LWLock *lock_cache = tde_lwlock_mk_cache(); + + // TODO: This recursion counter is a dirty hack until the metadata is in the catalog + // As otherwise we would call GetPrincipalKey recursively and deadlock + static int recursion = 0; + + if(recursion > 0) + { + return NULL; + } + + recursion++; + +#ifndef FRONTEND + /* We don't store global space key in cache */ + if (spcOid != GLOBALTABLESPACE_OID) + { + LWLockAcquire(lock_cache, LW_SHARED); + principalKey = get_principal_key_from_cache(dbOid); + LWLockRelease(lock_cache); + } + + if (principalKey) + { + recursion--; + return principalKey; + } +#endif + + /* + * We should hold an exclusive lock here to ensure that a valid principal key, if found, is added + * to the cache without any interference. + */ + LWLockAcquire(lock_files, LW_SHARED); + LWLockAcquire(lock_cache, LW_EXCLUSIVE); + +#ifndef FRONTEND + /* We don't store global space key in cache */ + if (spcOid != GLOBALTABLESPACE_OID) + { + principalKey = get_principal_key_from_cache(dbOid); + } + + if (principalKey) + { + LWLockRelease(lock_cache); + LWLockRelease(lock_files); + recursion--; + return principalKey; + } +#endif + + /* Principal key not present in cache. Load from the keyring */ + principalKeyInfo = pg_tde_get_principal_key(dbOid, spcOid); + if (principalKeyInfo == NULL) + { + LWLockRelease(lock_cache); + LWLockRelease(lock_files); + + recursion--; + return NULL; + } + + keyring = GetKeyProviderByID(principalKeyInfo->keyringId, dbOid, spcOid); + if (keyring == NULL) + { + LWLockRelease(lock_cache); + LWLockRelease(lock_files); + + recursion--; + return NULL; + } + + keyInfo = KeyringGetKey(keyring, principalKeyInfo->keyId.versioned_name, false, &keyring_ret); + if (keyInfo == NULL) + { + LWLockRelease(lock_cache); + LWLockRelease(lock_files); + + recursion--; + return NULL; + } + + principalKey = palloc(sizeof(TDEPrincipalKey)); + + memcpy(&principalKey->keyInfo, principalKeyInfo, sizeof(principalKey->keyInfo)); + memcpy(principalKey->keyData, keyInfo->data.data, keyInfo->data.len); + principalKey->keyLength = keyInfo->data.len; + + Assert(dbOid == principalKey->keyInfo.databaseId); + +#ifndef FRONTEND + /* We don't store global space key in cache */ + if (spcOid != GLOBALTABLESPACE_OID) + { + push_principal_key_to_cache(principalKey); + } +#endif + + /* Release the exclusive locks here */ + LWLockRelease(lock_cache); + LWLockRelease(lock_files); + + if (principalKeyInfo) + pfree(principalKeyInfo); + + recursion--; + return principalKey; +} diff --git a/src/common/pg_tde_utils.c b/src/common/pg_tde_utils.c index b367278f..c1f190c4 100644 --- a/src/common/pg_tde_utils.c +++ b/src/common/pg_tde_utils.c @@ -10,13 +10,16 @@ */ #include "postgres.h" -#include "access/genam.h" -#include "access/heapam.h" + #include "catalog/pg_tablespace_d.h" #include "utils/snapmgr.h" #include "commands/defrem.h" #include "common/pg_tde_utils.h" +#ifndef FRONTEND +#include "access/genam.h" +#include "access/heapam.h" + Oid get_tde_basic_table_am_oid(void) { @@ -79,6 +82,8 @@ get_tde_tables_count(void) return count; } +#endif /* !FRONTEND */ + /* returns the palloc'd string */ char * pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) diff --git a/src/encryption/enc_tde.c b/src/encryption/enc_tde.c index 39e6257d..d91fa04b 100644 --- a/src/encryption/enc_tde.c +++ b/src/encryption/enc_tde.c @@ -163,6 +163,7 @@ pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint3 } } +#ifndef FRONTEND /* * pg_tde_crypt_tuple: * Does the encryption/decryption of tuple data in place @@ -247,6 +248,8 @@ AesEncryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *rlocat AesEncrypt(principal_key->keyData, iv, ((unsigned char*)&rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_enc_rel_key_data)->internal_key), (int *)enc_key_bytes); } +#endif /* FRONTEND */ + /* * Provide a simple interface to decrypt a given key. * @@ -264,11 +267,21 @@ void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *r memcpy(iv, &rlocator->spcOid, sizeof(Oid)); memcpy(iv + sizeof(Oid), &rlocator->dbOid, sizeof(Oid)); - *p_rel_key_data = (RelKeyData *) MemoryContextAlloc(TopMemoryContext, sizeof(RelKeyData)); +#ifndef FRONTEND + MemoryContext oldcontext; + + oldcontext = MemoryContextSwitchTo(TopMemoryContext); +#endif + + *p_rel_key_data = (RelKeyData *) palloc(sizeof(RelKeyData)); + +#ifndef FRONTEND + MemoryContextSwitchTo(oldcontext); +#endif /* Fill in the structure */ memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData)); (*p_rel_key_data)->internal_key.ctx = NULL; AesDecrypt(principal_key->keyData, iv, ((unsigned char*) &enc_rel_key_data->internal_key), INTERNAL_KEY_LEN, ((unsigned char *)&(*p_rel_key_data)->internal_key) , (int *)key_bytes); -} +} \ No newline at end of file diff --git a/src/include/access/pg_tde_xlog.h b/src/include/access/pg_tde_xlog.h index 7ea9ae34..1ea24cf7 100644 --- a/src/include/access/pg_tde_xlog.h +++ b/src/include/access/pg_tde_xlog.h @@ -9,12 +9,11 @@ #ifndef PG_TDE_XLOG_H #define PG_TDE_XLOG_H +#ifndef FRONTEND + #include "postgres.h" #include "access/xlog.h" #include "access/xlog_internal.h" -#ifdef PERCONA_EXT -#include "access/xlog_smgr.h" -#endif /* TDE XLOG resource manager */ #define XLOG_TDE_ADD_RELATION_KEY 0x00 @@ -38,28 +37,5 @@ static const RmgrData tdeheap_rmgr = { .rm_identify = tdeheap_rmgr_identify }; -#ifdef PERCONA_EXT - -/* XLog encryption staff */ - -extern Size TDEXLogEncryptBuffSize(void); - -#define XLOG_TDE_ENC_BUFF_ALIGNED_SIZE add_size(TDEXLogEncryptBuffSize(), PG_IO_ALIGN_SIZE) - -extern void TDEXLogShmemInit(void); - -extern ssize_t tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset); -extern ssize_t tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset); - -static const XLogSmgr tde_xlog_smgr = { - .seg_read = tdeheap_xlog_seg_read, - .seg_write = tdeheap_xlog_seg_write, -}; - -extern void TDEXLogSmgrInit(void); - -extern void XLogInitGUC(void); - -#endif - +#endif /* !FRONTEND */ #endif /* PG_TDE_XLOG_H */ diff --git a/src/include/access/pg_tde_xlog_encrypt.h b/src/include/access/pg_tde_xlog_encrypt.h new file mode 100644 index 00000000..78295020 --- /dev/null +++ b/src/include/access/pg_tde_xlog_encrypt.h @@ -0,0 +1,35 @@ +/*------------------------------------------------------------------------- + * + * pg_tde_xlog_encrypt.h + * Encrypted XLog storage manager + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_TDE_XLOGENCRYPT_H +#define PG_TDE_XLOGENCRYPT_H + +#include "postgres.h" +#ifdef PERCONA_FORK +#include "access/xlog_smgr.h" + +extern Size TDEXLogEncryptBuffSize(void); + +#define XLOG_TDE_ENC_BUFF_ALIGNED_SIZE add_size(TDEXLogEncryptBuffSize(), PG_IO_ALIGN_SIZE) + +extern void TDEXLogShmemInit(void); + +extern ssize_t tdeheap_xlog_seg_read(int fd, void *buf, size_t count, off_t offset); +extern ssize_t tdeheap_xlog_seg_write(int fd, const void *buf, size_t count, off_t offset); + +static const XLogSmgr tde_xlog_smgr = { + .seg_read = tdeheap_xlog_seg_read, + .seg_write = tdeheap_xlog_seg_write, +}; + +extern void TDEXLogSmgrInit(void); +extern void XLogInitGUC(void); + +#endif /* PERCONA_FORK */ + +#endif /* PG_TDE_XLOGENCRYPT_H */ \ No newline at end of file diff --git a/src/include/catalog/tde_principal_key.h b/src/include/catalog/tde_principal_key.h index 0bebe59e..66be92f6 100644 --- a/src/include/catalog/tde_principal_key.h +++ b/src/include/catalog/tde_principal_key.h @@ -15,7 +15,9 @@ #include "catalog/tde_keyring.h" #include "keyring/keyring_api.h" #include "nodes/pg_list.h" +#ifndef FRONTEND #include "storage/lwlock.h" +#endif #define DEFAULT_PRINCIPAL_KEY_VERSION 1 #define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN @@ -57,8 +59,14 @@ typedef struct XLogPrincipalKeyRotate extern void InitializePrincipalKeyInfo(void); extern void cleanup_principal_key_info(Oid databaseId, Oid tablespaceId); + +#ifndef FRONTEND extern LWLock *tde_lwlock_mk_files(void); extern LWLock *tde_lwlock_mk_cache(void); +#else +#define tde_lwlock_mk_files() NULL +#define tde_lwlock_mk_cache() NULL +#endif extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo); diff --git a/src/include/common/pg_tde_utils.h b/src/include/common/pg_tde_utils.h index 4f80e5b2..26edf8f9 100644 --- a/src/include/common/pg_tde_utils.h +++ b/src/include/common/pg_tde_utils.h @@ -9,12 +9,15 @@ #define PG_TDE_UTILS_H #include "postgres.h" + +#ifndef FRONTEND #include "nodes/pg_list.h" extern Oid get_tde_basic_table_am_oid(void); extern Oid get_tde_table_am_oid(void); extern List *get_all_tde_tables(void); extern int get_tde_tables_count(void); +#endif /* !FRONTEND */ extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid); #endif /*PG_TDE_UTILS_H*/ diff --git a/src/include/keyring/keyring.h b/src/include/keyring/keyring.h deleted file mode 100644 index b9720acd..00000000 --- a/src/include/keyring/keyring.h +++ /dev/null @@ -1,4 +0,0 @@ - -#pragma once - -void keyringInitialize(void); diff --git a/src/include/keyring/keyring_config.h b/src/include/keyring/keyring_config.h deleted file mode 100644 index b458c3bd..00000000 --- a/src/include/keyring/keyring_config.h +++ /dev/null @@ -1,18 +0,0 @@ - -#ifndef KEYRING_CONFIG_H -#define KEYRING_CONFIG_H - -#include "postgres.h" - -enum KeyringProvider -{ - PROVIDER_UNKNOWN, - PROVIDER_FILE, - PROVIDER_VAULT_V2, -} ; - -extern enum KeyringProvider keyringProvider; - -void keyringRegisterVariables(void); - -#endif // KEYRING_CONFIG_H diff --git a/src/include/pg_tde_fe.h b/src/include/pg_tde_fe.h new file mode 100644 index 00000000..8862ef7d --- /dev/null +++ b/src/include/pg_tde_fe.h @@ -0,0 +1,77 @@ +/*------------------------------------------------------------------------- + * + * pg_tde_fe.h + * TDE redefinitions for frontend included code + * + * src/include/pg_tde_fe.h + * + *------------------------------------------------------------------------- + */ +#ifndef PG_TDE_EREPORT_H +#define PG_TDE_EREPORT_H + +#ifdef FRONTEND + +#include "postgres_fe.h" +#include "utils/elog.h" +#include "common/logging.h" +#include "common/file_perm.h" + +// #pragma GCC diagnostic warning "-Wno-unused-value" +#pragma GCC diagnostic ignored "-Wunused-macros" +#pragma GCC diagnostic ignored "-Wunused-value" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wextra" +/* + * Errors handeling + * ---------------------------------------- + */ + +#define tde_fe_errlog(_type, ...) \ + ({ \ + if (tde_fe_error_level >= ERROR) \ + pg_log_error##_type(__VA_ARGS__); \ + else if (tde_fe_error_level >= WARNING) \ + pg_log_warning##_type(__VA_ARGS__); \ + else if (tde_fe_error_level >= LOG) \ + pg_log_info##_type(__VA_ARGS__); \ + else \ + pg_log_debug##_type(__VA_ARGS__); \ + }) + +#define errmsg(...) tde_fe_errlog(, __VA_ARGS__) +#define errhint(...) tde_fe_errlog(_hint, __VA_ARGS__) +#define errdetail(...) tde_fe_errlog(_detail, __VA_ARGS__) + +#define errcode_for_file_access() NULL +#define errcode(e) NULL + +#define elog(elevel, fmt, ...) \ + do { \ + tde_fe_error_level = elevel; \ + errmsg(fmt, ##__VA_ARGS__); \ + } while(0) + +#define ereport(elevel,...) \ + do { \ + tde_fe_error_level = elevel; \ + __VA_ARGS__; \ + } while(0) + +static int tde_fe_error_level = 0; + +/* + * ------------- + */ + + +#define LWLockAcquire(lock, mode) NULL +#define LWLockRelease(lock_files) NULL +#define LWLock void + +#define BasicOpenFile(fileName, fileFlags) open(fileName, fileFlags, PG_FILE_MODE_OWNER) + +#define pg_fsync(fd) fsync(fd) +#endif /* FRONTEND */ + +#endif /* PG_TDE_EREPORT_H */ diff --git a/src/keyring/keyring.c b/src/keyring/keyring.c deleted file mode 100644 index c99a1e14..00000000 --- a/src/keyring/keyring.c +++ /dev/null @@ -1,10 +0,0 @@ - -#include "keyring/keyring.h" -#include "keyring/keyring_config.h" -#include "keyring/keyring_api.h" - -void keyringInitialize(void) -{ - keyringRegisterVariables(); - keyringInitializeCache(); -} diff --git a/src/keyring/keyring_api.c b/src/keyring/keyring_api.c index ff491780..cb702db0 100644 --- a/src/keyring/keyring_api.c +++ b/src/keyring/keyring_api.c @@ -2,13 +2,16 @@ #include "keyring/keyring_api.h" #include "keyring/keyring_file.h" #include "keyring/keyring_vault.h" -#include "keyring/keyring_config.h" #include "postgres.h" #include "access/xlog.h" #include "storage/shmem.h" #include "nodes/pg_list.h" #include "utils/memutils.h" +#ifdef FRONTEND +#include "fe_utils/simple_list.h" +#include "pg_tde_fe.h" +#endif #include #include @@ -19,9 +22,14 @@ typedef struct KeyProviders ProviderType type; } KeyProviders; +#ifndef FRONTEND List *registeredKeyProviders = NIL; +#else +SimplePtrList *registeredKeyProviders = NULL; +#endif static KeyProviders *find_key_provider(ProviderType type); +#ifndef FRONTEND static KeyProviders * find_key_provider(ProviderType type) { @@ -36,9 +44,25 @@ find_key_provider(ProviderType type) } return NULL; } +#else +static KeyProviders * +find_key_provider(ProviderType type) +{ + SimplePtrListCell *lc; + for (lc = registeredKeyProviders->head; lc; lc = lc->next) + { + KeyProviders *kp = (KeyProviders *) lc->ptr; + if (kp->type == type) + { + return kp; + } + } + return NULL; +} +#endif /* !FRONTEND */ + bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type) { - MemoryContext oldcontext; KeyProviders *kp; Assert(routine != NULL); @@ -52,12 +76,21 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type) (errmsg("Key provider of type %d already registered", type))); return false; } + +#ifndef FRONTEND + MemoryContext oldcontext; oldcontext = MemoryContextSwitchTo(TopMemoryContext); +#endif kp = palloc(sizeof(KeyProviders)); kp->routine = (TDEKeyringRoutine *)routine; kp->type = type; +#ifndef FRONTEND registeredKeyProviders = lappend(registeredKeyProviders, kp); MemoryContextSwitchTo(oldcontext); +#else + simple_ptr_list_append(registeredKeyProviders, kp); +#endif + return true; } diff --git a/src/keyring/keyring_config.c b/src/keyring/keyring_config.c deleted file mode 100644 index 2bee18f3..00000000 --- a/src/keyring/keyring_config.c +++ /dev/null @@ -1,17 +0,0 @@ - -#include "keyring/keyring_config.h" -#include "keyring/keyring_file.h" -#include "keyring/keyring_vault.h" - -#include -#include -#include - -#include "utils/guc.h" - -enum KeyringProvider keyringProvider = PROVIDER_UNKNOWN; - -void keyringRegisterVariables(void) -{ - // nop for now -} diff --git a/src/keyring/keyring_curl.c b/src/keyring/keyring_curl.c index 55cd61ab..188caa85 100644 --- a/src/keyring/keyring_curl.c +++ b/src/keyring/keyring_curl.c @@ -9,8 +9,9 @@ *------------------------------------------------------------------------- */ +#include "postgres.h" + #include "keyring/keyring_curl.h" -#include "keyring/keyring_config.h" #include "pg_tde_defines.h" CURL* keyringCurl = NULL; diff --git a/src/keyring/keyring_file.c b/src/keyring/keyring_file.c index f5d8648d..74f42a67 100644 --- a/src/keyring/keyring_file.c +++ b/src/keyring/keyring_file.c @@ -13,11 +13,16 @@ #include "postgres.h" #include "keyring/keyring_file.h" -#include "keyring/keyring_config.h" #include "catalog/tde_keyring.h" +#include "common/file_perm.h" #include "keyring/keyring_api.h" #include "storage/fd.h" #include "utils/wait_event.h" + +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif + #include #include @@ -131,6 +136,7 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error) file_keyring->file_name))); return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE; } + if (pg_fsync(fd) != 0) { close(fd); diff --git a/src/keyring/keyring_vault.c b/src/keyring/keyring_vault.c index 881f7296..49a03c45 100644 --- a/src/keyring/keyring_vault.c +++ b/src/keyring/keyring_vault.c @@ -12,7 +12,6 @@ #include "postgres.h" #include "keyring/keyring_vault.h" -#include "keyring/keyring_config.h" #include "keyring/keyring_curl.h" #include "keyring/keyring_api.h" #include "pg_tde_defines.h" @@ -26,6 +25,10 @@ #include "common/base64.h" +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif + /* * JSON parser state */ diff --git a/src/pg_tde.c b/src/pg_tde.c index f9162058..0f773de5 100644 --- a/src/pg_tde.c +++ b/src/pg_tde.c @@ -20,11 +20,11 @@ #include "storage/shmem.h" #include "access/pg_tde_ddl.h" #include "access/pg_tde_xlog.h" +#include "access/pg_tde_xlog_encrypt.h" #include "encryption/enc_aes.h" #include "access/pg_tde_tdemap.h" #include "access/xlog.h" #include "access/xloginsert.h" -#include "keyring/keyring_config.h" #include "keyring/keyring_api.h" #include "common/pg_tde_shmem.h" #include "common/pg_tde_utils.h" @@ -102,7 +102,6 @@ _PG_init(void) elog(WARNING, "pg_tde can only be loaded at server startup. Restart required."); } - keyringRegisterVariables(); InitializePrincipalKeyInfo(); InitializeKeyProviderInfo(); #ifdef PERCONA_EXT From 051be41db0c24a5f2d1e75bebc01d0634aec4279 Mon Sep 17 00:00:00 2001 From: Andrew Pogrebnoy Date: Wed, 28 Aug 2024 20:05:33 +0300 Subject: [PATCH 2/4] Add an option to set global kring dir ... and all the things work with pg_waldump --- src/access/pg_tde_xlog_encrypt.c | 4 ++ src/catalog/tde_global_space.c | 56 ++++++++++++++++---------- src/catalog/tde_keyring.c | 2 + src/common/pg_tde_utils.c | 14 +++++++ src/include/catalog/tde_global_space.h | 2 +- src/include/common/pg_tde_utils.h | 1 + src/include/pg_tde_fe.h | 14 +++++-- src/keyring/keyring_api.c | 6 +-- src/pg_tde.c | 4 +- 9 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/access/pg_tde_xlog_encrypt.c b/src/access/pg_tde_xlog_encrypt.c index 9016698e..dd5772ef 100644 --- a/src/access/pg_tde_xlog_encrypt.c +++ b/src/access/pg_tde_xlog_encrypt.c @@ -28,6 +28,10 @@ #include "catalog/tde_global_space.h" #include "encryption/enc_tde.h" +#ifdef FRONTEND +#include "pg_tde_fe.h" +#endif + static XLogPageHeaderData DecryptCurrentPageHrd; static void SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix); diff --git a/src/catalog/tde_global_space.c b/src/catalog/tde_global_space.c index 529e74d9..c56f123f 100644 --- a/src/catalog/tde_global_space.c +++ b/src/catalog/tde_global_space.c @@ -32,6 +32,7 @@ #define PRINCIPAL_KEY_DEFAULT_NAME "tde-global-catalog-key" #define KEYRING_DEFAULT_NAME "default_global_tablespace_keyring" +#define KEYRING_DEFAULT_FILE_NAME "pg_tde_default_keyring_CHANGE_AND_REMOVE_IT" #define DefaultKeyProvider GetKeyProviderByName(KEYRING_DEFAULT_NAME, \ GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) @@ -42,11 +43,11 @@ static void init_default_keyring(void); static TDEPrincipalKey * create_principal_key(const char *key_name, GenericKeyring * keyring, Oid dbOid, Oid spcOid); -#endif /* !FRONTEND */ +#endif /* !FRONTEND */ void -TDEInitGlobalKeys() +TDEInitGlobalKeys(const char *dir) { #ifndef FRONTEND char db_map_path[MAXPGPATH] = {0}; @@ -59,20 +60,23 @@ TDEInitGlobalKeys() init_keys(); } else -#endif /* !FRONTEND */ +#endif /* !FRONTEND */ { RelKeyData *ikey; - + + if (dir != NULL) + pg_tde_set_globalspace_dir(dir); ikey = pg_tde_get_key_from_file(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); /* - * Internal Key should be in the TopMemmoryContext because of SSL contexts. This - * context is being initialized by OpenSSL with the pointer to the encryption - * context which is valid only for the current backend. So new backends have to - * inherit a cached key with NULL SSL connext and any changes to it have to remain - * local ot the backend. - * (see https://github.com/Percona-Lab/pg_tde/pull/214#discussion_r1648998317) - */ + * Internal Key should be in the TopMemmoryContext because of SSL + * contexts. This context is being initialized by OpenSSL with the + * pointer to the encryption context which is valid only for the + * current backend. So new backends have to inherit a cached key with + * NULL SSL connext and any changes to it have to remain local ot the + * backend. (see + * https://github.com/Percona-Lab/pg_tde/pull/214#discussion_r1648998317) + */ pg_tde_put_key_into_map(XLOG_TDE_OID, ikey); } } @@ -84,18 +88,26 @@ init_default_keyring(void) { if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL) { + char path[MAXPGPATH] = {0}; static KeyringProvideRecord provider = { .provider_name = KEYRING_DEFAULT_NAME, .provider_type = FILE_KEY_PROVIDER, - .options = - "{" - "\"type\": \"file\"," - " \"path\": \"pg_tde_default_keyring_CHANGE_AND_REMOVE_IT\"" /* TODO: not sure about - * the location */ - "}" }; + if (getcwd(path, sizeof(path)) == NULL) + elog(WARNING, "unable to get current working dir"); + + /* TODO: not sure about the location. Currently it's in $PGDATA */ + join_path_components(path, path, KEYRING_DEFAULT_FILE_NAME); + + snprintf(provider.options, MAX_KEYRING_OPTION_LEN, + "{" + "\"type\": \"file\"," + "\"path\": \"%s\"" + "}", path + ); + /* * TODO: should we remove it automaticaly on * pg_tde_rotate_principal_key() ? @@ -111,11 +123,11 @@ init_default_keyring(void) /* * Create and store global space keys (principal and internal) and cache the * internal key. - * - * Since we always keep an Internal key in the memory for the global tablespace + * + * Since we always keep an Internal key in the memory for the global tablespace * and read it from disk once, only during the server start, we need no cache for * the principal key. - * + * * This function has to be run during the cluster start only, so no locks needed. */ static void @@ -173,7 +185,7 @@ create_principal_key(const char *key_name, GenericKeyring * keyring, principalKey->keyInfo.keyringId = keyring->key_id; strncpy(principalKey->keyInfo.keyId.name, key_name, TDE_KEY_NAME_LEN); snprintf(principalKey->keyInfo.keyId.versioned_name, TDE_KEY_NAME_LEN, - "%s_%d", principalKey->keyInfo.keyId.name, principalKey->keyInfo.keyId.version); + "%s_%d", principalKey->keyInfo.keyId.name, principalKey->keyInfo.keyId.version); gettimeofday(&principalKey->keyInfo.creationTime, NULL); keyInfo = KeyringGenerateNewKeyAndStore(keyring, principalKey->keyInfo.keyId.versioned_name, INTERNAL_KEY_LEN, false); @@ -189,6 +201,6 @@ create_principal_key(const char *key_name, GenericKeyring * keyring, return principalKey; } -#endif /* FRONTEND */ +#endif /* FRONTEND */ #endif /* PERCONA_EXT */ diff --git a/src/catalog/tde_keyring.c b/src/catalog/tde_keyring.c index 01d3254a..f1a47d59 100644 --- a/src/catalog/tde_keyring.c +++ b/src/catalog/tde_keyring.c @@ -506,6 +506,8 @@ scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oid dbOid, Oid #ifndef FRONTEND providers_list = lappend(providers_list, keyring); #else + if (providers_list == NULL) + providers_list = palloc(sizeof(providers_list)); simple_ptr_list_append(providers_list, keyring); #endif } diff --git a/src/common/pg_tde_utils.c b/src/common/pg_tde_utils.c index c1f190c4..c7768ff8 100644 --- a/src/common/pg_tde_utils.c +++ b/src/common/pg_tde_utils.c @@ -84,6 +84,15 @@ get_tde_tables_count(void) #endif /* !FRONTEND */ +static char globalspace_dir[MAXPGPATH] = {0}; + +void +pg_tde_set_globalspace_dir(const char *dir) +{ + Assert(dir != NULL); + strncpy(globalspace_dir, dir, sizeof(globalspace_dir)); +} + /* returns the palloc'd string */ char * pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) @@ -92,6 +101,11 @@ pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) * expects it (`dbOid`) to be `0` if this is a global space. */ if (spcOid == GLOBALTABLESPACE_OID) + { + if (strlen(globalspace_dir) > 0) + return pstrdup(globalspace_dir); + return pstrdup("global"); + } return GetDatabasePath(dbOid, spcOid); } diff --git a/src/include/catalog/tde_global_space.h b/src/include/catalog/tde_global_space.h index 43e14c95..669f3aa2 100644 --- a/src/include/catalog/tde_global_space.h +++ b/src/include/catalog/tde_global_space.h @@ -31,6 +31,6 @@ _obj_oid \ } -extern void TDEInitGlobalKeys(void); +extern void TDEInitGlobalKeys(const char *dir); #endif /* TDE_GLOBAL_CATALOG_H */ diff --git a/src/include/common/pg_tde_utils.h b/src/include/common/pg_tde_utils.h index 26edf8f9..bb0b3841 100644 --- a/src/include/common/pg_tde_utils.h +++ b/src/include/common/pg_tde_utils.h @@ -20,4 +20,5 @@ extern int get_tde_tables_count(void); #endif /* !FRONTEND */ extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid); +extern void pg_tde_set_globalspace_dir(const char *dir); #endif /*PG_TDE_UTILS_H*/ diff --git a/src/include/pg_tde_fe.h b/src/include/pg_tde_fe.h index 8862ef7d..029c434f 100644 --- a/src/include/pg_tde_fe.h +++ b/src/include/pg_tde_fe.h @@ -17,7 +17,6 @@ #include "common/logging.h" #include "common/file_perm.h" -// #pragma GCC diagnostic warning "-Wno-unused-value" #pragma GCC diagnostic ignored "-Wunused-macros" #pragma GCC diagnostic ignored "-Wunused-value" #pragma GCC diagnostic ignored "-Wunused-variable" @@ -46,16 +45,26 @@ #define errcode_for_file_access() NULL #define errcode(e) NULL +#define tde_error_handle_exit(elevel) \ + do { \ + if (elevel >= PANIC) \ + pg_unreachable(); \ + else if (elevel >= ERROR) \ + exit(1); \ + } while(0) + #define elog(elevel, fmt, ...) \ do { \ tde_fe_error_level = elevel; \ errmsg(fmt, ##__VA_ARGS__); \ + tde_error_handle_exit(elevel); \ } while(0) #define ereport(elevel,...) \ do { \ tde_fe_error_level = elevel; \ - __VA_ARGS__; \ + __VA_ARGS__; \ + tde_error_handle_exit(elevel); \ } while(0) static int tde_fe_error_level = 0; @@ -64,7 +73,6 @@ static int tde_fe_error_level = 0; * ------------- */ - #define LWLockAcquire(lock, mode) NULL #define LWLockRelease(lock_files) NULL #define LWLock void diff --git a/src/keyring/keyring_api.c b/src/keyring/keyring_api.c index cb702db0..24c9a060 100644 --- a/src/keyring/keyring_api.c +++ b/src/keyring/keyring_api.c @@ -25,7 +25,7 @@ typedef struct KeyProviders #ifndef FRONTEND List *registeredKeyProviders = NIL; #else -SimplePtrList *registeredKeyProviders = NULL; +SimplePtrList registeredKeyProviders = {NULL, NULL}; #endif static KeyProviders *find_key_provider(ProviderType type); @@ -49,7 +49,7 @@ static KeyProviders * find_key_provider(ProviderType type) { SimplePtrListCell *lc; - for (lc = registeredKeyProviders->head; lc; lc = lc->next) + for (lc = registeredKeyProviders.head; lc; lc = lc->next) { KeyProviders *kp = (KeyProviders *) lc->ptr; if (kp->type == type) @@ -88,7 +88,7 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type) registeredKeyProviders = lappend(registeredKeyProviders, kp); MemoryContextSwitchTo(oldcontext); #else - simple_ptr_list_append(registeredKeyProviders, kp); + simple_ptr_list_append(®isteredKeyProviders, kp); #endif return true; diff --git a/src/pg_tde.c b/src/pg_tde.c index 0f773de5..309e8a56 100644 --- a/src/pg_tde.c +++ b/src/pg_tde.c @@ -86,8 +86,8 @@ tde_shmem_startup(void) TdeShmemInit(); AesInit(); -#ifdef PERCONA_EXT - TDEInitGlobalKeys(); +#ifdef PERCONA_FORK + TDEInitGlobalKeys(NULL); TDEXLogShmemInit(); TDEXLogSmgrInit(); From 98287342a2847933b3de415b7b2058e0d5b5c564 Mon Sep 17 00:00:00 2001 From: Andrew Pogrebnoy Date: Tue, 3 Sep 2024 14:45:46 +0300 Subject: [PATCH 3/4] Add Xlog init macros for frontend --- src/catalog/tde_global_space.c | 3 ++- src/include/access/pg_tde_tdemap.h | 1 - src/include/access/pg_tde_xlog_encrypt_fe.h | 29 +++++++++++++++++++++ src/include/catalog/tde_global_space.h | 1 + src/include/pg_tde_fe.h | 3 ++- 5 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 src/include/access/pg_tde_xlog_encrypt_fe.h diff --git a/src/catalog/tde_global_space.c b/src/catalog/tde_global_space.c index c56f123f..56a600ae 100644 --- a/src/catalog/tde_global_space.c +++ b/src/catalog/tde_global_space.c @@ -63,9 +63,10 @@ TDEInitGlobalKeys(const char *dir) #endif /* !FRONTEND */ { RelKeyData *ikey; - + if (dir != NULL) pg_tde_set_globalspace_dir(dir); + ikey = pg_tde_get_key_from_file(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); /* diff --git a/src/include/access/pg_tde_tdemap.h b/src/include/access/pg_tde_tdemap.h index 0a6b632d..5260e9bd 100644 --- a/src/include/access/pg_tde_tdemap.h +++ b/src/include/access/pg_tde_tdemap.h @@ -12,7 +12,6 @@ #include "access/xlog_internal.h" #include "catalog/pg_tablespace_d.h" #include "catalog/tde_principal_key.h" -#include "storage/fd.h" #include "storage/relfilelocator.h" typedef struct InternalKey diff --git a/src/include/access/pg_tde_xlog_encrypt_fe.h b/src/include/access/pg_tde_xlog_encrypt_fe.h new file mode 100644 index 00000000..bc4c6718 --- /dev/null +++ b/src/include/access/pg_tde_xlog_encrypt_fe.h @@ -0,0 +1,29 @@ +/*------------------------------------------------------------------------- + * + * pg_tde_xlog_encrypt_fe.h + * Frontened definitions for encrypted XLog storage manager + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_TDE_XLOGENCRYPT_FE_H +#define PG_TDE_XLOGENCRYPT_FE_H + +#ifdef PERCONA_FORK +#include "access/pg_tde_xlog_encrypt.h" +#include "catalog/tde_global_space.h" +#include "encryption/enc_aes.h" +#include "keyring/keyring_file.h" +#include "keyring/keyring_vault.h" + +/* Frontend has to call it needs to read an encrypted XLog */ +#define TDE_XLOG_INIT(kring_dir) \ + AesInit(); \ + InstallFileKeyring(); \ + InstallVaultV2Keyring(); \ + TDEInitGlobalKeys(kring_dir); \ + TDEXLogSmgrInit() + +#endif /* PERCONA_FORK */ + +#endif /* PG_TDE_XLOGENCRYPT_FE_H */ \ No newline at end of file diff --git a/src/include/catalog/tde_global_space.h b/src/include/catalog/tde_global_space.h index 669f3aa2..42aaa0de 100644 --- a/src/include/catalog/tde_global_space.h +++ b/src/include/catalog/tde_global_space.h @@ -21,6 +21,7 @@ * We take Oids of the sql operators, so there is no overlap with the "real" * catalog objects possible. */ +#define GLOBAL_DATA_TDE_OID InvalidOid #define XLOG_TDE_OID 608 #define GLOBAL_DATA_TDE_OID InvalidOid diff --git a/src/include/pg_tde_fe.h b/src/include/pg_tde_fe.h index 029c434f..44f5c6a6 100644 --- a/src/include/pg_tde_fe.h +++ b/src/include/pg_tde_fe.h @@ -21,8 +21,9 @@ #pragma GCC diagnostic ignored "-Wunused-value" #pragma GCC diagnostic ignored "-Wunused-variable" #pragma GCC diagnostic ignored "-Wextra" + /* - * Errors handeling + * Errors handling * ---------------------------------------- */ From 0ef92bfadb668e04f150128e513f5eb3d026bca0 Mon Sep 17 00:00:00 2001 From: Andrew Pogrebnoy Date: Wed, 4 Sep 2024 15:07:21 +0300 Subject: [PATCH 4/4] Fix PERCONA_EXT renaming --- src/access/pg_tde_xlog_encrypt.c | 4 ++-- src/include/access/pg_tde_xlog_encrypt.h | 4 ++-- src/include/access/pg_tde_xlog_encrypt_fe.h | 4 ++-- src/pg_tde.c | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/access/pg_tde_xlog_encrypt.c b/src/access/pg_tde_xlog_encrypt.c index dd5772ef..539fdec9 100644 --- a/src/access/pg_tde_xlog_encrypt.c +++ b/src/access/pg_tde_xlog_encrypt.c @@ -12,7 +12,7 @@ #include "postgres.h" -#ifdef PERCONA_FORK +#ifdef PERCONA_EXT #include "pg_tde.h" #include "pg_tde_defines.h" #include "access/xlog.h" @@ -311,4 +311,4 @@ SetXLogPageIVPrefix(TimeLineID tli, XLogRecPtr lsn, char* iv_prefix) iv_prefix[11] = (lsn & 0xFF); } -#endif /* PERCONA_FORK */ \ No newline at end of file +#endif /* PERCONA_EXT */ \ No newline at end of file diff --git a/src/include/access/pg_tde_xlog_encrypt.h b/src/include/access/pg_tde_xlog_encrypt.h index 78295020..d8a9b474 100644 --- a/src/include/access/pg_tde_xlog_encrypt.h +++ b/src/include/access/pg_tde_xlog_encrypt.h @@ -10,7 +10,7 @@ #define PG_TDE_XLOGENCRYPT_H #include "postgres.h" -#ifdef PERCONA_FORK +#ifdef PERCONA_EXT #include "access/xlog_smgr.h" extern Size TDEXLogEncryptBuffSize(void); @@ -30,6 +30,6 @@ static const XLogSmgr tde_xlog_smgr = { extern void TDEXLogSmgrInit(void); extern void XLogInitGUC(void); -#endif /* PERCONA_FORK */ +#endif /* PERCONA_EXT */ #endif /* PG_TDE_XLOGENCRYPT_H */ \ No newline at end of file diff --git a/src/include/access/pg_tde_xlog_encrypt_fe.h b/src/include/access/pg_tde_xlog_encrypt_fe.h index bc4c6718..ea234cd0 100644 --- a/src/include/access/pg_tde_xlog_encrypt_fe.h +++ b/src/include/access/pg_tde_xlog_encrypt_fe.h @@ -9,7 +9,7 @@ #ifndef PG_TDE_XLOGENCRYPT_FE_H #define PG_TDE_XLOGENCRYPT_FE_H -#ifdef PERCONA_FORK +#ifdef PERCONA_EXT #include "access/pg_tde_xlog_encrypt.h" #include "catalog/tde_global_space.h" #include "encryption/enc_aes.h" @@ -24,6 +24,6 @@ TDEInitGlobalKeys(kring_dir); \ TDEXLogSmgrInit() -#endif /* PERCONA_FORK */ +#endif /* PERCONA_EXT */ #endif /* PG_TDE_XLOGENCRYPT_FE_H */ \ No newline at end of file diff --git a/src/pg_tde.c b/src/pg_tde.c index 309e8a56..bfeecf51 100644 --- a/src/pg_tde.c +++ b/src/pg_tde.c @@ -86,7 +86,7 @@ tde_shmem_startup(void) TdeShmemInit(); AesInit(); -#ifdef PERCONA_FORK +#ifdef PERCONA_EXT TDEInitGlobalKeys(NULL); TDEXLogShmemInit();