From a6807f76a959213074651198977809729ff66b24 Mon Sep 17 00:00:00 2001 From: Egor Masharskii Date: Fri, 24 Jul 2026 18:07:51 +0000 Subject: [PATCH 1/2] allow filestore to automatically update certificates --- cloud/filestore/config/server.proto | 4 + .../filestore/libs/daemon/common/bootstrap.h | 1 + .../libs/daemon/server/bootstrap.cpp | 23 ++++- .../filestore/libs/daemon/vhost/bootstrap.cpp | 94 +++++++++++++++++-- cloud/filestore/libs/server/config.cpp | 1 + cloud/filestore/libs/server/config.h | 2 + cloud/filestore/libs/storage/api/components.h | 1 + 7 files changed, 114 insertions(+), 12 deletions(-) diff --git a/cloud/filestore/config/server.proto b/cloud/filestore/config/server.proto index 64c285df5bb..34d1b39debe 100644 --- a/cloud/filestore/config/server.proto +++ b/cloud/filestore/config/server.proto @@ -67,6 +67,10 @@ message TServerConfig // Regions that have not been pinged within this timeout will be // invalidated and unmapped. optional uint32 SharedMemoryRegionTimeout = 23; + + // Certificate refresh period (in milliseconds) for automatic TLS certificate + // reloading. Zero disables periodic certificate reloading. + optional uint32 RefreshCertsPeriod = 24; } //////////////////////////////////////////////////////////////////////////////// diff --git a/cloud/filestore/libs/daemon/common/bootstrap.h b/cloud/filestore/libs/daemon/common/bootstrap.h index 8a7c471f4ed..08394d09882 100644 --- a/cloud/filestore/libs/daemon/common/bootstrap.h +++ b/cloud/filestore/libs/daemon/common/bootstrap.h @@ -80,6 +80,7 @@ class TBootstrapCommon IActorSystemPtr ActorSystem; NStorage::NFastShard::IServerPtr FastShardServer; NCloud::NStorage::IStatsFetcherPtr StatsFetcher; + ITaskQueuePtr LongRunningTaskExecutor; ICertificateProviderPtr CertificateProvider; public: diff --git a/cloud/filestore/libs/daemon/server/bootstrap.cpp b/cloud/filestore/libs/daemon/server/bootstrap.cpp index 64d8a220e60..c75e0339ae0 100644 --- a/cloud/filestore/libs/daemon/server/bootstrap.cpp +++ b/cloud/filestore/libs/daemon/server/bootstrap.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -139,12 +140,26 @@ void TBootstrapServer::InitComponents() }); } - if (!certPathList.empty()) { - CertificateProvider = CreateStaticCertificateProvider( - Configs->ServerConfig->GetRootCertsFile(), - std::move(certPathList)); + if (Configs->ServerConfig->GetSecurePort() && certPathList.empty()) { + ythrow yexception() + << "Secure port is configured without certificates"; } + if (Configs->ServerConfig->GetRefreshCertsPeriod()) { + LongRunningTaskExecutor = CreateLongRunningTaskExecutor("CertRefresh"); + } + + CertificateProvider = CreateCertificateProvider( + Logging, + GetComponentName( + NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), + Scheduler, + LongRunningTaskExecutor, + serverCounters, + Configs->ServerConfig->GetRootCertsFile(), + std::move(certPathList), + Configs->ServerConfig->GetRefreshCertsPeriod()); + Server = NServer::CreateServer( Configs->ServerConfig, Logging, diff --git a/cloud/filestore/libs/daemon/vhost/bootstrap.cpp b/cloud/filestore/libs/daemon/vhost/bootstrap.cpp index ec7db4276d3..7e1276b8e20 100644 --- a/cloud/filestore/libs/daemon/vhost/bootstrap.cpp +++ b/cloud/filestore/libs/daemon/vhost/bootstrap.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -85,8 +86,51 @@ const TString ServerMetricsComponent = "server"; //////////////////////////////////////////////////////////////////////////////// +struct TClientCertificateProviderFactory +{ + ILoggingServicePtr Logging; + TString LogComponent; + ISchedulerPtr Scheduler; + ITaskQueuePtr LongRunningTaskExecutor; + NMonitoring::TDynamicCountersPtr ServerGroup; + TDuration RefreshInterval; + + TClientCertificateProviderFactory( + ILoggingServicePtr logging, + TString logComponent, + ISchedulerPtr scheduler, + ITaskQueuePtr longRunningTaskExecutor, + NMonitoring::TDynamicCountersPtr serverGroup, + TDuration refreshInterval) + : Logging(std::move(logging)) + , LogComponent(std::move(logComponent)) + , Scheduler(std::move(scheduler)) + , LongRunningTaskExecutor(std::move(longRunningTaskExecutor)) + , ServerGroup(std::move(serverGroup)) + , RefreshInterval(refreshInterval) + {} + + ICertificateProviderPtr Build( + TString rootCertPath, + TVector certificates) const + { + return CreateCertificateProvider( + Logging, + LogComponent, + Scheduler, + LongRunningTaskExecutor, + ServerGroup, + std::move(rootCertPath), + std::move(certificates), + RefreshInterval); + } +}; + +//////////////////////////////////////////////////////////////////////////////// + ICertificateProviderPtr CreateClientCertificateProvider( - const NClient::TClientConfigPtr& config) + const NClient::TClientConfigPtr& config, + const TClientCertificateProviderFactory& factory) { TVector certPathList { { @@ -95,7 +139,12 @@ ICertificateProviderPtr CreateClientCertificateProvider( } }; - return CreateStaticCertificateProvider( + if (config->GetSecurePort() && certPathList.empty()) { + ythrow yexception() + << "Secure client port is configured without certificates"; + } + + return factory.Build( config->GetRootCertsFile(), std::move(certPathList)); } @@ -109,6 +158,7 @@ class TFileStoreEndpoints final using TEndpointsMap = TMap; private: + TClientCertificateProviderFactory CertificateProviderFactory; ITimerPtr Timer; ISchedulerPtr Scheduler; ILoggingServicePtr Logging; @@ -119,12 +169,14 @@ class TFileStoreEndpoints final public: TFileStoreEndpoints( + TClientCertificateProviderFactory certificateProviderFactory, ITimerPtr timer, ISchedulerPtr scheduler, ILoggingServicePtr logging, IFileStoreServicePtr localService, IActorSystemPtr actorSystem) - : Timer(std::move(timer)) + : CertificateProviderFactory(std::move(certificateProviderFactory)) + , Timer(std::move(timer)) , Scheduler(std::move(scheduler)) , Logging(std::move(logging)) , LocalService(std::move(localService)) @@ -181,7 +233,9 @@ class TFileStoreEndpoints final fileStore = NClient::CreateFileStoreClient( clientConfig, Logging, - CreateClientCertificateProvider(clientConfig)); + CreateClientCertificateProvider( + clientConfig, + CertificateProviderFactory)); } break; } @@ -394,12 +448,26 @@ void TBootstrapVhost::InitComponents() }); } - if (!certPathList.empty()) { - CertificateProvider = CreateStaticCertificateProvider( - Configs->ServerConfig->GetRootCertsFile(), - std::move(certPathList)); + if (Configs->ServerConfig->GetSecurePort() && certPathList.empty()) { + ythrow yexception() + << "Secure port is configured without certificates"; + } + + if (Configs->ServerConfig->GetRefreshCertsPeriod()) { + LongRunningTaskExecutor = CreateLongRunningTaskExecutor("CertRefresh"); } + CertificateProvider = CreateCertificateProvider( + Logging, + GetComponentName( + NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), + Scheduler, + LongRunningTaskExecutor, + serverCounters, + Configs->ServerConfig->GetRootCertsFile(), + std::move(certPathList), + Configs->ServerConfig->GetRefreshCertsPeriod()); + Server = CreateServer( Configs->ServerConfig, Logging, @@ -459,7 +527,17 @@ void TBootstrapVhost::InitEndpoints() localServiceConfig->Utf8DebugString().Quote().c_str()); } + TClientCertificateProviderFactory certFactory( + Logging, + GetComponentName( + NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), + Scheduler, + LongRunningTaskExecutor, + FilestoreCounters->GetSubgroup("component", VhostMetricsComponent), + Configs->ServerConfig->GetRefreshCertsPeriod()); + auto endpoints = std::make_shared( + std::move(certFactory), Timer, Scheduler, Logging, diff --git a/cloud/filestore/libs/server/config.cpp b/cloud/filestore/libs/server/config.cpp index 64f2b0c8725..be1a31516e7 100644 --- a/cloud/filestore/libs/server/config.cpp +++ b/cloud/filestore/libs/server/config.cpp @@ -48,6 +48,7 @@ constexpr TDuration Seconds(int s) xxx(SharedMemoryRegionTimeout, \ TDuration, \ TDuration::Max()) \ + xxx(RefreshCertsPeriod, TDuration, Seconds(0) )\ // FILESTORE_SERVER_CONFIG #define FILESTORE_SERVER_DECLARE_CONFIG(name, type, value) \ diff --git a/cloud/filestore/libs/server/config.h b/cloud/filestore/libs/server/config.h index 1fc590742bf..9f895486d3c 100644 --- a/cloud/filestore/libs/server/config.h +++ b/cloud/filestore/libs/server/config.h @@ -62,6 +62,8 @@ class TServerConfig TString GetSharedMemoryBasePath() const; TDuration GetSharedMemoryRegionTimeout() const; + TDuration GetRefreshCertsPeriod() const; + const NProto::TServerConfig& GetProto() const { return ProtoConfig; diff --git a/cloud/filestore/libs/storage/api/components.h b/cloud/filestore/libs/storage/api/components.h index d8de97ce3f8..3eadbe6d9d8 100644 --- a/cloud/filestore/libs/storage/api/components.h +++ b/cloud/filestore/libs/storage/api/components.h @@ -36,6 +36,7 @@ namespace NCloud::NFileStore::NStorage { xxx(CLIENT) \ xxx(AUTH) \ xxx(USER_STATS) \ + xxx(TLS_CERTIFICATE_PROVIDER) \ // FILESTORE_COMPONENTS //////////////////////////////////////////////////////////////////////////////// From 0ea29bb1f2c8adef17d62316a6179c54ff3d6c3b Mon Sep 17 00:00:00 2001 From: Egor Masharskii Date: Fri, 24 Jul 2026 18:56:36 +0000 Subject: [PATCH 2/2] update --- .../libs/daemon/server/bootstrap.cpp | 34 +++++----- .../filestore/libs/daemon/vhost/bootstrap.cpp | 66 +++++++++++++------ 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/cloud/filestore/libs/daemon/server/bootstrap.cpp b/cloud/filestore/libs/daemon/server/bootstrap.cpp index c75e0339ae0..31e53a61ef4 100644 --- a/cloud/filestore/libs/daemon/server/bootstrap.cpp +++ b/cloud/filestore/libs/daemon/server/bootstrap.cpp @@ -140,25 +140,29 @@ void TBootstrapServer::InitComponents() }); } - if (Configs->ServerConfig->GetSecurePort() && certPathList.empty()) { - ythrow yexception() - << "Secure port is configured without certificates"; - } - if (Configs->ServerConfig->GetRefreshCertsPeriod()) { LongRunningTaskExecutor = CreateLongRunningTaskExecutor("CertRefresh"); } - CertificateProvider = CreateCertificateProvider( - Logging, - GetComponentName( - NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), - Scheduler, - LongRunningTaskExecutor, - serverCounters, - Configs->ServerConfig->GetRootCertsFile(), - std::move(certPathList), - Configs->ServerConfig->GetRefreshCertsPeriod()); + if (certPathList.empty()) { + if (Configs->ServerConfig->GetSecurePort()) { + ythrow yexception() + << "Secure port is configured without certificates"; + } + + CertificateProvider = CreateCertificateProviderStub(); + } else { + CertificateProvider = CreateCertificateProvider( + Logging, + GetComponentName( + NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), + Scheduler, + LongRunningTaskExecutor, + serverCounters, + Configs->ServerConfig->GetRootCertsFile(), + std::move(certPathList), + Configs->ServerConfig->GetRefreshCertsPeriod()); + } Server = NServer::CreateServer( Configs->ServerConfig, diff --git a/cloud/filestore/libs/daemon/vhost/bootstrap.cpp b/cloud/filestore/libs/daemon/vhost/bootstrap.cpp index 7e1276b8e20..f1d1cad2430 100644 --- a/cloud/filestore/libs/daemon/vhost/bootstrap.cpp +++ b/cloud/filestore/libs/daemon/vhost/bootstrap.cpp @@ -156,6 +156,7 @@ class TFileStoreEndpoints final { private: using TEndpointsMap = TMap; + using TCertificateProvidersMap = TMap; private: TClientCertificateProviderFactory CertificateProviderFactory; @@ -166,6 +167,7 @@ class TFileStoreEndpoints final IActorSystemPtr ActorSystem; TEndpointsMap Endpoints; + TCertificateProvidersMap CertificateProviders; public: TFileStoreEndpoints( @@ -185,6 +187,11 @@ class TFileStoreEndpoints final void Start() override { + for (const auto& [name, certificateProvider]: CertificateProviders) { + Y_UNUSED(name); + certificateProvider->Start(); + } + for (const auto& [name, endpoint]: Endpoints) { endpoint->Start(); } @@ -195,6 +202,11 @@ class TFileStoreEndpoints final for (const auto& [name, endpoint]: Endpoints) { endpoint->Stop(); } + + for (const auto& [name, certificateProvider]: CertificateProviders) { + Y_UNUSED(name); + certificateProvider->Stop(); + } } IFileStoreServicePtr GetEndpoint(const TString& name) override @@ -211,6 +223,7 @@ class TFileStoreEndpoints final ui32 permanentActorCount) { auto clientConfig = std::make_shared(config); + ICertificateProviderPtr certificateProvider; IFileStoreServicePtr fileStore; switch (kind) { case NDaemon::EServiceKind::Null: { @@ -230,21 +243,28 @@ class TFileStoreEndpoints final if (LocalService) { fileStore = LocalService; } else { + certificateProvider = CreateClientCertificateProvider( + clientConfig, + CertificateProviderFactory); fileStore = NClient::CreateFileStoreClient( clientConfig, Logging, - CreateClientCertificateProvider( - clientConfig, - CertificateProviderFactory)); + certificateProvider); } break; } } - return AddEndpoint( + const bool inserted = AddEndpoint( name, std::move(clientConfig), std::move(fileStore)); + + if (inserted && certificateProvider) { + CertificateProviders.emplace(name, std::move(certificateProvider)); + } + + return inserted; } bool Empty() const @@ -421,6 +441,10 @@ void TBootstrapVhost::InitComponents() Configs->VhostServiceConfig->GetEndpointStorageType()); } + if (Configs->ServerConfig->GetRefreshCertsPeriod()) { + LongRunningTaskExecutor = CreateLongRunningTaskExecutor("CertRefresh"); + } + switch (Configs->Options->Service) { case NDaemon::EServiceKind::Local: case NDaemon::EServiceKind::Kikimr: @@ -448,26 +472,26 @@ void TBootstrapVhost::InitComponents() }); } - if (Configs->ServerConfig->GetSecurePort() && certPathList.empty()) { - ythrow yexception() - << "Secure port is configured without certificates"; - } + if (certPathList.empty()) { + if (Configs->ServerConfig->GetSecurePort()) { + ythrow yexception() + << "Secure port is configured without certificates"; + } - if (Configs->ServerConfig->GetRefreshCertsPeriod()) { - LongRunningTaskExecutor = CreateLongRunningTaskExecutor("CertRefresh"); + CertificateProvider = CreateCertificateProviderStub(); + } else { + CertificateProvider = CreateCertificateProvider( + Logging, + GetComponentName( + NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), + Scheduler, + LongRunningTaskExecutor, + serverCounters, + Configs->ServerConfig->GetRootCertsFile(), + std::move(certPathList), + Configs->ServerConfig->GetRefreshCertsPeriod()); } - CertificateProvider = CreateCertificateProvider( - Logging, - GetComponentName( - NStorage::TFileStoreComponents::TLS_CERTIFICATE_PROVIDER), - Scheduler, - LongRunningTaskExecutor, - serverCounters, - Configs->ServerConfig->GetRootCertsFile(), - std::move(certPathList), - Configs->ServerConfig->GetRefreshCertsPeriod()); - Server = CreateServer( Configs->ServerConfig, Logging,