diff --git a/.github/workflows/postgresql-16-pgdg-package-pgxs.yml b/.github/workflows/postgresql-16-pgdg-package-pgxs.yml index 41456390..82a5bb3e 100644 --- a/.github/workflows/postgresql-16-pgdg-package-pgxs.yml +++ b/.github/workflows/postgresql-16-pgdg-package-pgxs.yml @@ -24,7 +24,7 @@ jobs: run: | sudo apt-get install -y libreadline6-dev systemtap-sdt-dev wget \ zlib1g-dev libssl-dev libpam0g-dev bison flex libipc-run-perl \ - libjson-c-dev libcurl4-openssl-dev + libjson-c-dev libcurl4-openssl-dev libhttp-server-simple-perl sudo /usr/bin/perl -MCPAN -e 'install IPC::RUN' sudo /usr/bin/perl -MCPAN -e 'install Text::Trim' @@ -62,7 +62,7 @@ jobs: sudo tee -a /etc/postgresql/16/main/postgresql.conf echo "pg_tde.keyringConfigFile = '/tmp/keyring.json'" | sudo tee -a /etc/postgresql/16/main/postgresql.conf - cp keyring.json /tmp/keyring.json + cp keyring* /tmp/ sudo service postgresql start sudo psql -V sudo -u postgres bash -c 'make installcheck USE_PGXS=1' diff --git a/.github/workflows/postgresql-16-src-make.yml b/.github/workflows/postgresql-16-src-make.yml index 6211610a..4b32eb7c 100644 --- a/.github/workflows/postgresql-16-src-make.yml +++ b/.github/workflows/postgresql-16-src-make.yml @@ -26,7 +26,7 @@ jobs: libxml2-dev libxslt-dev xsltproc libkrb5-dev libldap2-dev \ libsystemd-dev gettext tcl-dev libperl-dev pkg-config clang-11 \ llvm-11 llvm-11-dev libselinux1-dev python3-dev \ - uuid-dev liblz4-dev libjson-c-dev libcurl4-openssl-dev + uuid-dev liblz4-dev libjson-c-dev libcurl4-openssl-dev libhttp-server-simple-perl sudo /usr/bin/perl -MCPAN -e 'install IPC::RUN' sudo /usr/bin/perl -MCPAN -e 'install Text::Trim' @@ -68,7 +68,7 @@ jobs: /opt/pgsql/data/postgresql.conf echo "pg_tde.keyringConfigFile = '/tmp/keyring.json'" >> \ /opt/pgsql/data/postgresql.conf - cp src/contrib/postgres-tde-ext/keyring.json /tmp/keyring.json + cp src/contrib/postgres-tde-ext/keyring* /tmp/ pg_ctl -D /opt/pgsql/data -l logfile start - name: Test postgres-tde-ext diff --git a/.github/workflows/postgresql-16-src-meson-perf.yml b/.github/workflows/postgresql-16-src-meson-perf.yml index 8d499e4c..450e171f 100644 --- a/.github/workflows/postgresql-16-src-meson-perf.yml +++ b/.github/workflows/postgresql-16-src-meson-perf.yml @@ -30,7 +30,7 @@ jobs: libsystemd-dev gettext tcl-dev libperl-dev pkg-config clang-11 \ llvm-11 llvm-11-dev libselinux1-dev python3-dev \ uuid-dev liblz4-dev meson ninja-build libjson-c-dev \ - sysbench libcurl4-openssl-dev + sysbench libcurl4-openssl-dev libhttp-server-simple-perl sudo /usr/bin/perl -MCPAN -e 'install IPC::RUN' sudo /usr/bin/perl -MCPAN -e 'install Text::Trim' @@ -58,7 +58,7 @@ jobs: - name: Test postgres-tde-ext run: | - cp ../contrib/postgres-tde-ext/keyring.json /tmp/keyring.json + cp ../contrib/postgres-tde-ext/keyring* /tmp/ meson test --suite setup -v meson test --suite postgres-tde-ext -v --num-processes 1 working-directory: src/build diff --git a/.github/workflows/postgresql-16-src-meson.yml b/.github/workflows/postgresql-16-src-meson.yml index e8efd1e5..7212d718 100644 --- a/.github/workflows/postgresql-16-src-meson.yml +++ b/.github/workflows/postgresql-16-src-meson.yml @@ -27,7 +27,7 @@ jobs: libsystemd-dev gettext tcl-dev libperl-dev pkg-config clang-11 \ llvm-11 llvm-11-dev libselinux1-dev python3-dev \ uuid-dev liblz4-dev meson ninja-build libjson-c-dev \ - gpg wget libcurl4-openssl-dev + gpg wget libcurl4-openssl-dev libhttp-server-simple-perl sudo /usr/bin/perl -MCPAN -e 'install IPC::RUN' sudo /usr/bin/perl -MCPAN -e 'install Text::Trim' wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg @@ -58,7 +58,7 @@ jobs: - name: Test postgres-tde-ext with keyring_file run: | - cp ../contrib/postgres-tde-ext/keyring.json /tmp/keyring.json + cp ../contrib/postgres-tde-ext/keyring* /tmp/ meson test --suite setup -v meson test --suite postgres-tde-ext -v --num-processes 1 working-directory: src/build @@ -92,6 +92,6 @@ jobs: with: name: Regressions diff and postgresql log path: | - src/build/testrun/postgres-tde-ext/regress/ + src/build/testrun/postgres-tde-ext/ retention-days: 3 diff --git a/Makefile.in b/Makefile.in index 56016e6a..f70f206e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -31,6 +31,7 @@ src/access/pg_tdeam_handler.o \ src/access/pg_tde_ddl.o \ src/transam/pg_tde_xact_handler.o \ src/keyring/keyring_config.o \ +src/keyring/keyring_curl.o \ src/keyring/keyring_file.o \ src/keyring/keyring_vault.o \ src/keyring/keyring_api.o \ diff --git a/keyring-vault.json b/keyring-vault.json index e4123aca..59fb0d4e 100644 --- a/keyring-vault.json +++ b/keyring-vault.json @@ -2,5 +2,9 @@ 'provider': 'vault-v2', 'token': 'ROOT_TOKEN', 'url': 'http://127.0.0.1:8200', - 'mountPath': 'secret' + 'mountPath': { + 'type': 'file', + 'path': '/tmp/vault-mount' + + } } diff --git a/keyring-w-file.json b/keyring-w-file.json new file mode 100644 index 00000000..9f8d2a66 --- /dev/null +++ b/keyring-w-file.json @@ -0,0 +1,7 @@ +{ + 'provider': 'file', + 'datafile': { + 'type': 'file', + 'path': '/tmp/datafile-location' + } +} diff --git a/keyring-w-http.json b/keyring-w-http.json new file mode 100644 index 00000000..f5fb7a63 --- /dev/null +++ b/keyring-w-http.json @@ -0,0 +1,7 @@ +{ + 'provider': 'file', + 'datafile': { + 'type': 'remote', + 'url': 'http://localhost:8888/hello' + } +} diff --git a/meson.build b/meson.build index 94ebd482..74b6dd34 100644 --- a/meson.build +++ b/meson.build @@ -24,6 +24,7 @@ pg_tde_sources = files( 'src/keyring/keyring_config.c', 'src/keyring/keyring_file.c', 'src/keyring/keyring_vault.c', + 'src/keyring/keyring_curl.c', 'src/keyring/keyring_api.c', 'src/pg_tde.c', @@ -84,6 +85,8 @@ tests += { 'tap': { 'tests': [ 't/001_basic.pl', + 't/002_remote_config.pl', + 't/003_file_config.pl', ], }, } diff --git a/src/include/keyring/keyring_config.h b/src/include/keyring/keyring_config.h index bc70aaae..6d6e6ad2 100644 --- a/src/include/keyring/keyring_config.h +++ b/src/include/keyring/keyring_config.h @@ -26,6 +26,6 @@ bool keyringLoadConfiguration(const char* configFileName); // { type: 'remote'. url: 'http://...' } // If it doesn't have a type key / not remote / ... returns NULL // Otherwise it retuns the JSON value interpreted as a string -const char* keyringParseStringParam(json_object* object); +bool keyringParseStringParam(const char* name, json_object* object, char* out, long outLen); #endif // KEYRING_CONFIG_H diff --git a/src/include/keyring/keyring_curl.h b/src/include/keyring/keyring_curl.h new file mode 100644 index 00000000..4607b03c --- /dev/null +++ b/src/include/keyring/keyring_curl.h @@ -0,0 +1,19 @@ + +#ifndef KEYRING_CURL_H +#define KEYRING_CURL_H + +#include "pg_tde_defines.h" + +#include +#include + +typedef struct curlString { + char *ptr; + size_t len; +} curlString; + +extern CURL* keyringCurl; + +bool curlSetupSession(const char* url, const char* caFile, curlString* outStr); + +#endif //KEYRING_CURL_H diff --git a/src/keyring/keyring_config.c b/src/keyring/keyring_config.c index 256304b6..6a9ddbd3 100644 --- a/src/keyring/keyring_config.c +++ b/src/keyring/keyring_config.c @@ -2,6 +2,7 @@ #include "keyring/keyring_config.h" #include "keyring/keyring_file.h" #include "keyring/keyring_vault.h" +#include "keyring/keyring_curl.h" #include #include @@ -154,12 +155,116 @@ bool keyringLoadConfiguration(const char* configFileName) return ret; } -const char* keyringParseStringParam(json_object* object) +bool keyringParseStringParam(const char* name, json_object* object, char* out, long outLen) { if(json_object_get_type(object) == json_type_object) { - elog(WARNING, "Remote parameters are not yet implemented"); + json_object* typeO; + const char* type; + + if(!json_object_object_get_ex(object, "type", &typeO)) + { + elog(ERROR, "Invalid object value for %s: Missing 'type'.", name); + return false; + } + + type = json_object_get_string(typeO); + + if(strncmp("remote", type, 7) == 0) + { + json_object* caO; + json_object* urlO; + const char* ca = NULL; + const char* url = NULL; + + long httpCode; + curlString outStr; + + if(json_object_object_get_ex(object, "ca", &caO)) + { + ca = json_object_get_string(caO); + } + if(json_object_object_get_ex(object, "url", &urlO)) + { + url = json_object_get_string(urlO); + } else + { + elog(ERROR, "Invalid remote object for %s: Missing 'url'.", name); + return false; + } + + outStr.ptr = palloc0(1); + outStr.len = 0; + if(!curlSetupSession(url, ca, &outStr)) + { + elog(ERROR, "CURL error for remote object %s", name); + return false; + } + if(curl_easy_perform(keyringCurl) != CURLE_OK) + { + elog(ERROR, "HTTP request error for remote object %s", name); + return false; + } + if(curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, &httpCode) != CURLE_OK) + { + elog(ERROR, "HTTP error for remote object %s, HTTP code %li", name, httpCode); + return false; + } +#if KEYRING_DEBUG + elog(DEBUG2, "HTTP response for config [%s] '%s'", name, outStr->ptr != NULL ? outStr->ptr : ""); +#endif + strncpy(out, outStr.ptr, outLen); + out[strcspn(out, "\r\n")] = 0; + + return true; + } + + if(strncmp("file", type, 5) == 0) + { + json_object* pathO; + const char* path = NULL; + FILE* f; + + if(json_object_object_get_ex(object, "path", &pathO)) + { + path = json_object_get_string(pathO); + } else + { + elog(ERROR, "Invalid file object for %s: Missing 'path'.", name); + return false; + } + + if(access(path, R_OK) != 0) + { + elog(ERROR, "The file referenced by %s doesn't exists, or is not readable to postgres: %s", name, path); + return false; + } + + f = fopen(path, "r"); + + if(!f) + { + elog(ERROR, "The file referenced by %s doesn't exists, or is not readable to postgres: %s", name, path); + return false; + } + + fgets(out, outLen, f); + out[strcspn(out, "\r\n")] = 0; + + fclose(f); + + return true; + } + + elog(ERROR, "Unknown type for %s: %s", name, type); + return false; } - return json_object_get_string(object); + { + const char* string; + string = json_object_get_string(object); + + strncpy(out, string, outLen); + } + return true; } diff --git a/src/keyring/keyring_curl.c b/src/keyring/keyring_curl.c new file mode 100644 index 00000000..52087321 --- /dev/null +++ b/src/keyring/keyring_curl.c @@ -0,0 +1,56 @@ + +#include "keyring/keyring_curl.h" +#include "keyring/keyring_config.h" +#include "pg_tde_defines.h" + +CURL* keyringCurl = NULL; + +static size_t writefunc(void *ptr, size_t size, size_t nmemb, struct curlString *s) +{ + size_t new_len = s->len + size*nmemb; + s->ptr = repalloc(s->ptr, new_len+1); + if (s->ptr == NULL) { + exit(EXIT_FAILURE); + } + memcpy(s->ptr+s->len, ptr, size*nmemb); + s->ptr[new_len] = '\0'; + s->len = new_len; + + return size*nmemb; +} + +bool curlSetupSession(const char* url, const char* caFile, curlString* outStr) +{ + if(keyringCurl == NULL) + { + keyringCurl = curl_easy_init(); + + if(keyringCurl == NULL) return 0; + } + + if(curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_SSL_VERIFYHOST, 1) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) return 0; + if(caFile == NULL || strlen(caFile) == 0) + { + //if(curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, "") != CURLE_OK) return 0; + //if(curl_easy_setopt(keyringCurl, CURLSSLOPT_NATIVE_CA, 1) != CURLE_OK) return 0; + } else + { + if(curl_easy_setopt(keyringCurl, CURLSSLOPT_NATIVE_CA, 0) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_CAINFO, caFile) != CURLE_OK) return 0; + } + if(curl_easy_setopt(keyringCurl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_TIMEOUT, 10) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_HTTP_VERSION,(long)CURL_HTTP_VERSION_1_1) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEFUNCTION,writefunc) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_WRITEDATA,outStr) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_URL, url) != CURLE_OK) return 0; + + if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_POST, 0) != CURLE_OK) return 0; + + return 1; +} + diff --git a/src/keyring/keyring_file.c b/src/keyring/keyring_file.c index 39943c17..5bd9cf3c 100644 --- a/src/keyring/keyring_file.c +++ b/src/keyring/keyring_file.c @@ -14,7 +14,6 @@ extern keyringCache* cache; // TODO: do not depend on cache internals int keyringFileParseConfiguration(json_object* configRoot) { json_object* dataO; - const char* datafile; if(!json_object_object_get_ex(configRoot, "datafile", &dataO)) { @@ -22,16 +21,13 @@ int keyringFileParseConfiguration(json_object* configRoot) return 0; } - datafile = keyringParseStringParam(dataO); - - if(datafile == NULL) + keyringFileDataFileName[0] = 0; + if(!keyringParseStringParam("datafile", dataO, keyringFileDataFileName, 512)) { elog(ERROR, "Couldn't parse 'datafile' attribute."); return 0; } - strcpy(keyringFileDataFileName, datafile); - return 1; } diff --git a/src/keyring/keyring_vault.c b/src/keyring/keyring_vault.c index 114ab0f6..ae5abed4 100644 --- a/src/keyring/keyring_vault.c +++ b/src/keyring/keyring_vault.c @@ -1,6 +1,6 @@ - #include "keyring/keyring_vault.h" #include "keyring/keyring_config.h" +#include "keyring/keyring_curl.h" #include "pg_tde_defines.h" #include @@ -15,37 +15,10 @@ char keyringVaultUrl[128]; char keyringVaultCaPath[256]; char keyringVaultMountPath[128]; -CURL* curl = NULL; struct curl_slist *curlList = NULL; -typedef struct curlString { - char *ptr; - size_t len; -} curlString; - -static size_t writefunc(void *ptr, size_t size, size_t nmemb, struct curlString *s) -{ - size_t new_len = s->len + size*nmemb; - s->ptr = repalloc(s->ptr, new_len+1); - if (s->ptr == NULL) { - exit(EXIT_FAILURE); - } - memcpy(s->ptr+s->len, ptr, size*nmemb); - s->ptr[new_len] = '\0'; - s->len = new_len; - - return size*nmemb; -} - -static bool curlSetupSession(const char* url, curlString* str) +static bool curlSetupToken() { - if(curl == NULL) - { - curl = curl_easy_init(); - - if(curl == NULL) return 0; - } - if(curlList == NULL) { char tokenHeader[256]; @@ -59,20 +32,7 @@ static bool curlSetupSession(const char* url, curlString* str) if(curlList == NULL) return 0; } - - if(curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL) != CURLE_OK) return 0; - if(strlen(keyringVaultCaPath) > 0 && curl_easy_setopt( - curl, CURLOPT_CAINFO, keyringVaultCaPath) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_HTTP_VERSION,(long)CURL_HTTP_VERSION_1_1) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,writefunc) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_WRITEDATA,str) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_URL, url) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_HTTPHEADER, curlList) != CURLE_OK) return 0; return 1; } @@ -89,19 +49,16 @@ static bool curlPerform(const char* url, curlString* outStr, long* httpCode, con outStr->ptr = palloc0(1); outStr->len = 0; - if(!curlSetupSession(url, outStr)) return 0; + if(!curlSetupSession(url, keyringVaultCaPath, outStr)) return 0; + if(!curlSetupToken()) return 0; if(postData != NULL) { - if(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData) != CURLE_OK) return 0; - } else - { - if(curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL) != CURLE_OK) return 0; - if(curl_easy_setopt(curl, CURLOPT_POST, 0) != CURLE_OK) return 0; + if(curl_easy_setopt(keyringCurl, CURLOPT_POSTFIELDS, postData) != CURLE_OK) return 0; } - if(curl_easy_perform(curl) != CURLE_OK) return 0; - if(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK) return 0; + if(curl_easy_perform(keyringCurl) != CURLE_OK) return 0; + if(curl_easy_getinfo(keyringCurl, CURLINFO_RESPONSE_CODE, httpCode) != CURLE_OK) return 0; #if KEYRING_DEBUG elog(DEBUG2, "Vault response [%li] '%s'", *httpCode, outStr->ptr != NULL ? outStr->ptr : ""); @@ -120,7 +77,6 @@ int keyringVaultPreloadCache(void) static bool keyringConfigExtractParameter(json_object* configRoot, const char* name, char* out, unsigned outMaxLen, bool optional) { json_object* dataO; - const char* stringData; if(!json_object_object_get_ex(configRoot, name, &dataO)) { @@ -131,9 +87,8 @@ static bool keyringConfigExtractParameter(json_object* configRoot, const char* n return 0; } - stringData = keyringParseStringParam(dataO); - - if(stringData == NULL) + out[0] = 0; + if(!keyringParseStringParam(name, dataO, out, outMaxLen-1)) { if(!optional) { @@ -142,13 +97,6 @@ static bool keyringConfigExtractParameter(json_object* configRoot, const char* n return 0; } - if(strlen(stringData) > outMaxLen-1) - { - elog(WARNING, "Attribute '%s' is too long, maximum is %u, truncated.", name, outMaxLen); - } - - strncpy(out, stringData, outMaxLen-1); - return 1; } diff --git a/t/002_remote_config.pl b/t/002_remote_config.pl new file mode 100644 index 00000000..de86e328 --- /dev/null +++ b/t/002_remote_config.pl @@ -0,0 +1,110 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use File::Basename; +use File::Compare; +use File::Copy; +use Test::More; +use lib 't'; +use pgtde; + +# Get file name and CREATE out file name and dirs WHERE requried +PGTDE::setup_files_dir(basename($0)); + +# CREATE new PostgreSQL node and do initdb +my $node = PGTDE->pgtde_init_pg(); +my $pgdata = $node->data_dir; + +{ +package MyWebServer; + +use HTTP::Server::Simple::CGI; +use base qw(HTTP::Server::Simple::CGI); + +my %dispatch = ( + '/hello' => \&resp_hello, + # ... +); + +sub handle_request { + my $self = shift; + my $cgi = shift; + + my $path = $cgi->path_info(); + my $handler = $dispatch{$path}; + + if (ref($handler) eq "CODE") { + print "HTTP/1.0 200 OK\r\n"; + $handler->($cgi); + + } else { + print "HTTP/1.0 404 Not found\r\n"; + print $cgi->header, + $cgi->start_html('Not found'), + $cgi->h1('Not found'), + $cgi->end_html; + } +} + +sub resp_hello { + my $cgi = shift; + print $cgi->header, + "/tmp/http_datafile\r\n"; +} + +} +my $pid = MyWebServer->new(8888)->background(); + + +# UPDATE postgresql.conf to include/load pg_tde library +open my $conf, '>>', "$pgdata/postgresql.conf"; +print $conf "shared_preload_libraries = 'pg_tde'\n"; +print $conf "pg_tde.keyringConfigFile = '/tmp/keyring-w-http.json'\n"; +close $conf; + +my $rt_value = $node->stop(); +$rt_value = $node->start(); +ok($rt_value == 1, "Restart Server"); + +my ($cmdret, $stdout, $stderr) = $node->psql('postgres', 'CREATE EXTENSION pg_tde;', extra_params => ['-a']); +ok($cmdret == 0, "CREATE PGTDE EXTENSION"); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'CREATE TABLE test_enc2(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'INSERT INTO test_enc2 (k) VALUES (5),(6);', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'SELECT * FROM test_enc2 ORDER BY id ASC;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +# Restart the server +PGTDE::append_to_file("-- server restart"); +$rt_value = $node->stop(); +$rt_value = $node->start(); + +$stdout = $node->safe_psql('postgres', 'SELECT * FROM test_enc2 ORDER BY id ASC;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'DROP TABLE test_enc2;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +# DROP EXTENSION +$stdout = $node->safe_psql('postgres', 'DROP EXTENSION pg_tde;', extra_params => ['-a']); +ok($cmdret == 0, "DROP PGTDE EXTENSION"); +PGTDE::append_to_file($stdout); +# Stop the server +$node->stop(); + +system("kill $pid"); + +# compare the expected and out file +my $compare = PGTDE->compare_results(); + +# Test/check if expected and result/out file match. If Yes, test passes. +is($compare,0,"Compare Files: $PGTDE::expected_filename_with_path and $PGTDE::out_filename_with_path files."); + +# Done testing for this testcase file. +done_testing(); diff --git a/t/003_file_config.pl b/t/003_file_config.pl new file mode 100644 index 00000000..4e0a8065 --- /dev/null +++ b/t/003_file_config.pl @@ -0,0 +1,72 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use File::Basename; +use File::Compare; +use File::Copy; +use Test::More; +use lib 't'; +use pgtde; + +# Get file name and CREATE out file name and dirs WHERE requried +PGTDE::setup_files_dir(basename($0)); + +# CREATE new PostgreSQL node and do initdb +my $node = PGTDE->pgtde_init_pg(); +my $pgdata = $node->data_dir; + +copy("$pgdata/postgresql.conf", "$pgdata/postgresql.conf.bak"); + +# UPDATE postgresql.conf to include/load pg_tde library +open my $conf, '>>', "$pgdata/postgresql.conf"; +print $conf "shared_preload_libraries = 'pg_tde'\n"; +print $conf "pg_tde.keyringConfigFile = '/tmp/keyring-w-file.json'\n"; +close $conf; + +open my $conf2, '>>', "/tmp/datafile-location"; +print $conf2 "/tmp/keyring_data_file\n"; +close $conf2; + +my $rt_value = $node->start(); +ok($rt_value == 1, "Start Server"); + +my ($cmdret, $stdout, $stderr) = $node->psql('postgres', 'CREATE EXTENSION pg_tde;', extra_params => ['-a']); +ok($cmdret == 0, "CREATE PGTDE EXTENSION"); +PGTDE::append_to_file($stdout); + +my $stdout = $node->safe_psql('postgres', 'CREATE TABLE test_enc1(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'INSERT INTO test_enc1 (k) VALUES (5),(6);', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'SELECT * FROM test_enc1 ORDER BY id ASC;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +# Restart the server +PGTDE::append_to_file("-- server restart"); +$rt_value = $node->stop(); +$rt_value = $node->start(); + +$stdout = $node->safe_psql('postgres', 'SELECT * FROM test_enc1 ORDER BY id ASC;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +$stdout = $node->safe_psql('postgres', 'DROP TABLE test_enc1;', extra_params => ['-a']); +PGTDE::append_to_file($stdout); + +# DROP EXTENSION +$stdout = $node->safe_psql('postgres', 'DROP EXTENSION pg_tde;', extra_params => ['-a']); +ok(my $cmdret == 0, "DROP PGTDE EXTENSION"); +PGTDE::append_to_file($stdout); +# Stop the server +$node->stop(); + +# compare the expected and out file +my $compare = PGTDE->compare_results(); + +# Test/check if expected and result/out file match. If Yes, test passes. +is($compare,0,"Compare Files: $PGTDE::expected_filename_with_path and $PGTDE::out_filename_with_path files."); + +# Done testing for this testcase file. +done_testing(); diff --git a/t/expected/002_remote_config.out b/t/expected/002_remote_config.out new file mode 100644 index 00000000..821a1c83 --- /dev/null +++ b/t/expected/002_remote_config.out @@ -0,0 +1,12 @@ +CREATE EXTENSION pg_tde; +CREATE TABLE test_enc2(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde; +INSERT INTO test_enc2 (k) VALUES (5),(6); +SELECT * FROM test_enc2 ORDER BY id ASC; +1|5 +2|6 +-- server restart +SELECT * FROM test_enc2 ORDER BY id ASC; +1|5 +2|6 +DROP TABLE test_enc2; +DROP EXTENSION pg_tde; diff --git a/t/expected/003_file_config.out b/t/expected/003_file_config.out new file mode 100644 index 00000000..d4d201dc --- /dev/null +++ b/t/expected/003_file_config.out @@ -0,0 +1,12 @@ +CREATE EXTENSION pg_tde; +CREATE TABLE test_enc1(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde; +INSERT INTO test_enc1 (k) VALUES (5),(6); +SELECT * FROM test_enc1 ORDER BY id ASC; +1|5 +2|6 +-- server restart +SELECT * FROM test_enc1 ORDER BY id ASC; +1|5 +2|6 +DROP TABLE test_enc1; +DROP EXTENSION pg_tde; diff --git a/t/results/001_basic.out b/t/results/001_basic.out new file mode 100644 index 00000000..d6f838c9 --- /dev/null +++ b/t/results/001_basic.out @@ -0,0 +1,13 @@ +CREATE EXTENSION pg_tde; +-- server restart +CREATE TABLE test_enc(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde; +INSERT INTO test_enc (k) VALUES (5),(6); +SELECT * FROM test_enc ORDER BY id ASC; +1|5 +2|6 +-- server restart +SELECT * FROM test_enc ORDER BY id ASC; +1|5 +2|6 +DROP TABLE test_enc; +DROP EXTENSION pg_tde; diff --git a/t/results/002_remote_config.out b/t/results/002_remote_config.out new file mode 100644 index 00000000..821a1c83 --- /dev/null +++ b/t/results/002_remote_config.out @@ -0,0 +1,12 @@ +CREATE EXTENSION pg_tde; +CREATE TABLE test_enc2(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde; +INSERT INTO test_enc2 (k) VALUES (5),(6); +SELECT * FROM test_enc2 ORDER BY id ASC; +1|5 +2|6 +-- server restart +SELECT * FROM test_enc2 ORDER BY id ASC; +1|5 +2|6 +DROP TABLE test_enc2; +DROP EXTENSION pg_tde; diff --git a/t/results/003_file_config.out b/t/results/003_file_config.out new file mode 100644 index 00000000..d4d201dc --- /dev/null +++ b/t/results/003_file_config.out @@ -0,0 +1,12 @@ +CREATE EXTENSION pg_tde; +CREATE TABLE test_enc1(id SERIAL,k INTEGER,PRIMARY KEY (id)) USING pg_tde; +INSERT INTO test_enc1 (k) VALUES (5),(6); +SELECT * FROM test_enc1 ORDER BY id ASC; +1|5 +2|6 +-- server restart +SELECT * FROM test_enc1 ORDER BY id ASC; +1|5 +2|6 +DROP TABLE test_enc1; +DROP EXTENSION pg_tde;