Update Redwood encryption interface (#8172)

Update Redwood encryption interface to make it better suit for per-tenant encryption, where we will need to do tenant page split.
This commit is contained in:
Yi Wu 2022-09-16 15:56:05 -07:00 committed by GitHub
parent 2bdfc52f97
commit e66942ada4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 481 additions and 394 deletions

View File

@ -2192,7 +2192,7 @@ public:
int64_t remapCleanupWindowBytes,
int concurrentExtentReads,
bool memoryOnly,
Reference<IEncryptionKeyProvider> keyProvider,
Reference<IPageEncryptionKeyProvider> keyProvider,
Promise<Void> errorPromise = {})
: keyProvider(keyProvider), ioLock(FLOW_KNOBS->MAX_OUTSTANDING, ioMaxPriority, FLOW_KNOBS->MAX_OUTSTANDING / 2),
pageCacheBytes(pageCacheSizeBytes), desiredPageSize(desiredPageSize), desiredExtentSize(desiredExtentSize),
@ -2974,7 +2974,7 @@ public:
try {
page->postReadHeader(pageID);
if (page->isEncrypted()) {
EncryptionKey k = wait(self->keyProvider->getSecrets(page->encryptionKey));
ArenaPage::EncryptionKey k = wait(self->keyProvider->getEncryptionKey(page->getEncodingHeader()));
page->encryptionKey = k;
}
page->postReadPayload(pageID);
@ -3042,7 +3042,7 @@ public:
try {
page->postReadHeader(pageIDs.front());
if (page->isEncrypted()) {
EncryptionKey k = wait(self->keyProvider->getSecrets(page->encryptionKey));
ArenaPage::EncryptionKey k = wait(self->keyProvider->getEncryptionKey(page->getEncodingHeader()));
page->encryptionKey = k;
}
page->postReadPayload(pageIDs.front());
@ -3955,7 +3955,7 @@ private:
int physicalExtentSize;
int pagesPerExtent;
Reference<IEncryptionKeyProvider> keyProvider;
Reference<IPageEncryptionKeyProvider> keyProvider;
PriorityMultiLock ioLock;
@ -5036,7 +5036,7 @@ public:
VersionedBTree(IPager2* pager,
std::string name,
EncodingType defaultEncodingType,
Reference<IEncryptionKeyProvider> keyProvider)
Reference<IPageEncryptionKeyProvider> keyProvider)
: m_pager(pager), m_encodingType(defaultEncodingType), m_enforceEncodingType(false), m_keyProvider(keyProvider),
m_pBuffer(nullptr), m_mutationCount(0), m_name(name) {
@ -5064,7 +5064,7 @@ public:
state Reference<ArenaPage> page = self->m_pager->newPageBuffer();
page->init(self->m_encodingType, PageType::BTreeNode, 1);
if (page->isEncrypted()) {
EncryptionKey k = wait(self->m_keyProvider->getByRange(dbBegin.key, dbEnd.key));
ArenaPage::EncryptionKey k = wait(self->m_keyProvider->getLatestDefaultEncryptionKey());
page->encryptionKey = k;
}
@ -5543,7 +5543,7 @@ private:
IPager2* m_pager;
EncodingType m_encodingType;
bool m_enforceEncodingType;
Reference<IEncryptionKeyProvider> m_keyProvider;
Reference<IPageEncryptionKeyProvider> m_keyProvider;
// Counter to update with DecodeCache memory usage
int64_t* m_pDecodeCacheMemory = nullptr;
@ -5843,7 +5843,7 @@ private:
(pagesToBuild[pageIndex].blockCount == 1) ? PageType::BTreeNode : PageType::BTreeSuperNode,
height);
if (page->isEncrypted()) {
EncryptionKey k = wait(self->m_keyProvider->getByRange(pageLowerBound.key, pageUpperBound.key));
ArenaPage::EncryptionKey k = wait(self->m_keyProvider->getLatestDefaultEncryptionKey());
page->encryptionKey = k;
}
@ -7694,7 +7694,7 @@ RedwoodRecordRef VersionedBTree::dbEnd(LiteralStringRef("\xff\xff\xff\xff\xff"))
class KeyValueStoreRedwood : public IKeyValueStore {
public:
KeyValueStoreRedwood(std::string filename, UID logID, Reference<IEncryptionKeyProvider> encryptionKeyProvider)
KeyValueStoreRedwood(std::string filename, UID logID, Reference<IPageEncryptionKeyProvider> encryptionKeyProvider)
: m_filename(filename), m_concurrentReads(SERVER_KNOBS->REDWOOD_KVSTORE_CONCURRENT_READS, 0),
prefetch(SERVER_KNOBS->REDWOOD_KVSTORE_RANGE_PREFETCH) {
@ -7723,7 +7723,7 @@ public:
//
// TODO(yiwu): When the cluster encryption config is available later, fail if the cluster is configured to
// enable encryption, but the Redwood instance is unencrypted.
if (encryptionKeyProvider && encryptionKeyProvider->shouldEnableEncryption()) {
if (encryptionKeyProvider && encryptionKeyProvider->enableEncryption()) {
encodingType = EncodingType::AESEncryptionV1;
m_keyProvider = encryptionKeyProvider;
}
@ -8020,7 +8020,7 @@ private:
PriorityMultiLock m_concurrentReads;
bool prefetch;
Version m_nextCommitVersion;
Reference<IEncryptionKeyProvider> m_keyProvider;
Reference<IPageEncryptionKeyProvider> m_keyProvider;
Future<Void> m_lastCommit = Void();
template <typename T>
@ -8031,7 +8031,7 @@ private:
IKeyValueStore* keyValueStoreRedwoodV1(std::string const& filename,
UID logID,
Reference<IEncryptionKeyProvider> encryptionKeyProvider) {
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider) {
return new KeyValueStoreRedwood(filename, logID, encryptionKeyProvider);
}
@ -9814,7 +9814,7 @@ TEST_CASE("Lredwood/correctness/btree") {
state EncodingType encodingType =
static_cast<EncodingType>(deterministicRandom()->randomInt(0, EncodingType::MAX_ENCODING_TYPE));
state Reference<IEncryptionKeyProvider> keyProvider;
state Reference<IPageEncryptionKeyProvider> keyProvider;
if (encodingType == EncodingType::AESEncryptionV1) {
keyProvider = makeReference<RandomEncryptionKeyProvider>();
} else if (encodingType == EncodingType::XOREncryption_TestOnly) {
@ -10300,7 +10300,7 @@ TEST_CASE(":/redwood/performance/extentQueue") {
remapCleanupWindowBytes,
concurrentExtentReads,
false,
Reference<IEncryptionKeyProvider>());
Reference<IPageEncryptionKeyProvider>());
wait(success(pager->init()));
@ -10358,7 +10358,7 @@ TEST_CASE(":/redwood/performance/extentQueue") {
remapCleanupWindowBytes,
concurrentExtentReads,
false,
Reference<IEncryptionKeyProvider>());
Reference<IPageEncryptionKeyProvider>());
wait(success(pager->init()));
printf("Starting ExtentQueue FastPath Recovery from Disk.\n");
@ -10503,9 +10503,9 @@ TEST_CASE(":/redwood/performance/set") {
remapCleanupWindowBytes,
concurrentExtentReads,
pagerMemoryOnly,
Reference<IEncryptionKeyProvider>());
Reference<IPageEncryptionKeyProvider>());
state VersionedBTree* btree =
new VersionedBTree(pager, file, EncodingType::XXHash64, Reference<IEncryptionKeyProvider>());
new VersionedBTree(pager, file, EncodingType::XXHash64, Reference<IPageEncryptionKeyProvider>());
wait(btree->init());
printf("Initialized. StorageBytes=%s\n", btree->getStorageBytes().toString().c_str());

View File

@ -0,0 +1,40 @@
/*
* IClosable.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FDBSERVER_ICLOSABLE_H
#define FDBSERVER_ICLOSABLE_H
#pragma once
class IClosable {
public:
// IClosable is a base interface for any disk-backed data structure that needs to support asynchronous errors,
// shutdown and deletion
virtual Future<Void> getError()
const = 0; // asynchronously throws an error if there is an internal error. Never set
// inside (on the stack of) a call to another API function on this object.
virtual Future<Void> onClosed()
const = 0; // the future is set to Void when this is totally shut down after dispose() or
// close(). But this function cannot be called after dispose or close!
virtual void dispose() = 0; // permanently delete the data AND invalidate this interface
virtual void close() = 0; // invalidate this interface, but do not delete the data. Outstanding operations may or
// may not take effect in the background.
};
#endif

View File

@ -1,298 +0,0 @@
/*
* IEncryptionKeyProvider.actor.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "fdbclient/BlobCipher.h"
#if defined(NO_INTELLISENSE) && !defined(FDBSERVER_IENCRYPTIONKEYPROVIDER_ACTOR_G_H)
#define FDBSERVER_IENCRYPTIONKEYPROVIDER_ACTOR_G_H
#include "fdbserver/IEncryptionKeyProvider.actor.g.h"
#elif !defined(FDBSERVER_IENCRYPTIONKEYPROVIDER_ACTOR_H)
#define FDBSERVER_IENCRYPTIONKEYPROVIDER_ACTOR_H
#include "fdbclient/GetEncryptCipherKeys.actor.h"
#include "fdbclient/Tenant.h"
#include "fdbserver/EncryptionOpsUtils.h"
#include "fdbserver/ServerDBInfo.h"
#include "flow/Arena.h"
#include "flow/EncryptUtils.h"
#define XXH_INLINE_ALL
#include "flow/xxhash.h"
#include "flow/actorcompiler.h" // This must be the last #include.
typedef uint64_t XOREncryptionKeyID;
// EncryptionKeyRef is somewhat multi-variant, it will contain members representing the union
// of all fields relevant to any implemented encryption scheme. They are generally of
// the form
// Page Fields - fields which come from or are stored in the Page
// Secret Fields - fields which are only known by the Key Provider
// but it is up to each encoding and provider which fields are which and which ones are used
//
// TODO(yiwu): Rename and/or refactor this struct. It doesn't sound like an encryption key should
// contain page fields like encryption header.
struct EncryptionKeyRef {
EncryptionKeyRef(){};
EncryptionKeyRef(Arena& arena, const EncryptionKeyRef& toCopy)
: cipherKeys(toCopy.cipherKeys), secret(arena, toCopy.secret), id(toCopy.id) {}
int expectedSize() const { return secret.size(); }
// Fields for AESEncryptionV1
TextAndHeaderCipherKeys cipherKeys;
Optional<BlobCipherEncryptHeader> cipherHeader;
// Fields for XOREncryption_TestOnly
StringRef secret;
Optional<XOREncryptionKeyID> id;
};
typedef Standalone<EncryptionKeyRef> EncryptionKey;
// Interface used by pager to get encryption keys reading pages from disk
// and by the BTree to get encryption keys to use for new pages
class IEncryptionKeyProvider : public ReferenceCounted<IEncryptionKeyProvider> {
public:
virtual ~IEncryptionKeyProvider() {}
// Get an EncryptionKey with Secret Fields populated based on the given Page Fields.
// It is up to the implementation which fields those are.
// The output Page Fields must match the input Page Fields.
virtual Future<EncryptionKey> getSecrets(const EncryptionKeyRef& key) = 0;
// Get encryption key that should be used for a given user Key-Value range
virtual Future<EncryptionKey> getByRange(const KeyRef& begin, const KeyRef& end) = 0;
// Setting tenant prefix to tenant name map.
virtual void setTenantPrefixIndex(Reference<TenantPrefixIndex> tenantPrefixIndex) {}
virtual bool shouldEnableEncryption() const = 0;
};
// The null key provider is useful to simplify page decoding.
// It throws an error for any key info requested.
class NullKeyProvider : public IEncryptionKeyProvider {
public:
virtual ~NullKeyProvider() {}
bool shouldEnableEncryption() const override { return true; }
Future<EncryptionKey> getSecrets(const EncryptionKeyRef& key) override { throw encryption_key_not_found(); }
Future<EncryptionKey> getByRange(const KeyRef& begin, const KeyRef& end) override {
throw encryption_key_not_found();
}
};
// Key provider for dummy XOR encryption scheme
class XOREncryptionKeyProvider_TestOnly : public IEncryptionKeyProvider {
public:
XOREncryptionKeyProvider_TestOnly(std::string filename) {
ASSERT(g_network->isSimulated());
// Choose a deterministic random filename (without path) byte for secret generation
// Remove any leading directory names
size_t lastSlash = filename.find_last_of("\\/");
if (lastSlash != filename.npos) {
filename.erase(0, lastSlash);
}
xorWith = filename.empty() ? 0x5e
: (uint8_t)filename[XXH3_64bits(filename.data(), filename.size()) % filename.size()];
}
virtual ~XOREncryptionKeyProvider_TestOnly() {}
bool shouldEnableEncryption() const override { return true; }
Future<EncryptionKey> getSecrets(const EncryptionKeyRef& key) override {
if (!key.id.present()) {
throw encryption_key_not_found();
}
EncryptionKey s = key;
uint8_t secret = ~(uint8_t)key.id.get() ^ xorWith;
s.secret = StringRef(s.arena(), &secret, 1);
return s;
}
Future<EncryptionKey> getByRange(const KeyRef& begin, const KeyRef& end) override {
EncryptionKeyRef k;
k.id = end.empty() ? 0 : *(end.end() - 1);
return getSecrets(k);
}
uint8_t xorWith;
};
// Key provider to provider cipher keys randomly from a pre-generated pool. Use for testing.
class RandomEncryptionKeyProvider : public IEncryptionKeyProvider {
public:
RandomEncryptionKeyProvider() {
for (unsigned i = 0; i < NUM_CIPHER; i++) {
BlobCipherDetails cipherDetails;
cipherDetails.encryptDomainId = i;
cipherDetails.baseCipherId = deterministicRandom()->randomUInt64();
cipherDetails.salt = deterministicRandom()->randomUInt64();
cipherKeys[i] = generateCipherKey(cipherDetails);
}
}
virtual ~RandomEncryptionKeyProvider() = default;
bool shouldEnableEncryption() const override { return true; }
Future<EncryptionKey> getSecrets(const EncryptionKeyRef& key) override {
ASSERT(key.cipherHeader.present());
EncryptionKey s = key;
s.cipherKeys.cipherTextKey = cipherKeys[key.cipherHeader.get().cipherTextDetails.encryptDomainId];
s.cipherKeys.cipherHeaderKey = cipherKeys[key.cipherHeader.get().cipherHeaderDetails.encryptDomainId];
return s;
}
Future<EncryptionKey> getByRange(const KeyRef& /*begin*/, const KeyRef& /*end*/) override {
EncryptionKey s;
s.cipherKeys.cipherTextKey = getRandomCipherKey();
s.cipherKeys.cipherHeaderKey = getRandomCipherKey();
return s;
}
private:
Reference<BlobCipherKey> generateCipherKey(const BlobCipherDetails& cipherDetails) {
static unsigned char SHA_KEY[] = "3ab9570b44b8315fdb261da6b1b6c13b";
Arena arena;
StringRef digest = computeAuthToken(reinterpret_cast<const unsigned char*>(&cipherDetails.baseCipherId),
sizeof(EncryptCipherBaseKeyId),
SHA_KEY,
AES_256_KEY_LENGTH,
arena);
return makeReference<BlobCipherKey>(cipherDetails.encryptDomainId,
cipherDetails.baseCipherId,
digest.begin(),
AES_256_KEY_LENGTH,
cipherDetails.salt,
std::numeric_limits<int64_t>::max() /* refreshAt */,
std::numeric_limits<int64_t>::max() /* expireAt */);
}
Reference<BlobCipherKey> getRandomCipherKey() {
return cipherKeys[deterministicRandom()->randomInt(0, NUM_CIPHER)];
}
static constexpr int NUM_CIPHER = 1000;
Reference<BlobCipherKey> cipherKeys[NUM_CIPHER];
};
// Key provider which extract tenant id from range key prefixes, and fetch tenant specific encryption keys from
// EncryptKeyProxy.
class TenantAwareEncryptionKeyProvider : public IEncryptionKeyProvider {
public:
TenantAwareEncryptionKeyProvider(Reference<AsyncVar<ServerDBInfo> const> db) : db(db) {}
virtual ~TenantAwareEncryptionKeyProvider() = default;
bool shouldEnableEncryption() const override {
return isEncryptionOpSupported(EncryptOperationType::STORAGE_SERVER_ENCRYPTION, db->get().client);
}
ACTOR static Future<EncryptionKey> getSecrets(TenantAwareEncryptionKeyProvider* self, EncryptionKeyRef key) {
if (!key.cipherHeader.present()) {
TraceEvent("TenantAwareEncryptionKeyProvider_CipherHeaderMissing");
throw encrypt_ops_error();
}
TextAndHeaderCipherKeys cipherKeys =
wait(getEncryptCipherKeys(self->db, key.cipherHeader.get(), BlobCipherMetrics::KV_REDWOOD));
EncryptionKey s = key;
s.cipherKeys = cipherKeys;
return s;
}
Future<EncryptionKey> getSecrets(const EncryptionKeyRef& key) override { return getSecrets(this, key); }
ACTOR static Future<EncryptionKey> getByRange(TenantAwareEncryptionKeyProvider* self, KeyRef begin, KeyRef end) {
EncryptCipherDomainNameRef domainName;
EncryptCipherDomainId domainId = self->getEncryptionDomainId(begin, end, &domainName);
TextAndHeaderCipherKeys cipherKeys =
wait(getLatestEncryptCipherKeysForDomain(self->db, domainId, domainName, BlobCipherMetrics::KV_REDWOOD));
EncryptionKey s;
s.cipherKeys = cipherKeys;
return s;
}
Future<EncryptionKey> getByRange(const KeyRef& begin, const KeyRef& end) override {
return getByRange(this, begin, end);
}
void setTenantPrefixIndex(Reference<TenantPrefixIndex> tenantPrefixIndex) override {
ASSERT(tenantPrefixIndex.isValid());
this->tenantPrefixIndex = tenantPrefixIndex;
}
private:
EncryptCipherDomainId getEncryptionDomainId(const KeyRef& begin,
const KeyRef& end,
EncryptCipherDomainNameRef* domainName) {
int64_t domainId = SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID;
int64_t beginTenantId = getTenantId(begin, true /*inclusive*/);
int64_t endTenantId = getTenantId(end, false /*inclusive*/);
if (beginTenantId == endTenantId && beginTenantId != SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID) {
ASSERT(tenantPrefixIndex.isValid());
Key tenantPrefix = TenantMapEntry::idToPrefix(beginTenantId);
auto view = tenantPrefixIndex->atLatest();
auto itr = view.find(tenantPrefix);
if (itr != view.end()) {
*domainName = *itr;
domainId = beginTenantId;
} else {
// No tenant with the same tenant id. We could be in optional or disabled tenant mode.
}
}
if (domainId == SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID) {
*domainName = FDB_SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_NAME;
}
return domainId;
}
int64_t getTenantId(const KeyRef& key, bool inclusive) {
// A valid tenant id is always a valid encrypt domain id.
static_assert(INVALID_ENCRYPT_DOMAIN_ID == -1);
if (key.size() && key >= systemKeys.begin) {
return SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID;
}
if (key.size() < TENANT_PREFIX_SIZE) {
// Encryption domain information not available, leverage 'default encryption domain'
return FDB_DEFAULT_ENCRYPT_DOMAIN_ID;
}
StringRef prefix = key.substr(0, TENANT_PREFIX_SIZE);
int64_t tenantId = TenantMapEntry::prefixToId(prefix, EnforceValidTenantId::False);
if (tenantId == TenantInfo::INVALID_TENANT) {
// Encryption domain information not available, leverage 'default encryption domain'
return FDB_DEFAULT_ENCRYPT_DOMAIN_ID;
}
if (!inclusive && key.size() == TENANT_PREFIX_SIZE) {
tenantId = tenantId - 1;
}
ASSERT(tenantId >= 0);
return tenantId;
}
Reference<AsyncVar<ServerDBInfo> const> db;
Reference<TenantPrefixIndex> tenantPrefixIndex;
};
#include "flow/unactorcompiler.h"
#endif

View File

@ -26,7 +26,8 @@
#include "fdbclient/StorageCheckpoint.h"
#include "fdbclient/Tenant.h"
#include "fdbserver/Knobs.h"
#include "fdbserver/IEncryptionKeyProvider.actor.h"
#include "fdbserver/IClosable.h"
#include "fdbserver/IPageEncryptionKeyProvider.actor.h"
#include "fdbserver/ServerDBInfo.h"
struct CheckpointRequest {
@ -44,22 +45,6 @@ struct CheckpointRequest {
: version(version), range(range), format(format), checkpointID(id), checkpointDir(checkpointDir) {}
};
class IClosable {
public:
// IClosable is a base interface for any disk-backed data structure that needs to support asynchronous errors,
// shutdown and deletion
virtual Future<Void> getError()
const = 0; // asynchronously throws an error if there is an internal error. Never set
// inside (on the stack of) a call to another API function on this object.
virtual Future<Void> onClosed()
const = 0; // the future is set to Void when this is totally shut down after dispose() or
// close(). But this function cannot be called after dispose or close!
virtual void dispose() = 0; // permanently delete the data AND invalidate this interface
virtual void close() = 0; // invalidate this interface, but do not delete the data. Outstanding operations may or
// may not take effect in the background.
};
class IKeyValueStore : public IClosable {
public:
virtual KeyValueStoreType getType() const = 0;
@ -151,7 +136,7 @@ extern IKeyValueStore* keyValueStoreSQLite(std::string const& filename,
bool checkIntegrity = false);
extern IKeyValueStore* keyValueStoreRedwoodV1(std::string const& filename,
UID logID,
Reference<IEncryptionKeyProvider> encryptionKeyProvider = {});
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider = {});
extern IKeyValueStore* keyValueStoreRocksDB(std::string const& path,
UID logID,
KeyValueStoreType storeType,
@ -190,7 +175,7 @@ inline IKeyValueStore* openKVStore(KeyValueStoreType storeType,
bool checkChecksums = false,
bool checkIntegrity = false,
bool openRemotely = false,
Reference<IEncryptionKeyProvider> encryptionKeyProvider = {}) {
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider = {}) {
if (openRemotely) {
return openRemoteKVStore(storeType, filename, logID, memoryLimit, checkChecksums, checkIntegrity);
}

View File

@ -0,0 +1,346 @@
/*
* IPageEncryptionKeyProvider.actor.h
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined(NO_INTELLISENSE) && !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H)
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_G_H
#include "fdbserver/IPageEncryptionKeyProvider.actor.g.h"
#elif !defined(FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H)
#define FDBSERVER_IPAGEENCRYPTIONKEYPROVIDER_ACTOR_H
#include "fdbclient/GetEncryptCipherKeys.actor.h"
#include "fdbclient/Tenant.h"
#include "fdbserver/EncryptionOpsUtils.h"
#include "fdbserver/IPager.h"
#include "fdbserver/ServerDBInfo.h"
#include "flow/Arena.h"
#include "flow/EncryptUtils.h"
#define XXH_INLINE_ALL
#include "flow/xxhash.h"
#include <tuple>
#include "flow/actorcompiler.h" // This must be the last #include.
// Interface used by pager to get encryption keys reading pages from disk
// and by the BTree to get encryption keys to use for new pages.
//
// Cipher key rotation:
// The key provider can rotate encryption keys, potentially per encryption domain (see below). Each of the new pages
// are encrypted using the latest encryption keys.
//
// Encryption domains:
// The key provider can specify how the page split the full key range into encryption domains by key prefixes.
// Encryption domains are expected to have their own set of encryption keys, which is managed by the key provider.
// The pager will ensure that data from different encryption domain won't fall in the same page, to make
// sure it can use one single encryption key to encrypt the whole page.
// The key provider needs to provide a default encryption domain, which is used to encrypt pages contain only
// full or partial encryption domain prefixes.
class IPageEncryptionKeyProvider : public ReferenceCounted<IPageEncryptionKeyProvider> {
public:
using EncryptionKey = ArenaPage::EncryptionKey;
virtual ~IPageEncryptionKeyProvider() = default;
// Expected encoding type being used with the encryption key provider.
virtual EncodingType expectedEncodingType() const = 0;
// Checks whether encryption should be enabled. If not, the encryption key provider will not be used by
// the pager, and instead the default non-encrypted encoding type (XXHash64) is used.
virtual bool enableEncryption() const = 0;
// Whether encryption domain is enabled.
virtual bool enableEncryptionDomain() const { return false; }
// Get an encryption key from given encoding header.
virtual Future<EncryptionKey> getEncryptionKey(void* encodingHeader) { throw not_implemented(); }
// Get latest encryption key. If encryption domain is enabled, get encryption key for the default domain.
virtual Future<EncryptionKey> getLatestDefaultEncryptionKey() { throw not_implemented(); }
// Get latest encryption key for data in given encryption domain.
virtual Future<EncryptionKey> getLatestEncryptionKey(int64_t domainId) { throw not_implemented(); }
// Return the default encryption domain.
virtual int64_t getDefaultEncryptionDomainId() const { throw not_implemented(); }
// Get encryption domain from a key. Return the domain id, and the size of the encryption domain prefix.
// It is assumed that all keys with the same encryption domain prefix as the given key falls in the same encryption
// domain. If possibleDomainId is given, it is a valid domain id previously returned by the key provider,
// potentially for a different key. The possibleDomainId parm is used by TenantAwareEncryptionKeyProvider to speed
// up encryption domain lookup.
virtual std::tuple<int64_t, size_t> getEncryptionDomain(const KeyRef& key,
Optional<int64_t> possibleDomainId = Optional<int64_t>()) {
throw not_implemented();
}
// Get encryption domain of a page given encoding header.
virtual int64_t getEncryptionDomain(void* encodingHeader) { throw not_implemented(); }
// Setting tenant prefix to tenant name map. Used by TenantAwareEncryptionKeyProvider.
virtual void setTenantPrefixIndex(Reference<TenantPrefixIndex> tenantPrefixIndex) {}
};
// The null key provider is useful to simplify page decoding.
// It throws an error for any key info requested.
class NullKeyProvider : public IPageEncryptionKeyProvider {
public:
virtual ~NullKeyProvider() {}
EncodingType expectedEncodingType() const override { return EncodingType::XXHash64; }
bool enableEncryption() const override { return false; }
};
// Key provider for dummy XOR encryption scheme
class XOREncryptionKeyProvider_TestOnly : public IPageEncryptionKeyProvider {
public:
using EncodingHeader = ArenaPage::XOREncryptionEncoder::Header;
XOREncryptionKeyProvider_TestOnly(std::string filename) {
ASSERT(g_network->isSimulated());
// Choose a deterministic random filename (without path) byte for secret generation
// Remove any leading directory names
size_t lastSlash = filename.find_last_of("\\/");
if (lastSlash != filename.npos) {
filename.erase(0, lastSlash);
}
xorWith = filename.empty() ? 0x5e
: (uint8_t)filename[XXH3_64bits(filename.data(), filename.size()) % filename.size()];
}
virtual ~XOREncryptionKeyProvider_TestOnly() {}
EncodingType expectedEncodingType() const override { return EncodingType::XOREncryption_TestOnly; }
bool enableEncryption() const override { return true; }
bool enableEncryptionDomain() const override { return true; }
Future<EncryptionKey> getEncryptionKey(void* encodingHeader) override {
EncodingHeader* h = reinterpret_cast<EncodingHeader*>(encodingHeader);
EncryptionKey s;
s.xorKey = h->xorKey;
return s;
}
Future<EncryptionKey> getLatestDefaultEncryptionKey() override { return getLatestEncryptionKey(0); }
Future<EncryptionKey> getLatestEncryptionKey(int64_t domainId) override {
EncryptionKey s;
s.xorKey = ~(uint8_t)domainId ^ xorWith;
return s;
}
int64_t getDefaultEncryptionDomainId() const override { return 0; }
std::tuple<int64_t, size_t> getEncryptionDomain(const KeyRef& key,
Optional<int64_t> /*possibleDomainId*/) override {
if (key.size() > 0) {
return { *key.begin(), 1 };
}
return { 0, 0 };
}
int64_t getEncryptionDomain(void* encodingHeader) override {
uint8_t xorKey = reinterpret_cast<EncodingHeader*>(encodingHeader)->xorKey;
return (int64_t)(~xorKey ^ xorWith);
}
uint8_t xorWith;
};
// Key provider to provider cipher keys randomly from a pre-generated pool. It does not maintain encryption domains.
// Use for testing.
class RandomEncryptionKeyProvider : public IPageEncryptionKeyProvider {
public:
RandomEncryptionKeyProvider() {
for (unsigned i = 0; i < NUM_CIPHER; i++) {
BlobCipherDetails cipherDetails;
cipherDetails.encryptDomainId = i;
cipherDetails.baseCipherId = deterministicRandom()->randomUInt64();
cipherDetails.salt = deterministicRandom()->randomUInt64();
cipherKeys[i] = generateCipherKey(cipherDetails);
}
}
virtual ~RandomEncryptionKeyProvider() = default;
EncodingType expectedEncodingType() const override { return EncodingType::AESEncryptionV1; }
bool enableEncryption() const override { return true; }
Future<EncryptionKey> getEncryptionKey(void* encodingHeader) override {
using Header = ArenaPage::AESEncryptionV1Encoder::Header;
Header* h = reinterpret_cast<Header*>(encodingHeader);
EncryptionKey s;
s.aesKey.cipherTextKey = cipherKeys[h->cipherTextDetails.encryptDomainId];
s.aesKey.cipherHeaderKey = cipherKeys[h->cipherHeaderDetails.encryptDomainId];
return s;
}
Future<EncryptionKey> getLatestDefaultEncryptionKey() override {
EncryptionKey s;
s.aesKey.cipherTextKey = cipherKeys[deterministicRandom()->randomInt(0, NUM_CIPHER)];
s.aesKey.cipherHeaderKey = cipherKeys[deterministicRandom()->randomInt(0, NUM_CIPHER)];
return s;
}
private:
Reference<BlobCipherKey> generateCipherKey(const BlobCipherDetails& cipherDetails) {
static unsigned char SHA_KEY[] = "3ab9570b44b8315fdb261da6b1b6c13b";
Arena arena;
StringRef digest = computeAuthToken(reinterpret_cast<const unsigned char*>(&cipherDetails.baseCipherId),
sizeof(EncryptCipherBaseKeyId),
SHA_KEY,
AES_256_KEY_LENGTH,
arena);
return makeReference<BlobCipherKey>(cipherDetails.encryptDomainId,
cipherDetails.baseCipherId,
digest.begin(),
AES_256_KEY_LENGTH,
cipherDetails.salt,
std::numeric_limits<int64_t>::max() /* refreshAt */,
std::numeric_limits<int64_t>::max() /* expireAt */);
}
static constexpr int NUM_CIPHER = 1000;
Reference<BlobCipherKey> cipherKeys[NUM_CIPHER];
};
// Key provider which extract tenant id from range key prefixes, and fetch tenant specific encryption keys from
// EncryptKeyProxy.
class TenantAwareEncryptionKeyProvider : public IPageEncryptionKeyProvider {
public:
using EncodingHeader = ArenaPage::AESEncryptionV1Encoder::Header;
TenantAwareEncryptionKeyProvider(Reference<AsyncVar<ServerDBInfo> const> db) : db(db) {}
virtual ~TenantAwareEncryptionKeyProvider() = default;
EncodingType expectedEncodingType() const override { return EncodingType::AESEncryptionV1; }
bool enableEncryption() const override {
return isEncryptionOpSupported(EncryptOperationType::STORAGE_SERVER_ENCRYPTION, db->get().client);
}
bool enableEncryptionDomain() const override { return true; }
ACTOR static Future<EncryptionKey> getEncryptionKey(TenantAwareEncryptionKeyProvider* self, void* encodingHeader) {
BlobCipherEncryptHeader* header = reinterpret_cast<EncodingHeader*>(encodingHeader);
TextAndHeaderCipherKeys cipherKeys =
wait(getEncryptCipherKeys(self->db, *header, BlobCipherMetrics::KV_REDWOOD));
EncryptionKey encryptionKey;
encryptionKey.aesKey = cipherKeys;
return encryptionKey;
}
Future<EncryptionKey> getEncryptionKey(void* encodingHeader) override {
return getEncryptionKey(this, encodingHeader);
}
Future<EncryptionKey> getLatestDefaultEncryptionKey() override {
return getLatestEncryptionKey(getDefaultEncryptionDomainId());
}
ACTOR static Future<EncryptionKey> getLatestEncryptionKey(TenantAwareEncryptionKeyProvider* self,
int64_t domainId) {
EncryptCipherDomainNameRef domainName = self->getDomainName(domainId);
TextAndHeaderCipherKeys cipherKeys =
wait(getLatestEncryptCipherKeysForDomain(self->db, domainId, domainName, BlobCipherMetrics::KV_REDWOOD));
EncryptionKey encryptionKey;
encryptionKey.aesKey = cipherKeys;
return encryptionKey;
}
Future<EncryptionKey> getLatestEncryptionKey(int64_t domainId) override {
return getLatestEncryptionKey(this, domainId);
}
int64_t getDefaultEncryptionDomainId() const override { return FDB_DEFAULT_ENCRYPT_DOMAIN_ID; }
std::tuple<int64_t, size_t> getEncryptionDomain(const KeyRef& key, Optional<int64_t> possibleDomainId) override {
// System key.
if (key.startsWith(LiteralStringRef("\xff\xff"))) {
return { SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID, 2 };
}
// Key smaller than tenant prefix in size belongs to the default domain.
if (key.size() < TENANT_PREFIX_SIZE) {
return { FDB_DEFAULT_ENCRYPT_DOMAIN_ID, 0 };
}
StringRef prefix = key.substr(0, TENANT_PREFIX_SIZE);
int64_t tenantId = TenantMapEntry::prefixToId(prefix);
// Tenant id must be non-negative.
if (tenantId < 0) {
return { FDB_DEFAULT_ENCRYPT_DOMAIN_ID, 0 };
}
// Optimization: Caller guarantee possibleDomainId is a valid domain id that we previously returned.
// We can return immediately without checking with tenant map.
if (possibleDomainId.present() && possibleDomainId.get() == tenantId) {
return { tenantId, TENANT_PREFIX_SIZE };
}
if (tenantPrefixIndex.isValid()) {
auto view = tenantPrefixIndex->atLatest();
auto itr = view.find(prefix);
if (itr != view.end()) {
// Tenant not found. Tenant must be disabled, or in optional mode.
return { tenantId, TENANT_PREFIX_SIZE };
}
}
// The prefix does not belong to any tenant. The key belongs to the default domain.
return { FDB_DEFAULT_ENCRYPT_DOMAIN_ID, 0 };
}
int64_t getEncryptionDomain(void* encodingHeader) override {
BlobCipherEncryptHeader* header = reinterpret_cast<EncodingHeader*>(encodingHeader);
return header->cipherTextDetails.encryptDomainId;
}
void setTenantPrefixIndex(Reference<TenantPrefixIndex> tenantPrefixIndex) override {
this->tenantPrefixIndex = tenantPrefixIndex;
}
private:
EncryptCipherDomainNameRef getDomainName(int64_t domainId) {
if (domainId == SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_ID) {
return FDB_SYSTEM_KEYSPACE_ENCRYPT_DOMAIN_NAME;
}
if (domainId == FDB_DEFAULT_ENCRYPT_DOMAIN_ID) {
return FDB_DEFAULT_ENCRYPT_DOMAIN_NAME;
}
if (tenantPrefixIndex.isValid()) {
StringRef prefix = TenantMapEntry::idToPrefix(domainId);
auto view = tenantPrefixIndex->atLatest();
auto itr = view.find(prefix);
if (itr != view.end()) {
return *itr;
}
}
TraceEvent(SevWarn, "TenantAwareEncryptionKeyProvider_TenantNotFoundForDomain").detail("DomainId", domainId);
throw tenant_not_found();
}
Reference<AsyncVar<ServerDBInfo> const> db;
Reference<TenantPrefixIndex> tenantPrefixIndex;
};
#include "flow/unactorcompiler.h"
#endif

View File

@ -19,16 +19,15 @@
*/
#pragma once
#include "fdbclient/BlobCipher.h"
#ifndef FDBSERVER_IPAGER_H
#define FDBSERVER_IPAGER_H
#include <cstddef>
#include <stdint.h>
#include "fdbclient/BlobCipher.h"
#include "fdbclient/FDBTypes.h"
#include "fdbclient/GetEncryptCipherKeys.actor.h"
#include "fdbclient/Tenant.h"
#include "fdbserver/IEncryptionKeyProvider.actor.h"
#include "fdbserver/IKeyValueStore.h"
#include "fdbserver/IClosable.h"
#include "flow/Error.h"
#include "flow/FastAlloc.h"
#include "flow/flow.h"
@ -221,6 +220,14 @@ public:
uint8_t* rawData() { return buffer; }
int rawSize() const { return bufferSize; }
// Encryption key used to encrypt a page. Different encoding types may use different structs to represent
// an encryption key, and EncryptionKeyRef is a union of these structs.
struct EncryptionKeyRef {
TextAndHeaderCipherKeys aesKey; // For AESEncryptionV1
uint8_t xorKey; // For XOREncryption_TestOnly
};
using EncryptionKey = Standalone<EncryptionKeyRef>;
#pragma pack(push, 1)
// The next few structs describe the byte-packed physical structure. The fields of Page
@ -245,10 +252,7 @@ public:
}
// Get encoding header pointer, casting to its type
template <typename T>
T* getEncodingHeader() const {
return (T*)((uint8_t*)this + encodingHeaderOffset);
}
void* getEncodingHeader() const { return (uint8_t*)this + encodingHeaderOffset; }
// Get payload pointer
uint8_t* getPayload() const { return (uint8_t*)this + payloadOffset; }
@ -304,12 +308,18 @@ public:
// An encoding that validates the payload with an XXHash checksum
struct XXHashEncoder {
XXH64_hash_t checksum;
void encode(uint8_t* payload, int len, PhysicalPageID seed) {
checksum = XXH3_64bits_withSeed(payload, len, seed);
struct Header {
XXH64_hash_t checksum;
};
static void encode(void* header, uint8_t* payload, int len, PhysicalPageID seed) {
Header* h = reinterpret_cast<Header*>(header);
h->checksum = XXH3_64bits_withSeed(payload, len, seed);
}
void decode(uint8_t* payload, int len, PhysicalPageID seed) {
if (checksum != XXH3_64bits_withSeed(payload, len, seed)) {
static void decode(void* header, uint8_t* payload, int len, PhysicalPageID seed) {
Header* h = reinterpret_cast<Header*>(header);
if (h->checksum != XXH3_64bits_withSeed(payload, len, seed)) {
throw page_decoding_failed();
}
}
@ -318,45 +328,61 @@ public:
// A dummy "encrypting" encoding which uses XOR with a 1 byte secret key on
// the payload to obfuscate it and protects the payload with an XXHash checksum.
struct XOREncryptionEncoder {
// Checksum is on unencrypted payload
XXH64_hash_t checksum;
uint8_t keyID;
struct Header {
// Checksum is on unencrypted payload
XXH64_hash_t checksum;
uint8_t xorKey;
};
void encode(uint8_t secret, uint8_t* payload, int len, PhysicalPageID seed) {
checksum = XXH3_64bits_withSeed(payload, len, seed);
static void encode(void* header,
const EncryptionKey& encryptionKey,
uint8_t* payload,
int len,
PhysicalPageID seed) {
Header* h = reinterpret_cast<Header*>(header);
h->checksum = XXH3_64bits_withSeed(payload, len, seed);
h->xorKey = encryptionKey.xorKey;
for (int i = 0; i < len; ++i) {
payload[i] ^= secret;
payload[i] ^= h->xorKey;
}
}
void decode(uint8_t secret, uint8_t* payload, int len, PhysicalPageID seed) {
static void decode(void* header,
const EncryptionKey& encryptionKey,
uint8_t* payload,
int len,
PhysicalPageID seed) {
Header* h = reinterpret_cast<Header*>(header);
for (int i = 0; i < len; ++i) {
payload[i] ^= secret;
payload[i] ^= h->xorKey;
}
if (checksum != XXH3_64bits_withSeed(payload, len, seed)) {
if (h->checksum != XXH3_64bits_withSeed(payload, len, seed)) {
throw page_decoding_failed();
}
}
};
struct AESEncryptionV1Encoder {
BlobCipherEncryptHeader header;
using Header = BlobCipherEncryptHeader;
void encode(const TextAndHeaderCipherKeys& cipherKeys, uint8_t* payload, int len) {
static void encode(void* header, const TextAndHeaderCipherKeys& cipherKeys, uint8_t* payload, int len) {
Header* h = reinterpret_cast<Header*>(header);
EncryptBlobCipherAes265Ctr cipher(cipherKeys.cipherTextKey,
cipherKeys.cipherHeaderKey,
ENCRYPT_HEADER_AUTH_TOKEN_MODE_SINGLE,
BlobCipherMetrics::KV_REDWOOD);
Arena arena;
StringRef ciphertext = cipher.encrypt(payload, len, &header, arena)->toStringRef();
StringRef ciphertext = cipher.encrypt(payload, len, h, arena)->toStringRef();
ASSERT_EQ(len, ciphertext.size());
memcpy(payload, ciphertext.begin(), len);
}
void decode(const TextAndHeaderCipherKeys& cipherKeys, uint8_t* payload, int len) {
static void decode(void* header, const TextAndHeaderCipherKeys& cipherKeys, uint8_t* payload, int len) {
Header* h = reinterpret_cast<Header*>(header);
DecryptBlobCipherAes256Ctr cipher(
cipherKeys.cipherTextKey, cipherKeys.cipherHeaderKey, header.iv, BlobCipherMetrics::KV_REDWOOD);
cipherKeys.cipherTextKey, cipherKeys.cipherHeaderKey, h->iv, BlobCipherMetrics::KV_REDWOOD);
Arena arena;
StringRef plaintext = cipher.decrypt(payload, len, header, arena)->toStringRef();
StringRef plaintext = cipher.decrypt(payload, len, *h, arena)->toStringRef();
ASSERT_EQ(len, plaintext.size());
memcpy(payload, plaintext.begin(), len);
}
@ -368,11 +394,11 @@ public:
// existing pages, the payload offset is stored in the page.
static int encodingHeaderSize(EncodingType t) {
if (t == EncodingType::XXHash64) {
return sizeof(XXHashEncoder);
return sizeof(XXHashEncoder::Header);
} else if (t == EncodingType::XOREncryption_TestOnly) {
return sizeof(XOREncryptionEncoder);
return sizeof(XOREncryptionEncoder::Header);
} else if (t == EncodingType::AESEncryptionV1) {
return sizeof(AESEncryptionV1Encoder);
return sizeof(AESEncryptionV1Encoder::Header);
} else {
throw page_encoding_not_supported();
}
@ -476,15 +502,11 @@ public:
ASSERT(VALGRIND_CHECK_MEM_IS_DEFINED(pPayload, payloadSize) == 0);
if (page->encodingType == EncodingType::XXHash64) {
page->getEncodingHeader<XXHashEncoder>()->encode(pPayload, payloadSize, pageID);
XXHashEncoder::encode(page->getEncodingHeader(), pPayload, payloadSize, pageID);
} else if (page->encodingType == EncodingType::XOREncryption_TestOnly) {
ASSERT(encryptionKey.secret.size() == 1);
XOREncryptionEncoder* xh = page->getEncodingHeader<XOREncryptionEncoder>();
xh->keyID = encryptionKey.id.orDefault(0);
xh->encode(encryptionKey.secret[0], pPayload, payloadSize, pageID);
XOREncryptionEncoder::encode(page->getEncodingHeader(), encryptionKey, pPayload, payloadSize, pageID);
} else if (page->encodingType == EncodingType::AESEncryptionV1) {
AESEncryptionV1Encoder* eh = page->getEncodingHeader<AESEncryptionV1Encoder>();
eh->encode(encryptionKey.cipherKeys, pPayload, payloadSize);
AESEncryptionV1Encoder::encode(page->getEncodingHeader(), encryptionKey.aesKey, pPayload, payloadSize);
} else {
throw page_encoding_not_supported();
}
@ -507,14 +529,6 @@ public:
pPayload = page->getPayload();
payloadSize = logicalSize - (pPayload - buffer);
// Populate encryption key with relevant fields from page
if (page->encodingType == EncodingType::XOREncryption_TestOnly) {
encryptionKey.id = page->getEncodingHeader<XOREncryptionEncoder>()->keyID;
} else if (page->encodingType == EncodingType::AESEncryptionV1) {
AESEncryptionV1Encoder* eh = page->getEncodingHeader<AESEncryptionV1Encoder>();
encryptionKey.cipherHeader = eh->header;
}
if (page->headerVersion == 1) {
if (verify) {
RedwoodHeaderV1* h = page->getMainHeader<RedwoodHeaderV1>();
@ -532,13 +546,11 @@ public:
// Post: Payload has been verified and decrypted if necessary
void postReadPayload(PhysicalPageID pageID) {
if (page->encodingType == EncodingType::XXHash64) {
page->getEncodingHeader<XXHashEncoder>()->decode(pPayload, payloadSize, pageID);
XXHashEncoder::decode(page->getEncodingHeader(), pPayload, payloadSize, pageID);
} else if (page->encodingType == EncodingType::XOREncryption_TestOnly) {
ASSERT(encryptionKey.secret.size() == 1);
page->getEncodingHeader<XOREncryptionEncoder>()->decode(
encryptionKey.secret[0], pPayload, payloadSize, pageID);
XOREncryptionEncoder::decode(page->getEncodingHeader(), encryptionKey, pPayload, payloadSize, pageID);
} else if (page->encodingType == EncodingType::AESEncryptionV1) {
page->getEncodingHeader<AESEncryptionV1Encoder>()->decode(encryptionKey.cipherKeys, pPayload, payloadSize);
AESEncryptionV1Encoder::decode(page->getEncodingHeader(), encryptionKey.aesKey, pPayload, payloadSize);
} else {
throw page_encoding_not_supported();
}
@ -553,6 +565,8 @@ public:
// Returns true if the page's encoding type employs encryption
bool isEncrypted() const { return isEncodingTypeEncrypted(getEncodingType()); }
void* getEncodingHeader() { return page->getEncodingHeader(); }
private:
Arena arena;

View File

@ -1116,7 +1116,7 @@ ACTOR Future<Void> encryptKeyProxyServer(EncryptKeyProxyInterface ei, Reference<
class IKeyValueStore;
class ServerCoordinators;
class IDiskQueue;
class IEncryptionKeyProvider;
class IPageEncryptionKeyProvider;
ACTOR Future<Void> storageServer(IKeyValueStore* persistentData,
StorageServerInterface ssi,
Tag seedTag,
@ -1126,7 +1126,7 @@ ACTOR Future<Void> storageServer(IKeyValueStore* persistentData,
ReplyPromise<InitializeStorageReply> recruitReply,
Reference<AsyncVar<ServerDBInfo> const> db,
std::string folder,
Reference<IEncryptionKeyProvider> encryptionKeyProvider);
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider);
ACTOR Future<Void> storageServer(
IKeyValueStore* persistentData,
StorageServerInterface ssi,
@ -1135,7 +1135,7 @@ ACTOR Future<Void> storageServer(
Promise<Void> recovered,
Reference<IClusterConnectionRecord>
connRecord, // changes pssi->id() to be the recovered ID); // changes pssi->id() to be the recovered ID
Reference<IEncryptionKeyProvider> encryptionKeyProvider);
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider);
ACTOR Future<Void> masterServer(MasterInterface mi,
Reference<AsyncVar<ServerDBInfo> const> db,
Reference<AsyncVar<Optional<ClusterControllerFullInterface>> const> ccInterface,

View File

@ -705,7 +705,7 @@ public:
std::map<Version, std::vector<KeyRange>>
pendingRemoveRanges; // Pending requests to remove ranges from physical shards
Reference<IEncryptionKeyProvider> encryptionKeyProvider;
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider;
bool shardAware; // True if the storage server is aware of the physical shards.
@ -1250,7 +1250,7 @@ public:
StorageServer(IKeyValueStore* storage,
Reference<AsyncVar<ServerDBInfo> const> const& db,
StorageServerInterface const& ssi,
Reference<IEncryptionKeyProvider> encryptionKeyProvider)
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider)
: tenantPrefixIndex(makeReference<TenantPrefixIndex>()), encryptionKeyProvider(encryptionKeyProvider),
shardAware(false), tlogCursorReadsLatencyHistogram(Histogram::getHistogram(STORAGESERVER_HISTOGRAM_GROUP,
TLOG_CURSOR_READS_LATENCY_HISTOGRAM,
@ -10694,7 +10694,7 @@ ACTOR Future<Void> storageServer(IKeyValueStore* persistentData,
ReplyPromise<InitializeStorageReply> recruitReply,
Reference<AsyncVar<ServerDBInfo> const> db,
std::string folder,
Reference<IEncryptionKeyProvider> encryptionKeyProvider) {
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider) {
state StorageServer self(persistentData, db, ssi, encryptionKeyProvider);
self.shardAware = SERVER_KNOBS->SHARD_ENCODE_LOCATION_METADATA && persistentData->shardAware();
state Future<Void> ssCore;
@ -10785,7 +10785,7 @@ ACTOR Future<Void> storageServer(IKeyValueStore* persistentData,
std::string folder,
Promise<Void> recovered,
Reference<IClusterConnectionRecord> connRecord,
Reference<IEncryptionKeyProvider> encryptionKeyProvider) {
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider) {
state StorageServer self(persistentData, db, ssi, encryptionKeyProvider);
state Future<Void> ssCore;
self.folder = folder;

View File

@ -1266,7 +1266,7 @@ ACTOR Future<Void> storageServerRollbackRebooter(std::set<std::pair<UID, KeyValu
IKeyValueStore* store,
bool validateDataFiles,
Promise<Void>* rebootKVStore,
Reference<IEncryptionKeyProvider> encryptionKeyProvider) {
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider) {
state TrackRunningStorage _(id, storeType, runningStorages);
loop {
ErrorOr<Void> e = wait(errorOr(prevStorageServer));
@ -1737,7 +1737,7 @@ ACTOR Future<Void> workerServer(Reference<IClusterConnectionRecord> connRecord,
if (s.storedComponent == DiskStore::Storage) {
LocalLineage _;
getCurrentLineage()->modify(&RoleLineage::role) = ProcessClass::ClusterRole::Storage;
Reference<IEncryptionKeyProvider> encryptionKeyProvider =
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider =
makeReference<TenantAwareEncryptionKeyProvider>(dbInfo);
IKeyValueStore* kv = openKVStore(
s.storeType,
@ -2380,7 +2380,7 @@ ACTOR Future<Void> workerServer(Reference<IClusterConnectionRecord> connRecord,
folder,
isTss ? testingStoragePrefix.toString() : fileStoragePrefix.toString(),
recruited.id());
Reference<IEncryptionKeyProvider> encryptionKeyProvider =
Reference<IPageEncryptionKeyProvider> encryptionKeyProvider =
makeReference<TenantAwareEncryptionKeyProvider>(dbInfo);
IKeyValueStore* data = openKVStore(
req.storeType,