mirror of
https://github.com/postgres/postgres.git
synced 2025-06-03 00:02:26 -04:00
PG-1419 Validate key provider access
This adds some validation to make sure we can access the key provider when it's created to make the user experience a little nicer. The actual access validation is very rudimentary for now but can easily be expanded.
This commit is contained in:
parent
1b8513c21e
commit
157230de39
@ -206,8 +206,6 @@ To add a database specific provider:
|
|||||||
pg_tde_add_database_key_provider_<TYPE>('provider_name', ... details ...)
|
pg_tde_add_database_key_provider_<TYPE>('provider_name', ... details ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that in these functions do not verify the parameters. For that, see `pg_tde_verify_key`.
|
|
||||||
|
|
||||||
### Changing providers
|
### Changing providers
|
||||||
|
|
||||||
To change a value of a global provider:
|
To change a value of a global provider:
|
||||||
|
@ -160,4 +160,7 @@ SELECT id, provider_name FROM pg_tde_list_all_global_key_providers();
|
|||||||
-1 | file-keyring
|
-1 | file-keyring
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- Creating a file key provider fails if we can't open or create the file
|
||||||
|
SELECT pg_tde_add_database_key_provider_file('will-not-work','/cant-create-file-in-root.per');
|
||||||
|
ERROR: Failed to open keyring file /cant-create-file-in-root.per: Permission denied
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -164,4 +164,7 @@ SELECT id, provider_name FROM pg_tde_list_all_global_key_providers();
|
|||||||
-2 | file-keyring
|
-2 | file-keyring
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- Creating a file key provider fails if we can't open or create the file
|
||||||
|
SELECT pg_tde_add_database_key_provider_file('will-not-work','/cant-create-file-in-root.per');
|
||||||
|
ERROR: Failed to open keyring file /cant-create-file-in-root.per: Permission denied
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -34,4 +34,7 @@ SELECT pg_tde_verify_key();
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE test_enc;
|
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');
|
||||||
|
ERROR: SSL error: BIO_do_connect failed
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -51,4 +51,7 @@ SELECT pg_tde_verify_key();
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE test_enc;
|
DROP TABLE test_enc;
|
||||||
|
-- Creating provider fails if we can't connect to vault
|
||||||
|
SELECT pg_tde_add_database_key_provider_vault_v2('will-not-work', :'root_token', 'http://127.0.0.1:61', 'secret', NULL);
|
||||||
|
ERROR: HTTP(S) request to keyring provider "will-not-work" failed
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -52,4 +52,7 @@ SELECT id, provider_name FROM pg_tde_list_all_global_key_providers();
|
|||||||
SELECT pg_tde_delete_global_key_provider('file-keyring2');
|
SELECT pg_tde_delete_global_key_provider('file-keyring2');
|
||||||
SELECT id, provider_name FROM pg_tde_list_all_global_key_providers();
|
SELECT id, provider_name FROM pg_tde_list_all_global_key_providers();
|
||||||
|
|
||||||
|
-- Creating a file key provider fails if we can't open or create the file
|
||||||
|
SELECT pg_tde_add_database_key_provider_file('will-not-work','/cant-create-file-in-root.per');
|
||||||
|
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -19,4 +19,7 @@ SELECT pg_tde_verify_key();
|
|||||||
|
|
||||||
DROP TABLE test_enc;
|
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');
|
||||||
|
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -31,4 +31,7 @@ SELECT pg_tde_verify_key();
|
|||||||
|
|
||||||
DROP TABLE test_enc;
|
DROP TABLE test_enc;
|
||||||
|
|
||||||
|
-- Creating provider fails if we can't connect to vault
|
||||||
|
SELECT pg_tde_add_database_key_provider_vault_v2('will-not-work', :'root_token', 'http://127.0.0.1:61', 'secret', NULL);
|
||||||
|
|
||||||
DROP EXTENSION pg_tde;
|
DROP EXTENSION pg_tde;
|
||||||
|
@ -472,6 +472,8 @@ check_provider_record(KeyringProviderRecord *provider_record)
|
|||||||
errmsg("Invalid provider options."));
|
errmsg("Invalid provider options."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyringValidate(provider);
|
||||||
|
|
||||||
pfree(provider);
|
pfree(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@ typedef struct TDEKeyringRoutine
|
|||||||
{
|
{
|
||||||
KeyInfo *(*keyring_get_key) (GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *returnCode);
|
KeyInfo *(*keyring_get_key) (GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *returnCode);
|
||||||
void (*keyring_store_key) (GenericKeyring *keyring, KeyInfo *key);
|
void (*keyring_store_key) (GenericKeyring *keyring, KeyInfo *key);
|
||||||
|
void (*keyring_validate) (GenericKeyring *keyring);
|
||||||
} TDEKeyringRoutine;
|
} TDEKeyringRoutine;
|
||||||
|
|
||||||
typedef struct FileKeyring
|
typedef struct FileKeyring
|
||||||
@ -91,5 +92,6 @@ extern void RegisterKeyProviderType(const TDEKeyringRoutine *routine, ProviderTy
|
|||||||
|
|
||||||
extern KeyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *returnCode);
|
extern KeyInfo *KeyringGetKey(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *returnCode);
|
||||||
extern KeyInfo *KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len);
|
extern KeyInfo *KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, unsigned key_len);
|
||||||
|
extern void KeyringValidate(GenericKeyring *keyring);
|
||||||
|
|
||||||
#endif /* KEYRING_API_H */
|
#endif /* KEYRING_API_H */
|
||||||
|
@ -74,6 +74,7 @@ RegisterKeyProviderType(const TDEKeyringRoutine *routine, ProviderType type)
|
|||||||
Assert(routine != NULL);
|
Assert(routine != NULL);
|
||||||
Assert(routine->keyring_get_key != NULL);
|
Assert(routine->keyring_get_key != NULL);
|
||||||
Assert(routine->keyring_store_key != NULL);
|
Assert(routine->keyring_store_key != NULL);
|
||||||
|
Assert(routine->keyring_validate != NULL);
|
||||||
|
|
||||||
kp = find_key_provider_type(type);
|
kp = find_key_provider_type(type);
|
||||||
if (kp)
|
if (kp)
|
||||||
@ -148,3 +149,15 @@ KeyringGenerateNewKeyAndStore(GenericKeyring *keyring, const char *key_name, uns
|
|||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
KeyringValidate(GenericKeyring *keyring)
|
||||||
|
{
|
||||||
|
RegisteredKeyProviderType *kp = find_key_provider_type(keyring->type);
|
||||||
|
|
||||||
|
if (kp == NULL)
|
||||||
|
ereport(ERROR,
|
||||||
|
errmsg("Key provider of type %d not registered", keyring->type));
|
||||||
|
|
||||||
|
kp->routine->keyring_validate(keyring);
|
||||||
|
}
|
||||||
|
@ -28,10 +28,12 @@
|
|||||||
|
|
||||||
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
||||||
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
||||||
|
static void validate(GenericKeyring *keyring);
|
||||||
|
|
||||||
const TDEKeyringRoutine keyringFileRoutine = {
|
const TDEKeyringRoutine keyringFileRoutine = {
|
||||||
.keyring_get_key = get_key_by_name,
|
.keyring_get_key = get_key_by_name,
|
||||||
.keyring_store_key = set_key_by_name
|
.keyring_store_key = set_key_by_name,
|
||||||
|
.keyring_validate = validate,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -143,3 +145,19 @@ set_key_by_name(GenericKeyring *keyring, KeyInfo *key)
|
|||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate(GenericKeyring *keyring)
|
||||||
|
{
|
||||||
|
FileKeyring *file_keyring = (FileKeyring *) keyring;
|
||||||
|
int fd = BasicOpenFile(file_keyring->file_name, O_CREAT | O_RDWR | PG_BINARY);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
ereport(ERROR,
|
||||||
|
errcode_for_file_access(),
|
||||||
|
errmsg("Failed to open keyring file %s: %m", file_keyring->file_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
@ -26,10 +26,12 @@
|
|||||||
|
|
||||||
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
||||||
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
||||||
|
static void validate(GenericKeyring *keyring);
|
||||||
|
|
||||||
const TDEKeyringRoutine keyringKmipRoutine = {
|
const TDEKeyringRoutine keyringKmipRoutine = {
|
||||||
.keyring_get_key = get_key_by_name,
|
.keyring_get_key = get_key_by_name,
|
||||||
.keyring_store_key = set_key_by_name
|
.keyring_store_key = set_key_by_name,
|
||||||
|
.keyring_validate = validate,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -204,3 +206,15 @@ get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCode
|
|||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate(GenericKeyring *keyring)
|
||||||
|
{
|
||||||
|
KmipKeyring *kmip_keyring = (KmipKeyring *) keyring;
|
||||||
|
KmipCtx ctx;
|
||||||
|
|
||||||
|
kmipSslConnect(&ctx, kmip_keyring, true);
|
||||||
|
|
||||||
|
BIO_free_all(ctx.bio);
|
||||||
|
SSL_CTX_free(ctx.ssl);
|
||||||
|
}
|
||||||
|
@ -70,10 +70,12 @@ static bool curl_perform(VaultV2Keyring *keyring, const char *url, CurlString *o
|
|||||||
|
|
||||||
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
static void set_key_by_name(GenericKeyring *keyring, KeyInfo *key);
|
||||||
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
static KeyInfo *get_key_by_name(GenericKeyring *keyring, const char *key_name, KeyringReturnCodes *return_code);
|
||||||
|
static void validate(GenericKeyring *keyring);
|
||||||
|
|
||||||
const TDEKeyringRoutine keyringVaultV2Routine = {
|
const TDEKeyringRoutine keyringVaultV2Routine = {
|
||||||
.keyring_get_key = get_key_by_name,
|
.keyring_get_key = get_key_by_name,
|
||||||
.keyring_store_key = set_key_by_name
|
.keyring_store_key = set_key_by_name,
|
||||||
|
.keyring_validate = validate,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -300,6 +302,41 @@ cleanup:
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
validate(GenericKeyring *keyring)
|
||||||
|
{
|
||||||
|
VaultV2Keyring *vault_keyring = (VaultV2Keyring *) keyring;
|
||||||
|
char url[VAULT_URL_MAX_LEN];
|
||||||
|
CurlString str;
|
||||||
|
long httpCode = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate connection by listing available keys at the root level of the
|
||||||
|
* mount point
|
||||||
|
*/
|
||||||
|
snprintf(url, VAULT_URL_MAX_LEN, "%s/v1/%s/metadata/?list=true",
|
||||||
|
vault_keyring->vault_url, vault_keyring->vault_mount_path);
|
||||||
|
|
||||||
|
if (!curl_perform(vault_keyring, url, &str, &httpCode, NULL))
|
||||||
|
{
|
||||||
|
ereport(ERROR,
|
||||||
|
errmsg("HTTP(S) request to keyring provider \"%s\" failed",
|
||||||
|
vault_keyring->keyring.provider_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the mount point doesn't have any secrets yet, we'll get a 404. */
|
||||||
|
if (httpCode != 200 && httpCode != 404)
|
||||||
|
{
|
||||||
|
ereport(ERROR,
|
||||||
|
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("Listing secrets of \"%s\" at mountpoint \"%s\" failed",
|
||||||
|
vault_keyring->vault_url, vault_keyring->vault_mount_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.ptr != NULL)
|
||||||
|
pfree(str.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSON parser routines
|
* JSON parser routines
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user