summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormregrock <[email protected]>2025-04-17 17:51:47 +0300
committerGitHub <[email protected]>2025-04-17 17:51:47 +0300
commitd71dab77fea14b45cfe4e82237bc61876badec4c (patch)
tree4805c6ab406e1708c42f958c43682b8c3f06d873
parenta97c3d07114bc6de0225a84da5224858ac2928ce (diff)
Move audit log from console to BSC/distconf in V2 (#17307)
-rw-r--r--ydb/core/blobstorage/base/blobstorage_console_events.h4
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_audit.cpp35
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_audit.h16
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_invoke.h1
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp33
-rw-r--r--ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp2
-rw-r--r--ydb/core/blobstorage/nodewarden/ya.make2
-rw-r--r--ydb/core/cms/console/console__replace_yaml_config.cpp78
-rw-r--r--ydb/core/cms/console/console_handshake.cpp1
-rw-r--r--ydb/core/grpc_services/rpc_config.cpp6
-rw-r--r--ydb/core/mind/bscontroller/bsc.cpp3
-rw-r--r--ydb/core/mind/bscontroller/bsc_audit.cpp35
-rw-r--r--ydb/core/mind/bscontroller/bsc_audit.h16
-rw-r--r--ydb/core/mind/bscontroller/commit_config.cpp37
-rw-r--r--ydb/core/mind/bscontroller/console_interaction.cpp9
-rw-r--r--ydb/core/mind/bscontroller/console_interaction.h2
-rw-r--r--ydb/core/mind/bscontroller/defs.h1
-rw-r--r--ydb/core/mind/bscontroller/impl.h8
-rw-r--r--ydb/core/mind/bscontroller/ya.make2
-rw-r--r--ydb/core/mind/bscontroller/yaml_config_helpers.h4
-rw-r--r--ydb/core/protos/blobstorage.proto4
-rw-r--r--ydb/core/protos/blobstorage_distributed_config.proto2
-rw-r--r--ydb/core/protos/console_config.proto2
-rw-r--r--ydb/tests/functional/config/test_config_with_metadata.py7
-rw-r--r--ydb/tests/library/clients/kikimr_config_client.py9
25 files changed, 268 insertions, 51 deletions
diff --git a/ydb/core/blobstorage/base/blobstorage_console_events.h b/ydb/core/blobstorage/base/blobstorage_console_events.h
index eb6798f35d6..bfda9202984 100644
--- a/ydb/core/blobstorage/base/blobstorage_console_events.h
+++ b/ydb/core/blobstorage/base/blobstorage_console_events.h
@@ -79,7 +79,7 @@ namespace NKikimr {
TEvControllerReplaceConfigRequest(std::optional<TString> clusterYaml, std::optional<TString> storageYaml,
std::optional<bool> switchDedicatedStorageSection, bool dedicatedConfigMode, bool allowUnknownFields,
- bool bypassMetadataChecks, bool enableConfigV2, bool disableConfigV2) {
+ bool bypassMetadataChecks, bool enableConfigV2, bool disableConfigV2, TString peerName, TString userToken) {
if (clusterYaml) {
Record.SetClusterYaml(*clusterYaml);
}
@@ -97,6 +97,8 @@ namespace NKikimr {
} else if (disableConfigV2) {
Record.SetSwitchEnableConfigV2(false);
}
+ Record.SetPeerName(peerName);
+ Record.SetUserToken(userToken);
}
TString ToString() const override {
diff --git a/ydb/core/blobstorage/nodewarden/distconf_audit.cpp b/ydb/core/blobstorage/nodewarden/distconf_audit.cpp
new file mode 100644
index 00000000000..92b26108435
--- /dev/null
+++ b/ydb/core/blobstorage/nodewarden/distconf_audit.cpp
@@ -0,0 +1,35 @@
+#include "distconf_audit.h"
+
+#include <ydb/core/audit/audit_log.h>
+#include <ydb/core/util/address_classifier.h>
+
+namespace NKikimr::NStorage {
+
+static const TString COMPONENT_NAME = "distconf";
+static const TString EMPTY_VALUE = "{none}";
+
+void AuditLogReplaceConfig(
+ const TString& peer,
+ const TString& userSID,
+ const TString& sanitizedToken,
+ const TString& oldConfig,
+ const TString& newConfig,
+ const TString& reason,
+ bool success)
+{
+ auto peerName = NKikimr::NAddressClassifier::ExtractAddress(peer);
+
+ AUDIT_LOG(
+ AUDIT_PART("component", COMPONENT_NAME)
+ AUDIT_PART("remote_address", (!peerName.empty() ? peerName : EMPTY_VALUE))
+ AUDIT_PART("subject", (!userSID.empty() ? userSID : EMPTY_VALUE))
+ AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EMPTY_VALUE))
+ AUDIT_PART("status", TString(success ? "SUCCESS" : "ERROR"))
+ AUDIT_PART("reason", reason, !reason.empty())
+ AUDIT_PART("operation", TString("REPLACE CONFIG"))
+ AUDIT_PART("old_config", oldConfig)
+ AUDIT_PART("new_config", newConfig)
+ );
+}
+
+} // namespace NKikimr::NStorage
diff --git a/ydb/core/blobstorage/nodewarden/distconf_audit.h b/ydb/core/blobstorage/nodewarden/distconf_audit.h
new file mode 100644
index 00000000000..efe6d211796
--- /dev/null
+++ b/ydb/core/blobstorage/nodewarden/distconf_audit.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NKikimr::NStorage {
+
+void AuditLogReplaceConfig(
+ const TString& peer,
+ const TString& userSID,
+ const TString& sanitizedToken,
+ const TString& oldConfig,
+ const TString& newConfig,
+ const TString& reason,
+ bool success);
+
+} // namespace NKikimr::NStorage
diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke.h b/ydb/core/blobstorage/nodewarden/distconf_invoke.h
index 97b2630237c..eaaf854a718 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_invoke.h
+++ b/ydb/core/blobstorage/nodewarden/distconf_invoke.h
@@ -121,6 +121,7 @@ namespace NKikimr::NStorage {
void AdvanceGeneration();
void StartProposition(NKikimrBlobStorage::TStorageConfig *config, bool updateFields = true);
+ bool CheckConfigUpdate(const NKikimrBlobStorage::TStorageConfig& proposed);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Query termination and result delivery
diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp
index 26a934cfb61..5247815ba67 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp
+++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_common.cpp
@@ -1,3 +1,4 @@
+#include "distconf_audit.h"
#include "distconf_invoke.h"
namespace NKikimr::NStorage {
@@ -186,13 +187,25 @@ namespace NKikimr::NStorage {
UpdateFingerprint(config);
}
- if (auto error = ValidateConfigUpdate(*Self->StorageConfig, *config)) {
- STLOG(PRI_DEBUG, BS_NODE, NWDC78, "StartProposition config validation failed", (SelfId, SelfId()),
- (Error, *error), (Config, config));
- return FinishWithError(TResult::ERROR, TStringBuilder()
- << "StartProposition config validation failed: " << *error);
+ if (!CheckConfigUpdate(*config)) {
+ return;
}
+ const auto& replaceConfig = Event->Get()->Record.GetReplaceStorageConfig();
+ TStringBuilder oldConfig;
+ oldConfig << Self->MainConfigYaml << (Self->StorageConfigYaml ? *Self->StorageConfigYaml : "");
+ TStringBuilder newConfig;
+ newConfig << *NewYaml << (NewStorageYaml ? *NewStorageYaml : "");
+ NACLib::TUserToken userToken = NACLib::TUserToken{replaceConfig.GetUserToken()};
+ AuditLogReplaceConfig(
+ /* peer = */ replaceConfig.GetPeerName(),
+ /* userSID = */ userToken.GetUserSID(),
+ /* sanitizedToken = */ userToken.GetSanitizedToken(),
+ /* oldConfig = */ oldConfig,
+ /* newConfig = */ newConfig,
+ /* reason = */ {},
+ /* success = */ true);
+
Self->CurrentProposedStorageConfig.emplace(std::move(*config));
auto done = [&](TEvGather *res) -> std::optional<TString> {
@@ -217,6 +230,16 @@ namespace NKikimr::NStorage {
Self->RootState = ERootState::IN_PROGRESS; // forbid any concurrent activity
}
+ bool TInvokeRequestHandlerActor::CheckConfigUpdate(const NKikimrBlobStorage::TStorageConfig& proposed) {
+ if (auto error = ValidateConfigUpdate(*Self->StorageConfig, proposed)) {
+ STLOG(PRI_DEBUG, BS_NODE, NWDC78, "Config update validation failed", (SelfId, SelfId()),
+ (Error, *error), (ProposedConfig, proposed));
+ FinishWithError(TResult::ERROR, TStringBuilder() << "Config update validation failed: " << *error);
+ return false;
+ }
+ return true;
+ }
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Query termination and result delivery
diff --git a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp
index 8d3ce407cd3..a2f4dd611b7 100644
--- a/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp
+++ b/ydb/core/blobstorage/nodewarden/distconf_invoke_storage_config.cpp
@@ -339,6 +339,8 @@ namespace NKikimr::NStorage {
record.SetOperation(NKikimrBlobStorage::TEvControllerDistconfRequest::DisableDistconf);
if (ProposedStorageConfig.HasExpectedStorageYamlVersion()) {
record.SetExpectedStorageConfigVersion(ProposedStorageConfig.GetExpectedStorageYamlVersion());
+ record.SetPeerName(replaceStorageConfig.GetPeerName());
+ record.SetUserToken(replaceStorageConfig.GetUserToken());
}
break;
diff --git a/ydb/core/blobstorage/nodewarden/ya.make b/ydb/core/blobstorage/nodewarden/ya.make
index 4e47edae2b7..8a2d2ae9676 100644
--- a/ydb/core/blobstorage/nodewarden/ya.make
+++ b/ydb/core/blobstorage/nodewarden/ya.make
@@ -5,6 +5,8 @@ SRCS(
group_stat_aggregator.h
distconf.cpp
distconf.h
+ distconf_audit.h
+ distconf_audit.cpp
distconf_binding.cpp
distconf_console.cpp
distconf_dynamic.cpp
diff --git a/ydb/core/cms/console/console__replace_yaml_config.cpp b/ydb/core/cms/console/console__replace_yaml_config.cpp
index a05210d836d..78ac3937cbb 100644
--- a/ydb/core/cms/console/console__replace_yaml_config.cpp
+++ b/ydb/core/cms/console/console__replace_yaml_config.cpp
@@ -30,6 +30,7 @@ class TConfigsManager::TTxReplaceYamlConfigBase
, AllowUnknownFields(ev->Get()->Record.GetRequest().allow_unknown_fields())
, DryRun(ev->Get()->Record.GetRequest().dry_run())
, IngressDatabase(ev->Get()->Record.HasIngressDatabase() ? TMaybe<TString>{ev->Get()->Record.GetIngressDatabase()} : TMaybe<TString>{})
+ , SkipAuditLog(ev->Get()->Record.GetSkipAuditLog() ? true : false)
{
}
@@ -90,6 +91,7 @@ protected:
TSimpleSharedPtr<NYamlConfig::TBasicUnknownFieldsCollector> UnknownFieldsCollector = nullptr;
TMaybe<TString> IngressDatabase;
bool WarnDatabaseBypass = false;
+ bool SkipAuditLog = false;
};
class TConfigsManager::TTxReplaceMainYamlConfig
@@ -177,14 +179,16 @@ public:
ctx.Send(Response.Release());
if (!Error && Modify && !DryRun) {
- AuditLogReplaceConfigTransaction(
- /* peer = */ Peer,
- /* userSID = */ UserToken.GetUserSID(),
- /* sanitizedToken = */ UserToken.GetSanitizedToken(),
- /* oldConfig = */ Self->MainYamlConfig,
- /* newConfig = */ Config,
- /* reason = */ {},
- /* success = */ true);
+ if (!SkipAuditLog) {
+ AuditLogReplaceConfigTransaction(
+ /* peer = */ Peer,
+ /* userSID = */ UserToken.GetUserSID(),
+ /* sanitizedToken = */ UserToken.GetSanitizedToken(),
+ /* oldConfig = */ Self->MainYamlConfig,
+ /* newConfig = */ Config,
+ /* reason = */ {},
+ /* success = */ true);
+ }
Self->YamlVersion = Version + 1;
Self->MainYamlConfig = UpdatedMainConfig;
@@ -195,14 +199,16 @@ public:
auto resp = MakeHolder<TConfigsProvider::TEvPrivate::TEvUpdateYamlConfig>(Self->MainYamlConfig, Self->DatabaseYamlConfigs);
ctx.Send(Self->ConfigsProvider, resp.Release());
} else if (Error && !DryRun) {
- AuditLogReplaceConfigTransaction(
- /* peer = */ Peer,
- /* userSID = */ UserToken.GetUserSID(),
- /* sanitizedToken = */ UserToken.GetSanitizedToken(),
- /* oldConfig = */ Self->MainYamlConfig,
- /* newConfig = */ Config,
- /* reason = */ ErrorReason,
- /* success = */ false);
+ if (!SkipAuditLog) {
+ AuditLogReplaceConfigTransaction(
+ /* peer = */ Peer,
+ /* userSID = */ UserToken.GetUserSID(),
+ /* sanitizedToken = */ UserToken.GetSanitizedToken(),
+ /* oldConfig = */ Self->MainYamlConfig,
+ /* newConfig = */ Config,
+ /* reason = */ ErrorReason,
+ /* success = */ false);
+ }
}
Self->TxProcessor->TxCompleted(this, ctx);
@@ -360,15 +366,17 @@ public:
}
if (!Error && Modify && !DryRun) {
- AuditLogReplaceDatabaseConfigTransaction(
- /* peer = */ Peer,
- /* userSID = */ UserToken.GetUserSID(),
- /* sanitizedToken = */ UserToken.GetSanitizedToken(),
- /* database = */ TargetDatabase,
- /* oldConfig = */ oldConfig,
- /* newConfig = */ Config,
- /* reason = */ {},
- /* success = */ true);
+ if (!SkipAuditLog) {
+ AuditLogReplaceDatabaseConfigTransaction(
+ /* peer = */ Peer,
+ /* userSID = */ UserToken.GetUserSID(),
+ /* sanitizedToken = */ UserToken.GetSanitizedToken(),
+ /* database = */ TargetDatabase,
+ /* oldConfig = */ oldConfig,
+ /* newConfig = */ Config,
+ /* reason = */ {},
+ /* success = */ true);
+ }
Self->DatabaseYamlConfigs[TargetDatabase] = TDatabaseYamlConfig {
.Config = UpdatedDatabaseConfig,
@@ -383,15 +391,17 @@ public:
ctx.Send(Self->ConfigsProvider, resp.Release());
} else if (Error && !DryRun) {
- AuditLogReplaceDatabaseConfigTransaction(
- /* peer = */ Peer,
- /* userSID = */ UserToken.GetUserSID(),
- /* sanitizedToken = */ UserToken.GetSanitizedToken(),
- /* database = */ TargetDatabase,
- /* oldConfig = */ oldConfig,
- /* newConfig = */ Config,
- /* reason = */ ErrorReason,
- /* success = */ false);
+ if (!SkipAuditLog) {
+ AuditLogReplaceDatabaseConfigTransaction(
+ /* peer = */ Peer,
+ /* userSID = */ UserToken.GetUserSID(),
+ /* sanitizedToken = */ UserToken.GetSanitizedToken(),
+ /* database = */ TargetDatabase,
+ /* oldConfig = */ oldConfig,
+ /* newConfig = */ Config,
+ /* reason = */ ErrorReason,
+ /* success = */ false);
+ }
}
Self->TxProcessor->TxCompleted(this, ctx);
diff --git a/ydb/core/cms/console/console_handshake.cpp b/ydb/core/cms/console/console_handshake.cpp
index 7fac6fb9601..b5b59ea530f 100644
--- a/ydb/core/cms/console/console_handshake.cpp
+++ b/ydb/core/cms/console/console_handshake.cpp
@@ -30,6 +30,7 @@ public:
void Bootstrap(const TActorId& consoleId) {
auto request = std::make_unique<TEvConsole::TEvSetYamlConfigRequest>();
request->Record.SetBypassAuth(true);
+ request->Record.SetSkipAuditLog(true);
request->Record.MutableRequest()->set_config(MainYamlConfig);
request->Record.MutableRequest()->set_allow_unknown_fields(true);
Send(consoleId, request.release());
diff --git a/ydb/core/grpc_services/rpc_config.cpp b/ydb/core/grpc_services/rpc_config.cpp
index e1ea3a19eec..17d22f1fd1a 100644
--- a/ydb/core/grpc_services/rpc_config.cpp
+++ b/ydb/core/grpc_services/rpc_config.cpp
@@ -201,6 +201,8 @@ public:
cmd->SetSwitchDedicatedStorageSection(*shim.SwitchDedicatedStorageSection);
}
cmd->SetDedicatedStorageSectionConfigMode(shim.DedicatedConfigMode);
+ cmd->SetUserToken(Request_->GetSerializedToken());
+ cmd->SetPeerName(Request_->GetPeerName());
}
void FillDistconfResult(NKikimrBlobStorage::TEvNodeConfigInvokeOnRootResult& /*record*/,
@@ -236,7 +238,9 @@ public:
request->allow_unknown_fields() || request->bypass_checks(),
request->bypass_checks(),
/*enableConfigV2=*/ ff.GetSwitchToConfigV2(),
- /*disableConfigV2=*/ ff.GetSwitchToConfigV1());
+ /*disableConfigV2=*/ ff.GetSwitchToConfigV1(),
+ Request_->GetPeerName(),
+ Request_->GetSerializedToken());
}
private:
diff --git a/ydb/core/mind/bscontroller/bsc.cpp b/ydb/core/mind/bscontroller/bsc.cpp
index 3ab5cdc7b11..02209c112e7 100644
--- a/ydb/core/mind/bscontroller/bsc.cpp
+++ b/ydb/core/mind/bscontroller/bsc.cpp
@@ -463,7 +463,8 @@ void TBlobStorageController::Handle(TEvBlobStorage::TEvControllerDistconfRequest
// commit it
Execute(CreateTxCommitConfig(std::move(yamlConfig), std::make_optional(std::move(storageYaml)), std::nullopt,
- expectedStorageYamlConfigVersion, std::exchange(h, {}), std::nullopt));
+ expectedStorageYamlConfigVersion, std::exchange(h, {}), std::nullopt,
+ TAuditLogInfo{record.GetPeerName(), NACLib::TUserToken{record.GetUserToken()}}));
break;
}
diff --git a/ydb/core/mind/bscontroller/bsc_audit.cpp b/ydb/core/mind/bscontroller/bsc_audit.cpp
new file mode 100644
index 00000000000..c111f8a9cda
--- /dev/null
+++ b/ydb/core/mind/bscontroller/bsc_audit.cpp
@@ -0,0 +1,35 @@
+#include "bsc_audit.h"
+
+#include <ydb/core/audit/audit_log.h>
+#include <ydb/core/util/address_classifier.h>
+
+namespace NKikimr::NBsController {
+
+static const TString COMPONENT_NAME = "bsc";
+static const TString EMPTY_VALUE = "{none}";
+
+void AuditLogCommitConfigTransaction(
+ const TString& peer,
+ const TString& userSID,
+ const TString& sanitizedToken,
+ const TString& oldConfig,
+ const TString& newConfig,
+ const TString& reason,
+ bool success)
+{
+ auto peerName = NKikimr::NAddressClassifier::ExtractAddress(peer);
+
+ AUDIT_LOG(
+ AUDIT_PART("component", COMPONENT_NAME)
+ AUDIT_PART("remote_address", (!peerName.empty() ? peerName : EMPTY_VALUE))
+ AUDIT_PART("subject", (!userSID.empty() ? userSID : EMPTY_VALUE))
+ AUDIT_PART("sanitized_token", (!sanitizedToken.empty() ? sanitizedToken : EMPTY_VALUE))
+ AUDIT_PART("status", TString(success ? "SUCCESS" : "ERROR"))
+ AUDIT_PART("reason", reason, !reason.empty())
+ AUDIT_PART("operation", TString("REPLACE CONFIG"))
+ AUDIT_PART("old_config", oldConfig)
+ AUDIT_PART("new_config", newConfig)
+ );
+}
+
+} // namespace NKikimr::NBsController
diff --git a/ydb/core/mind/bscontroller/bsc_audit.h b/ydb/core/mind/bscontroller/bsc_audit.h
new file mode 100644
index 00000000000..50245148150
--- /dev/null
+++ b/ydb/core/mind/bscontroller/bsc_audit.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include <util/generic/string.h>
+
+namespace NKikimr::NBsController {
+
+void AuditLogCommitConfigTransaction(
+ const TString& peer,
+ const TString& userSID,
+ const TString& sanitizedToken,
+ const TString& oldConfig,
+ const TString& newConfig,
+ const TString& reason,
+ bool success);
+
+} // namespace NKikimr::NBsController
diff --git a/ydb/core/mind/bscontroller/commit_config.cpp b/ydb/core/mind/bscontroller/commit_config.cpp
index fca8960d51a..ad2322d3c3b 100644
--- a/ydb/core/mind/bscontroller/commit_config.cpp
+++ b/ydb/core/mind/bscontroller/commit_config.cpp
@@ -1,5 +1,6 @@
#include "impl.h"
#include "console_interaction.h"
+#include "bsc_audit.h"
#include <ydb/library/yaml_config/yaml_config.h>
#include <ydb/library/yaml_config/yaml_config_parser.h>
#include <ydb/core/blobstorage/nodewarden/node_warden_impl.h>
@@ -16,6 +17,7 @@ namespace NKikimr::NBsController {
std::optional<ui64> ExpectedStorageYamlConfigVersion;
std::unique_ptr<IEventHandle> Handle;
std::optional<bool> SwitchEnableConfigV2;
+ std::optional<TAuditLogInfo> AuditLogInfo;
ui64 GenerationOnStart = 0;
TString FingerprintOnStart;
@@ -25,7 +27,7 @@ namespace NKikimr::NBsController {
std::optional<std::optional<TString>>&& storageYamlConfig,
std::optional<NKikimrBlobStorage::TStorageConfig>&& storageConfig,
std::optional<ui64> expectedStorageYamlConfigVersion, std::unique_ptr<IEventHandle> handle,
- std::optional<bool> switchEnableConfigV2)
+ std::optional<bool> switchEnableConfigV2, std::optional<TAuditLogInfo>&& auditLogInfo)
: TTransactionBase(controller)
, YamlConfig(std::move(yamlConfig))
, StorageYamlConfig(std::move(storageYamlConfig))
@@ -33,6 +35,7 @@ namespace NKikimr::NBsController {
, ExpectedStorageYamlConfigVersion(expectedStorageYamlConfigVersion)
, Handle(std::move(handle))
, SwitchEnableConfigV2(switchEnableConfigV2)
+ , AuditLogInfo(std::move(auditLogInfo))
{}
TTxType GetTxType() const override { return NBlobStorageController::TXTYPE_COMMIT_CONFIG; }
@@ -68,6 +71,34 @@ namespace NKikimr::NBsController {
LOG_ALERT_S(ctx, NKikimrServices::BS_CONTROLLER, "Storage config changed");
Y_DEBUG_ABORT("Storage config changed");
}
+
+ if (AuditLogInfo) {
+ TStringBuilder oldConfig;
+ if (Self->YamlConfig) {
+ oldConfig << GetSingleConfigYaml(*Self->YamlConfig);
+ }
+ if (Self->StorageYamlConfig) {
+ oldConfig << *Self->StorageYamlConfig;
+ }
+
+ TStringBuilder newConfig;
+ if (YamlConfig) {
+ newConfig << GetSingleConfigYaml(*YamlConfig);
+ }
+ if (StorageYamlConfig && *StorageYamlConfig) {
+ newConfig << **StorageYamlConfig;
+ }
+
+ AuditLogCommitConfigTransaction(
+ /* peer = */ AuditLogInfo->PeerName,
+ /* userSID = */ AuditLogInfo->UserToken.GetUserSID(),
+ /* sanitizedToken = */ AuditLogInfo->UserToken.GetSanitizedToken(),
+ /* oldConfig = */ oldConfig,
+ /* newConfig = */ newConfig,
+ /* reason = */ {},
+ /* success = */ true);
+ }
+
if (StorageConfig) {
Self->StorageConfig = std::move(*StorageConfig);
Self->ApplyStorageConfig(true);
@@ -136,9 +167,9 @@ namespace NKikimr::NBsController {
std::optional<std::optional<TString>>&& storageYamlConfig,
std::optional<NKikimrBlobStorage::TStorageConfig>&& storageConfig,
std::optional<ui64> expectedStorageYamlConfigVersion, std::unique_ptr<IEventHandle> handle,
- std::optional<bool> switchEnableConfigV2) {
+ std::optional<bool> switchEnableConfigV2, std::optional<TAuditLogInfo>&& auditLogInfo) {
return new TTxCommitConfig(this, std::move(yamlConfig), std::move(storageYamlConfig), std::move(storageConfig),
- expectedStorageYamlConfigVersion, std::move(handle), switchEnableConfigV2);
+ expectedStorageYamlConfigVersion, std::move(handle), switchEnableConfigV2, std::move(auditLogInfo));
}
} // namespace NKikimr::NBsController
diff --git a/ydb/core/mind/bscontroller/console_interaction.cpp b/ydb/core/mind/bscontroller/console_interaction.cpp
index a506e0cfac8..a28825b6fc5 100644
--- a/ydb/core/mind/bscontroller/console_interaction.cpp
+++ b/ydb/core/mind/bscontroller/console_interaction.cpp
@@ -105,7 +105,8 @@ namespace NKikimr::NBsController {
TYamlConfig yamlConfig(std::move(yaml), version, std::move(yamlReturnedByFetch));
Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::nullopt,
- std::move(storageConfig), std::nullopt, nullptr, std::nullopt));
+ std::move(storageConfig), std::nullopt, nullptr, std::nullopt,
+ std::nullopt));
CommitInProgress = true;
}
} catch (const std::exception& ex) {
@@ -240,6 +241,9 @@ namespace NKikimr::NBsController {
ClientId = ev->Sender;
++ExpectedValidationTimeoutCookie;
+ // audit log settings
+ AuditLogInfo.emplace(record.GetPeerName(), NACLib::TUserToken{record.GetUserToken()});
+
if (!Self.ConfigLock.empty() || Self.SelfManagementEnabled) {
return IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::OngoingCommit,
"configuration is locked by distconf");
@@ -517,7 +521,8 @@ namespace NKikimr::NBsController {
}
Self.Execute(Self.CreateTxCommitConfig(std::move(yamlConfig), std::exchange(PendingStorageYamlConfig, {}),
- std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr, SwitchEnableConfigV2));
+ std::move(storageConfig), expectedStorageYamlConfigVersion, nullptr, SwitchEnableConfigV2,
+ std::move(AuditLogInfo)));
CommitInProgress = true;
PendingYamlConfig.reset();
} catch (const TExError& error) {
diff --git a/ydb/core/mind/bscontroller/console_interaction.h b/ydb/core/mind/bscontroller/console_interaction.h
index 03a02425756..100b83e782a 100644
--- a/ydb/core/mind/bscontroller/console_interaction.h
+++ b/ydb/core/mind/bscontroller/console_interaction.h
@@ -49,6 +49,7 @@ namespace NKikimr::NBsController {
bool CommitInProgress = false;
std::optional<bool> SwitchEnableConfigV2;
TEvBlobStorage::TEvControllerReplaceConfigRequest::TPtr PendingReplaceRequest;
+ std::optional<TAuditLogInfo> AuditLogInfo;
std::optional<TString> PendingYamlConfig;
bool AllowUnknownFields = false;
@@ -62,5 +63,4 @@ namespace NKikimr::NBsController {
void IssueGRpcResponse(NKikimrBlobStorage::TEvControllerReplaceConfigResponse::EStatus status,
std::optional<TString> errorReason = std::nullopt, bool disabledConfigV2 = false);
};
-
}
diff --git a/ydb/core/mind/bscontroller/defs.h b/ydb/core/mind/bscontroller/defs.h
index f3755328ee5..a66843b5218 100644
--- a/ydb/core/mind/bscontroller/defs.h
+++ b/ydb/core/mind/bscontroller/defs.h
@@ -53,6 +53,7 @@
#include <ydb/library/actors/core/interconnect.h>
#include <ydb/library/actors/core/log.h>
#include <ydb/library/actors/interconnect/interconnect.h>
+#include <ydb/library/aclib/aclib.h>
#include <library/cpp/monlib/service/pages/templates.h>
#include <type_traits>
#include <util/generic/algorithm.h>
diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h
index b102e601a43..8bfea0ec58f 100644
--- a/ydb/core/mind/bscontroller/impl.h
+++ b/ydb/core/mind/bscontroller/impl.h
@@ -1986,12 +1986,18 @@ private:
ITransaction* CreateTxMigrate();
ITransaction* CreateTxLoadEverything();
ITransaction* CreateTxUpdateSeenOperational(TVector<TGroupId> groups);
+
+ struct TAuditLogInfo {
+ TString PeerName;
+ const NACLib::TUserToken UserToken;
+ };
+
ITransaction* CreateTxCommitConfig(std::optional<TYamlConfig>&& yamlConfig,
std::optional<std::optional<TString>>&& storageYamlConfig,
std::optional<NKikimrBlobStorage::TStorageConfig>&& storageConfig,
std::optional<ui64> expectedStorageYamlConfigVersion,
std::unique_ptr<IEventHandle> handle,
- std::optional<bool> switchEnableConfigV2);
+ std::optional<bool> switchEnableConfigV2, std::optional<TAuditLogInfo>&& auditLogInfo);
struct TVDiskAvailabilityTiming {
TVSlotId VSlotId;
diff --git a/ydb/core/mind/bscontroller/ya.make b/ydb/core/mind/bscontroller/ya.make
index da444bc5fcd..c0b8bc96857 100644
--- a/ydb/core/mind/bscontroller/ya.make
+++ b/ydb/core/mind/bscontroller/ya.make
@@ -3,6 +3,8 @@ LIBRARY()
SRCS(
bsc.cpp
bsc.h
+ bsc_audit.h
+ bsc_audit.cpp
cmds_box.cpp
cmds_drive_status.cpp
cmds_host_config.cpp
diff --git a/ydb/core/mind/bscontroller/yaml_config_helpers.h b/ydb/core/mind/bscontroller/yaml_config_helpers.h
index 21610b3bd54..d65b0e6f2f9 100644
--- a/ydb/core/mind/bscontroller/yaml_config_helpers.h
+++ b/ydb/core/mind/bscontroller/yaml_config_helpers.h
@@ -57,6 +57,10 @@ inline ui64 GetSingleConfigHash(const TYamlConfig& config) {
return NYaml::GetConfigHash(std::get<0>(config));
}
+inline TString GetSingleConfigYaml(const TYamlConfig& config) {
+ return std::get<0>(config);
+}
+
} // namespace NBsController
} // namespace NKikimr
diff --git a/ydb/core/protos/blobstorage.proto b/ydb/core/protos/blobstorage.proto
index dcecae12f0c..e4d79151a28 100644
--- a/ydb/core/protos/blobstorage.proto
+++ b/ydb/core/protos/blobstorage.proto
@@ -1449,6 +1449,8 @@ message TEvControllerReplaceConfigRequest {
optional bool SwitchDedicatedStorageSection = 6;
optional bool DedicatedConfigMode = 7;
optional bool SwitchEnableConfigV2 = 10; // if set, overrides EnableConfigV2 field in BSC
+ optional string PeerName = 11;
+ optional bytes UserToken = 12;
// console flags
optional bool AllowUnknownFields = 8;
optional bool BypassMetadataChecks = 9;
@@ -1530,6 +1532,8 @@ message TEvControllerDistconfRequest {
optional bytes CompressedStorageConfig = 3; // if used has provided storage config
optional bool DedicatedConfigMode = 4; // as provided in used command
optional uint64 ExpectedStorageConfigVersion = 5;
+ optional string PeerName = 6;
+ optional bytes UserToken = 7;
}
message TEvControllerDistconfResponse {
diff --git a/ydb/core/protos/blobstorage_distributed_config.proto b/ydb/core/protos/blobstorage_distributed_config.proto
index a186d1b710a..0005d943961 100644
--- a/ydb/core/protos/blobstorage_distributed_config.proto
+++ b/ydb/core/protos/blobstorage_distributed_config.proto
@@ -203,6 +203,8 @@ message TEvNodeConfigInvokeOnRoot {
optional bool SwitchDedicatedStorageSection = 4;
bool DedicatedStorageSectionConfigMode = 5;
bool SkipConsoleValidation = 2;
+ optional bytes UserToken = 6;
+ optional string PeerName = 7;
}
message TBootstrapCluster {
diff --git a/ydb/core/protos/console_config.proto b/ydb/core/protos/console_config.proto
index 4a4a65ae254..351f5e6944d 100644
--- a/ydb/core/protos/console_config.proto
+++ b/ydb/core/protos/console_config.proto
@@ -268,6 +268,7 @@ message TSetYamlConfigRequest {
optional string PeerName = 3;
optional string IngressDatabase = 4;
optional bool BypassAuth = 5;
+ optional bool SkipAuditLog = 6;
}
message TSetYamlConfigResponse {
@@ -280,6 +281,7 @@ message TReplaceYamlConfigRequest {
optional string PeerName = 3;
optional string IngressDatabase = 4;
optional bool BypassAuth = 5;
+ optional bool SkipAuditLog = 6;
}
message TReplaceYamlConfigResponse {
diff --git a/ydb/tests/functional/config/test_config_with_metadata.py b/ydb/tests/functional/config/test_config_with_metadata.py
index 13cad5ffdf0..1b4dae0ab10 100644
--- a/ydb/tests/functional/config/test_config_with_metadata.py
+++ b/ydb/tests/functional/config/test_config_with_metadata.py
@@ -51,6 +51,7 @@ class AbstractKiKiMRTest(object):
grpc_port = cls.cluster.nodes[1].port
cls.swagger_client = SwaggerClient(host, cls.cluster.nodes[1].mon_port)
cls.config_client = ConfigClient(host, grpc_port)
+ cls.config_client.set_auth_token('root@builtin')
@classmethod
def teardown_class(cls):
@@ -143,7 +144,10 @@ class TestKiKiMRStoreConfigDir(AbstractKiKiMRTest):
separate_node_configs=True,
extra_grpc_services=['config'],
metadata_section=cls.metadata_section,
- additional_log_configs={'BS_NODE': LogLevels.DEBUG},
+ additional_log_configs={'BS_NODE': LogLevels.DEBUG,
+ 'BS_CONTROLLER': LogLevels.DEBUG},
+ enable_audit_log=True,
+ default_users=dict((i, '') for i in ('root', 'other-user')),
)
cls.cluster = KiKiMR(configurator=configurator)
cls.cluster.start()
@@ -152,6 +156,7 @@ class TestKiKiMRStoreConfigDir(AbstractKiKiMRTest):
grpc_port = cls.cluster.nodes[1].port
cls.swagger_client = SwaggerClient(host, cls.cluster.nodes[1].mon_port)
cls.config_client = ConfigClient(host, grpc_port)
+ cls.config_client.set_auth_token('root@builtin')
def test_cluster_works_with_auto_conf_dir(self):
table_path = '/Root/mydb/mytable_auto_conf'
diff --git a/ydb/tests/library/clients/kikimr_config_client.py b/ydb/tests/library/clients/kikimr_config_client.py
index 44e657b47c8..016186f04ba 100644
--- a/ydb/tests/library/clients/kikimr_config_client.py
+++ b/ydb/tests/library/clients/kikimr_config_client.py
@@ -44,6 +44,10 @@ class ConfigClient(object):
]
self._channel = grpc.insecure_channel("%s:%s" % (self.server, self.port), options=self._options)
self._stub = grpc_server.ConfigServiceStub(self._channel)
+ self._auth_token = None
+
+ def set_auth_token(self, token):
+ self._auth_token = token
def _get_invoke_callee(self, method):
return getattr(self._stub, method)
@@ -53,7 +57,10 @@ class ConfigClient(object):
while True:
try:
callee = self._get_invoke_callee(method)
- return callee(request)
+ metadata = []
+ if self._auth_token:
+ metadata.append(('x-ydb-auth-ticket', self._auth_token))
+ return callee(request, metadata=metadata)
except (RuntimeError, grpc.RpcError):
retry -= 1