Files
scylladb/ent/encryption/encryption.hh
Calle Wilund af85b7f61b ent::encryption: Make text helper routines take std::string
Moving away from custom string type. Pure cosmetics.
2025-11-05 10:22:22 +00:00

198 lines
5.7 KiB
C++

/*
* Copyright (C) 2018 ScyllaDB
*
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0
*/
#pragma once
#include <map>
#include <seastar/core/future.hh>
#include <seastar/core/sstring.hh>
#include <seastar/core/shared_ptr.hh>
#include <seastar/core/sharded.hh>
#include <fmt/core.h>
#include <fmt/ostream.h>
#include "../../bytes.hh"
class service_set;
namespace replica {
class database;
}
namespace db {
class config;
class extensions;
}
namespace cql3 {
class query_processor;
}
namespace service {
class storage_service;
class migration_manager;
}
namespace sstables {
class sstable;
}
namespace encryption {
inline const sstring KEY_PROVIDER = "key_provider";
inline const sstring SECRET_KEY_PROVIDER_FACTORY_CLASS = "secret_key_provider_factory_class";
inline const sstring SECRET_KEY_FILE = "secret_key_file";
inline const sstring SYSTEM_KEY_FILE = "system_key_file";
inline const sstring CIPHER_ALGORITHM = "cipher_algorithm";
inline const sstring SECRET_KEY_STRENGTH = "secret_key_strength";
inline const sstring HOST_NAME = "kmip_host";
inline const sstring TEMPLATE_NAME = "template_name";
inline const sstring KEY_NAMESPACE = "key_namespace";
bytes base64_decode(const sstring&, size_t off = 0, size_t n = sstring::npos);
sstring base64_encode(const bytes&, size_t off = 0, size_t n = bytes::npos);
bytes calculate_md5(const bytes&, size_t off = 0, size_t n = bytes::npos);
bytes calculate_sha256(const bytes&, size_t off = 0, size_t n = bytes::npos);
bytes calculate_sha256(bytes_view);
bytes hmac_sha256(bytes_view msg, bytes_view key);
future<temporary_buffer<char>> read_text_file_fully(const std::string&);
future<> write_text_file_fully(const std::string&, temporary_buffer<char>);
future<> write_text_file_fully(const std::string&, const std::string&);
std::optional<std::chrono::milliseconds> parse_expiry(std::optional<std::string>);
class symmetric_key;
struct key_info;
using options = std::map<sstring, sstring>;
using opt_bytes = std::optional<bytes>;
using key_ptr = shared_ptr<symmetric_key>;
/**
* wrapper for "options" (map) to provide an
* interface returning empty optionals for
* non-available values. Makes query simpler
* and allows .value_or(...)-statements, which
* are neat for default values.
*
* In the long run one could contemplate
* using non-std maps with similar built-in
* functionality for all our various configs
* in the system, but for now we are firmly
* entrenched in map<string, string>
*/
template<typename Map>
class map_wrapper {
const Map& _options;
public:
using mapped_type = typename Map::mapped_type;
using key_type = typename Map::key_type;
map_wrapper(const Map& opts)
: _options(opts)
{}
std::optional<mapped_type> operator()(const key_type& k) const {
auto i = _options.find(k);
if (i != _options.end()) {
return i->second;
}
return std::nullopt;
}
};
using opt_wrapper = map_wrapper<options>;
key_info get_key_info(const options&);
class encryption_context;
class key_provider {
public:
virtual ~key_provider()
{}
virtual future<std::tuple<key_ptr, opt_bytes>> key(const key_info&, opt_bytes = {}) = 0;
virtual future<> validate() const {
return make_ready_future<>();
}
virtual bool should_delay_read(const opt_bytes&) const {
return false;
}
private:
friend std::ostream& operator<<(std::ostream&, const key_provider&);
virtual void print(std::ostream&) const = 0;
};
std::ostream& operator<<(std::ostream&, const key_provider&);
}
template <> struct fmt::formatter<encryption::key_provider> : fmt::ostream_formatter {};
namespace encryption {
class key_provider_factory {
public:
virtual ~key_provider_factory()
{}
virtual shared_ptr<key_provider> get_provider(encryption_context& c, const options&) = 0;
};
class encryption_config;
class system_key;
class kmip_host;
class kms_host;
class gcp_host;
class azure_host;
/**
* Context is a singleton object, shared across shards. I.e. even though there are obvious mutating
* calls in it, it guarantees thread/shard safety.
*
* Why is this not a sharded thingamajing? Because its own instance methods need to send itself
* as a shard-safe object forwards, and thus need to know that same shard, which breaks the circle of
* ownership and stuff.
*/
class encryption_context {
public:
virtual ~encryption_context() = default;
virtual shared_ptr<key_provider> get_provider(const options&) = 0;
virtual shared_ptr<system_key> get_system_key(const sstring&) = 0;
virtual shared_ptr<kmip_host> get_kmip_host(const sstring&) = 0;
virtual shared_ptr<kms_host> get_kms_host(const sstring&) = 0;
virtual shared_ptr<gcp_host> get_gcp_host(const sstring&) = 0;
virtual shared_ptr<azure_host> get_azure_host(const sstring&) = 0;
virtual shared_ptr<key_provider> get_cached_provider(const sstring& id) const = 0;
virtual void cache_provider(const sstring& id, shared_ptr<key_provider>) = 0;
virtual const encryption_config& config() const = 0;
virtual shared_ptr<symmetric_key> get_config_encryption_key() const = 0;
virtual sharded<cql3::query_processor>& get_query_processor() const = 0;
virtual sharded<service::storage_service>& get_storage_service() const = 0;
virtual sharded<replica::database>& get_database() const = 0;
virtual sharded<service::migration_manager>& get_migration_manager() const = 0;
sstring maybe_decrypt_config_value(const sstring&) const;
virtual future<> start() = 0;
virtual future<> stop() = 0;
};
future<seastar::shared_ptr<encryption_context>>
register_extensions(const db::config&, std::unique_ptr<encryption_config>, db::extensions&, const ::service_set&);
// for testing
std::string encryption_provider(const sstables::sstable&);
}