0008-Support-tablespace-encryption.patch

text/x-patch

Filename: 0008-Support-tablespace-encryption.patch
Type: text/x-patch
Part: 7
Message: Re: [Proposal] Table-level Transparent Data Encryption (TDE) and Key Management Service (KMS)

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: format-patch
Series: patch 0008
Subject: Support tablespace encryption.
File+
src/backend/access/common/reloptions.c 11 1
src/backend/commands/tablespace.c 43 2
src/backend/storage/file/copydir.c 1 1
src/backend/utils/cache/spccache.c 16 0
src/include/commands/tablespace.h 1 0
src/include/utils/spccache.h 1 0
From e0948d05e8ab52025072fedcb67e4faf784407a3 Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
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