From e0948d05e8ab52025072fedcb67e4faf784407a3 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Fri, 28 Jun 2019 18:10:53 +0900 Subject: [PATCH 8/9] Support tablespace encryption. User can create encryption enabled tablespaces using 'encryption' option for tablespace. All database relation such as tables, indexes, TOAST tables and WAL are encrypted transparently if it pertains to an encrypted tablespace. --- src/backend/access/common/reloptions.c | 12 ++++++++- src/backend/commands/tablespace.c | 45 ++++++++++++++++++++++++++++++++-- src/backend/storage/file/copydir.c | 2 +- src/backend/utils/cache/spccache.c | 16 ++++++++++++ src/include/commands/tablespace.h | 1 + src/include/utils/spccache.h | 1 + 6 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 5773021..9ee6ce5 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -158,6 +158,15 @@ static relopt_bool boolRelOpts[] = }, true }, + { + { + "encryption", + "Enables transparent encryption", + RELOPT_KIND_TABLESPACE, + ShareUpdateExclusiveLock + }, + false + }, /* list terminator */ {{NULL}} }; @@ -1559,7 +1568,8 @@ tablespace_reloptions(Datum reloptions, bool validate) static const relopt_parse_elt tab[] = { {"random_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, random_page_cost)}, {"seq_page_cost", RELOPT_TYPE_REAL, offsetof(TableSpaceOpts, seq_page_cost)}, - {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)} + {"effective_io_concurrency", RELOPT_TYPE_INT, offsetof(TableSpaceOpts, effective_io_concurrency)}, + {"encryption", RELOPT_TYPE_BOOL, offsetof(TableSpaceOpts, encryption)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_TABLESPACE, diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c index 5e43867..6f55086 100644 --- a/src/backend/commands/tablespace.c +++ b/src/backend/commands/tablespace.c @@ -73,6 +73,7 @@ #include "miscadmin.h" #include "postmaster/bgwriter.h" #include "storage/fd.h" +#include "storage/kmgr.h" #include "storage/lmgr.h" #include "storage/standby.h" #include "utils/acl.h" @@ -242,6 +243,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) char *location; Oid ownerId; Datum newOptions; + TableSpaceOpts *tsopts; /* Must be super user */ if (!superuser()) @@ -340,7 +342,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) newOptions = transformRelOptions((Datum) 0, stmt->options, NULL, NULL, false, false); - (void) tablespace_reloptions(newOptions, true); + tsopts = (TableSpaceOpts *) tablespace_reloptions(newOptions, true); if (newOptions != (Datum) 0) values[Anum_pg_tablespace_spcoptions - 1] = newOptions; else @@ -358,6 +360,17 @@ CreateTableSpace(CreateTableSpaceStmt *stmt) /* Post creation hook for new tablespace */ InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0); + /* Create an encryption key fot the tablespace */ + if (tsopts->encryption) + { + if (!TransparentEncryptionEnabled()) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("tablespace encryption requires a kmgr library"), + errhint("Please set kmgr_plugin_library parameter"))); + KeyringCreateKey(tablespaceoid); + } + create_tablespace_directories(location, tablespaceoid); /* Record the filesystem change in XLOG */ @@ -412,6 +425,9 @@ DropTableSpace(DropTableSpaceStmt *stmt) Form_pg_tablespace spcform; ScanKeyData entry[1]; Oid tablespaceoid; + TableSpaceOpts *tsopts; + Datum datum; + bool isnull; /* * Find the target tuple @@ -449,6 +465,10 @@ DropTableSpace(DropTableSpaceStmt *stmt) spcform = (Form_pg_tablespace) GETSTRUCT(tuple); tablespaceoid = spcform->oid; + datum = heap_getattr(tuple, Anum_pg_tablespace_spcoptions, + RelationGetDescr(rel), &isnull); + tsopts = (TableSpaceOpts *) tablespace_reloptions(datum, false); + /* Must be tablespace owner */ if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_TABLESPACE, @@ -519,6 +539,10 @@ DropTableSpace(DropTableSpaceStmt *stmt) } } + /* Drop encryption key if enabled */ + if (tsopts->encryption) + KeyringDropKey(tablespaceoid); + /* Record the filesystem change in XLOG */ { xl_tblspc_drop_rec xlrec; @@ -1003,7 +1027,11 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) bool isnull; bool repl_null[Natts_pg_tablespace]; bool repl_repl[Natts_pg_tablespace]; + bool encrypted_old; + bool encrypted_new; HeapTuple newtuple; + TableSpaceOpts *tsopts_old; + TableSpaceOpts *tsopts_new; /* Search pg_tablespace */ rel = table_open(TableSpaceRelationId, RowExclusiveLock); @@ -1021,6 +1049,10 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) stmt->tablespacename))); tablespaceoid = ((Form_pg_tablespace) GETSTRUCT(tup))->oid; + datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions, + RelationGetDescr(rel), &isnull); + tsopts_old = (TableSpaceOpts *) tablespace_reloptions(datum, false); + encrypted_old = tsopts_old != NULL && tsopts_old->encryption; /* Must be owner of the existing object */ if (!pg_tablespace_ownercheck(tablespaceoid, GetUserId())) @@ -1033,7 +1065,16 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, stmt->options, NULL, NULL, false, stmt->isReset); - (void) tablespace_reloptions(newOptions, true); + tsopts_new = (TableSpaceOpts *) tablespace_reloptions(newOptions, true); + encrypted_new = tsopts_new != NULL && tsopts_new->encryption; + + /* + * We don't support change un-encrypted tablespace to encrypted and + * vice versa. + */ + if (encrypted_old != encrypted_new) + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("could not change encryption option"))); /* Build new tuple. */ memset(repl_null, false, sizeof(repl_null)); diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c index d0d21f7..b2b2497 100644 --- a/src/backend/storage/file/copydir.c +++ b/src/backend/storage/file/copydir.c @@ -143,7 +143,7 @@ copy_file(char *fromfile, char *tofile) ForkNumber forknum; BlockNumber segment; bool is_relfile; - bool need_encryption; + bool need_encryption = false; /* Size of copy buffer (read and write requests) */ #define COPY_BUF_SIZE (8 * BLCKSZ) diff --git a/src/backend/utils/cache/spccache.c b/src/backend/utils/cache/spccache.c index 6309a01..41e6278 100644 --- a/src/backend/utils/cache/spccache.c +++ b/src/backend/utils/cache/spccache.c @@ -24,6 +24,7 @@ #include "miscadmin.h" #include "optimizer/optimizer.h" #include "storage/bufmgr.h" +#include "storage/kmgr.h" #include "utils/catcache.h" #include "utils/hsearch.h" #include "utils/inval.h" @@ -221,3 +222,18 @@ get_tablespace_io_concurrency(Oid spcid) else return spc->opts->effective_io_concurrency; } + +/* + * tablespace_is_encrypted + * + * Return true is the given tablespace is encrypted. This function + * checks if this tablespace is encrypted by checking the tablespace + * key existence rather than using spccache because this function + * can be called during buffer allocation when looking system cache, + * which is prohibited during processing buffer. + */ +bool +tablespace_is_encrypted(Oid spcid) +{ + return KeyringKeyExists(spcid); +} diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h index 273e31c..ea92ccd 100644 --- a/src/include/commands/tablespace.h +++ b/src/include/commands/tablespace.h @@ -40,6 +40,7 @@ typedef struct TableSpaceOpts float8 random_page_cost; float8 seq_page_cost; int effective_io_concurrency; + bool encryption; } TableSpaceOpts; extern Oid CreateTableSpace(CreateTableSpaceStmt *stmt); diff --git a/src/include/utils/spccache.h b/src/include/utils/spccache.h index 5f7aa6b..d0d0782 100644 --- a/src/include/utils/spccache.h +++ b/src/include/utils/spccache.h @@ -16,5 +16,6 @@ void get_tablespace_page_costs(Oid spcid, float8 *spc_random_page_cost, float8 *spc_seq_page_cost); int get_tablespace_io_concurrency(Oid spcid); +bool tablespace_is_encrypted(Oid spcid); #endif /* SPCCACHE_H */ -- 1.8.3.1