[EaR]: Update KMS APIs to split encryption keys endpoints (#9017)

* [EaR]: Update KMS APIs to split encryption keys endpoints

Description
  diff-1: Address review comments

Major changes proposed:
1. Extend fdbserver to allow parsing two endpoints for encryption at-rest
support: getEncrypitonKeys, getLatestEncryptionKeys
2. Update RESTKmsConnector to do the following:
 2.1. Split the getLatest and getCipher requests.
 2.2. "domain_id" for point lookup marked as 'optional'

Testing

devRunCorrectness - 100K
This commit is contained in:
Ata E Husain Bohra 2023-01-09 10:55:53 -08:00 committed by GitHub
parent d4cbe20d5f
commit f673fce975
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 32 additions and 22 deletions

View File

@ -1062,6 +1062,7 @@ void ServerKnobs::initialize(Randomize randomize, ClientKnobs* clientKnobs, IsSi
// NOTE: Care must be taken when attempting to update below configurations for a up/running FDB cluster.
init( REST_KMS_CONNECTOR_DISCOVER_KMS_URL_FILE, "");
init( REST_KMS_CONNECTOR_GET_ENCRYPTION_KEYS_ENDPOINT, "");
init( REST_KMS_CONNECTOR_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT, "");
init( REST_KMS_CONNECTOR_GET_BLOB_METADATA_ENDPOINT, "");
// Details to fetch validation token from a localhost file
// acceptable format: "<token_name1>#<absolute_file_path1>,<token_name2>#<absolute_file_path2>,.."

View File

@ -1024,6 +1024,7 @@ public:
bool REST_KMS_CONNECTOR_REFRESH_KMS_URLS;
double REST_KMS_CONNECTOR_REFRESH_KMS_URLS_INTERVAL_SEC;
std::string REST_KMS_CONNECTOR_GET_ENCRYPTION_KEYS_ENDPOINT;
std::string REST_KMS_CONNECTOR_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT;
std::string REST_KMS_CONNECTOR_GET_BLOB_METADATA_ENDPOINT;
// Idempotency ids

View File

@ -77,9 +77,6 @@ const char* TOKEN_NAME_FILE_SEP = "#";
const char* TOKEN_TUPLE_SEP = ",";
const char DISCOVER_URL_FILE_URL_SEP = '\n';
const char* QUERY_MODE_LOOKUP_BY_DOMAIN_ID = "lookupByDomainId";
const char* QUERY_MODE_LOOKUP_BY_KEY_ID = "lookupByKeyId";
const char* BLOB_METADATA_DETAILS_TAG = "blob_metadata_details";
const char* BLOB_METADATA_DOMAIN_ID_TAG = "domain_id";
const char* BLOB_METADATA_BASE_LOCATION_TAG = "base_location";
@ -615,7 +612,7 @@ StringRef getEncryptKeysByKeyIdsRequestBody(Reference<RESTKmsConnectorCtx> ctx,
// "cipher_key_details" = [
// {
// "base_cipher_id" : <cipherKeyId>
// "encrypt_domain_id" : <domainId>
// "encrypt_domain_id" : <domainId> // Optional
// },
// {
// ....
@ -637,9 +634,6 @@ StringRef getEncryptKeysByKeyIdsRequestBody(Reference<RESTKmsConnectorCtx> ctx,
rapidjson::Document doc;
doc.SetObject();
// Append 'query_mode' object
addQueryModeSection(ctx, doc, QUERY_MODE_LOOKUP_BY_KEY_ID);
// Append 'cipher_key_details' as json array
rapidjson::Value keyIdDetails(rapidjson::kArrayType);
for (const auto& detail : req.encryptKeyInfos) {
@ -651,11 +645,13 @@ StringRef getEncryptKeysByKeyIdsRequestBody(Reference<RESTKmsConnectorCtx> ctx,
baseKeyId.SetUint64(detail.baseCipherId);
keyIdDetail.AddMember(key, baseKeyId, doc.GetAllocator());
// Add 'encrypt_domain_id'
key.SetString(ENCRYPT_DOMAIN_ID_TAG, doc.GetAllocator());
rapidjson::Value domainId;
domainId.SetInt64(detail.domainId);
keyIdDetail.AddMember(key, domainId, doc.GetAllocator());
if (detail.domainId.present()) {
// Add 'encrypt_domain_id'
key.SetString(ENCRYPT_DOMAIN_ID_TAG, doc.GetAllocator());
rapidjson::Value domainId;
domainId.SetInt64(detail.domainId.get());
keyIdDetail.AddMember(key, domainId, doc.GetAllocator());
}
// push above object to the array
keyIdDetails.PushBack(keyIdDetail, doc.GetAllocator());
@ -812,9 +808,6 @@ StringRef getEncryptKeysByDomainIdsRequestBody(Reference<RESTKmsConnectorCtx> ct
rapidjson::Document doc;
doc.SetObject();
// Append 'query_mode' object
addQueryModeSection(ctx, doc, QUERY_MODE_LOOKUP_BY_DOMAIN_ID);
// Append 'cipher_key_details' as json array
addLatestDomainDetailsToDoc(doc, CIPHER_KEY_DETAILS_TAG, ENCRYPT_DOMAIN_ID_TAG, req.encryptDomainIds);
@ -849,7 +842,7 @@ ACTOR Future<Void> fetchEncryptionKeysByDomainIds(Reference<RESTKmsConnectorCtx>
f = &parseEncryptCipherResponse;
Standalone<VectorRef<EncryptCipherKeyDetailsRef>> result = wait(kmsRequestImpl(
ctx, SERVER_KNOBS->REST_KMS_CONNECTOR_GET_ENCRYPTION_KEYS_ENDPOINT, requestBodyRef, std::move(f)));
ctx, SERVER_KNOBS->REST_KMS_CONNECTOR_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT, requestBodyRef, std::move(f)));
reply.cipherKeyDetails = result;
reply.arena.dependsOn(result.arena());
req.reply.send(reply);

View File

@ -123,13 +123,15 @@ ACTOR Future<Void> ekLookupByIds(Reference<SimKmsConnectorContext> ctx,
for (const auto& item : req.encryptKeyInfos) {
const auto& itr = ctx->simEncryptKeyStore.find(item.baseCipherId);
if (itr != ctx->simEncryptKeyStore.end()) {
// TODO: Relax assert if EKP APIs are updated to make 'domain_id' optional for encryption keys point lookups
ASSERT(item.domainId.present());
rep.cipherKeyDetails.emplace_back_deep(
rep.arena, item.domainId, itr->first, StringRef(itr->second.get()->key), refAtTS, expAtTS);
rep.arena, item.domainId.get(), itr->first, StringRef(itr->second.get()->key), refAtTS, expAtTS);
if (dbgKIdTrace.present()) {
// {encryptDomainId, baseCipherId} forms a unique tuple across encryption domains
dbgKIdTrace.get().detail(
getEncryptDbgTraceKey(ENCRYPT_DBG_TRACE_RESULT_PREFIX, item.domainId, itr->first), "");
getEncryptDbgTraceKey(ENCRYPT_DBG_TRACE_RESULT_PREFIX, item.domainId.get(), itr->first), "");
}
} else {
success = false;

View File

@ -117,7 +117,7 @@ enum {
OPT_METRICSPREFIX, OPT_LOGGROUP, OPT_LOCALITY, OPT_IO_TRUST_SECONDS, OPT_IO_TRUST_WARN_ONLY, OPT_FILESYSTEM, OPT_PROFILER_RSS_SIZE, OPT_KVFILE,
OPT_TRACE_FORMAT, OPT_WHITELIST_BINPATH, OPT_BLOB_CREDENTIAL_FILE, OPT_CONFIG_PATH, OPT_USE_TEST_CONFIG_DB, OPT_NO_CONFIG_DB, OPT_FAULT_INJECTION, OPT_PROFILER, OPT_PRINT_SIMTIME,
OPT_FLOW_PROCESS_NAME, OPT_FLOW_PROCESS_ENDPOINT, OPT_IP_TRUSTED_MASK, OPT_KMS_CONN_DISCOVERY_URL_FILE, OPT_KMS_CONNECTOR_TYPE, OPT_KMS_CONN_VALIDATION_TOKEN_DETAILS,
OPT_KMS_CONN_GET_ENCRYPTION_KEYS_ENDPOINT, OPT_KMS_CONN_GET_BLOB_METADATA_ENDPOINT, OPT_NEW_CLUSTER_KEY, OPT_AUTHZ_PUBLIC_KEY_FILE, OPT_USE_FUTURE_PROTOCOL_VERSION
OPT_KMS_CONN_GET_ENCRYPTION_KEYS_ENDPOINT, OPT_KMS_CONN_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT, OPT_KMS_CONN_GET_BLOB_METADATA_ENDPOINT, OPT_NEW_CLUSTER_KEY, OPT_AUTHZ_PUBLIC_KEY_FILE, OPT_USE_FUTURE_PROTOCOL_VERSION
};
CSimpleOpt::SOption g_rgOptions[] = {
@ -218,6 +218,7 @@ CSimpleOpt::SOption g_rgOptions[] = {
{ OPT_KMS_CONNECTOR_TYPE, "--kms-connector-type", SO_REQ_SEP },
{ OPT_KMS_CONN_VALIDATION_TOKEN_DETAILS, "--kms-conn-validation-token-details", SO_REQ_SEP },
{ OPT_KMS_CONN_GET_ENCRYPTION_KEYS_ENDPOINT, "--kms-conn-get-encryption-keys-endpoint", SO_REQ_SEP },
{ OPT_KMS_CONN_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT, "--kms-conn-get-latest-encryption-keys-endpoint", SO_REQ_SEP },
{ OPT_KMS_CONN_GET_BLOB_METADATA_ENDPOINT, "--kms-conn-get-blob-metadata-endpoint", SO_REQ_SEP },
{ OPT_USE_FUTURE_PROTOCOL_VERSION, "--use-future-protocol-version", SO_REQ_SEP },
TLS_OPTION_FLAGS,
@ -1708,6 +1709,10 @@ private:
knobs.emplace_back("rest_kms_connector_get_encryption_keys_endpoint", args.OptionArg());
break;
}
case OPT_KMS_CONN_GET_LATEST_ENCRYPTION_KEYS_ENDPOINT: {
knobs.emplace_back("rest_kms_connector_get_latest_encryption_keys_endpoint", args.OptionArg());
break;
}
case OPT_KMS_CONN_GET_BLOB_METADATA_ENDPOINT: {
knobs.emplace_back("rest_kms_connector_get_blob_metadata_endpoint", args.OptionArg());
break;

View File

@ -127,15 +127,23 @@ struct KmsConnLookupEKsByKeyIdsRep {
struct KmsConnLookupKeyIdsReqInfo {
constexpr static FileIdentifier file_identifier = 3092256;
EncryptCipherDomainId domainId;
// Encryption at-rest relies on partioning database to define encryption domains, one such possible domain is
// "Tenants". It is possible that KMS assigned 'baseCipherId' embedded 'encryption domain information', hence, make
// the field optional.
Optional<EncryptCipherDomainId> domainId;
EncryptCipherBaseKeyId baseCipherId;
KmsConnLookupKeyIdsReqInfo() : domainId(INVALID_ENCRYPT_DOMAIN_ID), baseCipherId(INVALID_ENCRYPT_CIPHER_KEY_ID) {}
explicit KmsConnLookupKeyIdsReqInfo(const EncryptCipherDomainId dId, const EncryptCipherBaseKeyId bCId)
explicit KmsConnLookupKeyIdsReqInfo(const Optional<EncryptCipherDomainId> dId, const EncryptCipherBaseKeyId bCId)
: domainId(dId), baseCipherId(bCId) {}
bool operator==(const KmsConnLookupKeyIdsReqInfo& info) const {
return domainId == info.domainId && baseCipherId == info.baseCipherId;
if (domainId.present()) {
if (!info.domainId.present() || domainId.get() != info.domainId.get()) {
return false;
}
}
return baseCipherId == info.baseCipherId;
}
template <class Ar>