Add separate parameter for kmip client key

Previously this was required to be in the same file as the client
certificate.

Co-authored-by: Zsolt Parragi <zsolt.parragi@cancellar.hu>
pull/230/head
Anders Åstrand 4 months ago committed by AndersAstrand
parent 77d48074a0
commit 443d33c96a
  1. 1
      ci_scripts/setup-keyring-servers.sh
  2. 11
      contrib/pg_tde/documentation/docs/functions.md
  3. 7
      contrib/pg_tde/documentation/docs/how-to/multi-tenant-setup.md
  4. 7
      contrib/pg_tde/documentation/docs/wal-encryption.md
  5. 4
      contrib/pg_tde/expected/kmip_test.out
  6. 48
      contrib/pg_tde/pg_tde--1.0-rc.sql
  7. 4
      contrib/pg_tde/sql/kmip_test.sql
  8. 9
      contrib/pg_tde/src/catalog/tde_keyring.c
  9. 7
      contrib/pg_tde/src/catalog/tde_keyring_parse_opts.c
  10. 1
      contrib/pg_tde/src/include/keyring/keyring_api.h
  11. 2
      contrib/pg_tde/src/keyring/keyring_kmip.c
  12. 4
      contrib/pg_tde/src/pg_tde_change_key_provider.c

@ -6,7 +6,6 @@ cd /tmp
wget https://raw.githubusercontent.com/OpenKMIP/PyKMIP/refs/heads/master/bin/create_certificates.py
python3 create_certificates.py
cat client_certificate_jane_doe.pem >> client_key_jane_doe.pem
mkdir policies
cd policies

@ -106,15 +106,15 @@ The KMIP provider uses a remote KMIP server.
Use these functions to add a KMIP provider:
```sql
SELECT pg_tde_add_database_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_add_global_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_add_database_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
SELECT pg_tde_add_global_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
```
These functions change the KMIP provider:
```sql
SELECT pg_tde_change_database_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_change_global_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_change_database_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
SELECT pg_tde_change_global_key_provider_kmip('provider-name','kmip-addr', `port`, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
```
where:
@ -124,7 +124,8 @@ where:
* `port` is the port to communicate with the KMIP server.
Most KMIP servers use port 5696.
* `server-certificate` is the path to the certificate file for the KMIP server.
* `client key` is the path to the client key.
* `client-cert` is the path to the client certificate.
* `client-key` is the path to the client key.
The specified access parameters require permission to read and write keys at the server.

@ -61,7 +61,7 @@ You must do these steps for every database where you have created the extension.
For testing purposes, you can use the PyKMIP server which enables you to set up required certificates. To use a real KMIP server, make sure to obtain the valid certificates issued by the key management appliance.
```sql
SELECT pg_tde_add_database_key_provider_kmip('provider-name','kmip-addr', 5696, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_add_database_key_provider_kmip('provider-name','kmip-addr', 5696, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
```
where:
@ -70,12 +70,13 @@ You must do these steps for every database where you have created the extension.
* `kmip-addr` is the IP address of a domain name of the KMIP server
* `port` is the port to communicate with the KMIP server. Typically used port is 5696.
* `server-certificate` is the path to the certificate file for the KMIP server.
* `client key` is the path to the client key.
* `client-cert` is the path to the client certificate.
* `client-key` is the path to the client key.
<i warning>:material-information: Warning:</i> This example is for testing purposes only:
```
SELECT pg_tde_add_database_key_provider_kmip('kmip','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_database_key_provider_kmip('kmip','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_cert_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
```
=== "With HashiCorp Vault"

@ -19,7 +19,7 @@ Before turning WAL encryption on, you must follow the steps below to create your
For testing purposes, you can use the PyKMIP server which enables you to set up required certificates. To use a real KMIP server, make sure to obtain the valid certificates issued by the key management appliance.
```sql
SELECT pg_tde_add_global_key_provider_kmip('provider-name','kmip-addr', 5696, '/path_to/server_certificate.pem', '/path_to/client_key.pem');
SELECT pg_tde_add_global_key_provider_kmip('provider-name','kmip-addr', 5696, '/path_to/server_certificate.pem', '/path_to/client_cert.pem', '/path_to/client_key.pem');
```
where:
@ -28,12 +28,13 @@ Before turning WAL encryption on, you must follow the steps below to create your
* `kmip-addr` is the IP address of a domain name of the KMIP server
* `port` is the port to communicate with the KMIP server. Typically used port is 5696.
* `server-certificate` is the path to the certificate file for the KMIP server.
* `client key` is the path to the client key.
* `client-cert` is the path to the client certificate.
* `client-key` is the path to the client key.
<i warning>:material-information: Warning:</i> This example is for testing purposes only:
```
SELECT pg_tde_add_key_using_global_key_provider_kmip('kmip','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_key_using_global_key_provider_kmip('kmip','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_cert_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
```
=== "With HashiCorp Vault"

@ -1,5 +1,5 @@
CREATE EXTENSION pg_tde;
SELECT pg_tde_add_database_key_provider_kmip('kmip-prov','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_database_key_provider_kmip('kmip-prov','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_certificate_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
pg_tde_add_database_key_provider_kmip
---------------------------------------
1
@ -35,6 +35,6 @@ SELECT pg_tde_verify_key();
DROP TABLE test_enc;
-- Creating provider fails if we can't connect to kmip server
SELECT pg_tde_add_database_key_provider_kmip('will-not-work','127.0.0.1', 61, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_database_key_provider_kmip('will-not-work','127.0.0.1', 61, '/tmp/server_certificate.pem', '/tmp/client_certificate_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
ERROR: SSL error: BIO_do_connect failed
DROP EXTENSION pg_tde;

@ -67,7 +67,8 @@ CREATE FUNCTION pg_tde_add_database_key_provider_kmip(provider_name TEXT,
kmip_host TEXT,
kmip_port INT,
kmip_ca_path TEXT,
kmip_cert_path TEXT)
kmip_cert_path TEXT,
kmip_key_path TEXT)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -77,14 +78,16 @@ BEGIN ATOMIC
json_object('host' VALUE COALESCE(kmip_host, ''),
'port' VALUE kmip_port,
'caPath' VALUE COALESCE(kmip_ca_path, ''),
'certPath' VALUE COALESCE(kmip_cert_path, '')));
'certPath' VALUE COALESCE(kmip_cert_path, ''),
'keyPath' VALUE COALESCE(kmip_key_path, '')));
END;
CREATE FUNCTION pg_tde_add_database_key_provider_kmip(provider_name TEXT,
kmip_host JSON,
kmip_port JSON,
kmip_ca_path JSON,
kmip_cert_path JSON)
kmip_cert_path JSON,
kmip_key_path JSON)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -94,7 +97,8 @@ BEGIN ATOMIC
json_object('host' VALUE kmip_host,
'port' VALUE kmip_port,
'caPath' VALUE kmip_ca_path,
'certPath' VALUE kmip_cert_path));
'certPath' VALUE kmip_cert_path,
'keyPath' VALUE kmip_key_path));
END;
CREATE FUNCTION pg_tde_list_all_database_key_providers
@ -179,7 +183,8 @@ CREATE FUNCTION pg_tde_add_global_key_provider_kmip(provider_name TEXT,
kmip_host TEXT,
kmip_port INT,
kmip_ca_path TEXT,
kmip_cert_path TEXT)
kmip_cert_path TEXT,
kmip_key_path TEXT DEFAULT '')
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -189,14 +194,16 @@ BEGIN ATOMIC
json_object('host' VALUE COALESCE(kmip_host, ''),
'port' VALUE kmip_port,
'caPath' VALUE COALESCE(kmip_ca_path, ''),
'certPath' VALUE COALESCE(kmip_cert_path, '')));
'certPath' VALUE COALESCE(kmip_cert_path, ''),
'keyPath' VALUE COALESCE(kmip_key_path, '')));
END;
CREATE FUNCTION pg_tde_add_global_key_provider_kmip(provider_name TEXT,
kmip_host JSON,
kmip_port JSON,
kmip_ca_path JSON,
kmip_cert_path JSON)
kmip_cert_path JSON,
kmip_key_path JSON)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -206,7 +213,8 @@ BEGIN ATOMIC
json_object('host' VALUE kmip_host,
'port' VALUE kmip_port,
'caPath' VALUE kmip_ca_path,
'certPath' VALUE kmip_cert_path));
'certPath' VALUE kmip_cert_path,
'keyPath' VALUE kmip_key_path));
END;
-- Key Provider Management
@ -273,7 +281,8 @@ CREATE FUNCTION pg_tde_change_database_key_provider_kmip(provider_name TEXT,
kmip_host TEXT,
kmip_port INT,
kmip_ca_path TEXT,
kmip_cert_path TEXT)
kmip_cert_path TEXT,
kmip_key_path TEXT)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -283,14 +292,16 @@ BEGIN ATOMIC
json_object('host' VALUE COALESCE(kmip_host, ''),
'port' VALUE kmip_port,
'caPath' VALUE COALESCE(kmip_ca_path, ''),
'certPath' VALUE COALESCE(kmip_cert_path, '')));
'certPath' VALUE COALESCE(kmip_cert_path, ''),
'keyPath' VALUE COALESCE(kmip_key_path, '')));
END;
CREATE FUNCTION pg_tde_change_database_key_provider_kmip(provider_name TEXT,
kmip_host JSON,
kmip_port JSON,
kmip_ca_path JSON,
kmip_cert_path JSON)
kmip_cert_path JSON,
kmip_key_path JSON)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -300,7 +311,8 @@ BEGIN ATOMIC
json_object('host' VALUE kmip_host,
'port' VALUE kmip_port,
'caPath' VALUE kmip_ca_path,
'certPath' VALUE kmip_cert_path));
'certPath' VALUE kmip_cert_path,
'keyPath' VALUE kmip_key_path));
END;
-- Global Tablespace Key Provider Management
@ -367,7 +379,8 @@ CREATE FUNCTION pg_tde_change_global_key_provider_kmip(provider_name TEXT,
kmip_host TEXT,
kmip_port INT,
kmip_ca_path TEXT,
kmip_cert_path TEXT)
kmip_cert_path TEXT,
kmip_key_path TEXT)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -377,14 +390,16 @@ BEGIN ATOMIC
json_object('host' VALUE COALESCE(kmip_host, ''),
'port' VALUE kmip_port,
'caPath' VALUE COALESCE(kmip_ca_path, ''),
'certPath' VALUE COALESCE(kmip_cert_path, '')));
'certPath' VALUE COALESCE(kmip_cert_path, ''),
'keyPath' VALUE COALESCE(kmip_key_path, '')));
END;
CREATE FUNCTION pg_tde_change_global_key_provider_kmip(provider_name TEXT,
kmip_host JSON,
kmip_port JSON,
kmip_ca_path JSON,
kmip_cert_path JSON)
kmip_cert_path JSON,
kmip_key_path JSON)
RETURNS INT
LANGUAGE SQL
BEGIN ATOMIC
@ -394,7 +409,8 @@ BEGIN ATOMIC
json_object('host' VALUE kmip_host,
'port' VALUE kmip_port,
'caPath' VALUE kmip_ca_path,
'certPath' VALUE kmip_cert_path));
'certPath' VALUE kmip_cert_path,
'keyPath' VALUE kmip_key_path));
END;
CREATE FUNCTION pg_tde_is_encrypted(relation REGCLASS)

@ -1,6 +1,6 @@
CREATE EXTENSION pg_tde;
SELECT pg_tde_add_database_key_provider_kmip('kmip-prov','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_database_key_provider_kmip('kmip-prov','127.0.0.1', 5696, '/tmp/server_certificate.pem', '/tmp/client_certificate_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_set_key_using_database_key_provider('kmip-key','kmip-prov');
CREATE TABLE test_enc(
@ -20,6 +20,6 @@ SELECT pg_tde_verify_key();
DROP TABLE test_enc;
-- Creating provider fails if we can't connect to kmip server
SELECT pg_tde_add_database_key_provider_kmip('will-not-work','127.0.0.1', 61, '/tmp/server_certificate.pem', '/tmp/client_key_jane_doe.pem');
SELECT pg_tde_add_database_key_provider_kmip('will-not-work','127.0.0.1', 61, '/tmp/server_certificate.pem', '/tmp/client_certificate_jane_doe.pem', '/tmp/client_key_jane_doe.pem');
DROP EXTENSION pg_tde;

@ -888,15 +888,17 @@ load_kmip_keyring_provider_options(char *keyring_options)
if (kmip_keyring->kmip_host == NULL || kmip_keyring->kmip_host[0] == '\0' ||
kmip_keyring->kmip_port == NULL || kmip_keyring->kmip_port[0] == '\0' ||
kmip_keyring->kmip_ca_path == NULL || kmip_keyring->kmip_ca_path[0] == '\0' ||
kmip_keyring->kmip_cert_path == NULL || kmip_keyring->kmip_cert_path[0] == '\0')
kmip_keyring->kmip_cert_path == NULL || kmip_keyring->kmip_cert_path[0] == '\0' ||
kmip_keyring->kmip_key_path == NULL || kmip_keyring->kmip_key_path[0] == '\0')
{
ereport(WARNING,
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing in the keyring options:%s%s%s%s",
errmsg("missing in the keyring options:%s%s%s%s%s",
(kmip_keyring->kmip_host != NULL && kmip_keyring->kmip_host[0] != '\0') ? "" : " host",
(kmip_keyring->kmip_port != NULL && kmip_keyring->kmip_port[0] != '\0') ? "" : " port",
(kmip_keyring->kmip_ca_path != NULL && kmip_keyring->kmip_ca_path[0] != '\0') ? "" : " caPath",
(kmip_keyring->kmip_cert_path != NULL && kmip_keyring->kmip_cert_path[0] != '\0') ? "" : " certPath"));
(kmip_keyring->kmip_cert_path != NULL && kmip_keyring->kmip_cert_path[0] != '\0') ? "" : " certPath",
(kmip_keyring->kmip_key_path != NULL && kmip_keyring->kmip_key_path[0] != '\0') ? "" : " keyPath"));
return NULL;
}
@ -925,6 +927,7 @@ debug_print_kerying(GenericKeyring *keyring)
elog(DEBUG2, "KMIP Keyring Port: %s", ((KmipKeyring *) keyring)->kmip_port);
elog(DEBUG2, "KMIP Keyring CA Path: %s", ((KmipKeyring *) keyring)->kmip_ca_path);
elog(DEBUG2, "KMIP Keyring Cert Path: %s", ((KmipKeyring *) keyring)->kmip_cert_path);
elog(DEBUG2, "KMIP Keyring Key Path: %s", ((KmipKeyring *) keyring)->kmip_key_path);
break;
case UNKNOWN_KEY_PROVIDER:
break;

@ -72,6 +72,7 @@ typedef enum JsonKeyringField
JK_KMIP_PORT,
JK_KMIP_CA_PATH,
JK_KMIP_CERT_PATH,
JK_KMIP_KEY_PATH,
/* must be the last */
JK_FIELDS_TOTAL
@ -100,6 +101,7 @@ static const char *JK_FIELD_NAMES[JK_FIELDS_TOTAL] = {
[JK_KMIP_PORT] = "port",
[JK_KMIP_CA_PATH] = "caPath",
[JK_KMIP_CERT_PATH] = "certPath",
[JK_KMIP_KEY_PATH] = "keyPath",
};
typedef struct JsonKeyringState
@ -387,6 +389,8 @@ json_kring_object_field_start(void *state, char *fname, bool isnull)
parse->top_level_field = JK_KMIP_CA_PATH;
else if (strcmp(fname, JK_FIELD_NAMES[JK_KMIP_CERT_PATH]) == 0)
parse->top_level_field = JK_KMIP_CERT_PATH;
else if (strcmp(fname, JK_FIELD_NAMES[JK_KMIP_KEY_PATH]) == 0)
parse->top_level_field = JK_KMIP_KEY_PATH;
else
{
parse->top_level_field = JK_FIELD_UNKNOWN;
@ -518,6 +522,9 @@ json_kring_assign_scalar(JsonKeyringState *parse, JsonKeyringField field, char *
case JK_KMIP_CERT_PATH:
kmip->kmip_cert_path = value;
break;
case JK_KMIP_KEY_PATH:
kmip->kmip_key_path = value;
break;
default:
elog(ERROR, "json keyring: unexpected scalar field %d", field);

@ -86,6 +86,7 @@ typedef struct KmipKeyring
char *kmip_port;
char *kmip_ca_path;
char *kmip_cert_path;
char *kmip_key_path;
} KmipKeyring;
extern void RegisterKeyProviderType(const TDEKeyringRoutine *routine, ProviderType type);

@ -61,7 +61,7 @@ kmipSslConnect(KmipCtx *ctx, KmipKeyring *kmip_keyring, bool throw_error)
return false;
}
if (SSL_CTX_use_PrivateKey_file(ctx->ssl, kmip_keyring->kmip_cert_path, SSL_FILETYPE_PEM) != 1)
if (SSL_CTX_use_PrivateKey_file(ctx->ssl, kmip_keyring->kmip_key_path, SSL_FILETYPE_PEM) != 1)
{
SSL_CTX_free(ctx->ssl);
ereport(level, errmsg("SSL error: Loading the client key failed"));

@ -203,7 +203,7 @@ main(int argc, char *argv[])
{
provider_found = true;
if (argc - argstart != 7 && argc - argstart != 8)
if (argc - argstart != 8 && argc - argstart != 9)
{
help();
puts("\n");
@ -211,7 +211,7 @@ main(int argc, char *argv[])
exit(1);
}
if (!build_json(json, 5, "type", "kmip", "host", argv[4 + argstart], "port", argv[5 + argstart], "caPath", (argc - argstart > 7 ? argv[7 + argstart] : ""), "certPath", argv[6 + argstart]))
if (!build_json(json, 6, "type", "kmip", "host", argv[4 + argstart], "port", argv[5 + argstart], "caPath", (argc - argstart > 8 ? argv[8 + argstart] : ""), "certPath", argv[6 + argstart], "keyPath", argv[7 + argstart]))
{
exit(1);
}

Loading…
Cancel
Save