Skip to content

Commit

Permalink
feat secdist: implement inline config
Browse files Browse the repository at this point in the history
commit_hash:daed0ddfcb4658e09eeb5e12ac15eede3397715c
  • Loading branch information
segoon committed Nov 7, 2024
1 parent 20badeb commit 17aee6f
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 17 deletions.
2 changes: 2 additions & 0 deletions .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@
"core/functional_tests/https/static_config.yaml":"taxi/uservices/userver/core/functional_tests/https/static_config.yaml",
"core/functional_tests/https/tests-deadline/conftest.py":"taxi/uservices/userver/core/functional_tests/https/tests-deadline/conftest.py",
"core/functional_tests/https/tests-deadline/test_server.py":"taxi/uservices/userver/core/functional_tests/https/tests-deadline/test_server.py",
"core/functional_tests/https/tests-secdist-inline/conftest.py":"taxi/uservices/userver/core/functional_tests/https/tests-secdist-inline/conftest.py",
"core/functional_tests/https/tests-secdist-inline/test_test.py":"taxi/uservices/userver/core/functional_tests/https/tests-secdist-inline/test_test.py",
"core/functional_tests/https_no_passphrase/CMakeLists.txt":"taxi/uservices/userver/core/functional_tests/https_no_passphrase/CMakeLists.txt",
"core/functional_tests/https_no_passphrase/Readme.md":"taxi/uservices/userver/core/functional_tests/https_no_passphrase/Readme.md",
"core/functional_tests/https_no_passphrase/cert.crt":"taxi/uservices/userver/core/functional_tests/https_no_passphrase/cert.crt",
Expand Down
2 changes: 2 additions & 0 deletions core/functional_tests/https/service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <userver/dynamic_config/client/component.hpp>
#include <userver/dynamic_config/updater/component.hpp>
#include <userver/server/handlers/on_log_rotate.hpp>
#include <userver/server/handlers/ping.hpp>
#include <userver/server/handlers/server_monitor.hpp>
#include <userver/server/handlers/tests_control.hpp>
#include <userver/utest/using_namespace_userver.hpp>
Expand All @@ -27,6 +28,7 @@ int main(int argc, char* argv[]) {
.Append<components::TestsuiteSupport>()
.Append<server::handlers::TestsControl>()
.Append<server::handlers::ServerMonitor>()
.Append<server::handlers::Ping>()
.Append<clients::dns::Component>()
.Append<alerts::Handler>()
.Append<server::handlers::OnLogRotate>();
Expand Down
5 changes: 5 additions & 0 deletions core/functional_tests/https/static_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ components_manager:
method: GET
task_processor: main-task-processor

handler-ping:
path: /ping
method: GET
task_processor: main-task-processor

handler-on-log-rotate:
path: /service/on-log-rotate/
method: POST
Expand Down
38 changes: 38 additions & 0 deletions core/functional_tests/https/tests-secdist-inline/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import aiohttp
import pytest

pytest_plugins = ['pytest_userver.plugins.core']
USERVER_CONFIG_HOOKS = ['userver_config_secdist']


@pytest.fixture(scope='session')
def userver_config_secdist(userver_config_http_client, service_source_dir):
def patch_config(config_yaml, config_vars) -> None:
components = config_yaml['components_manager']['components']

tls = components['server']['listener']['tls']
tls['cert'] = str(service_source_dir / 'cert.crt')
tls['private-key'] = str(service_source_dir / 'private_key.key')

if 'config' in components['default-secdist-provider']:
del components['default-secdist-provider']['config']
components['default-secdist-provider']['inline'] = {
'passphrases': {'tls': 'asd'},
}

return patch_config


@pytest.fixture(scope='session')
def service_baseurl(service_port) -> str:
return f'https://localhost:{service_port}/'


@pytest.fixture(scope='session')
def service_client_session_factory(event_loop, service_source_dir):
def make_session(**kwargs):
kwargs.setdefault('loop', event_loop)
kwargs['connector'] = aiohttp.TCPConnector(verify_ssl=False)
return aiohttp.ClientSession(**kwargs)

return make_session
3 changes: 3 additions & 0 deletions core/functional_tests/https/tests-secdist-inline/test_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
async def test_ping(service_client):
response = await service_client.get('ping')
assert response.status_code == 200
5 changes: 0 additions & 5 deletions core/include/userver/storages/secdist/component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,7 @@ namespace components {
/// Name | Description | Default value
/// ---- | ----------- | -------------
/// provider | optional secdist provider component name | 'default-secdist-provider'
/// config | path to the config file with data | ''
/// format | config format, either `json` or `yaml` | 'json'
/// missing-ok | do not terminate components load if no file found by the config option | false
/// environment-secrets-key | name of environment variable from which to load additional data | -
/// update-period | period between data updates in utils::StringToDuration() suitable format ('0s' for no updates) | 0s
/// blocking-task-processor | name of task processor for background blocking operations | --

// clang-format on

Expand Down
4 changes: 3 additions & 1 deletion core/include/userver/storages/secdist/provider_component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class DefaultLoader final : public storages::secdist::SecdistProvider {
bool missing_ok{false};
std::optional<std::string> environment_secrets_key;
engine::TaskProcessor* blocking_task_processor{nullptr};
formats::json::Value inline_config;
};

explicit DefaultLoader(Settings settings);
Expand All @@ -46,7 +47,8 @@ namespace components {
/// Name | Description | Default value
/// ---- | ----------- | -------------
/// config | path to the config file with data | ''
/// format | config format, either `json` or `yaml` | 'json'
/// inline | inline data | -
/// format | config format, one of `json`, `yaml`, `yaml_config` | 'json'
/// missing-ok | do not terminate components load if no file found by the config option | false
/// environment-secrets-key | name of environment variable from which to load additional data | -
/// blocking-task-processor | name of task processor for background blocking operations | --
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ class StandAloneCheckerTest : public ::testing::Test {
};

StandAloneCheckerTest()
: default_loader({temp_file_provider.GetFilePath(), storages::secdist::SecdistFormat::kJson, true, std::nullopt}
: default_loader(
{temp_file_provider.GetFilePath(),
storages::secdist::SecdistFormat::kJson,
true,
std::nullopt,
nullptr,
{}}
),
secdist_config({&default_loader, std::chrono::milliseconds::zero()}),
digest_settings_({
Expand Down
21 changes: 19 additions & 2 deletions core/src/storages/secdist/provider_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,14 @@ void UpdateFromEnv(formats::json::Value& doc, const std::optional<std::string>&
DefaultLoader::DefaultLoader(Settings settings) : settings_{settings} {}

formats::json::Value DefaultLoader::Get() const {
auto doc =
LoadFromFile(settings_.config_path, settings_.format, settings_.missing_ok, settings_.blocking_task_processor);
formats::json::Value doc;
if (!settings_.config_path.empty()) {
doc = LoadFromFile(
settings_.config_path, settings_.format, settings_.missing_ok, settings_.blocking_task_processor
);
} else {
doc = settings_.inline_config;
}
UpdateFromEnv(doc, settings_.environment_secrets_key);
return doc;
}
Expand Down Expand Up @@ -169,6 +175,12 @@ ParseSettings(const components::ComponentConfig& config, const components::Compo
settings.blocking_task_processor =
blocking_task_processor_name ? &context.GetTaskProcessor(*blocking_task_processor_name) : nullptr;
settings.config_path = config["config"].As<std::string>({});
settings.inline_config = config["inline"].As<formats::json::Value>({});
LOG_INFO() << "INLINE " << settings.inline_config;
if (!settings.config_path.empty() && !settings.inline_config.IsNull()) {
throw std::runtime_error("'config' and 'inline' cannot be set together");
}

settings.format = FormatFromString(config["format"].As<std::string>({}));
settings.missing_ok = config["missing-ok"].As<bool>(false);
settings.environment_secrets_key = config["environment-secrets-key"].As<std::optional<std::string>>();
Expand All @@ -193,6 +205,11 @@ additionalProperties: false
type: string
description: path to the config file with data
defaultDescription: ''
inline:
type: object
description: inline data
additionalProperties: true
properties: {}
format:
type: string
description: secdist format
Expand Down
16 changes: 9 additions & 7 deletions core/src/storages/secdist/secdist_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ TEST(SecdistConfig, Sample) {
fs::blocking::RewriteFileContents(temp_file.GetPath(), kSecdistJson);

storages::secdist::DefaultLoader provider{
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, std::nullopt}};
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, std::nullopt, nullptr, {}}};
storages::secdist::SecdistConfig secdist_config{{&provider}};
/// [Secdist Usage Sample - SecdistConfig]
const auto& user_passwords = secdist_config.Get<UserPasswords>();
Expand All @@ -96,7 +96,7 @@ TEST(SecdistYamlConfig, Sample) {
fs::blocking::RewriteFileContents(temp_file.GetPath(), kSecdistYaml);

storages::secdist::DefaultLoader provider{
{temp_file.GetPath(), storages::secdist::SecdistFormat::kYaml, false, std::nullopt}};
{temp_file.GetPath(), storages::secdist::SecdistFormat::kYaml, false, std::nullopt, nullptr, {}}};
storages::secdist::SecdistConfig secdist_config{{&provider}};

const auto& user_passwords = secdist_config.Get<UserPasswords>();
Expand All @@ -119,7 +119,7 @@ UTEST(SecdistYamlConfigConfig, Sample) {
fs::blocking::RewriteFileContents(temp_file.GetPath(), kSecdistYamlConfig);

storages::secdist::DefaultLoader provider{
{temp_file.GetPath(), storages::secdist::SecdistFormat::kYamlConfig, false, std::nullopt}};
{temp_file.GetPath(), storages::secdist::SecdistFormat::kYamlConfig, false, std::nullopt, nullptr, {}}};
storages::secdist::SecdistConfig secdist_config{{&provider}};

const auto& user_passwords = secdist_config.Get<UserPasswords>();
Expand All @@ -143,7 +143,8 @@ UTEST(SecdistConfig, EnvironmentVariable) {
ASSERT_EQ(setenv(kVarName.c_str(), kSecdistJson.c_str(), 1), 0);
engine::subprocess::UpdateCurrentEnvironmentVariables();

storages::secdist::DefaultLoader provider{{"", storages::secdist::SecdistFormat::kJson, false, kVarName}};
storages::secdist::DefaultLoader provider{
{"", storages::secdist::SecdistFormat::kJson, false, kVarName, nullptr, {}}};
storages::secdist::SecdistConfig secdist_config{{&provider}};

const auto& user_passwords = secdist_config.Get<UserPasswords>();
Expand Down Expand Up @@ -186,7 +187,7 @@ UTEST(SecdistConfig, FileAndEnvironmentVariable) {
engine::subprocess::UpdateCurrentEnvironmentVariables();

storages::secdist::DefaultLoader provider{
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, kVarName}};
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, kVarName, nullptr, {}}};
storages::secdist::SecdistConfig secdist_config{{&provider}};

const auto& user_passwords = secdist_config.Get<UserPasswords>();
Expand All @@ -209,7 +210,7 @@ UTEST(Secdist, WithoutUpdates) {
fs::blocking::RewriteFileContents(temp_file.GetPath(), kSecdistJson);

storages::secdist::DefaultLoader provider{
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, std::nullopt}};
{temp_file.GetPath(), storages::secdist::SecdistFormat::kJson, false, std::nullopt, nullptr, {}}};
storages::secdist::Secdist secdist{{&provider}};

const auto& secdist_config = secdist.Get();
Expand Down Expand Up @@ -268,7 +269,8 @@ UTEST(Secdist, DynamicUpdate) {
storages::secdist::SecdistFormat::kJson,
false,
std::nullopt,
&engine::current_task::GetTaskProcessor()}};
&engine::current_task::GetTaskProcessor(),
{}}};
storages::secdist::Secdist secdist{{&provider, std::chrono::milliseconds(100)}};

auto subscriber = secdist.UpdateAndListen(&storage, "test/update_secdist", &SecdistConfigStorage::OnSecdistUpdate);
Expand Down
3 changes: 2 additions & 1 deletion mongo/src/storages/mongo/multimongo_mongotest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ UTEST(MultiMongo, DynamicSecdistUpdate) {
storages::secdist::SecdistFormat::kJson,
false,
std::nullopt,
&engine::current_task::GetTaskProcessor()}};
&engine::current_task::GetTaskProcessor(),
{}}};
storages::secdist::Secdist secdist{{&provider, std::chrono::milliseconds(100)}};
auto subscriber =
secdist.UpdateAndListen(&storage, "test/multimongo_update_secdist", &SecdistConfigStorage::OnSecdistUpdate);
Expand Down

0 comments on commit 17aee6f

Please sign in to comment.