Merge pull request #214 from dAdAbird/xlog_key_mgmt

Add key management for WAL

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

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

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

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

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

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

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

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

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

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

Binary file not shown.

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

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

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

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

Loading…
Cancel
Save