diff --git a/expected/keyprovider_dependency.out b/expected/keyprovider_dependency.out index e9bc3d2f..d02736dc 100644 --- a/expected/keyprovider_dependency.out +++ b/expected/keyprovider_dependency.out @@ -17,6 +17,14 @@ SELECT pg_tde_add_key_provider_vault_v2('V2-vault','vault-token','percona.com/va 3 (1 row) +SELECT * FROM pg_tde_list_all_key_providers(); + id | provider_name | provider_type | options +----+---------------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------- + 1 | mk-file | file | {"type" : "file", "path" : "/tmp/pg_tde_test_keyring.per"} + 2 | free-file | file | {"type" : "file", "path" : "/tmp/pg_tde_test_keyring_2.per"} + 3 | V2-vault | vault-v2 | {"type" : "vault-v2", "url" : "percona.com/vault-v2/percona", "token" : "vault-token", "mountPath" : "/mount/dev", "caPath" : "ca-cert-auth"} +(3 rows) + SELECT pg_tde_set_principal_key('test-db-principal-key','mk-file'); pg_tde_set_principal_key -------------------------- diff --git a/pg_tde--1.0.sql b/pg_tde--1.0.sql index ae4ca39a..8a0aa37f 100644 --- a/pg_tde--1.0.sql +++ b/pg_tde--1.0.sql @@ -56,6 +56,15 @@ AS $$ $$ LANGUAGE SQL; +CREATE FUNCTION pg_tde_list_all_key_providers + (OUT id INT, + OUT provider_name VARCHAR(128), + OUT provider_type VARCHAR(10), + OUT options JSON) +RETURNS SETOF record +AS 'MODULE_PATHNAME' +LANGUAGE C STRICT VOLATILE; + -- Table access method CREATE FUNCTION pg_tdeam_basic_handler(internal) RETURNS table_am_handler diff --git a/sql/keyprovider_dependency.sql b/sql/keyprovider_dependency.sql index d9c88dd4..26575ecd 100644 --- a/sql/keyprovider_dependency.sql +++ b/sql/keyprovider_dependency.sql @@ -4,6 +4,8 @@ SELECT pg_tde_add_key_provider_file('mk-file','/tmp/pg_tde_test_keyring.per'); SELECT pg_tde_add_key_provider_file('free-file','/tmp/pg_tde_test_keyring_2.per'); SELECT pg_tde_add_key_provider_vault_v2('V2-vault','vault-token','percona.com/vault-v2/percona','/mount/dev','ca-cert-auth'); +SELECT * FROM pg_tde_list_all_key_providers(); + SELECT pg_tde_set_principal_key('test-db-principal-key','mk-file'); DROP EXTENSION pg_tde; diff --git a/src/catalog/tde_keyring.c b/src/catalog/tde_keyring.c index 6409bad7..6c5b4431 100644 --- a/src/catalog/tde_keyring.c +++ b/src/catalog/tde_keyring.c @@ -10,6 +10,7 @@ *------------------------------------------------------------------------- */ #include "postgres.h" +#include "funcapi.h" #include "access/xlog.h" #include "access/xloginsert.h" #include "access/pg_tde_xlog.h" @@ -34,6 +35,8 @@ PG_FUNCTION_INFO_V1(pg_tde_add_key_provider_internal); Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(pg_tde_list_all_key_providers); +Datum pg_tde_list_all_key_providers(PG_FUNCTION_ARGS); #define PG_TDE_KEYRING_FILENAME "pg_tde_keyrings" /* @@ -51,6 +54,7 @@ Datum pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS); */ #define FILE_KEYRING_PATH_KEY "path" #define FILE_KEYRING_TYPE_KEY "type" +#define PG_TDE_LIST_PROVIDERS_COLS 4 typedef enum ProviderScanType { @@ -70,7 +74,7 @@ static char *get_keyring_infofile_path(char *resPath, Oid dbOid, Oid spcOid); static void key_provider_startup_cleanup(int tde_tbl_count, XLogExtensionInstall *ext_info, bool redo, void *arg); static uint32 write_key_provider_info(KeyringProvideRecord *provider, Oid database_id, Oid tablespace_id, off_t position, bool redo); static uint32 save_new_key_provider_info(KeyringProvideRecord *provider); - +static const char *get_keyring_provider_typename(ProviderType p_type); static Size initialize_shared_state(void *start_address); static Size required_shared_mem_size(void); @@ -141,8 +145,22 @@ get_keyring_provider_from_typename(char *provider_type) return UNKNOWN_KEY_PROVIDER; } -static GenericKeyring * -load_keyring_provider_from_record(KeyringProvideRecord* provider) +static const char * +get_keyring_provider_typename(ProviderType p_type) +{ + switch (p_type) + { + case FILE_KEY_PROVIDER: + return FILE_KEYRING_TYPE; + case VAULT_V2_KEY_PROVIDER: + return VAULTV2_KEYRING_TYPE; + default: + break; + } + return NULL; +} + +static GenericKeyring *load_keyring_provider_from_record(KeyringProvideRecord *provider) { Datum option_datum; GenericKeyring *keyring = NULL; @@ -155,6 +173,7 @@ load_keyring_provider_from_record(KeyringProvideRecord* provider) 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; @@ -513,3 +532,58 @@ pg_tde_add_key_provider_internal(PG_FUNCTION_ARGS) PG_RETURN_INT32(provider.provider_id); } + +Datum +pg_tde_list_all_key_providers(PG_FUNCTION_ARGS) +{ + List* all_providers = GetAllKeyringProviders(); + 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); + } + tuplestore_donestoring(tupstore); + list_free_deep(all_providers); + return (Datum)0; +} diff --git a/src/include/catalog/tde_keyring.h b/src/include/catalog/tde_keyring.h index f35b4b2d..c6ec46f4 100644 --- a/src/include/catalog/tde_keyring.h +++ b/src/include/catalog/tde_keyring.h @@ -38,6 +38,7 @@ typedef struct GenericKeyring ProviderType type; /* Must be the first field */ Oid key_id; char provider_name[MAX_PROVIDER_NAME_LEN]; + char options[MAX_KEYRING_OPTION_LEN]; /* User provided options string*/ } GenericKeyring; typedef struct FileKeyring