Make related code compilable with frontend (#266)

* 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
pull/209/head
Andrew Pogrebnoi 1 year ago committed by GitHub
parent 19f722e403
commit bf4725fc46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      Makefile.in
  2. 2
      meson.build
  3. 1011
      src/access/pg_tde_tdemap.c
  4. 287
      src/access/pg_tde_xlog.c
  5. 314
      src/access/pg_tde_xlog_encrypt.c
  6. 55
      src/catalog/tde_global_space.c
  7. 548
      src/catalog/tde_keyring.c
  8. 5
      src/catalog/tde_keyring_parse_opts.c
  9. 262
      src/catalog/tde_principal_key.c
  10. 23
      src/common/pg_tde_utils.c
  11. 15
      src/encryption/enc_tde.c
  12. 1
      src/include/access/pg_tde_tdemap.h
  13. 30
      src/include/access/pg_tde_xlog.h
  14. 35
      src/include/access/pg_tde_xlog_encrypt.h
  15. 29
      src/include/access/pg_tde_xlog_encrypt_fe.h
  16. 3
      src/include/catalog/tde_global_space.h
  17. 8
      src/include/catalog/tde_principal_key.h
  18. 4
      src/include/common/pg_tde_utils.h
  19. 4
      src/include/keyring/keyring.h
  20. 18
      src/include/keyring/keyring_config.h
  21. 86
      src/include/pg_tde_fe.h
  22. 10
      src/keyring/keyring.c
  23. 37
      src/keyring/keyring_api.c
  24. 17
      src/keyring/keyring_config.c
  25. 3
      src/keyring/keyring_curl.c
  26. 8
      src/keyring/keyring_file.c
  27. 5
      src/keyring/keyring_vault.c
  28. 5
      src/pg_tde.c

@ -36,8 +36,8 @@ src$(MAJORVERSION)/access/pg_tde_rewrite.o \
src$(MAJORVERSION)/access/pg_tdeam_handler.o \ src$(MAJORVERSION)/access/pg_tdeam_handler.o \
src/access/pg_tde_ddl.o \ src/access/pg_tde_ddl.o \
src/access/pg_tde_xlog.o \ src/access/pg_tde_xlog.o \
src/access/pg_tde_xlog_encrypt.o \
src/transam/pg_tde_xact_handler.o \ src/transam/pg_tde_xact_handler.o \
src/keyring/keyring_config.o \
src/keyring/keyring_curl.o \ src/keyring/keyring_curl.o \
src/keyring/keyring_file.o \ src/keyring/keyring_file.o \
src/keyring/keyring_vault.o \ src/keyring/keyring_vault.o \

@ -32,11 +32,11 @@ pg_tde_sources = files(
src_version / 'access/pg_tde_visibilitymap.c', src_version / 'access/pg_tde_visibilitymap.c',
'src/access/pg_tde_ddl.c', 'src/access/pg_tde_ddl.c',
'src/access/pg_tde_xlog.c', 'src/access/pg_tde_xlog.c',
'src/access/pg_tde_xlog_encrypt.c',
'src/encryption/enc_tde.c', 'src/encryption/enc_tde.c',
'src/encryption/enc_aes.c', 'src/encryption/enc_aes.c',
'src/keyring/keyring_config.c',
'src/keyring/keyring_curl.c', 'src/keyring/keyring_curl.c',
'src/keyring/keyring_file.c', 'src/keyring/keyring_file.c',
'src/keyring/keyring_vault.c', 'src/keyring/keyring_vault.c',

File diff suppressed because it is too large Load Diff

@ -24,24 +24,8 @@
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "access/pg_tde_tdemap.h"
#include "access/pg_tde_xlog.h" #include "access/pg_tde_xlog.h"
#include "encryption/enc_tde.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 * TDE fork XLog
@ -139,274 +123,3 @@ tdeheap_rmgr_identify(uint8 info)
return NULL; 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

@ -0,0 +1,314 @@
/*-------------------------------------------------------------------------
*
* pg_tde_xlog_encrypt.c
* Encrypted XLog storage manager
*
*
* IDENTIFICATION
* src/access/pg_tde_xlog_encrypt.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#ifdef PERCONA_EXT
#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"
#ifdef FRONTEND
#include "pg_tde_fe.h"
#endif
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_EXT */

@ -15,15 +15,16 @@
#ifdef PERCONA_EXT #ifdef PERCONA_EXT
#include "catalog/pg_tablespace_d.h" #include "catalog/pg_tablespace_d.h"
#include "nodes/pg_list.h"
#include "storage/shmem.h"
#include "utils/guc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "access/pg_tde_tdemap.h" #include "access/pg_tde_tdemap.h"
#include "catalog/tde_global_space.h" #include "catalog/tde_global_space.h"
#include "catalog/tde_keyring.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 <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -31,19 +32,24 @@
#define PRINCIPAL_KEY_DEFAULT_NAME "tde-global-catalog-key" #define PRINCIPAL_KEY_DEFAULT_NAME "tde-global-catalog-key"
#define KEYRING_DEFAULT_NAME "default_global_tablespace_keyring" #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, \ #define DefaultKeyProvider GetKeyProviderByName(KEYRING_DEFAULT_NAME, \
GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID)
#ifndef FRONTEND
static void init_keys(void); static void init_keys(void);
static void init_default_keyring(void); static void init_default_keyring(void);
static TDEPrincipalKey * create_principal_key(const char *key_name, static TDEPrincipalKey * create_principal_key(const char *key_name,
GenericKeyring * keyring, Oid dbOid, GenericKeyring * keyring, Oid dbOid,
Oid spcOid); Oid spcOid);
#endif /* !FRONTEND */
void void
TDEInitGlobalKeys(void) TDEInitGlobalKeys(const char *dir)
{ {
#ifndef FRONTEND
char db_map_path[MAXPGPATH] = {0}; char db_map_path[MAXPGPATH] = {0};
pg_tde_set_db_file_paths(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID), pg_tde_set_db_file_paths(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID),
@ -54,39 +60,54 @@ TDEInitGlobalKeys(void)
init_keys(); init_keys();
} }
else else
#endif /* !FRONTEND */
{ {
RelKeyData *ikey; RelKeyData *ikey;
if (dir != NULL)
pg_tde_set_globalspace_dir(dir);
ikey = pg_tde_get_key_from_file(&GLOBAL_SPACE_RLOCATOR(XLOG_TDE_OID)); 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 * Internal Key should be in the TopMemmoryContext because of SSL
* context is being initialized by OpenSSL with the pointer to the encryption * contexts. This context is being initialized by OpenSSL with the
* context which is valid only for the current backend. So new backends have to * pointer to the encryption context which is valid only for the
* inherit a cached key with NULL SSL connext and any changes to it have to remain * current backend. So new backends have to inherit a cached key with
* local ot the backend. * NULL SSL connext and any changes to it have to remain local ot the
* (see https://github.com/Percona-Lab/pg_tde/pull/214#discussion_r1648998317) * backend. (see
* https://github.com/Percona-Lab/pg_tde/pull/214#discussion_r1648998317)
*/ */
pg_tde_put_key_into_map(XLOG_TDE_OID, ikey); pg_tde_put_key_into_map(XLOG_TDE_OID, ikey);
} }
} }
#ifndef FRONTEND
static void static void
init_default_keyring(void) init_default_keyring(void)
{ {
if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL) if (GetAllKeyringProviders(GLOBAL_DATA_TDE_OID, GLOBALTABLESPACE_OID) == NIL)
{ {
char path[MAXPGPATH] = {0};
static KeyringProvideRecord provider = static KeyringProvideRecord provider =
{ {
.provider_name = KEYRING_DEFAULT_NAME, .provider_name = KEYRING_DEFAULT_NAME,
.provider_type = FILE_KEY_PROVIDER, .provider_type = FILE_KEY_PROVIDER,
.options = };
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\"," "\"type\": \"file\","
" \"path\": \"pg_tde_default_keyring_CHANGE_AND_REMOVE_IT\"" /* TODO: not sure about "\"path\": \"%s\""
* the location */ "}", path
"}" );
};
/* /*
* TODO: should we remove it automaticaly on * TODO: should we remove it automaticaly on
@ -181,4 +202,6 @@ create_principal_key(const char *key_name, GenericKeyring * keyring,
return principalKey; return principalKey;
} }
#endif /* FRONTEND */
#endif /* PERCONA_EXT */ #endif /* PERCONA_EXT */

@ -10,7 +10,6 @@
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include "funcapi.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "access/xloginsert.h" #include "access/xloginsert.h"
#include "access/pg_tde_xlog.h" #include "access/pg_tde_xlog.h"
@ -18,29 +17,27 @@
#include "catalog/tde_keyring.h" #include "catalog/tde_keyring.h"
#include "catalog/tde_principal_key.h" #include "catalog/tde_principal_key.h"
#include "access/skey.h" #include "access/skey.h"
#include "access/relscan.h"
#include "access/relation.h"
#include "catalog/namespace.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "access/heapam.h"
#include "utils/snapmgr.h" #include "utils/snapmgr.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "common/pg_tde_utils.h" #include "common/pg_tde_utils.h"
#include "common/pg_tde_shmem.h"
#include "executor/spi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "unistd.h" #include "unistd.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "pg_tde.h" #include "pg_tde.h"
PG_FUNCTION_INFO_V1(pg_tde_add_key_provider_internal); #ifndef FRONTEND
Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS); #include "access/heapam.h"
#include "common/pg_tde_shmem.h"
PG_FUNCTION_INFO_V1(pg_tde_list_all_key_providers); #include "funcapi.h"
Datum pg_tde_list_all_key_providers(PG_FUNCTION_ARGS); #include "access/relscan.h"
#include "access/relation.h"
#define PG_TDE_KEYRING_FILENAME "pg_tde_keyrings" #include "catalog/namespace.h"
#define PG_TDE_LIST_PROVIDERS_COLS 4 #include "executor/spi.h"
#else
#include "fe_utils/simple_list.h"
#include "pg_tde_fe.h"
#endif /* !FRONTEND */
typedef enum ProviderScanType typedef enum ProviderScanType
{ {
@ -50,13 +47,33 @@ typedef enum ProviderScanType
PROVIDER_SCAN_ALL PROVIDER_SCAN_ALL
} ProviderScanType; } 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 FileKeyring *load_file_keyring_provider_options(char *keyring_options);
static GenericKeyring *load_keyring_provider_options(ProviderType provider_type, 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 VaultV2Keyring *load_vaultV2_keyring_provider_options(char *keyring_options);
static void debug_print_kerying(GenericKeyring *keyring); 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 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 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 const char *get_keyring_provider_typename(ProviderType p_type);
static uint32 write_key_provider_info(KeyringProvideRecord *provider, static uint32 write_key_provider_info(KeyringProvideRecord *provider,
@ -148,22 +165,6 @@ get_keyring_provider_typename(ProviderType p_type)
return NULL; 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 * List *
GetAllKeyringProviders(Oid dbOid, Oid spcOid) GetAllKeyringProviders(Oid dbOid, Oid spcOid)
{ {
@ -190,140 +191,6 @@ GetKeyProviderByName(const char *provider_name, Oid dbOid, Oid spcOid)
return keyring; 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 static uint32
write_key_provider_info(KeyringProvideRecord *provider, Oid database_id, write_key_provider_info(KeyringProvideRecord *provider, Oid database_id,
@ -436,16 +303,160 @@ 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); return write_key_provider_info(&xlrec->provider, xlrec->database_id, xlrec->tablespace_id, xlrec->offset_in_file, true, false);
} }
void
cleanup_key_provider_info(Oid databaseId, Oid tablespaceId)
{
/* Remove the key provider info file */
char kp_info_path[MAXPGPATH] = {0};
get_keyring_infofile_path(kp_info_path, databaseId, tablespaceId);
PathNameDeleteTemporaryFile(kp_info_path, false);
}
Datum
pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS)
{
char *provider_type = text_to_cstring(PG_GETARG_TEXT_PP(0));
char *provider_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
char *options = text_to_cstring(PG_GETARG_TEXT_PP(2));
bool is_global = PG_GETARG_BOOL(3);
KeyringProvideRecord provider;
Oid dbOid = MyDatabaseId;
Oid spcOid = MyDatabaseTableSpace;
if (is_global)
{
dbOid = GLOBAL_DATA_TDE_OID;
spcOid = GLOBALTABLESPACE_OID;
}
strncpy(provider.options, options, sizeof(provider.options));
strncpy(provider.provider_name, provider_name, sizeof(provider.provider_name));
provider.provider_type = get_keyring_provider_from_typename(provider_type);
save_new_key_provider_info(&provider, dbOid, spcOid, false);
PG_RETURN_INT32(provider.provider_id);
}
Datum
pg_tde_list_all_key_providers(PG_FUNCTION_ARGS)
{
List* all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace);
ListCell *lc;
Tuplestorestate *tupstore;
TupleDesc tupdesc;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo;
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("pg_tde_list_all_key_providers: set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("pg_tde_list_all_key_providers: materialize mode required, but it is not allowed in this context")));
/* Switch into long-lived context to construct returned data structures */
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "pg_tde_list_all_key_providers: return type must be a row type");
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
foreach (lc, all_providers)
{
Datum values[PG_TDE_LIST_PROVIDERS_COLS] = {0};
bool nulls[PG_TDE_LIST_PROVIDERS_COLS] = {0};
GenericKeyring *keyring = (GenericKeyring *)lfirst(lc);
int i = 0;
values[i++] = Int32GetDatum(keyring->key_id);
values[i++] = CStringGetTextDatum(keyring->provider_name);
values[i++] = CStringGetTextDatum(get_keyring_provider_typename(keyring->type));
values[i++] = CStringGetTextDatum(keyring->options);
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
debug_print_kerying(keyring);
}
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 * 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) #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; off_t curr_pos = 0;
int fd; int fd;
char kp_info_path[MAXPGPATH] = {0}; char kp_info_path[MAXPGPATH] = {0};
KeyringProvideRecord provider; KeyringProvideRecord provider;
#ifndef FRONTEND
List *providers_list = NIL; List *providers_list = NIL;
#else
SimplePtrList *providers_list = NULL;
#endif
if (scanType != PROVIDER_SCAN_ALL) if (scanType != PROVIDER_SCAN_ALL)
Assert(scanKey != NULL); Assert(scanKey != NULL);
@ -461,7 +472,7 @@ static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oi
ereport(DEBUG2, ereport(DEBUG2,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open tde file \"%s\": %m", kp_info_path))); errmsg("could not open tde file \"%s\": %m", kp_info_path)));
return NIL; return providers_list;
} }
while (fetch_next_key_provider(fd, &curr_pos, &provider)) while (fetch_next_key_provider(fd, &curr_pos, &provider))
{ {
@ -492,7 +503,13 @@ static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oi
GenericKeyring *keyring = load_keyring_provider_from_record(&provider); GenericKeyring *keyring = load_keyring_provider_from_record(&provider);
if (keyring) if (keyring)
{ {
#ifndef FRONTEND
providers_list = lappend(providers_list, keyring); 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
} }
} }
} }
@ -501,101 +518,152 @@ static List *scan_key_provider_file(ProviderScanType scanType, void *scanKey, Oi
return providers_list; return providers_list;
} }
void static GenericKeyring *
cleanup_key_provider_info(Oid databaseId, Oid tablespaceId) load_keyring_provider_from_record(KeyringProvideRecord *provider)
{ {
/* Remove the key provider info file */ GenericKeyring *keyring = NULL;
char kp_info_path[MAXPGPATH] = {0};
get_keyring_infofile_path(kp_info_path, databaseId, tablespaceId); keyring = load_keyring_provider_options(provider->provider_type, provider->options);
PathNameDeleteTemporaryFile(kp_info_path, false); 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 char*
get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid) static GenericKeyring *
load_keyring_provider_options(ProviderType provider_type, char *keyring_options)
{ {
char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid); switch (provider_type)
Assert(db_path != NULL); {
join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME); case FILE_KEY_PROVIDER:
pfree(db_path); return (GenericKeyring *)load_file_keyring_provider_options(keyring_options);
return resPath; break;
case VAULT_V2_KEY_PROVIDER:
return (GenericKeyring *)load_vaultV2_keyring_provider_options(keyring_options);
break;
default:
break;
}
return NULL;
} }
Datum static FileKeyring *
pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS) load_file_keyring_provider_options(char *keyring_options)
{ {
char *provider_type = text_to_cstring(PG_GETARG_TEXT_PP(0)); FileKeyring *file_keyring = palloc0(sizeof(FileKeyring));
char *provider_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
char *options = text_to_cstring(PG_GETARG_TEXT_PP(2));
bool is_global = PG_GETARG_BOOL(3);
KeyringProvideRecord provider;
Oid dbOid = MyDatabaseId;
Oid spcOid = MyDatabaseTableSpace;
if (is_global) file_keyring->keyring.type = FILE_KEY_PROVIDER;
if (!ParseKeyringJSONOptions(FILE_KEY_PROVIDER, file_keyring,
keyring_options, strlen(keyring_options)))
{ {
dbOid = GLOBAL_DATA_TDE_OID; return NULL;
spcOid = GLOBALTABLESPACE_OID;
} }
strncpy(provider.options, options, sizeof(provider.options)); if(strlen(file_keyring->file_name) == 0)
strncpy(provider.provider_name, provider_name, sizeof(provider.provider_name)); {
provider.provider_type = get_keyring_provider_from_typename(provider_type); ereport(WARNING,
save_new_key_provider_info(&provider, dbOid, spcOid, false); (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("file path is missing in the keyring options")));
return NULL;
}
PG_RETURN_INT32(provider.provider_id); return file_keyring;
} }
Datum static VaultV2Keyring *
pg_tde_list_all_key_providers(PG_FUNCTION_ARGS) load_vaultV2_keyring_provider_options(char *keyring_options)
{ {
List* all_providers = GetAllKeyringProviders(MyDatabaseId, MyDatabaseTableSpace); VaultV2Keyring *vaultV2_keyring = palloc0(sizeof(VaultV2Keyring));
ListCell *lc;
Tuplestorestate *tupstore;
TupleDesc tupdesc;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo;
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("pg_tde_list_all_key_providers: set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("pg_tde_list_all_key_providers: materialize mode required, but it is not allowed in this context")));
/* Switch into long-lived context to construct returned data structures */ vaultV2_keyring->keyring.type = VAULT_V2_KEY_PROVIDER;
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
/* Build a tuple descriptor for our result type */ if (!ParseKeyringJSONOptions(VAULT_V2_KEY_PROVIDER, vaultV2_keyring,
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) keyring_options, strlen(keyring_options)))
elog(ERROR, "pg_tde_list_all_key_providers: return type must be a row type"); {
return NULL;
}
tupstore = tuplestore_begin_heap(true, false, work_mem); if(strlen(vaultV2_keyring->vault_token) == 0 ||
rsinfo->returnMode = SFRM_Materialize; strlen(vaultV2_keyring->vault_url) == 0 ||
rsinfo->setResult = tupstore; strlen(vaultV2_keyring->vault_mount_path) == 0)
rsinfo->setDesc = tupdesc; {
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;
}
MemoryContextSwitchTo(oldcontext); return vaultV2_keyring;
}
foreach (lc, all_providers) 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)
{ {
Datum values[PG_TDE_LIST_PROVIDERS_COLS] = {0}; case FILE_KEY_PROVIDER:
bool nulls[PG_TDE_LIST_PROVIDERS_COLS] = {0}; elog(debug_level, "File Keyring Path: %s", ((FileKeyring *)keyring)->file_name);
GenericKeyring *keyring = (GenericKeyring *)lfirst(lc); break;
int i = 0; 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;
}
}
values[i++] = Int32GetDatum(keyring->key_id); static char*
values[i++] = CStringGetTextDatum(keyring->provider_name); get_keyring_infofile_path(char* resPath, Oid dbOid, Oid spcOid)
values[i++] = CStringGetTextDatum(get_keyring_provider_typename(keyring->type)); {
values[i++] = CStringGetTextDatum(keyring->options); char *db_path = pg_tde_get_tde_file_dir(dbOid, spcOid);
tuplestore_putvalues(tupstore, tupdesc, values, nulls); Assert(db_path != NULL);
join_path_components(resPath, db_path, PG_TDE_KEYRING_FILENAME);
pfree(db_path);
return resPath;
}
debug_print_kerying(keyring); /*
* 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) )));
} }
list_free_deep(all_providers); return true;
return (Datum)0;
} }

@ -23,6 +23,7 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "common/file_perm.h"
#include "common/jsonapi.h" #include "common/jsonapi.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "storage/fd.h" #include "storage/fd.h"
@ -30,6 +31,10 @@
#include "catalog/tde_keyring.h" #include "catalog/tde_keyring.h"
#include "keyring/keyring_curl.h" #include "keyring/keyring_curl.h"
#ifdef FRONTEND
#include "pg_tde_fe.h"
#endif
#include <unistd.h> #include <unistd.h>
#define MAX_CONFIG_FILE_DATA_LENGTH 1024 #define MAX_CONFIG_FILE_DATA_LENGTH 1024

@ -13,8 +13,6 @@
#include "access/xlog.h" #include "access/xlog.h"
#include "access/xloginsert.h" #include "access/xloginsert.h"
#include "catalog/tde_principal_key.h" #include "catalog/tde_principal_key.h"
#include "common/pg_tde_shmem.h"
#include "storage/lwlock.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "utils/palloc.h" #include "utils/palloc.h"
#include "utils/memutils.h" #include "utils/memutils.h"
@ -22,14 +20,22 @@
#include "utils/timestamp.h" #include "utils/timestamp.h"
#include "common/relpath.h" #include "common/relpath.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "funcapi.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "pg_tde.h" #include "pg_tde.h"
#include "access/pg_tde_xlog.h" #include "access/pg_tde_xlog.h"
#include <sys/time.h>
#include "access/pg_tde_tdemap.h" #include "access/pg_tde_tdemap.h"
#include "catalog/tde_global_space.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 <sys/time.h>
#ifndef FRONTEND
typedef struct TdePrincipalKeySharedState typedef struct TdePrincipalKeySharedState
{ {
@ -206,125 +212,6 @@ save_principal_key_info(TDEPrincipalKeyInfo *principal_key_info)
return pg_tde_save_principal_key(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: * SetPrincipalkey:
* We need to ensure that only one principal key is set for a database. * 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); 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;
}

@ -10,13 +10,16 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/pg_tablespace_d.h" #include "catalog/pg_tablespace_d.h"
#include "utils/snapmgr.h" #include "utils/snapmgr.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "common/pg_tde_utils.h" #include "common/pg_tde_utils.h"
#ifndef FRONTEND
#include "access/genam.h"
#include "access/heapam.h"
Oid Oid
get_tde_basic_table_am_oid(void) get_tde_basic_table_am_oid(void)
{ {
@ -79,6 +82,17 @@ get_tde_tables_count(void)
return count; return count;
} }
#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 */ /* returns the palloc'd string */
char * char *
pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid) pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid)
@ -87,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. * expects it (`dbOid`) to be `0` if this is a global space.
*/ */
if (spcOid == GLOBALTABLESPACE_OID) if (spcOid == GLOBALTABLESPACE_OID)
{
if (strlen(globalspace_dir) > 0)
return pstrdup(globalspace_dir);
return pstrdup("global"); return pstrdup("global");
}
return GetDatabasePath(dbOid, spcOid); return GetDatabasePath(dbOid, spcOid);
} }

@ -163,6 +163,7 @@ pg_tde_crypt(const char* iv_prefix, uint32 start_offset, const char* data, uint3
} }
} }
#ifndef FRONTEND
/* /*
* pg_tde_crypt_tuple: * pg_tde_crypt_tuple:
* Does the encryption/decryption of tuple data in place * 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); 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. * Provide a simple interface to decrypt a given key.
* *
@ -264,7 +267,17 @@ void AesDecryptKey(const TDEPrincipalKey *principal_key, const RelFileLocator *r
memcpy(iv, &rlocator->spcOid, sizeof(Oid)); memcpy(iv, &rlocator->spcOid, sizeof(Oid));
memcpy(iv + sizeof(Oid), &rlocator->dbOid, 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 */ /* Fill in the structure */
memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData)); memcpy(*p_rel_key_data, enc_rel_key_data, sizeof(RelKeyData));

@ -12,7 +12,6 @@
#include "access/xlog_internal.h" #include "access/xlog_internal.h"
#include "catalog/pg_tablespace_d.h" #include "catalog/pg_tablespace_d.h"
#include "catalog/tde_principal_key.h" #include "catalog/tde_principal_key.h"
#include "storage/fd.h"
#include "storage/relfilelocator.h" #include "storage/relfilelocator.h"
typedef struct InternalKey typedef struct InternalKey

@ -9,12 +9,11 @@
#ifndef PG_TDE_XLOG_H #ifndef PG_TDE_XLOG_H
#define PG_TDE_XLOG_H #define PG_TDE_XLOG_H
#ifndef FRONTEND
#include "postgres.h" #include "postgres.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "access/xlog_internal.h" #include "access/xlog_internal.h"
#ifdef PERCONA_EXT
#include "access/xlog_smgr.h"
#endif
/* TDE XLOG resource manager */ /* TDE XLOG resource manager */
#define XLOG_TDE_ADD_RELATION_KEY 0x00 #define XLOG_TDE_ADD_RELATION_KEY 0x00
@ -38,28 +37,5 @@ static const RmgrData tdeheap_rmgr = {
.rm_identify = tdeheap_rmgr_identify .rm_identify = tdeheap_rmgr_identify
}; };
#ifdef PERCONA_EXT #endif /* !FRONTEND */
/* 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 /* PG_TDE_XLOG_H */ #endif /* PG_TDE_XLOG_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_EXT
#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_EXT */
#endif /* PG_TDE_XLOGENCRYPT_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_EXT
#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_EXT */
#endif /* PG_TDE_XLOGENCRYPT_FE_H */

@ -21,6 +21,7 @@
* We take Oids of the sql operators, so there is no overlap with the "real" * We take Oids of the sql operators, so there is no overlap with the "real"
* catalog objects possible. * catalog objects possible.
*/ */
#define GLOBAL_DATA_TDE_OID InvalidOid
#define XLOG_TDE_OID 608 #define XLOG_TDE_OID 608
#define GLOBAL_DATA_TDE_OID InvalidOid #define GLOBAL_DATA_TDE_OID InvalidOid
@ -31,6 +32,6 @@
_obj_oid \ _obj_oid \
} }
extern void TDEInitGlobalKeys(void); extern void TDEInitGlobalKeys(const char *dir);
#endif /* TDE_GLOBAL_CATALOG_H */ #endif /* TDE_GLOBAL_CATALOG_H */

@ -15,7 +15,9 @@
#include "catalog/tde_keyring.h" #include "catalog/tde_keyring.h"
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#ifndef FRONTEND
#include "storage/lwlock.h" #include "storage/lwlock.h"
#endif
#define DEFAULT_PRINCIPAL_KEY_VERSION 1 #define DEFAULT_PRINCIPAL_KEY_VERSION 1
#define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN #define PRINCIPAL_KEY_NAME_LEN TDE_KEY_NAME_LEN
@ -57,8 +59,14 @@ typedef struct XLogPrincipalKeyRotate
extern void InitializePrincipalKeyInfo(void); extern void InitializePrincipalKeyInfo(void);
extern void cleanup_principal_key_info(Oid databaseId, Oid tablespaceId); extern void cleanup_principal_key_info(Oid databaseId, Oid tablespaceId);
#ifndef FRONTEND
extern LWLock *tde_lwlock_mk_files(void); extern LWLock *tde_lwlock_mk_files(void);
extern LWLock *tde_lwlock_mk_cache(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); extern bool save_principal_key_info(TDEPrincipalKeyInfo *principalKeyInfo);

@ -9,12 +9,16 @@
#define PG_TDE_UTILS_H #define PG_TDE_UTILS_H
#include "postgres.h" #include "postgres.h"
#ifndef FRONTEND
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
extern Oid get_tde_basic_table_am_oid(void); extern Oid get_tde_basic_table_am_oid(void);
extern Oid get_tde_table_am_oid(void); extern Oid get_tde_table_am_oid(void);
extern List *get_all_tde_tables(void); extern List *get_all_tde_tables(void);
extern int get_tde_tables_count(void); extern int get_tde_tables_count(void);
#endif /* !FRONTEND */
extern char *pg_tde_get_tde_file_dir(Oid dbOid, Oid spcOid); 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*/ #endif /*PG_TDE_UTILS_H*/

@ -1,4 +0,0 @@
#pragma once
void keyringInitialize(void);

@ -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

@ -0,0 +1,86 @@
/*-------------------------------------------------------------------------
*
* 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 ignored "-Wunused-macros"
#pragma GCC diagnostic ignored "-Wunused-value"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wextra"
/*
* Errors handling
* ----------------------------------------
*/
#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 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__; \
tde_error_handle_exit(elevel); \
} 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 */

@ -1,10 +0,0 @@
#include "keyring/keyring.h"
#include "keyring/keyring_config.h"
#include "keyring/keyring_api.h"
void keyringInitialize(void)
{
keyringRegisterVariables();
keyringInitializeCache();
}

@ -2,13 +2,16 @@
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#include "keyring/keyring_file.h" #include "keyring/keyring_file.h"
#include "keyring/keyring_vault.h" #include "keyring/keyring_vault.h"
#include "keyring/keyring_config.h"
#include "postgres.h" #include "postgres.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "storage/shmem.h" #include "storage/shmem.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#ifdef FRONTEND
#include "fe_utils/simple_list.h"
#include "pg_tde_fe.h"
#endif
#include <assert.h> #include <assert.h>
#include <openssl/rand.h> #include <openssl/rand.h>
@ -19,9 +22,14 @@ typedef struct KeyProviders
ProviderType type; ProviderType type;
} KeyProviders; } KeyProviders;
#ifndef FRONTEND
List *registeredKeyProviders = NIL; List *registeredKeyProviders = NIL;
#else
SimplePtrList registeredKeyProviders = {NULL, NULL};
#endif
static KeyProviders *find_key_provider(ProviderType type); static KeyProviders *find_key_provider(ProviderType type);
#ifndef FRONTEND
static KeyProviders * static KeyProviders *
find_key_provider(ProviderType type) find_key_provider(ProviderType type)
{ {
@ -36,9 +44,25 @@ find_key_provider(ProviderType type)
} }
return NULL; 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) bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
{ {
MemoryContext oldcontext;
KeyProviders *kp; KeyProviders *kp;
Assert(routine != NULL); Assert(routine != NULL);
@ -52,12 +76,21 @@ bool RegisterKeyProvider(const TDEKeyringRoutine *routine, ProviderType type)
(errmsg("Key provider of type %d already registered", type))); (errmsg("Key provider of type %d already registered", type)));
return false; return false;
} }
#ifndef FRONTEND
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
#endif
kp = palloc(sizeof(KeyProviders)); kp = palloc(sizeof(KeyProviders));
kp->routine = (TDEKeyringRoutine *)routine; kp->routine = (TDEKeyringRoutine *)routine;
kp->type = type; kp->type = type;
#ifndef FRONTEND
registeredKeyProviders = lappend(registeredKeyProviders, kp); registeredKeyProviders = lappend(registeredKeyProviders, kp);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
#else
simple_ptr_list_append(&registeredKeyProviders, kp);
#endif
return true; return true;
} }

@ -1,17 +0,0 @@
#include "keyring/keyring_config.h"
#include "keyring/keyring_file.h"
#include "keyring/keyring_vault.h"
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include "utils/guc.h"
enum KeyringProvider keyringProvider = PROVIDER_UNKNOWN;
void keyringRegisterVariables(void)
{
// nop for now
}

@ -9,8 +9,9 @@
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h"
#include "keyring/keyring_curl.h" #include "keyring/keyring_curl.h"
#include "keyring/keyring_config.h"
#include "pg_tde_defines.h" #include "pg_tde_defines.h"
CURL* keyringCurl = NULL; CURL* keyringCurl = NULL;

@ -13,11 +13,16 @@
#include "postgres.h" #include "postgres.h"
#include "keyring/keyring_file.h" #include "keyring/keyring_file.h"
#include "keyring/keyring_config.h"
#include "catalog/tde_keyring.h" #include "catalog/tde_keyring.h"
#include "common/file_perm.h"
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "utils/wait_event.h" #include "utils/wait_event.h"
#ifdef FRONTEND
#include "pg_tde_fe.h"
#endif
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -131,6 +136,7 @@ set_key_by_name(GenericKeyring* keyring, keyInfo *key, bool throw_error)
file_keyring->file_name))); file_keyring->file_name)));
return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE; return KEYRING_CODE_RESOURCE_NOT_ACCESSABLE;
} }
if (pg_fsync(fd) != 0) if (pg_fsync(fd) != 0)
{ {
close(fd); close(fd);

@ -12,7 +12,6 @@
#include "postgres.h" #include "postgres.h"
#include "keyring/keyring_vault.h" #include "keyring/keyring_vault.h"
#include "keyring/keyring_config.h"
#include "keyring/keyring_curl.h" #include "keyring/keyring_curl.h"
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#include "pg_tde_defines.h" #include "pg_tde_defines.h"
@ -26,6 +25,10 @@
#include "common/base64.h" #include "common/base64.h"
#ifdef FRONTEND
#include "pg_tde_fe.h"
#endif
/* /*
* JSON parser state * JSON parser state
*/ */

@ -20,11 +20,11 @@
#include "storage/shmem.h" #include "storage/shmem.h"
#include "access/pg_tde_ddl.h" #include "access/pg_tde_ddl.h"
#include "access/pg_tde_xlog.h" #include "access/pg_tde_xlog.h"
#include "access/pg_tde_xlog_encrypt.h"
#include "encryption/enc_aes.h" #include "encryption/enc_aes.h"
#include "access/pg_tde_tdemap.h" #include "access/pg_tde_tdemap.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "access/xloginsert.h" #include "access/xloginsert.h"
#include "keyring/keyring_config.h"
#include "keyring/keyring_api.h" #include "keyring/keyring_api.h"
#include "common/pg_tde_shmem.h" #include "common/pg_tde_shmem.h"
#include "common/pg_tde_utils.h" #include "common/pg_tde_utils.h"
@ -87,7 +87,7 @@ tde_shmem_startup(void)
AesInit(); AesInit();
#ifdef PERCONA_EXT #ifdef PERCONA_EXT
TDEInitGlobalKeys(); TDEInitGlobalKeys(NULL);
TDEXLogShmemInit(); TDEXLogShmemInit();
TDEXLogSmgrInit(); TDEXLogSmgrInit();
@ -102,7 +102,6 @@ _PG_init(void)
elog(WARNING, "pg_tde can only be loaded at server startup. Restart required."); elog(WARNING, "pg_tde can only be loaded at server startup. Restart required.");
} }
keyringRegisterVariables();
InitializePrincipalKeyInfo(); InitializePrincipalKeyInfo();
InitializeKeyProviderInfo(); InitializeKeyProviderInfo();
#ifdef PERCONA_EXT #ifdef PERCONA_EXT

Loading…
Cancel
Save