diff options
| author | mregrock <[email protected]> | 2025-04-17 17:51:47 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-04-17 17:51:47 +0300 |
| commit | d71dab77fea14b45cfe4e82237bc61876badec4c (patch) | |
| tree | 4805c6ab406e1708c42f958c43682b8c3f06d873 | |
| parent | a97c3d07114bc6de0225a84da5224858ac2928ce (diff) | |
Move audit log from console to BSC/distconf in V2 (#17307)
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 |
