summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormolotkov-and <[email protected]>2022-11-18 12:50:29 +0300
committermolotkov-and <[email protected]>2022-11-18 12:50:29 +0300
commita45acb262bfb6f7d06d70f9f04a763d61e811966 (patch)
tree2e4eacaa4f1ecfba0bea894abf4888b7718712ad
parentd563b5b3a6578243440353c5cfafdb56cc05fff3 (diff)
Authorization of registration node
-rw-r--r--library/cpp/grpc/client/grpc_common.h12
-rw-r--r--library/cpp/grpc/server/grpc_async_ctx_base.h10
-rw-r--r--library/cpp/grpc/server/grpc_request.h4
-rw-r--r--library/cpp/grpc/server/grpc_request_base.h2
-rw-r--r--library/cpp/grpc/server/grpc_server.cpp6
-rw-r--r--library/cpp/grpc/server/grpc_server.h1
-rw-r--r--ydb/core/client/server/CMakeLists.txt2
-rw-r--r--ydb/core/client/server/dynamic_node_auth_processor.cpp127
-rw-r--r--ydb/core/client/server/dynamic_node_auth_processor.h60
-rw-r--r--ydb/core/client/server/grpc_server.cpp6
-rw-r--r--ydb/core/client/server/grpc_server.h8
-rw-r--r--ydb/core/client/server/msgbus_server.cpp26
-rw-r--r--ydb/core/client/server/msgbus_server.h5
-rw-r--r--ydb/core/client/server/msgbus_server_node_registration.cpp45
-rw-r--r--ydb/core/driver_lib/cli_base/cli_cmds_db.cpp2
-rw-r--r--ydb/core/driver_lib/cli_base/cli_cmds_root.cpp2
-rw-r--r--ydb/core/driver_lib/cli_base/cli_grpc.h2
-rw-r--r--ydb/core/driver_lib/cli_utils/cli_cmds_root.cpp2
-rw-r--r--ydb/core/driver_lib/cli_utils/cli_cmds_server.cpp12
-rw-r--r--ydb/core/driver_lib/cli_utils/cli_cmds_tenant.cpp2
-rw-r--r--ydb/core/driver_lib/run/CMakeLists.txt2
-rw-r--r--ydb/core/driver_lib/run/cert_auth_props.cpp28
-rw-r--r--ydb/core/driver_lib/run/cert_auth_props.h11
-rw-r--r--ydb/core/driver_lib/run/run.cpp5
-rw-r--r--ydb/core/grpc_services/base/base.h16
-rw-r--r--ydb/core/grpc_services/local_rpc/local_rpc.h5
-rw-r--r--ydb/core/health_check/health_check.cpp16
-rw-r--r--ydb/core/http_proxy/discovery_actor.cpp2
-rw-r--r--ydb/core/persqueue/actor_persqueue_client_iface.h2
-rw-r--r--ydb/core/protos/config.proto17
-rw-r--r--ydb/core/protos/console_config.proto1
-rw-r--r--ydb/core/protos/node_broker.proto1
-rw-r--r--ydb/core/public_http/grpc_request_context_wrapper.h1
-rw-r--r--ydb/core/testlib/CMakeLists.txt1
-rw-r--r--ydb/core/testlib/test_client.cpp15
-rw-r--r--ydb/core/testlib/test_client.h2
-rw-r--r--ydb/core/yq/libs/health/health.cpp2
-rw-r--r--ydb/core/yq/libs/private_client/internal_service.cpp2
-rw-r--r--ydb/core/yq/libs/read_rule/read_rule_creator.cpp2
-rw-r--r--ydb/core/yq/libs/read_rule/read_rule_deleter.cpp2
-rw-r--r--ydb/core/yq/libs/shared_resources/db_pool.cpp2
-rw-r--r--ydb/core/yq/libs/ydb/ydb.cpp6
-rw-r--r--ydb/library/ycloud/impl/grpc_service_client.h2
-rw-r--r--ydb/library/yql/providers/common/token_accessor/client/factory.cpp2
-rw-r--r--ydb/library/yql/providers/common/token_accessor/client/token_accessor_client.cpp2
-rw-r--r--ydb/library/yql/providers/common/token_accessor/client/token_accessor_client_factory.cpp4
-rw-r--r--ydb/library/yql/providers/pq/async_io/dq_pq_read_actor.cpp2
-rw-r--r--ydb/library/yql/providers/pq/async_io/dq_pq_write_actor.cpp2
-rw-r--r--ydb/library/yql/providers/pq/gateway/native/yql_pq_session.cpp4
-rw-r--r--ydb/library/yql/providers/ydb/actors/yql_ydb_read_actor.cpp2
-rw-r--r--ydb/library/yql/providers/ydb/comp_nodes/yql_kik_scan.cpp2
-rw-r--r--ydb/library/yql/providers/ydb/provider/yql_ydb_load_meta.cpp2
-rw-r--r--ydb/public/lib/experimental/ydb_clickhouse_internal.cpp2
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h26
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.cpp15
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.h20
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.cpp12
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.h13
-rw-r--r--ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/params.h4
-rw-r--r--ydb/public/sdk/cpp/client/ydb_common_client/impl/client.h9
-rw-r--r--ydb/public/sdk/cpp/client/ydb_common_client/settings.cpp2
-rw-r--r--ydb/public/sdk/cpp/client/ydb_common_client/settings.h12
-rw-r--r--ydb/public/sdk/cpp/client/ydb_driver/driver.cpp19
-rw-r--r--ydb/public/sdk/cpp/client/ydb_driver/driver.h1
-rw-r--r--ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/persqueue_impl.h2
-rw-r--r--ydb/services/datastreams/datastreams_ut.cpp2
-rw-r--r--ydb/services/ydb/CMakeLists.txt2
-rw-r--r--ydb/services/ydb/cert_gen.cpp499
-rw-r--r--ydb/services/ydb/cert_gen.h45
-rw-r--r--ydb/services/ydb/ut/CMakeLists.darwin.txt4
-rw-r--r--ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt4
-rw-r--r--ydb/services/ydb/ut/CMakeLists.linux.txt4
-rw-r--r--ydb/services/ydb/ydb_client_certs_ut.cpp623
-rw-r--r--ydb/services/ydb/ydb_common_ut.h15
74 files changed, 1725 insertions, 111 deletions
diff --git a/library/cpp/grpc/client/grpc_common.h b/library/cpp/grpc/client/grpc_common.h
index ffcdafe0458..d19e42d4acd 100644
--- a/library/cpp/grpc/client/grpc_common.h
+++ b/library/cpp/grpc/client/grpc_common.h
@@ -19,7 +19,7 @@ struct TGRpcClientConfig {
ui64 MaxOutboundMessageSize = 0; // overrides MaxMessageSize for outgoing requests
ui32 MaxInFlight = 0;
bool EnableSsl = false;
- TString SslCaCert; //Implicitly enables Ssl if not empty
+ grpc::SslCredentialsOptions SslCredentials;
grpc_compression_algorithm CompressionAlgoritm = GRPC_COMPRESS_NONE;
ui64 MemQuota = 0;
std::unordered_map<TString, TString> StringChannelParams;
@@ -34,14 +34,14 @@ struct TGRpcClientConfig {
TGRpcClientConfig& operator=(TGRpcClientConfig&&) = default;
TGRpcClientConfig(const TString& locator, TDuration timeout = TDuration::Max(),
- ui64 maxMessageSize = DEFAULT_GRPC_MESSAGE_SIZE_LIMIT, ui32 maxInFlight = 0, TString caCert = "",
- grpc_compression_algorithm compressionAlgorithm = GRPC_COMPRESS_NONE, bool enableSsl = false)
+ ui64 maxMessageSize = DEFAULT_GRPC_MESSAGE_SIZE_LIMIT, ui32 maxInFlight = 0, const TString& caCert = "", const TString& clientCert = "",
+ const TString& clientPrivateKey = "", grpc_compression_algorithm compressionAlgorithm = GRPC_COMPRESS_NONE, bool enableSsl = false)
: Locator(locator)
, Timeout(timeout)
, MaxMessageSize(maxMessageSize)
, MaxInFlight(maxInFlight)
, EnableSsl(enableSsl)
- , SslCaCert(caCert)
+ , SslCredentials{.pem_root_certs = caCert, .pem_private_key = clientPrivateKey, .pem_cert_chain = clientCert}
, CompressionAlgoritm(compressionAlgorithm)
{}
};
@@ -74,8 +74,8 @@ inline std::shared_ptr<grpc::ChannelInterface> CreateChannelInterface(const TGRp
if (!config.SslTargetNameOverride.empty()) {
args.SetSslTargetNameOverride(config.SslTargetNameOverride);
}
- if (config.EnableSsl || config.SslCaCert) {
- return grpc::CreateCustomChannel(config.Locator, grpc::SslCredentials(grpc::SslCredentialsOptions{config.SslCaCert, "", ""}), args);
+ if (config.EnableSsl || config.SslCredentials.pem_root_certs) {
+ return grpc::CreateCustomChannel(config.Locator, grpc::SslCredentials(config.SslCredentials), args);
} else {
return grpc::CreateCustomChannel(config.Locator, grpc::InsecureChannelCredentials(), args);
}
diff --git a/library/cpp/grpc/server/grpc_async_ctx_base.h b/library/cpp/grpc/server/grpc_async_ctx_base.h
index 51356d4ce5a..079bce4102f 100644
--- a/library/cpp/grpc/server/grpc_async_ctx_base.h
+++ b/library/cpp/grpc/server/grpc_async_ctx_base.h
@@ -69,6 +69,16 @@ public:
return values;
}
+ TVector<TStringBuf> FindClientCert() const {
+ auto authContext = Context.auth_context();
+
+ TVector<TStringBuf> values;
+ for (auto& value: authContext->FindPropertyValues(GRPC_X509_PEM_CERT_PROPERTY_NAME)) {
+ values.emplace_back(value.data(), value.size());
+ }
+ return values;
+ }
+
grpc_compression_level GetCompressionLevel() const {
return Context.compression_level();
}
diff --git a/library/cpp/grpc/server/grpc_request.h b/library/cpp/grpc/server/grpc_request.h
index a3a5c291f07..c4b7e9c040e 100644
--- a/library/cpp/grpc/server/grpc_request.h
+++ b/library/cpp/grpc/server/grpc_request.h
@@ -170,6 +170,10 @@ public:
return TBaseAsyncContext<TService>::GetPeerMetaValues(key);
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return TBaseAsyncContext<TService>::FindClientCert();
+ }
+
grpc_compression_level GetCompressionLevel() const override {
return TBaseAsyncContext<TService>::GetCompressionLevel();
}
diff --git a/library/cpp/grpc/server/grpc_request_base.h b/library/cpp/grpc/server/grpc_request_base.h
index 105f9515d0a..42b78ed7df1 100644
--- a/library/cpp/grpc/server/grpc_request_base.h
+++ b/library/cpp/grpc/server/grpc_request_base.h
@@ -82,6 +82,8 @@ public:
//! Returns peer optional metavalue
virtual TVector<TStringBuf> GetPeerMetaValues(TStringBuf key) const = 0;
+ virtual TVector<TStringBuf> FindClientCert() const = 0;
+
//! Returns request compression level
virtual grpc_compression_level GetCompressionLevel() const = 0;
diff --git a/library/cpp/grpc/server/grpc_server.cpp b/library/cpp/grpc/server/grpc_server.cpp
index 7437b7a8f5e..97472206e20 100644
--- a/library/cpp/grpc/server/grpc_server.cpp
+++ b/library/cpp/grpc/server/grpc_server.cpp
@@ -3,6 +3,7 @@
#include <util/string/join.h>
#include <util/generic/yexception.h>
#include <util/system/thread.h>
+#include <util/generic/map.h>
#include <grpc++/resource_quota.h>
#include <contrib/libs/grpc/src/core/lib/iomgr/socket_mutator.h>
@@ -64,6 +65,11 @@ void TGRpcServer::Start() {
grpc::SslServerCredentialsOptions sslOps;
sslOps.pem_root_certs = std::move(Options_.SslData->Root);
sslOps.pem_key_cert_pairs.push_back(keycert);
+
+ if (Options_.SslData->DoRequestClientCertificate) {
+ sslOps.client_certificate_request = GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY;
+ }
+
credentials = grpc::SslServerCredentials(sslOps);
}
if (Options_.ExternalListener) {
diff --git a/library/cpp/grpc/server/grpc_server.h b/library/cpp/grpc/server/grpc_server.h
index d6814a90a0d..c9b48a6676a 100644
--- a/library/cpp/grpc/server/grpc_server.h
+++ b/library/cpp/grpc/server/grpc_server.h
@@ -25,6 +25,7 @@ struct TSslData {
TString Cert;
TString Key;
TString Root;
+ bool DoRequestClientCertificate = false;
};
struct IExternalListener
diff --git a/ydb/core/client/server/CMakeLists.txt b/ydb/core/client/server/CMakeLists.txt
index 3c8a48ea36f..ad5f5ca3c85 100644
--- a/ydb/core/client/server/CMakeLists.txt
+++ b/ydb/core/client/server/CMakeLists.txt
@@ -31,6 +31,7 @@ target_link_libraries(core-client-server PUBLIC
ydb-core-engine
core-engine-minikql
ydb-core-grpc_services
+ core-grpc_services-base
ydb-core-keyvalue
core-kqp-common
ydb-core-node_whiteboard
@@ -51,6 +52,7 @@ target_link_libraries(core-client-server PUBLIC
cpp-deprecated-atomic
)
target_sources(core-client-server PRIVATE
+ ${CMAKE_SOURCE_DIR}/ydb/core/client/server/dynamic_node_auth_processor.cpp
${CMAKE_SOURCE_DIR}/ydb/core/client/server/http_ping.cpp
${CMAKE_SOURCE_DIR}/ydb/core/client/server/msgbus_blobstorage_config.cpp
${CMAKE_SOURCE_DIR}/ydb/core/client/server/msgbus_bsadm.cpp
diff --git a/ydb/core/client/server/dynamic_node_auth_processor.cpp b/ydb/core/client/server/dynamic_node_auth_processor.cpp
new file mode 100644
index 00000000000..af086cc8ede
--- /dev/null
+++ b/ydb/core/client/server/dynamic_node_auth_processor.cpp
@@ -0,0 +1,127 @@
+#include "dynamic_node_auth_processor.h"
+
+#include <contrib/libs/openssl/include/openssl/x509.h>
+#include <contrib/libs/openssl/include/openssl/pem.h>
+#include <contrib/libs/openssl/include/openssl/bio.h>
+#include <contrib/libs/openssl/include/openssl/objects.h>
+#include <contrib/libs/openssl/include/openssl/obj_mac.h>
+
+#include <util/generic/yexception.h>
+#include <util/generic/map.h>
+#include <util/generic/string.h>
+
+namespace NKikimr {
+
+X509CertificateReader::X509Ptr X509CertificateReader::ReadCertAsPEM(const TStringBuf& cert) {
+ auto bio = BIOPtr(BIO_new_mem_buf(cert.data(), cert.size()));
+ if (!bio) {
+ return {};
+ }
+
+ auto x509 = X509Ptr(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL));
+ if (!x509) {
+ return {};
+ }
+
+ return x509;
+}
+
+std::pair<TString, TString> X509CertificateReader::GetTermFromX509Name(X509_NAME* name, int nid) {
+ if (name == nullptr) {
+ return {};
+ }
+
+ const char* sn = OBJ_nid2sn(nid);
+ if (sn == nullptr) {
+ return {};
+ }
+
+ char cnbuf[1024];
+ int name_len = X509_NAME_get_text_by_NID(name, nid, cnbuf, sizeof(cnbuf));
+ if (name_len == 0) {
+ return {};
+ }
+
+ return std::make_pair(TString(sn, strlen(sn)), TString(cnbuf, name_len));
+}
+
+TVector<std::pair<TString, TString>> X509CertificateReader::ReadSubjectTerms(const X509Ptr& x509) {
+ X509_NAME* name = X509_get_subject_name(x509.get()); // return internal pointer
+
+ TVector<std::pair<TString, TString>> extractions = {
+ GetTermFromX509Name(name, NID_countryName),
+ GetTermFromX509Name(name, NID_stateOrProvinceName),
+ GetTermFromX509Name(name, NID_localityName),
+ GetTermFromX509Name(name, NID_organizationName),
+ GetTermFromX509Name(name, NID_organizationalUnitName),
+ GetTermFromX509Name(name, NID_commonName)
+ };
+
+ auto newEnd = std::remove(extractions.begin(), extractions.end(), std::pair<TString, TString>{});
+ extractions.erase(newEnd, extractions.end());
+
+ return extractions;
+}
+
+TDynamicNodeAuthorizationParams::TDistinguishedName& TDynamicNodeAuthorizationParams::TDistinguishedName::AddRelativeDistinguishedName(TRelativeDistinguishedName name) {
+ RelativeDistinguishedNames.push_back(std::move(name));
+ return *this;
+}
+
+TDynamicNodeAuthorizationParams::operator bool() const {
+ return bool(CertSubjectsDescriptions);
+}
+
+bool TDynamicNodeAuthorizationParams::IsSubjectDescriptionMatched(const TMap<TString, TString>& subjectDescription) const {
+ for (const auto& description: CertSubjectsDescriptions) {
+ bool isDescriptionMatched = false;
+ for (const auto& name: description.RelativeDistinguishedNames) {
+ isDescriptionMatched = false;
+ auto fieldIt = subjectDescription.find(name.Attribute);
+ if (fieldIt == subjectDescription.cend()) {
+ break;
+ }
+
+ const auto& attributeValue = fieldIt->second;
+ for (const auto& value: name.Values) {
+ if (value == attributeValue) {
+ isDescriptionMatched = true;
+ break;
+ }
+ }
+ for (const auto& suffix: name.Suffixes) {
+ if (attributeValue.EndsWith(suffix)) {
+ isDescriptionMatched = true;
+ break;
+ }
+ }
+ if (!isDescriptionMatched) {
+ break;
+ }
+ }
+
+ if (isDescriptionMatched) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TDynamicNodeAuthorizationParams::TRelativeDistinguishedName::TRelativeDistinguishedName(const TString& Attribute)
+ :Attribute(Attribute)
+{}
+
+TDynamicNodeAuthorizationParams::TRelativeDistinguishedName& TDynamicNodeAuthorizationParams::TRelativeDistinguishedName::AddValue(const TString& val)
+{
+ Values.push_back(val);
+ return *this;
+}
+
+TDynamicNodeAuthorizationParams::TRelativeDistinguishedName& TDynamicNodeAuthorizationParams::TRelativeDistinguishedName::AddSuffix(const TString& suffix)
+{
+ Suffixes.push_back(suffix);
+ return *this;
+}
+
+} //namespace NKikimr {
diff --git a/ydb/core/client/server/dynamic_node_auth_processor.h b/ydb/core/client/server/dynamic_node_auth_processor.h
new file mode 100644
index 00000000000..d1532fbd14d
--- /dev/null
+++ b/ydb/core/client/server/dynamic_node_auth_processor.h
@@ -0,0 +1,60 @@
+#pragma once
+#include <contrib/libs/openssl/include/openssl/x509.h>
+
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+
+namespace NKikimr {
+
+struct TDynamicNodeAuthorizationParams {
+ struct TRelativeDistinguishedName {
+ TString Attribute;
+ TVector<TString> Values;
+ TVector<TString> Suffixes;
+
+ TRelativeDistinguishedName(const TString& Attribute);
+ TRelativeDistinguishedName& AddValue(const TString& val);
+ TRelativeDistinguishedName& AddSuffix(const TString& suffix);
+ };
+
+ struct TDistinguishedName {
+ TVector<TRelativeDistinguishedName> RelativeDistinguishedNames;
+
+ TDistinguishedName& AddRelativeDistinguishedName(TRelativeDistinguishedName name);
+ };
+
+ operator bool () const;
+ bool IsSubjectDescriptionMatched(const TMap<TString, TString>& subjectDescription) const;
+ TDynamicNodeAuthorizationParams& AddCertSubjectDescription(const TDistinguishedName& description) {
+ CertSubjectsDescriptions.push_back(description);
+ return *this;
+ }
+
+ bool IsHostMatchAttributeCN(const TString&) const {
+ return true;
+ }
+
+ bool CanCheckNodeByAttributeCN = false;
+ TVector<TDistinguishedName> CertSubjectsDescriptions;
+};
+
+
+struct X509CertificateReader {
+ template <auto fn>
+ struct deleter_from_fn {
+ template <typename T>
+ constexpr void operator()(T* arg) const {
+ fn(arg);
+ }
+ };
+
+ using X509Ptr = std::unique_ptr<X509, deleter_from_fn<&::X509_free>>;
+ using BIOPtr = std::unique_ptr<BIO, deleter_from_fn<&::BIO_free>>;
+
+ static X509Ptr ReadCertAsPEM(const TStringBuf& cert);
+ static TVector<std::pair<TString, TString>> ReadSubjectTerms(const X509Ptr& x509);
+private:
+ static std::pair<TString, TString> GetTermFromX509Name(X509_NAME* name, int nid);
+};
+
+} //namespace NKikimr
diff --git a/ydb/core/client/server/grpc_server.cpp b/ydb/core/client/server/grpc_server.cpp
index 019ad3d1291..f4ed1c87007 100644
--- a/ydb/core/client/server/grpc_server.cpp
+++ b/ydb/core/client/server/grpc_server.cpp
@@ -269,6 +269,10 @@ public:
return GetPeerName();
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return TGrpcBaseAsyncContext::FindClientCert();
+ }
+
private:
void* GetGRpcTag() {
return static_cast<IQueueEvent*>(this);
@@ -507,7 +511,7 @@ void TGRpcService::SetupIncomingRequests() {
// dynamic node registration
ADD_REQUEST(RegisterNode, TNodeRegistrationRequest, TNodeRegistrationResponse, {
NMsgBusProxy::TBusMessageContext msg(ctx->BindBusContext(NMsgBusProxy::MTYPE_CLIENT_NODE_REGISTRATION_REQUEST));
- RegisterRequestActor(CreateMessageBusRegisterNode(msg));
+ RegisterRequestActor(CreateMessageBusRegisterNode(msg, DynamicNodeAuthorizationParams));
})
// CMS request
diff --git a/ydb/core/client/server/grpc_server.h b/ydb/core/client/server/grpc_server.h
index e668a67322f..e08ffdffb83 100644
--- a/ydb/core/client/server/grpc_server.h
+++ b/ydb/core/client/server/grpc_server.h
@@ -1,4 +1,5 @@
#pragma once
+#include "dynamic_node_auth_processor.h"
#include <ydb/core/protos/grpc.grpc.pb.h>
@@ -47,6 +48,8 @@ public:
//! Bind MessageBus context to the request.
virtual NMsgBusProxy::TBusMessageContext BindBusContext(int type) = 0;
+ virtual TVector<TStringBuf> FindClientCert() const = 0;
+
//! Returns peer address
virtual TString GetPeer() const = 0;
};
@@ -58,6 +61,10 @@ class TGRpcService
public:
TGRpcService();
+ void SetDynamicNodeAuthParams(const TDynamicNodeAuthorizationParams& dynamicNodeAuthorizationParams) {
+ DynamicNodeAuthorizationParams = dynamicNodeAuthorizationParams;
+ }
+
void InitService(grpc::ServerCompletionQueue* cq, NGrpc::TLoggerPtr logger) override;
void SetGlobalLimiterHandle(NGrpc::TGlobalLimiter* limiter) override;
@@ -93,6 +100,7 @@ private:
// In flight request management.
NGrpc::TGlobalLimiter* Limiter_ = nullptr;
+ TDynamicNodeAuthorizationParams DynamicNodeAuthorizationParams = {};
};
}
diff --git a/ydb/core/client/server/msgbus_server.cpp b/ydb/core/client/server/msgbus_server.cpp
index 0a415da70b0..2611241b5e3 100644
--- a/ydb/core/client/server/msgbus_server.cpp
+++ b/ydb/core/client/server/msgbus_server.cpp
@@ -15,6 +15,7 @@ public:
virtual NBus::TBusMessage* GetMessage() = 0;
virtual NBus::TBusMessage* ReleaseMessage() = 0;
virtual void SendReplyMove(NBus::TBusMessageAutoPtr response) = 0;
+ virtual TVector<TStringBuf> FindClientCert() const = 0;
virtual THolder<TMessageBusSessionIdentHolder::TImpl> CreateSessionIdentHolder() = 0;
};
@@ -57,6 +58,11 @@ public:
return GetMessage()->GetHeader()->Id;
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return {};
+ }
+
+
THolder<TMessageBusSessionIdentHolder::TImpl> CreateSessionIdentHolder() override;
};
@@ -191,6 +197,10 @@ public:
SendReply(response.Get());
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return RequestContext->FindClientCert();
+ };
+
THolder<TMessageBusSessionIdentHolder::TImpl> CreateSessionIdentHolder() override;
};
@@ -236,6 +246,8 @@ void TBusMessageContext::Swap(TBusMessageContext &msg) {
std::swap(Impl, msg.Impl);
}
+TVector<TStringBuf> TBusMessageContext::FindClientCert() const { return Impl->FindClientCert(); }
+
THolder<TMessageBusSessionIdentHolder::TImpl> TBusMessageContext::CreateSessionIdentHolder() {
Y_VERIFY(Impl);
return Impl->CreateSessionIdentHolder();
@@ -248,6 +260,8 @@ public:
virtual void SendReply(NBus::TBusMessage *resp) = 0;
virtual void SendReplyMove(NBus::TBusMessageAutoPtr resp) = 0;
virtual ui64 GetTotalTimeout() const = 0;
+ virtual TVector<TStringBuf> FindClientCert() const = 0;
+
};
class TMessageBusSessionIdentHolder::TImplMessageBus
@@ -287,6 +301,10 @@ public:
ui64 GetTotalTimeout() const override {
return Session->GetConfig()->TotalTimeout;
}
+
+ TVector<TStringBuf> FindClientCert() const override {
+ return {};
+ }
};
THolder<TMessageBusSessionIdentHolder::TImpl> TBusMessageContext::TImplMessageBus::CreateSessionIdentHolder() {
@@ -324,6 +342,10 @@ public:
auto context = std::move(Context);
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return Context->FindClientCert();
+ }
+
ui64 GetTotalTimeout() const override {
return 90000;
}
@@ -363,6 +385,10 @@ void TMessageBusSessionIdentHolder::SendReplyMove(NBus::TBusMessageAutoPtr resp)
Impl->SendReplyMove(resp);
}
+TVector<TStringBuf> TMessageBusSessionIdentHolder::FindClientCert() const {
+ return Impl->FindClientCert();
+}
+
void TBusMessageWatcher::NotifyForget() {
if (MessageWatcher) {
diff --git a/ydb/core/client/server/msgbus_server.h b/ydb/core/client/server/msgbus_server.h
index 85483132a79..7aa5402b766 100644
--- a/ydb/core/client/server/msgbus_server.h
+++ b/ydb/core/client/server/msgbus_server.h
@@ -1,4 +1,5 @@
#pragma once
+#include "dynamic_node_auth_processor.h"
#include <library/cpp/actors/core/actorsystem.h>
#include <library/cpp/actors/core/actor_bootstrapped.h>
#include <ydb/public/lib/base/defs.h>
@@ -59,6 +60,7 @@ public:
~TMessageBusSessionIdentHolder();
void SendReply(NBus::TBusMessage *resp);
void SendReplyMove(NBus::TBusMessageAutoPtr resp);
+ TVector<TStringBuf> FindClientCert() const;
template <typename U /* <: TBusMessage */>
void SendReplyAutoPtr(TAutoPtr<U>& resp) { SendReplyMove(resp); }
@@ -84,6 +86,7 @@ public:
NBus::TBusMessage* ReleaseMessage();
void SendReplyMove(NBus::TBusMessageAutoPtr response);
void Swap(TBusMessageContext& msg);
+ TVector<TStringBuf> FindClientCert() const;
private:
friend class TMessageBusSessionIdentHolder;
@@ -296,7 +299,7 @@ IActor* CreateMessageBusBlobStorageConfig(TBusMessageContext &msg);
IActor* CreateMessageBusDrainNode(TBusMessageContext &msg);
IActor* CreateMessageBusFillNode(TBusMessageContext &msg);
IActor* CreateMessageBusResolveNode(TBusMessageContext &msg);
-IActor* CreateMessageBusRegisterNode(TBusMessageContext &msg);
+IActor* CreateMessageBusRegisterNode(TBusMessageContext &msg, const TDynamicNodeAuthorizationParams& dynamicNodeAuthorizationParams);
IActor* CreateMessageBusCmsRequest(TBusMessageContext &msg);
IActor* CreateMessageBusSqsRequest(TBusMessageContext &msg);
IActor* CreateMessageBusWhoAmI(TBusMessageContext &msg);
diff --git a/ydb/core/client/server/msgbus_server_node_registration.cpp b/ydb/core/client/server/msgbus_server_node_registration.cpp
index 68dbe201619..3b57aafcb48 100644
--- a/ydb/core/client/server/msgbus_server_node_registration.cpp
+++ b/ydb/core/client/server/msgbus_server_node_registration.cpp
@@ -1,4 +1,5 @@
#include "msgbus_servicereq.h"
+#include "grpc_server.h"
#include <library/cpp/actors/core/actor_bootstrapped.h>
#include <library/cpp/actors/core/hfunc.h>
@@ -25,14 +26,19 @@ public:
return NKikimrServices::TActivity::MSGBUS_COMMON;
}
- TNodeRegistrationActor(NKikimrClient::TNodeRegistrationRequest &request, NMsgBusProxy::TBusMessageContext &msg)
+ TNodeRegistrationActor(NKikimrClient::TNodeRegistrationRequest &request, NMsgBusProxy::TBusMessageContext &msg, const NKikimr::TDynamicNodeAuthorizationParams& dynamicNodeAuthorizationParams)
: TMessageBusSessionIdentHolder(msg)
, Request(request)
+ , DynamicNodeAuthorizationParams(dynamicNodeAuthorizationParams)
{
}
void Bootstrap(const TActorContext &ctx)
{
+ if (!IsNodeAuthorized()) {
+ SendReplyAndDie(ctx);
+ }
+
auto dinfo = AppData(ctx)->DomainsInfo;
ui32 group;
@@ -62,6 +68,7 @@ public:
TAutoPtr<TEvNodeBroker::TEvRegistrationRequest> request
= new TEvNodeBroker::TEvRegistrationRequest;
+
request->Record.SetHost(Request.GetHost());
request->Record.SetPort(Request.GetPort());
request->Record.SetResolveHost(Request.GetResolveHost());
@@ -165,17 +172,49 @@ public:
}
private:
+ bool IsNodeAuthorized() {
+ auto* appdata = AppData();
+ if (appdata && appdata->FeatureFlags.GetEnableDynamicNodeAuthorization() && DynamicNodeAuthorizationParams) {
+ const auto& nodeAuthValues = FindClientCert();
+ if (nodeAuthValues.empty()) {
+ Response.MutableStatus()->SetCode(TStatus::UNAUTHORIZED);
+ Response.MutableStatus()->SetReason("Cannot authorize node. Node has not provided certificate");
+ return false;
+ }
+ const auto& pemCert = nodeAuthValues.front();
+ TMap<TString, TString> subjectDescription;
+ X509CertificateReader::X509Ptr x509cert = X509CertificateReader::ReadCertAsPEM(pemCert);
+ for(const auto& term: X509CertificateReader::ReadSubjectTerms(x509cert)) {
+ subjectDescription.insert(term);
+ }
+
+ if (!DynamicNodeAuthorizationParams.IsSubjectDescriptionMatched(subjectDescription)) {
+ Response.MutableStatus()->SetCode(TStatus::UNAUTHORIZED);
+ Response.MutableStatus()->SetReason("Cannot authorize node by certificate");
+ return false;
+ }
+ auto host = Request.GetHost();
+ if (!DynamicNodeAuthorizationParams.IsHostMatchAttributeCN(host)) {
+ Response.MutableStatus()->SetCode(TStatus::UNAUTHORIZED);
+ Response.MutableStatus()->SetReason("Cannot authorize node with host: " + host);
+ return false;
+ }
+ }
+ return true;
+ }
+
NKikimrClient::TNodeRegistrationRequest Request;
NKikimrClient::TNodeRegistrationResponse Response;
TActorId NodeBrokerPipe;
+ const TDynamicNodeAuthorizationParams DynamicNodeAuthorizationParams;
};
} // namespace
-IActor *CreateMessageBusRegisterNode(NMsgBusProxy::TBusMessageContext &msg) {
+IActor *CreateMessageBusRegisterNode(NMsgBusProxy::TBusMessageContext &msg, const NKikimr::TDynamicNodeAuthorizationParams& dynamicNodeAuthorizationParams) {
NKikimrClient::TNodeRegistrationRequest &record
= static_cast<TBusNodeRegistrationRequest*>(msg.GetMessage())->Record;
- return new TNodeRegistrationActor(record, msg);
+ return new TNodeRegistrationActor(record, msg, dynamicNodeAuthorizationParams);
}
} // namespace NMsgBusProxy
diff --git a/ydb/core/driver_lib/cli_base/cli_cmds_db.cpp b/ydb/core/driver_lib/cli_base/cli_cmds_db.cpp
index 2de76f26b75..1dd0c64b1bf 100644
--- a/ydb/core/driver_lib/cli_base/cli_cmds_db.cpp
+++ b/ydb/core/driver_lib/cli_base/cli_cmds_db.cpp
@@ -826,7 +826,7 @@ public:
ClientConfig.MaxMessageSize = p->MaxMessageSize;
ClientConfig.MaxInFlight = p->MaxInFlight;
ClientConfig.EnableSsl = p->EnableSsl;
- ClientConfig.SslCaCert = p->SslCaCert;
+ ClientConfig.SslCredentials.pem_root_certs = p->SslCredentials.pem_root_certs;
}
}
}
diff --git a/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp b/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp
index 946fb0ca504..e4b8a10b2f2 100644
--- a/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp
+++ b/ydb/core/driver_lib/cli_base/cli_cmds_root.cpp
@@ -121,7 +121,7 @@ public:
if (config.EnableSsl) {
auto *p = std::get_if<NGrpc::TGRpcClientConfig>(&CommandConfig.ClientConfig.GetRef());
p->EnableSsl = config.EnableSsl;
- p->SslCaCert = config.CaCerts;
+ p->SslCredentials.pem_root_certs = config.CaCerts;
}
}
diff --git a/ydb/core/driver_lib/cli_base/cli_grpc.h b/ydb/core/driver_lib/cli_base/cli_grpc.h
index 61d09c9f70e..574ac731ea1 100644
--- a/ydb/core/driver_lib/cli_base/cli_grpc.h
+++ b/ydb/core/driver_lib/cli_base/cli_grpc.h
@@ -95,7 +95,7 @@ public:
ClientConfig.MaxMessageSize = p->MaxMessageSize;
ClientConfig.MaxInFlight = p->MaxInFlight;
ClientConfig.EnableSsl = p->EnableSsl;
- ClientConfig.SslCaCert = p->SslCaCert;
+ ClientConfig.SslCredentials.pem_root_certs = p->SslCredentials.pem_root_certs;
}
}
}
diff --git a/ydb/core/driver_lib/cli_utils/cli_cmds_root.cpp b/ydb/core/driver_lib/cli_utils/cli_cmds_root.cpp
index 802557cc942..92ebf7ab8c6 100644
--- a/ydb/core/driver_lib/cli_utils/cli_cmds_root.cpp
+++ b/ydb/core/driver_lib/cli_utils/cli_cmds_root.cpp
@@ -62,7 +62,7 @@ public:
if (config.EnableSsl) {
auto *p = std::get_if<NGrpc::TGRpcClientConfig>(&CommandConfig.ClientConfig.GetRef());
p->EnableSsl = config.EnableSsl;
- p->SslCaCert = config.CaCerts;
+ p->SslCredentials.pem_root_certs = config.CaCerts;
}
break;
case TCommandConfig::EServerType::MessageBus:
diff --git a/ydb/core/driver_lib/cli_utils/cli_cmds_server.cpp b/ydb/core/driver_lib/cli_utils/cli_cmds_server.cpp
index 8e24edef2ec..34c1e505449 100644
--- a/ydb/core/driver_lib/cli_utils/cli_cmds_server.cpp
+++ b/ydb/core/driver_lib/cli_utils/cli_cmds_server.cpp
@@ -854,8 +854,9 @@ protected:
{
// static node
if (NodeBrokerAddresses.empty() && !NodeBrokerPort) {
- if (!NodeId)
+ if (!NodeId) {
ythrow yexception() << "Either --node [NUM|'static'] or --node-broker[-port] should be specified";
+ }
if (!HierarchicalCfg && RunConfig.PathToConfigCacheFile)
LoadCachedConfigsForStaticNode();
@@ -1113,8 +1114,13 @@ private:
grpcConfig.LoadBalancingPolicy = "round_robin";
if (endpoint.EnableSsl.Defined()) {
grpcConfig.EnableSsl = endpoint.EnableSsl.GetRef();
- if (!PathToInterconnectCaFile.Empty()) {
- grpcConfig.SslCaCert = ReadFromFile(PathToInterconnectCaFile, "CA certificates");
+ auto& sslCredentials = grpcConfig.SslCredentials;
+ if (PathToGrpcCaFile) {
+ sslCredentials.pem_root_certs = ReadFromFile(PathToGrpcCaFile, "CA certificates");
+ }
+ if (PathToGrpcCertFile && PathToGrpcPrivateKeyFile) {
+ sslCredentials.pem_cert_chain = ReadFromFile(PathToGrpcCertFile, "Client certificates");
+ sslCredentials.pem_private_key = ReadFromFile(PathToGrpcPrivateKeyFile, "Client certificates key");
}
}
return NClient::TKikimr(grpcConfig);
diff --git a/ydb/core/driver_lib/cli_utils/cli_cmds_tenant.cpp b/ydb/core/driver_lib/cli_utils/cli_cmds_tenant.cpp
index ff3738a48c7..8a7ce8272d5 100644
--- a/ydb/core/driver_lib/cli_utils/cli_cmds_tenant.cpp
+++ b/ydb/core/driver_lib/cli_utils/cli_cmds_tenant.cpp
@@ -142,7 +142,7 @@ public:
ClientConfig.MaxMessageSize = p->MaxMessageSize;
ClientConfig.MaxInFlight = p->MaxInFlight;
ClientConfig.EnableSsl = p->EnableSsl;
- ClientConfig.SslCaCert = p->SslCaCert;
+ ClientConfig.SslCredentials.pem_root_certs = p->SslCredentials.pem_root_certs;
}
}
}
diff --git a/ydb/core/driver_lib/run/CMakeLists.txt b/ydb/core/driver_lib/run/CMakeLists.txt
index ecc840965dd..0680f3a50c1 100644
--- a/ydb/core/driver_lib/run/CMakeLists.txt
+++ b/ydb/core/driver_lib/run/CMakeLists.txt
@@ -57,6 +57,7 @@ target_link_libraries(run PUBLIC
cli_utils
ydb-core-formats
ydb-core-grpc_services
+ core-grpc_services-base
ydb-core-health_check
ydb-core-http_proxy
core-kesus-proxy
@@ -145,4 +146,5 @@ target_sources(run PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/driver_lib/run/run.cpp
${CMAKE_SOURCE_DIR}/ydb/core/driver_lib/run/service_initializer.cpp
${CMAKE_SOURCE_DIR}/ydb/core/driver_lib/run/version.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/driver_lib/run/cert_auth_props.cpp
)
diff --git a/ydb/core/driver_lib/run/cert_auth_props.cpp b/ydb/core/driver_lib/run/cert_auth_props.cpp
new file mode 100644
index 00000000000..d01c3140819
--- /dev/null
+++ b/ydb/core/driver_lib/run/cert_auth_props.cpp
@@ -0,0 +1,28 @@
+#include "cert_auth_props.h"
+
+namespace NKikimr {
+
+TDynamicNodeAuthorizationParams GetDynamicNodeAuthorizationParams(const NKikimrConfig::TClientCertificateAuthorization &clientSertificateAuth) {
+ TDynamicNodeAuthorizationParams certAuthConf;
+ if (!clientSertificateAuth.HasDynamicNodeAuthorization()) {
+ return certAuthConf;
+ }
+
+ const auto& dynNodeAuth = clientSertificateAuth.GetDynamicNodeAuthorization();
+ TDynamicNodeAuthorizationParams::TDistinguishedName distinguishedName;
+ for (const auto& term: dynNodeAuth.GetSubjectTerms()) {
+ auto name = TDynamicNodeAuthorizationParams::TRelativeDistinguishedName(term.GetShortName());
+ for (const auto& value: term.GetValues()) {
+ name.AddValue(value);
+ }
+ for (const auto& suffix: term.GetSuffixes()) {
+ name.AddSuffix(suffix);
+ }
+ distinguishedName.AddRelativeDistinguishedName(std::move(name));
+ }
+ certAuthConf.AddCertSubjectDescription(distinguishedName);
+ certAuthConf.CanCheckNodeByAttributeCN = dynNodeAuth.GetCanCheckNodeHostByCN();
+ return certAuthConf;
+}
+
+} //namespace NKikimr
diff --git a/ydb/core/driver_lib/run/cert_auth_props.h b/ydb/core/driver_lib/run/cert_auth_props.h
new file mode 100644
index 00000000000..9415c229a25
--- /dev/null
+++ b/ydb/core/driver_lib/run/cert_auth_props.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <ydb/core/client/server/dynamic_node_auth_processor.h>
+#include <ydb/core/protos/config.pb.h>
+#include <util/generic/string.h>
+
+namespace NKikimr {
+
+TDynamicNodeAuthorizationParams GetDynamicNodeAuthorizationParams(const NKikimrConfig::TClientCertificateAuthorization& clientSertificateAuth);
+
+} //namespace NKikimr
diff --git a/ydb/core/driver_lib/run/run.cpp b/ydb/core/driver_lib/run/run.cpp
index dd498a22d74..b8c385f7c50 100644
--- a/ydb/core/driver_lib/run/run.cpp
+++ b/ydb/core/driver_lib/run/run.cpp
@@ -1,5 +1,6 @@
#include "run.h"
#include "dummy.h"
+#include "cert_auth_props.h"
#include "service_initializer.h"
#include "kikimr_services_initializers.h"
@@ -668,6 +669,9 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) {
if (hasLegacy) {
// start legacy service
auto grpcService = new NGRpcProxy::TGRpcService();
+ if (!opts.SslData.Empty()) {
+ grpcService->SetDynamicNodeAuthParams(GetDynamicNodeAuthorizationParams(appConfig.GetClientCertificateAuthorization()));
+ }
auto future = grpcService->Prepare(ActorSystem.Get(), NMsgBusProxy::CreatePersQueueMetaCacheV2Id(), NMsgBusProxy::CreateMsgBusProxyId(), Counters);
auto startCb = [grpcService](NThreading::TFuture<void> result) {
if (result.HasException()) {
@@ -866,6 +870,7 @@ void TKikimrRunner::InitializeGRpc(const TKikimrRunConfig& runConfig) {
sslData.Root = ReadFile(pathToCaFile);
sslData.Cert = ReadFile(pathToCertificateFile);
sslData.Key = ReadFile(pathToPrivateKeyFile);
+ sslData.DoRequestClientCertificate = appConfig.GetFeatureFlags().GetEnableDynamicNodeAuthorization() && appConfig.GetClientCertificateAuthorization().HasDynamicNodeAuthorization();
sslOpts.SetSslData(sslData);
GRpcServers.push_back({ "grpcs", new NGrpc::TGRpcServer(sslOpts) });
diff --git a/ydb/core/grpc_services/base/base.h b/ydb/core/grpc_services/base/base.h
index e76529d07be..ab69d7beb16 100644
--- a/ydb/core/grpc_services/base/base.h
+++ b/ydb/core/grpc_services/base/base.h
@@ -268,6 +268,8 @@ public:
virtual TInstant GetDeadline() const = 0;
// Meta value from request
virtual const TMaybe<TString> GetPeerMetaValues(const TString&) const = 0;
+ // Auth property from connection
+ virtual TVector<TStringBuf> FindClientCert() const = 0;
// Returns path and resource for rate limiter
virtual TMaybe<NRpcService::TRlPath> GetRlPath() const = 0;
// Raise issue on the context
@@ -509,6 +511,11 @@ public:
return TMaybe<TString>{};
}
+ TVector<TStringBuf> FindClientCert() const override {
+ Y_FAIL("Unimplemented");
+ return {};
+ }
+
void SetDiskQuotaExceeded(bool) override {
}
@@ -774,6 +781,11 @@ public:
return ToMaybe(Ctx_->GetPeerMetaValues(key));
}
+ TVector<TStringBuf> FindClientCert() const override {
+ Y_FAIL("Unimplemented");
+ return {};
+ }
+
void SetDiskQuotaExceeded(bool) override {
}
@@ -966,6 +978,10 @@ public:
return ToMaybe(Ctx_->GetPeerMetaValues(key));
}
+ TVector<TStringBuf> FindClientCert() const override {
+ return Ctx_->FindClientCert();
+ }
+
void SetDiskQuotaExceeded(bool disk) override {
if (!QuotaExceeded) {
QuotaExceeded = google::protobuf::Arena::CreateMessage<Ydb::QuotaExceeded>(GetArena());
diff --git a/ydb/core/grpc_services/local_rpc/local_rpc.h b/ydb/core/grpc_services/local_rpc/local_rpc.h
index b70b9b420ca..e6a87677c6f 100644
--- a/ydb/core/grpc_services/local_rpc/local_rpc.h
+++ b/ydb/core/grpc_services/local_rpc/local_rpc.h
@@ -56,6 +56,11 @@ public:
return TMaybe<TString>{};
}
+ TVector<TStringBuf> FindClientCert() const override {
+ Y_FAIL("Unimplemented");
+ return {};
+ }
+
void ReplyWithYdbStatus(Ydb::StatusIds::StatusCode status) override {
TResp resp;
NGRpcService::TCommonResponseFiller<TResp, true>::Fill(resp, IssueManager.GetIssues(), CostInfo.get(), status);
diff --git a/ydb/core/health_check/health_check.cpp b/ydb/core/health_check/health_check.cpp
index 78a11347d1c..3cb47e4fc9e 100644
--- a/ydb/core/health_check/health_check.cpp
+++ b/ydb/core/health_check/health_check.cpp
@@ -333,7 +333,7 @@ public:
void SetOverallStatus(Ydb::Monitoring::StatusFlag::Status status) {
OverallStatus = status;
}
-
+
void InheritFrom(TSelfCheckResult& lower) {
if (lower.GetOverallStatus() >= OverallStatus) {
OverallStatus = lower.GetOverallStatus();
@@ -559,7 +559,7 @@ public:
storagePoolName = STATIC_STORAGE_POOL_NAME;
}
StoragePoolState[storagePoolName].Groups.emplace(group.groupid());
-
+
if (!IsSpecificDatabaseFilter()) {
DatabaseState[DomainPath].StoragePoolNames.emplace_back(storagePoolName);
}
@@ -1665,14 +1665,14 @@ public:
struct TMergeIssuesContext {
std::unordered_map<ETags, TList<TSelfCheckContext::TIssueRecord>> recordsMap;
std::unordered_set<TString> removeIssuesIds;
-
+
TMergeIssuesContext(TList<TSelfCheckContext::TIssueRecord>& records) {
for (auto it = records.begin(); it != records.end(); ) {
auto move = it++;
recordsMap[move->Tag].splice(recordsMap[move->Tag].end(), records, move);
}
}
-
+
void RemoveUnlinkIssues(TList<TSelfCheckContext::TIssueRecord>& records) {
bool isRemovingIssuesIteration = true;
while (isRemovingIssuesIteration) {
@@ -1780,7 +1780,7 @@ public:
++it;
}
}
-
+
if (similar.size() <= MERGING_IGNORE_SIZE) {
Mergeed.splice(Mergeed.end(), similar);
}
@@ -1846,7 +1846,7 @@ public:
default:
break;
}
-
+
auto donorReasons = it->IssueLog.mutable_reason();
for (auto donorReasonIt = donorReasons->begin(); donorReasonIt != donorReasons->end(); donorReasonIt++) {
if (!mainReasonIds.contains(*donorReasonIt)) {
@@ -1859,7 +1859,7 @@ public:
it = similar.erase(it);
}
- similar.begin()->IssueLog.set_count(ids.size());
+ similar.begin()->IssueLog.set_count(ids.size());
similar.begin()->IssueLog.set_listed(ids.size());
}
@@ -2147,7 +2147,7 @@ public:
Ydb::Monitoring::StatusFlag::Status Status = Ydb::Monitoring::StatusFlag::GREY;
bool HasDegraded = false;
std::unordered_set<std::pair<TString, TString>> IssueIds;
-
+
TOverallStateContext(Ydb::Monitoring::SelfCheckResult* result) {
Result = result;
}
diff --git a/ydb/core/http_proxy/discovery_actor.cpp b/ydb/core/http_proxy/discovery_actor.cpp
index 674ed7af794..59014f28779 100644
--- a/ydb/core/http_proxy/discovery_actor.cpp
+++ b/ydb/core/http_proxy/discovery_actor.cpp
@@ -28,7 +28,7 @@ namespace NKikimr::NHttpProxy {
grpcConf.Locator = Settings.DiscoveryEndpoint;
if (Settings.CaCert) {
grpcConf.EnableSsl = true;
- grpcConf.SslCaCert = *Settings.CaCert;
+ grpcConf.SslCredentials.pem_root_certs = *Settings.CaCert;
}
Connection = GrpcClient.CreateGRpcServiceConnection<TProtoService>(grpcConf);
}
diff --git a/ydb/core/persqueue/actor_persqueue_client_iface.h b/ydb/core/persqueue/actor_persqueue_client_iface.h
index 76c1a8545ac..3f6edbe357c 100644
--- a/ydb/core/persqueue/actor_persqueue_client_iface.h
+++ b/ydb/core/persqueue/actor_persqueue_client_iface.h
@@ -96,7 +96,7 @@ public:
.DiscoveryEndpoint(TStringBuilder() << config.GetEndpoint() << ":" << config.GetEndpointPort())
.DiscoveryMode(NYdb::EDiscoveryMode::Async)
.CredentialsProviderFactory(credentialsProviderFactory)
- .EnableSsl(config.GetUseSecureConnection());
+ .SslCredentials(NYdb::TSslCredentials(config.GetUseSecureConnection()));
if (config.HasDatabase()) {
clientSettings.Database(config.GetDatabase());
}
diff --git a/ydb/core/protos/config.proto b/ydb/core/protos/config.proto
index f77e99ed4c6..60e7fe2487d 100644
--- a/ydb/core/protos/config.proto
+++ b/ydb/core/protos/config.proto
@@ -746,6 +746,7 @@ message TFeatureFlags {
optional bool EnableBorrowedSplitCompaction = 76 [default = true];
optional bool EnableChangefeedInitialScan = 77 [default = false];
optional bool EnableKqpScanQuerySourceRead = 78 [default = false];
+ optional bool EnableDynamicNodeAuthorization = 79 [default = false];
}
@@ -1617,6 +1618,21 @@ message TConfigVersion {
repeated TConfigItemVersion Items = 1;
}
+message TClientCertificateAuthorization {
+ message TSubjectTerm {
+ optional string ShortName = 1;
+ repeated string Values = 2;
+ repeated string Suffixes = 3;
+ }
+
+ message TDynamicNodeDefinition {
+ repeated TSubjectTerm SubjectTerms = 1;
+ optional bool CanCheckNodeHostByCN = 2 [default = false];
+ }
+
+ optional TDynamicNodeDefinition DynamicNodeAuthorization = 1;
+}
+
message TAppConfig {
optional TActorSystemConfig ActorSystemConfig = 1;
optional TLogConfig LogConfig = 2;
@@ -1674,6 +1690,7 @@ message TAppConfig {
optional TMetadataProviderConfig MetadataProviderConfig = 59;
optional TBackgroundTasksConfig BackgroundTasksConfig = 60;
optional TAuditConfig AuditConfig = 61;
+ optional TClientCertificateAuthorization ClientCertificateAuthorization = 62;
optional NYq.NConfig.TConfig YandexQueryConfig = 50; // TODO: remove after migration to FederatedQueryConfig
diff --git a/ydb/core/protos/console_config.proto b/ydb/core/protos/console_config.proto
index ac7ecbf9ae1..da590e23a51 100644
--- a/ydb/core/protos/console_config.proto
+++ b/ydb/core/protos/console_config.proto
@@ -114,6 +114,7 @@ message TConfigItem {
CompactionConfigItem = 52;
HttpProxyConfigItem = 53;
SchemeShardConfigItem = 54;
+ ClientCertificateAuthorizationConfigItem = 55;
NamedConfigsItem = 100;
ClusterYamlConfigItem = 101;
diff --git a/ydb/core/protos/node_broker.proto b/ydb/core/protos/node_broker.proto
index ee0908902c6..84b418c4b09 100644
--- a/ydb/core/protos/node_broker.proto
+++ b/ydb/core/protos/node_broker.proto
@@ -48,6 +48,7 @@ message TStatus {
ERROR = 2;
ERROR_TEMP = 3;
WRONG_REQUEST = 4;
+ UNAUTHORIZED = 5;
}
optional ECode Code = 1;
diff --git a/ydb/core/public_http/grpc_request_context_wrapper.h b/ydb/core/public_http/grpc_request_context_wrapper.h
index 25605e2c20c..9dc718e633a 100644
--- a/ydb/core/public_http/grpc_request_context_wrapper.h
+++ b/ydb/core/public_http/grpc_request_context_wrapper.h
@@ -34,6 +34,7 @@ public:
virtual TInstant Deadline() const;
virtual TSet<TStringBuf> GetPeerMetaKeys() const;
virtual TVector<TStringBuf> GetPeerMetaValues(TStringBuf key) const;
+ virtual TVector<TStringBuf> FindClientCert() const {return {};}
virtual grpc_compression_level GetCompressionLevel() const { return GRPC_COMPRESS_LEVEL_NONE; }
virtual google::protobuf::Arena* GetArena();
diff --git a/ydb/core/testlib/CMakeLists.txt b/ydb/core/testlib/CMakeLists.txt
index 636e2c0d694..ca2ac9ef8d2 100644
--- a/ydb/core/testlib/CMakeLists.txt
+++ b/ydb/core/testlib/CMakeLists.txt
@@ -26,6 +26,7 @@ target_link_libraries(ydb-core-testlib PUBLIC
cpp-regex-pcre
cpp-testing-gmock_in_unittest
cpp-testing-unittest
+ run
ydb-core-base
core-blobstorage-base
core-blobstorage-pdisk
diff --git a/ydb/core/testlib/test_client.cpp b/ydb/core/testlib/test_client.cpp
index d7a2136c2a6..6b4c2c68241 100644
--- a/ydb/core/testlib/test_client.cpp
+++ b/ydb/core/testlib/test_client.cpp
@@ -71,12 +71,14 @@
#include <ydb/core/mind/tenant_pool.h>
#include <ydb/core/mind/tenant_slot_broker.h>
#include <ydb/core/mind/tenant_node_enumeration.h>
+#include <ydb/core/mind/node_broker.h>
#include <ydb/core/kesus/tablet/events.h>
#include <ydb/core/sys_view/service/sysview_service.h>
#include <ydb/library/yql/minikql/mkql_function_registry.h>
#include <ydb/library/yql/minikql/invoke_builtins/mkql_builtins.h>
#include <ydb/library/yql/public/issue/yql_issue_message.h>
#include <ydb/core/engine/mkql_engine_flat.h>
+#include <ydb/core/driver_lib/run/cert_auth_props.h>
#include <library/cpp/testing/unittest/registar.h>
#include <ydb/core/kesus/proxy/proxy.h>
@@ -228,6 +230,11 @@ namespace Tests {
Runtime->GetAppData(nodeIdx).DataStreamsAuthFactory = Settings->DataStreamsAuthFactory.get();
Runtime->GetAppData(nodeIdx).PersQueueMirrorReaderFactory = Settings->PersQueueMirrorReaderFactory.get();
+ Runtime->GetAppData(nodeIdx).DynamicNameserviceConfig = new TDynamicNameserviceConfig;
+ auto dnConfig = Runtime->GetAppData(nodeIdx).DynamicNameserviceConfig;
+ dnConfig->MaxStaticNodeId = 1023;
+ dnConfig->MaxDynamicNodeId = 1024 + 100;
+
SetupConfigurators(nodeIdx);
SetupProxies(nodeIdx);
}
@@ -291,6 +298,10 @@ namespace Tests {
system->Register(NGRpcService::CreateGrpcEndpointPublishActor(desc.Get()), TMailboxType::ReadAsFilled, appData.UserPoolId);
}
+ if (!options.SslData.Empty()) {
+ grpcService->SetDynamicNodeAuthParams(NKikimr::GetDynamicNodeAuthorizationParams(Settings->AppConfig.GetClientCertificateAuthorization()));
+ }
+
auto future = grpcService->Prepare(
system,
NMsgBusProxy::CreatePersQueueMetaCacheV2Id(),
@@ -428,8 +439,10 @@ namespace Tests {
CreateTestBootstrapper(*Runtime, CreateTestTabletInfo(ChangeStateStorage(Hive, domainId), TTabletTypes::Hive), &CreateDefaultHive);
CreateTestBootstrapper(*Runtime, CreateTestTabletInfo(MakeBSControllerID(domainId), TTabletTypes::BSController), &CreateFlatBsController);
CreateTestBootstrapper(*Runtime, CreateTestTabletInfo(MakeTenantSlotBrokerID(domainId), TTabletTypes::TenantSlotBroker), &NTenantSlotBroker::CreateTenantSlotBroker);
- if (Settings->EnableConsole)
+ if (Settings->EnableConsole) {
CreateTestBootstrapper(*Runtime, CreateTestTabletInfo(MakeConsoleID(domainId), TTabletTypes::Console), &NConsole::CreateConsole);
+ }
+ CreateTestBootstrapper(*Runtime, CreateTestTabletInfo(MakeNodeBrokerID(domainId), TTabletTypes::NodeBroker), &NNodeBroker::CreateNodeBroker);
}
void TServer::SetupStorage() {
diff --git a/ydb/core/testlib/test_client.h b/ydb/core/testlib/test_client.h
index 649cb5d0f7a..94996587249 100644
--- a/ydb/core/testlib/test_client.h
+++ b/ydb/core/testlib/test_client.h
@@ -115,6 +115,7 @@ namespace Tests {
TStoragePoolKinds StoragePoolTypes;
TVector<NKikimrKqp::TKqpSetting> KqpSettings;
bool EnableConsole = true;
+ bool EnableNodeBroker = false;
bool EnableConfigsDispatcher = true;
bool UseRealThreads = true;
bool EnableKqpSpilling = false;
@@ -153,6 +154,7 @@ namespace Tests {
TServerSettings& AddStoragePool(const TString& poolKind, const TString& poolName = {}, ui32 numGroups = 1, ui32 encryptionMode = 0);
TServerSettings& SetKqpSettings(const TVector<NKikimrKqp::TKqpSetting>& settings) { KqpSettings = settings; return *this; }
TServerSettings& SetEnableConsole(bool value) { EnableConsole = value; return *this; }
+ TServerSettings& SetEnableNodeBroker(bool value) { EnableNodeBroker = value; return *this; }
TServerSettings& SetEnableConfigsDispatcher(bool value) { EnableConfigsDispatcher = value; return *this; }
TServerSettings& SetUseRealThreads(bool value) { UseRealThreads = value; return *this; }
TServerSettings& SetAppConfig(const NKikimrConfig::TAppConfig value) { AppConfig = value; return *this; }
diff --git a/ydb/core/yq/libs/health/health.cpp b/ydb/core/yq/libs/health/health.cpp
index aa8b2dca60b..ab8f637c67f 100644
--- a/ydb/core/yq/libs/health/health.cpp
+++ b/ydb/core/yq/libs/health/health.cpp
@@ -25,7 +25,7 @@ public:
, Client(yqSharedResources->CoreYdbDriver,
NYdb::TCommonClientSettings()
.DiscoveryEndpoint("localhost:" + ToString(Config.GetPort()))
- .EnableSsl(Config.GetSecure())
+ .SslCredentials(NYdb::TSslCredentials(Config.GetSecure()))
.Database(Config.GetDatabase()))
, YqSharedResources(yqSharedResources)
{
diff --git a/ydb/core/yq/libs/private_client/internal_service.cpp b/ydb/core/yq/libs/private_client/internal_service.cpp
index ce18110764e..23b8d313903 100644
--- a/ydb/core/yq/libs/private_client/internal_service.cpp
+++ b/ydb/core/yq/libs/private_client/internal_service.cpp
@@ -37,7 +37,7 @@ public:
NYdb::TCommonClientSettings()
.DiscoveryEndpoint(privateApiConfig.GetTaskServiceEndpoint())
.CredentialsProviderFactory(credentialsProviderFactory({.SaKeyFile = privateApiConfig.GetSaKeyFile(), .IamEndpoint = privateApiConfig.GetIamEndpoint()}))
- .EnableSsl(privateApiConfig.GetSecureTaskService())
+ .SslCredentials(NYdb::TSslCredentials(privateApiConfig.GetSecureTaskService()))
.Database(privateApiConfig.GetTaskServiceDatabase() ? privateApiConfig.GetTaskServiceDatabase() : TMaybe<TString>()),
counters)
{
diff --git a/ydb/core/yq/libs/read_rule/read_rule_creator.cpp b/ydb/core/yq/libs/read_rule/read_rule_creator.cpp
index 0ebdbc4f70b..1ee5fa00774 100644
--- a/ydb/core/yq/libs/read_rule/read_rule_creator.cpp
+++ b/ydb/core/yq/libs/read_rule/read_rule_creator.cpp
@@ -188,7 +188,7 @@ private:
.DiscoveryEndpoint(Topic.GetEndpoint())
.CredentialsProviderFactory(std::move(credentialsProvider))
.DiscoveryMode(NYdb::EDiscoveryMode::Async)
- .EnableSsl(Topic.GetUseSsl());
+ .SslCredentials(NYdb::TSslCredentials(Topic.GetUseSsl()));
}
private:
diff --git a/ydb/core/yq/libs/read_rule/read_rule_deleter.cpp b/ydb/core/yq/libs/read_rule/read_rule_deleter.cpp
index 32927270d3f..3db6600584a 100644
--- a/ydb/core/yq/libs/read_rule/read_rule_deleter.cpp
+++ b/ydb/core/yq/libs/read_rule/read_rule_deleter.cpp
@@ -162,7 +162,7 @@ private:
.DiscoveryEndpoint(Topic.cluster_endpoint())
.CredentialsProviderFactory(std::move(credentialsProvider))
.DiscoveryMode(NYdb::EDiscoveryMode::Async)
- .EnableSsl(Topic.use_ssl());
+ .SslCredentials(NYdb::TSslCredentials(Topic.use_ssl()));
}
private:
diff --git a/ydb/core/yq/libs/shared_resources/db_pool.cpp b/ydb/core/yq/libs/shared_resources/db_pool.cpp
index 9af52e67e19..8204117bd26 100644
--- a/ydb/core/yq/libs/shared_resources/db_pool.cpp
+++ b/ydb/core/yq/libs/shared_resources/db_pool.cpp
@@ -319,7 +319,7 @@ TDbPool::TPtr TDbPoolMap::GetOrCreate(EDbPoolId dbPoolId, ui32 sessionsCount, co
clientSettings.CredentialsProviderFactory(CredentialsProviderFactory(credSettings));
- clientSettings.EnableSsl(Config.GetStorage().GetUseSsl());
+ clientSettings.SslCredentials(NYdb::TSslCredentials(Config.GetStorage().GetUseSsl()));
TableClient = MakeHolder<NYdb::NTable::TTableClient>(Driver, clientSettings);
}
diff --git a/ydb/core/yq/libs/ydb/ydb.cpp b/ydb/core/yq/libs/ydb/ydb.cpp
index 3403d825e88..c70e1089bda 100644
--- a/ydb/core/yq/libs/ydb/ydb.cpp
+++ b/ydb/core/yq/libs/ydb/ydb.cpp
@@ -198,14 +198,12 @@ TSettings GetClientSettings(const NConfig::TYdbStorageConfig& config,
settings.CredentialsProviderFactory(credProviderFactory(credSettings));
if (config.GetUseLocalMetadataService()) {
- settings.EnableSsl(true);
+ settings.SslCredentials(TSslCredentials(true));
}
if (config.GetCertificateFile()) {
auto cert = StripString(TFileInput(config.GetCertificateFile()).ReadAll());
- settings
- .EnableSsl(true)
- .CaCert(cert);
+ settings.SslCredentials(TSslCredentials(true, cert));
}
return settings;
diff --git a/ydb/library/ycloud/impl/grpc_service_client.h b/ydb/library/ycloud/impl/grpc_service_client.h
index c89515d8654..d2837a69264 100644
--- a/ydb/library/ycloud/impl/grpc_service_client.h
+++ b/ydb/library/ycloud/impl/grpc_service_client.h
@@ -74,7 +74,7 @@ public:
const auto& requestId = ev->Get()->RequestId;
if (!Connection) {
BLOG_GRPC_D(Prefix(requestId) << "Connect to "
- << ((Config.EnableSsl || !Config.SslCaCert.empty()) ? "grpcs://" : "grpc://")
+ << ((Config.EnableSsl || !Config.SslCredentials.pem_root_certs.empty()) ? "grpcs://" : "grpc://")
<< Config.Locator);
Connection = Client.CreateGRpcServiceConnection<TGrpcService>(Config);
}
diff --git a/ydb/library/yql/providers/common/token_accessor/client/factory.cpp b/ydb/library/yql/providers/common/token_accessor/client/factory.cpp
index 0a7e9b6af4e..1993ab2e92c 100644
--- a/ydb/library/yql/providers/common/token_accessor/client/factory.cpp
+++ b/ydb/library/yql/providers/common/token_accessor/client/factory.cpp
@@ -27,7 +27,7 @@ public:
{
GrpcClientConfig.Locator = tokenAccessorEndpoint;
GrpcClientConfig.EnableSsl = useSsl;
- GrpcClientConfig.SslCaCert = sslCaCert;
+ GrpcClientConfig.SslCredentials.pem_root_certs = sslCaCert;
Connections.reserve(connectionPoolSize);
for (ui32 i = 0; i < connectionPoolSize; ++i) {
Connections.push_back(Client->CreateGRpcServiceConnection<TokenAccessorService>(GrpcClientConfig));
diff --git a/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client.cpp b/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client.cpp
index b11c1d0f47b..f29acf6fa34 100644
--- a/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client.cpp
+++ b/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client.cpp
@@ -182,7 +182,7 @@ std::shared_ptr<NYdb::ICredentialsProvider> CreateTokenAccessorCredentialsProvid
NGrpc::TGRpcClientConfig grpcConf;
grpcConf.Locator = tokenAccessorEndpoint;
grpcConf.EnableSsl = useSsl;
- grpcConf.SslCaCert = sslCaCert;
+ grpcConf.SslCredentials.pem_root_certs = sslCaCert;
std::shared_ptr<NGrpc::TServiceConnection<TokenAccessorService>> connection = client->CreateGRpcServiceConnection<TokenAccessorService>(grpcConf);
return CreateTokenAccessorCredentialsProvider(std::move(client), std::move(connection), serviceAccountId, serviceAccountIdSignature, refreshPeriod, requestTimeout);
diff --git a/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client_factory.cpp b/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client_factory.cpp
index da77d08ff66..d44cc248994 100644
--- a/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client_factory.cpp
+++ b/ydb/library/yql/providers/common/token_accessor/client/token_accessor_client_factory.cpp
@@ -55,7 +55,7 @@ std::shared_ptr<NYdb::ICredentialsProviderFactory> CreateTokenAccessorCredential
NGrpc::TGRpcClientConfig grpcConf;
grpcConf.Locator = tokenAccessorEndpoint;
grpcConf.EnableSsl = useSsl;
- grpcConf.SslCaCert = sslCaCert;
+ grpcConf.SslCredentials.pem_root_certs = sslCaCert;
std::shared_ptr<NGrpc::TServiceConnection<TokenAccessorService>> connection = client->CreateGRpcServiceConnection<TokenAccessorService>(grpcConf);
return CreateTokenAccessorCredentialsProviderFactory(std::move(client), std::move(connection), serviceAccountId, serviceAccountIdSignature, refreshPeriod, requestTimeout);
@@ -70,7 +70,7 @@ std::shared_ptr<NYdb::ICredentialsProviderFactory> CreateTokenAccessorCredential
const TDuration& requestTimeout
)
{
- return std::make_shared<TTokenAccessorCredentialsProviderFactory>(std::move(client), std::move(connection), serviceAccountId, serviceAccountIdSignature, refreshPeriod, requestTimeout);
+ return std::make_shared<TTokenAccessorCredentialsProviderFactory>(std::move(client), std::move(connection), serviceAccountId, serviceAccountIdSignature, refreshPeriod, requestTimeout);
}
}
diff --git a/ydb/library/yql/providers/pq/async_io/dq_pq_read_actor.cpp b/ydb/library/yql/providers/pq/async_io/dq_pq_read_actor.cpp
index 1fb54221a00..ad097c9525d 100644
--- a/ydb/library/yql/providers/pq/async_io/dq_pq_read_actor.cpp
+++ b/ydb/library/yql/providers/pq/async_io/dq_pq_read_actor.cpp
@@ -131,7 +131,7 @@ public:
NYdb::NPersQueue::TPersQueueClientSettings opts;
opts.Database(SourceParams.GetDatabase())
.DiscoveryEndpoint(SourceParams.GetEndpoint())
- .EnableSsl(SourceParams.GetUseSsl())
+ .SslCredentials(NYdb::TSslCredentials(SourceParams.GetUseSsl()))
.CredentialsProviderFactory(CredentialsProviderFactory);
return opts;
diff --git a/ydb/library/yql/providers/pq/async_io/dq_pq_write_actor.cpp b/ydb/library/yql/providers/pq/async_io/dq_pq_write_actor.cpp
index ce7879f45a3..1b853fc8769 100644
--- a/ydb/library/yql/providers/pq/async_io/dq_pq_write_actor.cpp
+++ b/ydb/library/yql/providers/pq/async_io/dq_pq_write_actor.cpp
@@ -239,7 +239,7 @@ private:
return NYdb::NPersQueue::TPersQueueClientSettings()
.Database(SinkParams.GetDatabase())
.DiscoveryEndpoint(SinkParams.GetEndpoint())
- .EnableSsl(SinkParams.GetUseSsl())
+ .SslCredentials(NYdb::TSslCredentials(SinkParams.GetUseSsl()))
.CredentialsProviderFactory(CredentialsProviderFactory);
}
diff --git a/ydb/library/yql/providers/pq/gateway/native/yql_pq_session.cpp b/ydb/library/yql/providers/pq/gateway/native/yql_pq_session.cpp
index 18d1ae0e476..61bd28b50d2 100644
--- a/ydb/library/yql/providers/pq/gateway/native/yql_pq_session.cpp
+++ b/ydb/library/yql/providers/pq/gateway/native/yql_pq_session.cpp
@@ -20,7 +20,7 @@ NYdb::NPersQueue::TPersQueueClientSettings GetYdbPqClientOptions(const TString&
opts
.DiscoveryEndpoint(cfg.GetEndpoint())
.Database(database)
- .EnableSsl(cfg.GetUseSsl())
+ .SslCredentials(NYdb::TSslCredentials(cfg.GetUseSsl()))
.CredentialsProviderFactory(credentialsProviderFactory);
return opts;
@@ -31,7 +31,7 @@ NYdb::TCommonClientSettings GetDsClientOptions(const TString& database, const NY
opts
.DiscoveryEndpoint(cfg.GetEndpoint())
.Database(database)
- .EnableSsl(cfg.GetUseSsl())
+ .SslCredentials(NYdb::TSslCredentials(cfg.GetUseSsl()))
.CredentialsProviderFactory(credentialsProviderFactory);
return opts;
diff --git a/ydb/library/yql/providers/ydb/actors/yql_ydb_read_actor.cpp b/ydb/library/yql/providers/ydb/actors/yql_ydb_read_actor.cpp
index b10d6b4c1fd..844685d952a 100644
--- a/ydb/library/yql/providers/ydb/actors/yql_ydb_read_actor.cpp
+++ b/ydb/library/yql/providers/ydb/actors/yql_ydb_read_actor.cpp
@@ -87,7 +87,7 @@ public:
, Path(path), Columns(columns), KeyColumnTypes(keyColumnTypes)
, MaxRows(maxRowsInRequest), MaxBytes(maxBytesInRequest)
, EndKey(keyTo)
- , Connection(driver, ::NYdb::TCommonClientSettings().Database(database).DiscoveryEndpoint(endpoint).CredentialsProviderFactory(credentialsProviderFactory).DiscoveryMode(::NYdb::EDiscoveryMode::Async).EnableSsl(secure))
+ , Connection(driver, ::NYdb::TCommonClientSettings().Database(database).DiscoveryEndpoint(endpoint).CredentialsProviderFactory(credentialsProviderFactory).DiscoveryMode(::NYdb::EDiscoveryMode::Async).SslCredentials(::NYdb::TSslCredentials(secure)))
, LastReadKey(keyFrom.empty() ? NKikimr::TSerializedCellVec::Serialize(TVector<NKikimr::TCell>(KeyColumnTypes.size())) : keyFrom)
, LastReadKeyInclusive(false)
, Retried(0U)
diff --git a/ydb/library/yql/providers/ydb/comp_nodes/yql_kik_scan.cpp b/ydb/library/yql/providers/ydb/comp_nodes/yql_kik_scan.cpp
index 1e69f3346fd..074901f74fa 100644
--- a/ydb/library/yql/providers/ydb/comp_nodes/yql_kik_scan.cpp
+++ b/ydb/library/yql/providers/ydb/comp_nodes/yql_kik_scan.cpp
@@ -111,7 +111,7 @@ using TBaseComputation = TMutableComputationNode<TKikScan<Async>>;
, MaxBytes(maxBytesInRequest)
, EndKey(keyTo)
, Settings(settings)
- , Connection(driver, NYdb::TCommonClientSettings().Database(database).DiscoveryEndpoint(endpoint).AuthToken(token).DiscoveryMode(NYdb::EDiscoveryMode::Async).EnableSsl(secure))
+ , Connection(driver, NYdb::TCommonClientSettings().Database(database).DiscoveryEndpoint(endpoint).AuthToken(token).DiscoveryMode(NYdb::EDiscoveryMode::Async).SslCredentials(NYdb::TSslCredentials(secure)))
, LastReadKey(keyFrom.empty() ? NKikimr::TSerializedCellVec::Serialize(TVector<NKikimr::TCell>(KeyColumnTypes.size())) : keyFrom)
, LastReadKeyInclusive(false)
, Retried(0U)
diff --git a/ydb/library/yql/providers/ydb/provider/yql_ydb_load_meta.cpp b/ydb/library/yql/providers/ydb/provider/yql_ydb_load_meta.cpp
index 1473e356e7c..0d735d0b98d 100644
--- a/ydb/library/yql/providers/ydb/provider/yql_ydb_load_meta.cpp
+++ b/ydb/library/yql/providers/ydb/provider/yql_ydb_load_meta.cpp
@@ -153,7 +153,7 @@ public:
const auto ins = Clients_->emplace(cluster, std::pair<TMetaClient, std::optional<TCreateSnapshotHandleResult>>{{Driver_, NYdb::TCommonClientSettings()
.Database(config.Database)
.DiscoveryEndpoint(config.Endpoint)
- .EnableSsl(config.Secure)
+ .SslCredentials(NYdb::TSslCredentials(config.Secure))
.CredentialsProviderFactory(credentialsProviderFactory)
.DiscoveryMode(NYdb::EDiscoveryMode::Async)}, std::nullopt});
diff --git a/ydb/public/lib/experimental/ydb_clickhouse_internal.cpp b/ydb/public/lib/experimental/ydb_clickhouse_internal.cpp
index 2566c84ec2a..5e137a1c879 100644
--- a/ydb/public/lib/experimental/ydb_clickhouse_internal.cpp
+++ b/ydb/public/lib/experimental/ydb_clickhouse_internal.cpp
@@ -159,7 +159,7 @@ TScanIterator::TScanIterator(const TDriver& driver, const TString &database, con
, MaxRows(maxRowsInRequest)
, MaxBytes(maxBytesInRequest)
, Settings(settings)
- , Connection(driver, NYdb::TCommonClientSettings().Database(database).AuthToken(token).DiscoveryEndpoint(endpoint).DiscoveryMode(NYdb::EDiscoveryMode::Async).EnableSsl(ssl))
+ , Connection(driver, NYdb::TCommonClientSettings().Database(database).AuthToken(token).DiscoveryEndpoint(endpoint).DiscoveryMode(NYdb::EDiscoveryMode::Async).SslCredentials(NYdb::TSslCredentials(ssl)))
, LastReadKey(keyFrom.empty() ? NKikimr::TSerializedCellVec::Serialize(TVector<NKikimr::TCell>(KeyColumnTypes.size())) : keyFrom)
, LastReadKeyInclusive(false)
, EndKey(keyTo)
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h b/ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h
new file mode 100644
index 00000000000..016a01dcdd4
--- /dev/null
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "type_switcher.h"
+
+namespace NYdb {
+
+struct TSslCredentials {
+ bool IsEnabled = false;
+ TStringType CaCert;
+ TStringType Cert;
+ TStringType PrivateKey;
+
+ TSslCredentials() = default;
+
+ TSslCredentials(const bool isEnabled, const TStringType& caCert = "", const TStringType& cert = "", const TStringType& privateKey = "")
+ : IsEnabled(isEnabled), CaCert(caCert), Cert(cert), PrivateKey(privateKey) {}
+
+ bool operator==(const TSslCredentials& other) const {
+ return IsEnabled == other.IsEnabled &&
+ CaCert == other.CaCert &&
+ Cert == other.Cert &&
+ PrivateKey == other.PrivateKey;
+ }
+};
+
+} // namespace NYdb
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.cpp b/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.cpp
index 43397b40169..afa6919c062 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.cpp
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.cpp
@@ -2,6 +2,7 @@
#include "state.h"
#include <ydb/public/sdk/cpp/client/ydb_types/credentials/credentials.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/logger/log.h>
#include <library/cpp/string_utils/quote/quote.h>
@@ -19,15 +20,13 @@ TDbDriverState::TDbDriverState(
const TStringType& database,
const TStringType& discoveryEndpoint,
EDiscoveryMode discoveryMode,
- bool enableSsl,
- const TStringType& caCert,
+ const TSslCredentials& sslCredentials,
IInternalClient* client
)
: Database(database)
, DiscoveryEndpoint(discoveryEndpoint)
, DiscoveryMode(discoveryMode)
- , EnableSsl(enableSsl)
- , CaCert(caCert)
+ , SslCredentials(sslCredentials)
, Client(client)
, EndpointPool([this, client]() mutable {
// this callback will be called just after shared_ptr initialization
@@ -135,8 +134,7 @@ TDbDriverStatePtr TDbDriverStateTracker::GetDriverState(
TStringType database,
TStringType discoveryEndpoint,
EDiscoveryMode discoveryMode,
- bool enableSsl,
- TStringType caCert,
+ const TSslCredentials& sslCredentials,
std::shared_ptr<ICredentialsProviderFactory> credentialsProviderFactory
) {
TStringType clientIdentity;
@@ -144,7 +142,7 @@ TDbDriverStatePtr TDbDriverStateTracker::GetDriverState(
clientIdentity = credentialsProviderFactory->GetClientIdentity();
}
Quote(database);
- const TStateKey key{database, discoveryEndpoint, clientIdentity, discoveryMode, enableSsl, caCert};
+ const TStateKey key{database, discoveryEndpoint, clientIdentity, discoveryMode, sslCredentials};
{
std::shared_lock lock(Lock_);
auto state = States_.find(key);
@@ -190,8 +188,7 @@ TDbDriverStatePtr TDbDriverStateTracker::GetDriverState(
database,
discoveryEndpoint,
discoveryMode,
- enableSsl,
- caCert,
+ sslCredentials,
DiscoveryClient_),
deleter);
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.h b/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.h
index 96b4c17e0e5..0246f7166b1 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.h
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/db_driver_state/state.h
@@ -5,6 +5,7 @@
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/internal_header.h>
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/internal_client/client.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include <ydb/public/sdk/cpp/client/ydb_types/core_facility/core_facility.h>
namespace NYdb {
@@ -30,8 +31,7 @@ public:
const TStringType& database,
const TStringType& discoveryEndpoint,
EDiscoveryMode discoveryMode,
- bool enableSsl,
- const TStringType& caCert,
+ const TSslCredentials& sslCredentials,
IInternalClient* client
);
@@ -52,8 +52,7 @@ public:
const TStringType Database;
const TStringType DiscoveryEndpoint;
const EDiscoveryMode DiscoveryMode;
- const bool EnableSsl;
- const TStringType CaCert;
+ const TSslCredentials SslCredentials;
std::shared_ptr<ICredentialsProvider> CredentialsProvider;
IInternalClient* Client;
TEndpointPool EndpointPool;
@@ -73,16 +72,18 @@ public:
// Tracker allows to get driver state by database and credentials
class TDbDriverStateTracker {
- using TStateKey = std::tuple<TStringType, TStringType, TStringType, EDiscoveryMode, bool, TStringType>;
+ using TStateKey = std::tuple<TStringType, TStringType, TStringType, EDiscoveryMode, TSslCredentials>;
struct TStateKeyHash {
size_t operator()(const TStateKey& k) const noexcept {
THash<TStringType> strHash;
const size_t h0 = strHash(std::get<0>(k));
const size_t h1 = strHash(std::get<1>(k));
const size_t h2 = strHash(std::get<2>(k));
- const size_t h3 = ((size_t)std::get<3>(k) << 1) + (size_t)std::get<4>(k);
- const size_t h5 = strHash(std::get<5>(k));
- return (h0 ^ h1 ^ h2 ^ h3 ^ h5);
+ const auto& sslCredentials = std::get<4>(k);
+ const size_t h3 = (static_cast<size_t>(std::get<3>(k)) << 1) + static_cast<size_t>(sslCredentials.IsEnabled);
+ const size_t h5 = strHash(sslCredentials.CaCert);
+ const size_t h6 = strHash(sslCredentials.Cert);
+ return (h0 ^ h1 ^ h2 ^ h3 ^ h5 ^ h6);
}
};
public:
@@ -91,8 +92,7 @@ public:
TStringType database,
TStringType DiscoveryEndpoint,
EDiscoveryMode discoveryMode,
- bool enableSsl,
- TStringType caCert,
+ const TSslCredentials& sslCredentials,
std::shared_ptr<ICredentialsProviderFactory> credentialsProviderFactory
);
NThreading::TFuture<void> SendNotification(
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.cpp b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.cpp
index db3247a41c5..f6e90a622f1 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.cpp
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.cpp
@@ -138,8 +138,7 @@ TGRpcConnectionsImpl::TGRpcConnectionsImpl(std::shared_ptr<IConnectionsParams> p
: MetricRegistryPtr_(nullptr)
, ResponseQueue_(CreateThreadPool(params->GetClientThreadsNum()))
, DefaultDiscoveryEndpoint_(params->GetEndpoint())
- , EnableSsl_(params->IsSslEnabled())
- , CaCert_(params->GetCaCert())
+ , SslCredentials_(params->GetSslCredentials())
, DefaultDatabase_(params->GetDatabase())
, DefaultCredentialsProviderFactory_(params->GetCredentialsProviderFactory())
, StateTracker_(this)
@@ -182,8 +181,7 @@ TGRpcConnectionsImpl::TGRpcConnectionsImpl(std::shared_ptr<IConnectionsParams> p
DefaultDatabase_,
DefaultDiscoveryEndpoint_,
DefaultDiscoveryMode_,
- EnableSsl_,
- CaCert_,
+ SslCredentials_,
DefaultCredentialsProviderFactory_
);
}
@@ -270,16 +268,14 @@ TDbDriverStatePtr TGRpcConnectionsImpl::GetDriverState(
const TMaybe<TStringType>& database,
const TMaybe<TStringType>& discoveryEndpoint,
const TMaybe<EDiscoveryMode>& discoveryMode,
- const TMaybe<bool>& enableSsl,
- const TMaybe<TStringType>& caCert,
+ const TMaybe<TSslCredentials>& sslCredentials,
const TMaybe<std::shared_ptr<ICredentialsProviderFactory>>& credentialsProviderFactory
) {
return StateTracker_.GetDriverState(
database ? database.GetRef() : DefaultDatabase_,
discoveryEndpoint ? discoveryEndpoint.GetRef() : DefaultDiscoveryEndpoint_,
discoveryMode ? discoveryMode.GetRef() : DefaultDiscoveryMode_,
- enableSsl ? enableSsl.GetRef() : EnableSsl_,
- caCert ? caCert.GetRef() : CaCert_,
+ sslCredentials ? sslCredentials.GetRef() : SslCredentials_,
credentialsProviderFactory ? credentialsProviderFactory.GetRef() : DefaultCredentialsProviderFactory_);
}
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.h b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.h
index e07ab5a9e4e..4f27a5a25a7 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.h
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/grpc_connections.h
@@ -1,6 +1,7 @@
#pragma once
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/internal_header.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include "actions.h"
#include "params.h"
@@ -60,8 +61,7 @@ public:
const TMaybe<TStringType>& database,
const TMaybe<TStringType>& discoveryEndpoint,
const TMaybe<EDiscoveryMode>& discoveryMode,
- const TMaybe<bool>& enableSsl,
- const TMaybe<TStringType>& caCert,
+ const TMaybe<TSslCredentials>& sslCredentials,
const TMaybe<std::shared_ptr<ICredentialsProviderFactory>>& credentialsProviderFactory
);
IQueueClientContextPtr CreateContext() override;
@@ -80,8 +80,10 @@ public:
TRpcRequestSettings::TEndpointPolicy endpointPolicy)
{
auto clientConfig = NGrpc::TGRpcClientConfig(dbState->DiscoveryEndpoint);
- clientConfig.EnableSsl = dbState->EnableSsl;
- clientConfig.SslCaCert = dbState->CaCert;
+ const auto& sslCredentials = dbState->SslCredentials;
+ clientConfig.SslCredentials = {.pem_root_certs = sslCredentials.CaCert, .pem_private_key = sslCredentials.PrivateKey, .pem_cert_chain = sslCredentials.Cert};
+ clientConfig.EnableSsl = sslCredentials.IsEnabled;
+
clientConfig.MemQuota = MemoryQuota_;
if (MaxMessageSize_ > 0) {
@@ -703,8 +705,7 @@ private:
std::unique_ptr<IThreadPool> ResponseQueue_;
const TStringType DefaultDiscoveryEndpoint_;
- const bool EnableSsl_;
- const TStringType CaCert_;
+ const TSslCredentials SslCredentials_;
const TStringType DefaultDatabase_;
std::shared_ptr<ICredentialsProviderFactory> DefaultCredentialsProviderFactory_;
TDbDriverStateTracker StateTracker_;
diff --git a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/params.h b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/params.h
index 9de2911a4f2..033274c8fa5 100644
--- a/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/params.h
+++ b/ydb/public/sdk/cpp/client/impl/ydb_internal/grpc_connections/params.h
@@ -1,6 +1,7 @@
#pragma once
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/internal_header.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
namespace NYdb {
@@ -11,8 +12,7 @@ public:
virtual size_t GetNetworkThreadsNum() const = 0;
virtual size_t GetClientThreadsNum() const = 0;
virtual size_t GetMaxQueuedResponses() const = 0;
- virtual bool IsSslEnabled() const = 0;
- virtual TStringType GetCaCert() const = 0;
+ virtual TSslCredentials GetSslCredentials() const = 0;
virtual TStringType GetDatabase() const = 0;
virtual std::shared_ptr<ICredentialsProviderFactory> GetCredentialsProviderFactory() const = 0;
virtual EDiscoveryMode GetDiscoveryMode() const = 0;
diff --git a/ydb/public/sdk/cpp/client/ydb_common_client/impl/client.h b/ydb/public/sdk/cpp/client/ydb_common_client/impl/client.h
index b1ce76ce3b4..6b26c7b0494 100644
--- a/ydb/public/sdk/cpp/client/ydb_common_client/impl/client.h
+++ b/ydb/public/sdk/cpp/client/ydb_common_client/impl/client.h
@@ -5,6 +5,7 @@
#undef INCLUDE_YDB_INTERNAL_H
#include <ydb/public/sdk/cpp/client/ydb_types/exceptions/exceptions.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include <memory>
@@ -18,11 +19,10 @@ public:
const TMaybe<TString>& database,
const TMaybe<TString>& discoveryEndpoint,
const TMaybe<EDiscoveryMode>& discoveryMode,
- const TMaybe<bool>& enableSsl,
- const TMaybe<TString>& caCert,
+ const TMaybe<TSslCredentials>& sslCredentials,
const TMaybe<std::shared_ptr<ICredentialsProviderFactory>>& credentialsProviderFactory)
: Connections_(std::move(connections))
- , DbDriverState_(Connections_->GetDriverState(database, discoveryEndpoint, discoveryMode, enableSsl, caCert, credentialsProviderFactory))
+ , DbDriverState_(Connections_->GetDriverState(database, discoveryEndpoint, discoveryMode, sslCredentials, credentialsProviderFactory))
{
Y_VERIFY(DbDriverState_);
}
@@ -36,8 +36,7 @@ public:
settings.Database_,
settings.DiscoveryEndpoint_,
settings.DiscoveryMode_,
- settings.EnableSsl_,
- settings.CaCert_,
+ settings.SslCredentials_,
settings.CredentialsProviderFactory_
)
)
diff --git a/ydb/public/sdk/cpp/client/ydb_common_client/settings.cpp b/ydb/public/sdk/cpp/client/ydb_common_client/settings.cpp
index 8bffcd7a5ae..9baa0c1328d 100644
--- a/ydb/public/sdk/cpp/client/ydb_common_client/settings.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_common_client/settings.cpp
@@ -13,7 +13,7 @@ TCommonClientSettings GetClientSettingsFromConnectionString(const TStringType& c
auto connectionInfo = ParseConnectionString(connectionString);
settings.Database(connectionInfo.Database);
settings.DiscoveryEndpoint(connectionInfo.Endpoint);
- settings.EnableSsl(connectionInfo.EnableSsl);
+ settings.SslCredentials(TSslCredentials(connectionInfo.EnableSsl));
return settings;
}
diff --git a/ydb/public/sdk/cpp/client/ydb_common_client/settings.h b/ydb/public/sdk/cpp/client/ydb_common_client/settings.h
index d7333926390..e73f504e8d8 100644
--- a/ydb/public/sdk/cpp/client/ydb_common_client/settings.h
+++ b/ydb/public/sdk/cpp/client/ydb_common_client/settings.h
@@ -5,10 +5,13 @@
#include <ydb/public/sdk/cpp/client/ydb_types/ydb.h>
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/type_switcher.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include <functional>
namespace NYdb {
+using TCertificateAndPrivateKey = std::pair<TStringType, TStringType>;
+
struct TCommonClientSettings {
using TSelf = TCommonClientSettings;
@@ -29,10 +32,8 @@ struct TCommonClientSettings {
FLUENT_SETTING_OPTIONAL(std::shared_ptr<ICredentialsProviderFactory>, CredentialsProviderFactory);
//! Allows to override discovery mode
FLUENT_SETTING_OPTIONAL(EDiscoveryMode, DiscoveryMode);
- //! Allows to override current Ssl mode
- FLUENT_SETTING_OPTIONAL(bool, EnableSsl);
- //! Allows to override current Ssl cert
- FLUENT_SETTING_OPTIONAL(TStringType, CaCert);
+ //! Allows to override current Ssl credentials
+ FLUENT_SETTING_OPTIONAL(TSslCredentials, SslCredentials);
};
template<class TDerived>
@@ -49,8 +50,7 @@ struct TCommonClientSettingsBase : public TCommonClientSettings {
COMMON_CLIENT_SETTINGS_TO_DERIVED(TMaybe<TStringType>, AuthToken);
COMMON_CLIENT_SETTINGS_TO_DERIVED(std::shared_ptr<ICredentialsProviderFactory>, CredentialsProviderFactory);
COMMON_CLIENT_SETTINGS_TO_DERIVED(EDiscoveryMode, DiscoveryMode);
- COMMON_CLIENT_SETTINGS_TO_DERIVED(bool, EnableSsl);
- COMMON_CLIENT_SETTINGS_TO_DERIVED(TStringType, CaCert);
+ COMMON_CLIENT_SETTINGS_TO_DERIVED(TSslCredentials, SslCredentials);
#undef COMMON_CLIENT_SETTINGS_TO_DERIVED
diff --git a/ydb/public/sdk/cpp/client/ydb_driver/driver.cpp b/ydb/public/sdk/cpp/client/ydb_driver/driver.cpp
index fae0334abfd..d7be6064b76 100644
--- a/ydb/public/sdk/cpp/client/ydb_driver/driver.cpp
+++ b/ydb/public/sdk/cpp/client/ydb_driver/driver.cpp
@@ -9,6 +9,7 @@
#include <library/cpp/logger/log.h>
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/parser.h>
#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/getenv.h>
+#include <ydb/public/sdk/cpp/client/impl/ydb_internal/common/ssl_credentials.h>
#include <util/stream/file.h>
#include <ydb/public/sdk/cpp/client/resources/ydb_ca.h>
@@ -32,8 +33,7 @@ public:
size_t GetNetworkThreadsNum() const override { return NetworkThreadsNum; }
size_t GetClientThreadsNum() const override { return ClientThreadsNum; }
size_t GetMaxQueuedResponses() const override { return MaxQueuedResponses; }
- bool IsSslEnabled() const override { return EnableSsl; }
- TStringType GetCaCert() const override { return CaCert; }
+ TSslCredentials GetSslCredentials() const override { return SslCredentials; }
TStringType GetDatabase() const override { return Database; }
std::shared_ptr<ICredentialsProviderFactory> GetCredentialsProviderFactory() const override { return CredentialsProviderFactory; }
EDiscoveryMode GetDiscoveryMode() const override { return DiscoveryMode; }
@@ -54,8 +54,7 @@ public:
size_t NetworkThreadsNum = 2;
size_t ClientThreadsNum = 0;
size_t MaxQueuedResponses = 0;
- bool EnableSsl = false;
- TStringType CaCert;
+ TSslCredentials SslCredentials;
TStringType Database;
std::shared_ptr<ICredentialsProviderFactory> CredentialsProviderFactory = CreateInsecureCredentialsProviderFactory();
EDiscoveryMode DiscoveryMode = EDiscoveryMode::Sync;
@@ -85,7 +84,7 @@ TDriverConfig::TDriverConfig(const TStringType& connectionString)
auto connectionInfo = ParseConnectionString(connectionString);
SetEndpoint(connectionInfo.Endpoint);
SetDatabase(connectionInfo.Database);
- Impl_->EnableSsl = connectionInfo.EnableSsl;
+ Impl_->SslCredentials.IsEnabled = connectionInfo.EnableSsl;
}
}
@@ -110,8 +109,14 @@ TDriverConfig& TDriverConfig::SetMaxClientQueueSize(size_t sz) {
}
TDriverConfig& TDriverConfig::UseSecureConnection(const TStringType& cert) {
- Impl_->EnableSsl = true;
- Impl_->CaCert = cert;
+ Impl_->SslCredentials.IsEnabled = true;
+ Impl_->SslCredentials.CaCert = cert;
+ return *this;
+}
+
+TDriverConfig& TDriverConfig::UseClientCertificate(const TStringType& clientCert, const TStringType& clientPrivateKey) {
+ Impl_->SslCredentials.Cert = clientCert;
+ Impl_->SslCredentials.PrivateKey = clientPrivateKey;
return *this;
}
diff --git a/ydb/public/sdk/cpp/client/ydb_driver/driver.h b/ydb/public/sdk/cpp/client/ydb_driver/driver.h
index e8027bfad7d..f4589bd367a 100644
--- a/ydb/public/sdk/cpp/client/ydb_driver/driver.h
+++ b/ydb/public/sdk/cpp/client/ydb_driver/driver.h
@@ -51,6 +51,7 @@ public:
//! caCerts - The buffer containing the PEM encoding of the server root certificates.
//! If this parameter is empty, the default roots will be used.
TDriverConfig& UseSecureConnection(const TStringType& caCerts = TStringType());
+ TDriverConfig& UseClientCertificate(const TStringType& clientCert, const TStringType& clientPrivateKey);
//! Set token, this option can be overridden for client by ClientSettings
TDriverConfig& SetAuthToken(const TStringType& token);
//! Set database, this option can be overridden for client by ClientSettings
diff --git a/ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/persqueue_impl.h b/ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/persqueue_impl.h
index f223b5bc461..cb74163ffc0 100644
--- a/ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/persqueue_impl.h
+++ b/ydb/public/sdk/cpp/client/ydb_persqueue_core/impl/persqueue_impl.h
@@ -24,7 +24,7 @@ public:
// Async discovery mode is used because this client is created inside SDK threads.
// See YDB-1231 and YDB-1232.
TImpl(const TString& clusterEndpoint, std::shared_ptr<TGRpcConnectionsImpl> connections, const TPersQueueClientSettings& settings)
- : TClientImplCommon(std::move(connections), settings.Database_, clusterEndpoint, EDiscoveryMode::Async, settings.EnableSsl_, settings.CaCert_, settings.CredentialsProviderFactory_)
+ : TClientImplCommon(std::move(connections), settings.Database_, clusterEndpoint, EDiscoveryMode::Async, settings.SslCredentials_, settings.CredentialsProviderFactory_)
, Settings(settings)
, CustomEndpoint(clusterEndpoint)
{
diff --git a/ydb/services/datastreams/datastreams_ut.cpp b/ydb/services/datastreams/datastreams_ut.cpp
index 839adb01c34..10e5116790d 100644
--- a/ydb/services/datastreams/datastreams_ut.cpp
+++ b/ydb/services/datastreams/datastreams_ut.cpp
@@ -91,7 +91,7 @@ public:
TString location = TStringBuilder() << "localhost:" << grpc;
auto driverConfig = TDriverConfig().SetEndpoint(location).SetLog(CreateLogBackend("cerr", TLOG_DEBUG));
if (secure) {
- driverConfig.UseSecureConnection(NYdbSslTestData::CaCrt);
+ driverConfig.UseSecureConnection(TString(NYdbSslTestData::CaCrt));
} else {
driverConfig.SetDatabase("/Root/");
}
diff --git a/ydb/services/ydb/CMakeLists.txt b/ydb/services/ydb/CMakeLists.txt
index 487894646ad..4c7ba850237 100644
--- a/ydb/services/ydb/CMakeLists.txt
+++ b/ydb/services/ydb/CMakeLists.txt
@@ -6,6 +6,7 @@
# original buildsystem will not be accepted.
+find_package(OpenSSL REQUIRED)
add_subdirectory(index_ut)
add_subdirectory(sdk_credprovider_ut)
add_subdirectory(ut)
@@ -29,6 +30,7 @@ target_link_libraries(ydb-services-ydb PUBLIC
api-grpc-draft
api-protos
yql-public-types
+ OpenSSL::OpenSSL
)
target_sources(ydb-services-ydb PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_clickhouse_internal.cpp
diff --git a/ydb/services/ydb/cert_gen.cpp b/ydb/services/ydb/cert_gen.cpp
new file mode 100644
index 00000000000..141b599fc64
--- /dev/null
+++ b/ydb/services/ydb/cert_gen.cpp
@@ -0,0 +1,499 @@
+#include "cert_gen.h"
+
+#include <contrib/libs/openssl/include/openssl/bio.h>
+#include <contrib/libs/openssl/include/openssl/err.h>
+#include <contrib/libs/openssl/include/openssl/evp.h>
+#include <contrib/libs/openssl/include/openssl/pem.h>
+#include <contrib/libs/openssl/include/openssl/rsa.h>
+#include <contrib/libs/openssl/include/openssl/x509.h>
+#include <contrib/libs/openssl/include/openssl/x509v3.h>
+#include <contrib/libs/openssl/include/openssl/x509_vfy.h>
+
+
+#include <array>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <stdexcept>
+
+
+using namespace NTest;
+
+namespace {
+
+constexpr size_t maxCertSize = 17 * 1024;
+constexpr size_t errStringBufSize = 1024;
+
+#define CHECK(expr, msg) \
+ if (!expr) { \
+ char errString[errStringBufSize]{0}; \
+ ERR_error_string_n(ERR_get_error(), errString, errStringBufSize); \
+ std::cerr << msg << std::endl; \
+ std::cerr << errString << std::endl; \
+ exit (1); \
+ }
+
+template <auto fn>
+struct deleter_from_fn {
+ template <typename T>
+ constexpr void operator()(T* arg) const {
+ fn(arg);
+ }
+};
+
+using PKeyPtr = std::unique_ptr<EVP_PKEY, deleter_from_fn<&::EVP_PKEY_free>>;
+using X509Ptr = std::unique_ptr<X509, deleter_from_fn<&::X509_free>>;
+using RSAPtr = std::unique_ptr<RSA, deleter_from_fn<&::RSA_free>>;
+using BNPtr = std::unique_ptr<BIGNUM, deleter_from_fn<&::BN_free>>;
+using BIOPtr = std::unique_ptr<BIO, deleter_from_fn<&::BIO_free>>;
+using ExtPrt = std::unique_ptr<X509_EXTENSION, deleter_from_fn<&::X509_EXTENSION_free>>;
+using X509REQPtr = std::unique_ptr<X509_REQ, deleter_from_fn<&::X509_REQ_free>>;
+using X509StorePtr = std::unique_ptr<X509_STORE, deleter_from_fn<&::X509_STORE_free>>;
+using X509StoreCtxPtr = std::unique_ptr<X509_STORE_CTX, deleter_from_fn<&::X509_STORE_CTX_free>>;
+
+void FillExtFromProps0(X509V3_CTX* ctx, STACK_OF(X509_EXTENSION) *exts, const TProps& props);
+void FillExtFromProps1(X509V3_CTX* ctx, STACK_OF(X509_EXTENSION) *exts, const TProps& props);
+
+void VerifyCert(const X509Ptr& cert, const X509Ptr& cacert) {
+ auto store = X509StorePtr(X509_STORE_new());
+ X509_STORE_add_cert(store.get(), cacert.get());
+
+ auto ctx = X509StoreCtxPtr(X509_STORE_CTX_new());
+ X509_STORE_CTX_init(ctx.get(), store.get(), cert.get(), NULL);
+
+ int result = X509_verify_cert(ctx.get());
+ CHECK(result == 1, "VerifyCert failed.");
+}
+
+PKeyPtr GenerateKeys() {
+ /* EVP_PKEY structure is for storing an algorithm-independent private key in memory. */
+ auto pkey = PKeyPtr(EVP_PKEY_new());
+ CHECK(pkey, "Unable to create pkey structure.");
+
+ /* Generate a RSA key and assign it to pkey.
+ * RSA_generate_key is deprecated.
+ */
+ auto bne = BNPtr(BN_new());
+ CHECK(bne, "Unable to create bignum structure.");
+
+ BN_set_word(bne.get(), RSA_F4);
+
+ auto rsa = RSAPtr(RSA_new());
+ CHECK(rsa, "Unable to create rsa structure.");
+
+ RSA_generate_key_ex(rsa.get(), 2048, bne.get(), nullptr);
+
+ EVP_PKEY_assign_RSA(pkey.get(), rsa.get());
+
+ rsa.release(); // mem is grabbed by pkkey
+
+ return std::move(pkey);
+}
+
+int FillNameFromProps(X509_NAME* name, const TProps& props) {
+ if (!name) {
+ return 1;
+ }
+
+ if (!props.Coutry.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_countryName, MBSTRING_ASC, (const unsigned char*)props.Coutry.c_str(), -1, -1, 0);
+ }
+
+ if (!props.State.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_stateOrProvinceName, MBSTRING_ASC, (const unsigned char*)props.State.c_str(), -1, -1, 0);
+ }
+
+ if (!props.Location.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_localityName, MBSTRING_ASC, (const unsigned char*)props.Location.c_str(), -1, -1, 0);
+ }
+
+ if (!props.Organization.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_organizationName, MBSTRING_ASC, (const unsigned char*)props.Organization.c_str(), -1, -1, 0);
+ }
+
+ if (!props.Unit.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_organizationalUnitName, MBSTRING_ASC, (const unsigned char*)props.Unit.c_str(), -1, -1, 0);
+ }
+
+ if (!props.CommonName.empty()) {
+ X509_NAME_add_entry_by_txt(name, SN_commonName, MBSTRING_ASC, (const unsigned char*)props.CommonName.c_str(), -1, -1, 0);
+ }
+
+ return 0;
+}
+
+/* Generates a self-signed x509 certificate. */
+X509Ptr GenerateSelfSignedCertificate(PKeyPtr& pkey, const TProps& props) {
+ /* Allocate memory for the X509 structure. */
+ auto x509 = X509Ptr(X509_new());
+ CHECK(x509, "Unable to create X509 structure.");
+
+ X509_set_version(x509.get(), 3);
+
+ /* Set the serial number. */
+ constexpr int Serial = 1;
+ ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), Serial);
+
+ /* This certificate is valid from now until exactly one year from now. */
+ X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
+ X509_gmtime_adj(X509_get_notAfter(x509.get()), props.SecondsValid);
+
+ int errNo = 0;
+ /* Set the public key for our certificate. */
+ errNo = X509_set_pubkey(x509.get(), pkey.get());
+ CHECK(x509,"Error setting public key for X509 structure.");
+
+ /* We want to copy the subject name to the issuer name. */
+ X509_NAME* name = X509_get_subject_name(x509.get());
+ CHECK(name,"Error getting subject name from X509 structure.");
+
+ /* Set the country code and common name. */
+ errNo = FillNameFromProps(name, props);
+ CHECK(errNo == 0,"Error setting names.");
+
+ errNo = X509_set_subject_name(x509.get(), name);
+ CHECK(errNo, "Error setting subject name.");
+
+ errNo = X509_set_issuer_name(x509.get(), name);
+ CHECK(errNo, "Error setting issier name.");
+
+ { // fill ext properties witch don't requere filled issuer indentity
+ X509V3_CTX ctx;
+ X509V3_set_ctx_nodb(&ctx);
+ X509V3_set_ctx(&ctx, x509.get(), x509.get(), nullptr, nullptr, 0);
+
+ STACK_OF (X509_EXTENSION)* exts = sk_X509_EXTENSION_new_null();
+ CHECK(exts, "Unable to create STACK_OF X509_EXTENSION structure.");
+
+ FillExtFromProps0(&ctx, exts, props);
+
+ int count = X509v3_get_ext_count(exts);
+ for (int i = 0; i < count; ++i) {
+ auto tmpExt = X509v3_get_ext(exts, i);
+ errNo = X509_add_ext(x509.get(), tmpExt, -1);
+ CHECK(errNo, "Error adding ext value");
+ tmpExt = nullptr;
+ }
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ }
+
+ { // fill ext properties witch requere filled issuer indentity, NID_authority_key_identifier
+ X509V3_CTX ctx;
+ X509V3_set_ctx_nodb(&ctx);
+ X509V3_set_ctx(&ctx, x509.get(), x509.get(), nullptr, nullptr, 0);
+
+ STACK_OF (X509_EXTENSION)* exts = sk_X509_EXTENSION_new_null();
+ CHECK(exts, "Unable to create STACK_OF X509_EXTENSION structure.");
+
+ FillExtFromProps1(&ctx, exts, props);
+
+ int count = X509v3_get_ext_count(exts);
+ for (int i = 0; i < count; ++i) {
+ auto tmpExt = X509v3_get_ext(exts, i);
+ errNo = X509_add_ext(x509.get(), tmpExt, -1);
+ CHECK(errNo, "Error adding ext value");
+ tmpExt = nullptr;
+ }
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ }
+
+
+ /* Actually sign the certificate with our key. */
+ errNo = X509_sign(x509.get(), pkey.get(), EVP_sha1());
+ CHECK(errNo, "Error signing certificate.");
+
+ return std::move(x509);
+}
+
+std::string WriteAsPEM(PKeyPtr& pkey) {
+ std::array<char, maxCertSize> buf{0};
+
+ auto bio = BIOPtr(BIO_new(BIO_s_mem()));
+ CHECK(bio, "Unable to create BIO structure.");
+
+ PEM_write_bio_RSAPrivateKey(bio.get(), EVP_PKEY_get0_RSA(pkey.get()), nullptr, nullptr, 0, nullptr, nullptr);
+
+ BIO_read(bio.get(), buf.data(), maxCertSize - 1);
+
+ return std::string(buf.data());
+}
+
+std::string WriteAsPEM(X509Ptr& cert) {
+ std::array<char, maxCertSize> buf{0};
+
+ auto bio = BIOPtr(BIO_new(BIO_s_mem()));
+ CHECK(bio, "Unable to create BIO structure.");
+
+ PEM_write_bio_X509(bio.get(), cert.get());
+
+ BIO_read(bio.get(), buf.data(), maxCertSize - 1);
+
+ return std::string(buf.data());
+}
+
+X509Ptr ReadCertAsPEM(const std::string& cert) {
+ auto bio = BIOPtr(BIO_new_mem_buf(cert.data(), cert.size()));
+ CHECK(bio,"Unable to create BIO structure.");
+
+ auto x509 = X509Ptr(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL));
+ CHECK(x509, "failed to load certificate");
+
+ return std::move(x509);
+}
+
+PKeyPtr ReadPrivateKeyAsPEM(const std::string& key) {
+ auto bio = BIOPtr(BIO_new_mem_buf(key.data(), key.size()));
+ CHECK(bio,"Unable to create BIO structure.");
+
+ auto pkey = PKeyPtr(PEM_read_bio_PrivateKey(bio.get(), NULL, NULL, NULL));
+ CHECK(pkey, "failed to private key certificate");
+
+ return std::move(pkey);
+}
+
+void add_ext(X509V3_CTX* ctx, STACK_OF(X509_EXTENSION)* exts, int nid, const char *value) {
+ X509_EXTENSION *ex;
+ ex = X509V3_EXT_conf_nid(NULL, ctx, nid, value);
+ CHECK(ex, "failed to add ext value " << value);
+ sk_X509_EXTENSION_push(exts, ex);
+}
+
+void FillExtFromProps0(X509V3_CTX* ctx, STACK_OF(X509_EXTENSION) *exts, const TProps& props) {
+ CHECK(ctx, "no context is provided");
+
+ if (!props.AltNames.empty()) {
+ bool first = true;
+ std::string concat;
+ for (const auto& an: props.AltNames) {
+ if (an.empty()) {
+ continue;
+ }
+ if (!first) {
+ concat += ",";
+ } else {
+ first = false;
+ }
+
+ concat += an;
+ }
+ add_ext(ctx, exts, NID_subject_alt_name, concat.c_str());
+ }
+
+ if (!props.BasicConstraints.empty()) {
+ add_ext(ctx, exts, NID_basic_constraints, props.BasicConstraints.c_str());
+ }
+
+ if (!props.KeyUsage.empty()) {
+ add_ext(ctx, exts, NID_key_usage, props.KeyUsage.c_str());
+ }
+
+ if (!props.ExtKeyUsage.empty()) {
+ add_ext(ctx, exts, NID_ext_key_usage, props.ExtKeyUsage.c_str());
+ }
+
+ if (!props.SubjectKeyIdentifier.empty()) {
+ add_ext(ctx, exts, NID_subject_key_identifier, props.SubjectKeyIdentifier.c_str());
+ }
+
+ if (!props.NsComment.empty()) {
+ add_ext(ctx, exts, NID_netscape_comment, props.NsComment.c_str());
+ }
+}
+
+void FillExtFromProps1(X509V3_CTX* ctx, STACK_OF(X509_EXTENSION) *exts, const TProps& props) {
+ CHECK(ctx, "no context is provided");
+
+ if (!props.AuthorityKeyIdentifier.empty()) {
+ add_ext(ctx, exts, NID_authority_key_identifier, props.AuthorityKeyIdentifier.c_str());
+ }
+}
+
+X509REQPtr GenerateRequest(PKeyPtr& pkey, const TProps& props) {
+ auto request = X509REQPtr(X509_REQ_new());
+ CHECK(request, "Error creating new X509_REQ structure.");
+
+ int errNo = 0;
+
+ errNo = X509_REQ_set_pubkey(request.get(), pkey.get());
+ CHECK(errNo, "Error setting public key for X509_REQ structure.");
+
+ X509_NAME* name = X509_REQ_get_subject_name(request.get());
+ CHECK(name, "Error setting public key for X509_REQ structure.");
+
+ errNo = FillNameFromProps(name, props);
+ CHECK(errNo == 0,"Error setting names.");
+
+ {
+ X509V3_CTX ctx;
+ X509V3_set_ctx_nodb(&ctx);
+ X509V3_set_ctx(&ctx, nullptr, nullptr, request.get(), nullptr, 0);
+
+ STACK_OF (X509_EXTENSION)* exts = sk_X509_EXTENSION_new_null();
+ FillExtFromProps0(&ctx, exts, props);
+ X509_REQ_add_extensions(request.get(), exts);
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ }
+
+ errNo = X509_REQ_sign(request.get(), pkey.get(), EVP_md5());
+ CHECK(errNo, "Error MD5 signing X509_REQ structure.");
+
+ return std::move(request);
+}
+
+X509Ptr SingRequest(X509REQPtr& request, X509Ptr& rootCert, PKeyPtr& rootKey, const TProps& props) {
+ auto* pktmp = X509_REQ_get0_pubkey(request.get()); // X509_REQ_get0_pubkey returns the key, that shouldn't freed
+ CHECK(pktmp, "Error unpacking public key from request.");
+
+ int errNo = 0;
+ errNo = X509_REQ_verify(request.get(), pktmp);
+ CHECK(errNo > 0, "Error verification request signature.");
+
+ auto x509 = X509Ptr(X509_new());
+ CHECK(x509, "Unable to create X509 structure.");
+
+ X509_set_version(x509.get(), 3);
+
+ /* Set the serial number. */
+ constexpr int Serial = 2;
+ ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), Serial);
+
+ /* This certificate is valid from now until exactly one year from now. */
+ X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
+ X509_gmtime_adj(X509_get_notAfter(x509.get()), props.SecondsValid);
+
+ X509_set_pubkey(x509.get(), pktmp);
+
+ X509_set_subject_name(x509.get(), X509_REQ_get_subject_name(request.get()));
+ X509_set_issuer_name(x509.get(), X509_get_subject_name(rootCert.get()));
+
+ {
+
+ X509V3_CTX ctx;
+ X509V3_set_ctx_nodb(&ctx);
+ X509V3_set_ctx(&ctx, rootCert.get(), x509.get(), request.get(), nullptr, 0);
+
+ // fill ext properties witch don't requere filled issuer indentity, actually copy them from request
+ STACK_OF(X509_EXTENSION)* exts = X509_REQ_get_extensions(request.get());
+ CHECK(exts, "Unable to get STACK_OF X509_EXTENSION structure from request.");
+
+ // fill ext properties witch requere filled issuer indentity, NID_authority_key_identifier
+ FillExtFromProps1(&ctx, exts, props);
+
+ int count = X509v3_get_ext_count(exts);
+ for (int i = 0; i < count; ++i) {
+ auto tmpExt = X509v3_get_ext(exts, i);
+ errNo = X509_add_ext(x509.get(), tmpExt, -1);
+ CHECK(errNo, "Error adding ext value");
+ tmpExt = nullptr;
+ }
+
+ sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
+ }
+
+ /* Actually sign the certificate with our key. */
+ errNo = X509_sign(x509.get(), rootKey.get(), EVP_sha1());
+ CHECK(errNo, "Error signing certificate.");
+
+ pktmp = nullptr;
+
+ return std::move(x509);
+}
+
+}
+
+namespace NTest {
+
+TCertAndKey GenerateCA(const TProps& props) {
+ auto keys = GenerateKeys();
+ auto cert = GenerateSelfSignedCertificate(keys, props);
+
+ TCertAndKey result;
+ result.Certificate = WriteAsPEM(cert);
+ result.PrivateKey = WriteAsPEM(keys);
+
+ return result;
+}
+
+TCertAndKey GenerateSignedCert(const TCertAndKey& rootCA, const TProps& props) {
+ auto keys = GenerateKeys();
+ auto request = GenerateRequest(keys, props);
+
+ auto rootCert = ReadCertAsPEM(rootCA.Certificate);
+ auto rootKey = ReadPrivateKeyAsPEM(rootCA.PrivateKey);
+ auto cert = SingRequest(request, rootCert, rootKey, props); // NID_authority_key_identifier must see ca
+
+ TCertAndKey result;
+ result.Certificate = WriteAsPEM(cert);
+ result.PrivateKey = WriteAsPEM(keys);
+
+ return result;
+}
+
+void VerifyCert(const std::string& cert, const std::string& caCert) {
+ auto rootCert = ReadCertAsPEM(caCert);
+ auto otherCert = ReadCertAsPEM(cert);
+
+ VerifyCert(otherCert, rootCert);
+}
+
+TProps TProps::AsCA() {
+ TProps props;
+
+ props.SecondsValid = 3*365 * 24 * 60 *60; // 3 years
+ props.Coutry = "RU";
+ props.State = "MSK";
+ props.Location = "MSK";
+ props.Organization = "YA";
+ props.Unit = "UtTest";
+ props.CommonName = "testCA";
+
+ props.AltNames = {"IP:127.0.0.1", "DNS:localhost"};
+
+ props.BasicConstraints = "critical,CA:TRUE";
+ props.AuthorityKeyIdentifier = "keyid:always,issuer";
+ props.SubjectKeyIdentifier = "hash";
+ props.KeyUsage = "critical,keyCertSign,cRLSign";
+ props.ExtKeyUsage = "";
+ props.NsComment = "Test Generated Certificate for self-signed CA";
+
+ return props;
+}
+
+TProps TProps::AsServer() {
+ TProps props = AsCA();
+
+ props.CommonName = "localhost";
+ props.AltNames.push_back("DNS:*.yandex.ru");
+
+ props.BasicConstraints = "CA:FALSE";
+ props.AuthorityKeyIdentifier = "keyid,issuer";
+ props.KeyUsage = "digitalSignature,nonRepudiation,keyEncipherment";
+ props.ExtKeyUsage = "serverAuth";
+ props.NsComment = "Test Generated Certificate for test Server";
+
+ return props;
+}
+
+TProps TProps::AsClient() {
+ TProps props = AsServer();
+
+ props.ExtKeyUsage = "clientAuth";
+ props.NsComment = "Test Generated Certificate for test Client";
+
+ return props;
+}
+
+TProps TProps::AsClientServer() {
+ TProps props = AsClient();
+
+ props.ExtKeyUsage = "serverAuth,clientAuth";
+ props.NsComment = "Test Generated Certificate for test Client/Server";
+
+ return props;
+}
+
+TProps& TProps::WithValid(TDuration duration) { SecondsValid = duration.Seconds(); return *this; }
+
+}
diff --git a/ydb/services/ydb/cert_gen.h b/ydb/services/ydb/cert_gen.h
new file mode 100644
index 00000000000..3de82e2e0e4
--- /dev/null
+++ b/ydb/services/ydb/cert_gen.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <util/datetime/base.h>
+
+#include <string>
+#include <vector>
+
+namespace NTest {
+
+ struct TCertAndKey {
+ std::string Certificate;
+ std::string PrivateKey;
+ };
+
+ struct TProps {
+ long SecondsValid = 0;
+ std::string Coutry; // C
+ std::string State; // ST
+ std::string Location; // L
+ std::string Organization; // O
+ std::string Unit; // OU
+ std::string CommonName; // CN
+
+ std::vector<std::string> AltNames; // X509v3 Subject Alternative Name
+
+ std::string BasicConstraints; // X509v3 Basic Constraints
+ std::string AuthorityKeyIdentifier; // X509v3 Authority Key Identifier
+ std::string SubjectKeyIdentifier; // X509v3 Subject Key Identifier
+ std::string KeyUsage; // X509v3 Key Usage
+ std::string ExtKeyUsage; // X509v3 Extended Key Usage
+ std::string NsComment; // Netscape Comment
+
+ static TProps AsCA();
+ static TProps AsServer();
+ static TProps AsClient();
+ static TProps AsClientServer();
+
+ TProps& WithValid(TDuration duration);
+ };
+
+ TCertAndKey GenerateCA(const TProps& props);
+ TCertAndKey GenerateSignedCert(const TCertAndKey& ca, const TProps& props);
+ void VerifyCert(const std::string& cert, const std::string& caCert);
+};
+
diff --git a/ydb/services/ydb/ut/CMakeLists.darwin.txt b/ydb/services/ydb/ut/CMakeLists.darwin.txt
index 1fb9b5abfd9..52ffe38ec62 100644
--- a/ydb/services/ydb/ut/CMakeLists.darwin.txt
+++ b/ydb/services/ydb/ut/CMakeLists.darwin.txt
@@ -27,6 +27,8 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC
library-cpp-svnversion
kqp-ut-common
core-testlib-default
+ core-grpc_services-base
+ ydb-core-testlib
yql-minikql-dom
yql-minikql-jsonpath
public-lib-experimental
@@ -55,6 +57,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_index_table_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_import_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_client_certs_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_s3_internal_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_scripting_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_table_ut.cpp
@@ -66,6 +69,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_monitoring_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/json_udf.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/re2_udf.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/cert_gen.cpp
)
add_test(
NAME
diff --git a/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt b/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt
index 346b86dd319..49616e6f0ab 100644
--- a/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt
+++ b/ydb/services/ydb/ut/CMakeLists.linux-aarch64.txt
@@ -27,6 +27,8 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC
library-cpp-svnversion
kqp-ut-common
core-testlib-default
+ core-grpc_services-base
+ ydb-core-testlib
yql-minikql-dom
yql-minikql-jsonpath
public-lib-experimental
@@ -57,6 +59,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_index_table_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_import_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_client_certs_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_s3_internal_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_scripting_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_table_ut.cpp
@@ -68,6 +71,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_monitoring_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/json_udf.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/re2_udf.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/cert_gen.cpp
)
add_test(
NAME
diff --git a/ydb/services/ydb/ut/CMakeLists.linux.txt b/ydb/services/ydb/ut/CMakeLists.linux.txt
index 82a7bd8b799..27ff76b7b92 100644
--- a/ydb/services/ydb/ut/CMakeLists.linux.txt
+++ b/ydb/services/ydb/ut/CMakeLists.linux.txt
@@ -29,6 +29,8 @@ target_link_libraries(ydb-services-ydb-ut PUBLIC
library-cpp-svnversion
kqp-ut-common
core-testlib-default
+ core-grpc_services-base
+ ydb-core-testlib
yql-minikql-dom
yql-minikql-jsonpath
public-lib-experimental
@@ -59,6 +61,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_index_table_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_import_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_client_certs_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_s3_internal_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_scripting_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_table_ut.cpp
@@ -70,6 +73,7 @@ target_sources(ydb-services-ydb-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ydb_monitoring_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/json_udf.cpp
${CMAKE_SOURCE_DIR}/ydb/services/ydb/ut/re2_udf.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/services/ydb/cert_gen.cpp
)
add_test(
NAME
diff --git a/ydb/services/ydb/ydb_client_certs_ut.cpp b/ydb/services/ydb/ydb_client_certs_ut.cpp
new file mode 100644
index 00000000000..6fcc7a203a0
--- /dev/null
+++ b/ydb/services/ydb/ydb_client_certs_ut.cpp
@@ -0,0 +1,623 @@
+#include <library/cpp/testing/unittest/tests_data.h>
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <grpc++/client_context.h>
+#include <grpc++/create_channel.h>
+
+#include <ydb/core/base/storage_pools.h>
+#include <ydb/core/base/location.h>
+#include <ydb/core/protos/flat_scheme_op.pb.h>
+#include <ydb/core/scheme/scheme_tablecell.h>
+#include <ydb/core/testlib/test_client.h>
+#include <ydb/core/driver_lib/cli_config_base/config_base.h>
+#include <ydb/core/client/server/dynamic_node_auth_processor.h>
+
+#include <ydb/public/api/grpc/ydb_scheme_v1.grpc.pb.h>
+#include <ydb/public/api/grpc/ydb_operation_v1.grpc.pb.h>
+#include <ydb/public/api/grpc/ydb_table_v1.grpc.pb.h>
+#include <ydb/public/api/grpc/draft/dummy.grpc.pb.h>
+#include <ydb/public/api/protos/ydb_table.pb.h>
+
+#include <library/cpp/grpc/client/grpc_client_low.h>
+
+#include <google/protobuf/any.h>
+
+#include <ydb/library/yql/core/issue/yql_issue.h>
+#include <ydb/library/yql/public/issue/yql_issue.h>
+#include <ydb/library/yql/public/issue/yql_issue_message.h>
+
+#include <ydb/public/sdk/cpp/client/ydb_params/params.h>
+#include <ydb/public/sdk/cpp/client/ydb_result/result.h>
+#include <ydb/public/sdk/cpp/client/ydb_scheme/scheme.h>
+#include <ydb/public/sdk/cpp/client/ydb_table/table.h>
+#include <ydb/public/sdk/cpp/client/resources/ydb_resources.h>
+
+#include <ydb/public/lib/deprecated/kicli/kicli.h>
+
+#include "ydb_common_ut.h"
+#include "cert_gen.h"
+
+#include <util/generic/ymath.h>
+
+namespace NKikimr {
+
+using namespace Tests;
+using namespace NYdb;
+using namespace NYdb::NTable;
+using namespace NYdb::NScheme;
+
+struct TKikimrTestWithServerCert : TKikimrTestWithAuthAndSsl {
+ static constexpr bool SSL = true;
+
+ static const NTest::TCertAndKey& GetCACertAndKey() {
+ static const NTest::TCertAndKey ca = NTest::GenerateCA(NTest::TProps::AsCA());
+ return ca;
+ }
+
+ static const NTest::TCertAndKey& GetServertCert() {
+ static const NTest::TCertAndKey server = NTest::GenerateSignedCert(GetCACertAndKey(), NTest::TProps::AsServer());
+ return server;
+ }
+
+ static TString GetCaCrt() {
+ return GetCACertAndKey().Certificate.c_str();
+ }
+
+ static TString GetServerCrt() {
+ return GetServertCert().Certificate.c_str();
+ }
+
+ static TString GetServerKey() {
+ return GetServertCert().PrivateKey.c_str();
+ }
+};
+
+NKikimrConfig::TClientCertificateAuthorization::TSubjectTerm MakeSubjectTerm(TString name, const TVector<TString>& values, const TVector<TString>& suffixes = {}) {
+ NKikimrConfig::TClientCertificateAuthorization::TSubjectTerm term;
+ term.SetShortName(name);
+ for (const auto& val: values) {
+ *term.MutableValues()->Add() = val;
+ }
+ for (const auto& suf: suffixes) {
+ *term.MutableSuffixes()->Add() = suf;
+ }
+ return term;
+}
+
+using TKikimrServerWithOutCertVerification = TBasicKikimrWithGrpcAndRootSchema<TKikimrTestWithServerCert>;
+
+struct TKikimrServerWithCertVerification: public TBasicKikimrWithGrpcAndRootSchema<TKikimrTestWithServerCert> {
+ using TBase = TBasicKikimrWithGrpcAndRootSchema<TKikimrTestWithServerCert>;
+
+ TKikimrServerWithCertVerification()
+ : TBase(GetAppConfig())
+ {}
+
+ static NKikimrConfig::TAppConfig GetAppConfig() {
+ auto config = NKikimrConfig::TAppConfig();
+
+ config.MutableFeatureFlags()->SetEnableDynamicNodeAuthorization(true);
+
+ auto& dynNodeDefinition = *config.MutableClientCertificateAuthorization()->MutableDynamicNodeAuthorization();
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("C", {"RU"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("ST", {"MSK"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("L", {"MSK"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("O", {"YA"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("OU", {"UtTest"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("CN", {"localhost"}, {".yandex.ru"});
+
+ return config;
+ }
+};
+
+struct TKikimrServerWithCertVerificationAndWrongIndentity : public TBasicKikimrWithGrpcAndRootSchema<TKikimrTestWithServerCert> {
+ using TBase = TBasicKikimrWithGrpcAndRootSchema<TKikimrTestWithServerCert>;
+
+ TKikimrServerWithCertVerificationAndWrongIndentity()
+ : TBase(GetAppConfig())
+ {}
+
+ static NKikimrConfig::TAppConfig GetAppConfig() {
+ auto config = NKikimrConfig::TAppConfig();
+
+ config.MutableFeatureFlags()->SetEnableDynamicNodeAuthorization(true);
+
+ auto& dynNodeDefinition = *config.MutableClientCertificateAuthorization()->MutableDynamicNodeAuthorization();
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("C", {"WRONG"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("ST", {"MSK"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("L", {"MSK"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("O", {"YA"});
+ *dynNodeDefinition.AddSubjectTerms() = MakeSubjectTerm("OU", {"UtTest"});
+
+ return config;
+ }
+};
+
+Y_UNIT_TEST_SUITE(TGRpcClientCerts) {
+
+Y_UNIT_TEST(TestGenerateAndVerify) {
+ using namespace NTest;
+ TCertAndKey ca = GenerateCA(TProps::AsCA());
+
+ TCertAndKey server = GenerateSignedCert(ca, TProps::AsServer());
+ VerifyCert(server.Certificate, ca.Certificate);
+
+ TCertAndKey client = GenerateSignedCert(ca, TProps::AsClient());
+ VerifyCert(client.Certificate, ca.Certificate);
+
+ TCertAndKey clientServer = GenerateSignedCert(ca, TProps::AsClientServer());
+ VerifyCert(clientServer.Certificate, ca.Certificate);
+}
+
+Y_UNIT_TEST(TestClientCertAuthorizationParamsMatch) {
+ {
+ TDynamicNodeAuthorizationParams authParams;
+ TDynamicNodeAuthorizationParams::TDistinguishedName dn;
+ dn.AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("C").AddValue("RU"))
+ .AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("ST").AddValue("MSK"))
+ .AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("L").AddValue("MSK"))
+ .AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("O").AddValue("YA"))
+ .AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("OU").AddValue("UtTest"))
+ .AddRelativeDistinguishedName(TDynamicNodeAuthorizationParams::TRelativeDistinguishedName("CN").AddValue("localhost").AddSuffix(".yandex.ru"));
+ authParams.AddCertSubjectDescription(dn);
+
+ {
+ TMap<TString, TString> subjectTerms;
+ subjectTerms["C"] = "RU";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "localhost";
+
+ UNIT_ASSERT(authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+
+ {
+ TMap<TString, TString> subjectTerms;
+ subjectTerms["C"] = "RU";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "test.yandex.ru";
+
+ UNIT_ASSERT(authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+
+ {
+ TMap<TString, TString> subjectTerms;
+ subjectTerms["C"] = "RU";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "test.yandex.ru";
+ subjectTerms["ELSE"] = "WhatEver";
+
+ UNIT_ASSERT(authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+
+ {
+ TMap<TString, TString> subjectTerms;
+ subjectTerms["C"] = "WRONG";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "test.yandex.ru";
+
+ UNIT_ASSERT(!authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+
+ {
+ TMap<TString, TString> subjectTerms;
+ subjectTerms["C"] = "RU";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "test.not-yandex.ru";
+
+ UNIT_ASSERT(!authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+
+ {
+ TMap<TString, TString> subjectTerms;
+ //subjectTerms["C"] = "RU";
+ subjectTerms["ST"] = "MSK";
+ subjectTerms["L"] = "MSK";
+ subjectTerms["O"] = "YA";
+ subjectTerms["OU"] = "UtTest";
+ subjectTerms["CN"] = "test.yandex.ru";
+
+ UNIT_ASSERT(!authParams.IsSubjectDescriptionMatched(subjectTerms));
+ }
+ }
+}
+
+Y_UNIT_TEST(TestAllCertIsOk) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ const NTest::TCertAndKey& clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(),clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(!sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ UNIT_ASSERT_EQUAL(sessionValue.GetStatus(), EStatus::SUCCESS);
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestWrongCertIndentity) {
+ TKikimrServerWithCertVerificationAndWrongIndentity server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ const NTest::TCertAndKey& clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(), clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(!sessionValue.IsTransportError(), sessionValue.GetIssues().ToString()); // do not authorize table service through cert
+ UNIT_ASSERT_EQUAL(sessionValue.GetStatus(), EStatus::SUCCESS);
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestIncorrectUsageClientCertFails) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ const NTest::TCertAndKey& serverCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsServer()); // client or client-server is allowed, not just server
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(serverCert.Certificate.c_str(), serverCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestCorruptedCertFails) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+ if (clientServerCert.Certificate[50] != 'a') {
+ clientServerCert.Certificate[50] = 'a';
+ } else {
+ clientServerCert.Certificate[50] = 'b';
+ }
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(), clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestCorruptedKeyFails) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+ if (clientServerCert.PrivateKey[20] != 'a') {
+ clientServerCert.PrivateKey[20] = 'a';
+ } else {
+ clientServerCert.Certificate[20] = 'b';
+ }
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(), clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestExpiredCertFails) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer().WithValid(TDuration::Seconds(2)));
+
+ // wait intil cert expires
+ Sleep(TDuration::Seconds(10));
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(), clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestServerWithoutCertVerificationAndExpiredCertWorks) {
+ TKikimrServerWithOutCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer().WithValid(TDuration::Seconds(2)));
+
+ // wait intil cert expires
+ Sleep(TDuration::Seconds(10));
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .UseClientCertificate(clientServerCert.Certificate.c_str(), clientServerCert.PrivateKey.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(!sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ UNIT_ASSERT_EQUAL(sessionValue.GetStatus(), EStatus::SUCCESS);
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+Y_UNIT_TEST(TestClientWithoutCertPassed) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .UseSecureConnection(caCert.Certificate.c_str())
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(!sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ UNIT_ASSERT_EQUAL(sessionValue.GetStatus(), EStatus::SUCCESS);
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+ connection.Stop(true);
+}
+
+NClient::TKikimr GetKikimr(const TString& addr, const NTest::TCertAndKey& caCert, const NTest::TCertAndKey& clientServerCert) {
+ NGrpc::TGRpcClientConfig grpcConfig(addr, TDuration::Seconds(15));
+ grpcConfig.EnableSsl = true;
+ grpcConfig.SslCredentials = {.pem_root_certs = caCert.Certificate.c_str(),
+ .pem_private_key = clientServerCert.PrivateKey.c_str(),
+ .pem_cert_chain = clientServerCert.Certificate.c_str()};
+ grpcConfig.LoadBalancingPolicy = "round_robin";
+
+ return NClient::TKikimr(grpcConfig);
+}
+
+THolder<NClient::TRegistrationResult> TryToRegisterDynamicNode(
+ NClient::TKikimr& kikimr,
+ const TString &domainName,
+ const TString &nodeHost,
+ const TString &nodeAddress,
+ const TString &nodeResolveHost,
+ ui16 interconnectPort)
+{
+ auto registrant = kikimr.GetNodeRegistrant();
+
+ NActorsInterconnect::TNodeLocation location;
+ location.SetDataCenter("DataCenter");
+ location.SetRack("Rack");
+ location.SetUnit("Body");
+ TNodeLocation loc(location);
+
+ NActorsInterconnect::TNodeLocation legacy;
+ legacy.SetDataCenterNum(DataCenterFromString("DataCenter"));
+ legacy.SetRoomNum(0);
+ legacy.SetRackNum(RackFromString("Rack"));
+ legacy.SetBodyNum(2);
+ loc.InheritLegacyValue(TNodeLocation(legacy));
+
+ return MakeHolder<NClient::TRegistrationResult>
+ (registrant.SyncRegisterNode(ToString(domainName),
+ nodeHost,
+ interconnectPort,
+ nodeAddress,
+ nodeResolveHost,
+ std::move(loc),
+ false));
+}
+
+Y_UNIT_TEST(TestServerWithCertVerificationClientWithCertCallsRegisterNode) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+
+ NClient::TKikimr kikimr = GetKikimr(location, caCert, clientServerCert);
+
+ Cerr << "Trying to register node" << Endl;
+
+ auto resp = TryToRegisterDynamicNode(kikimr, "Root", "localhost", "localhost", "localhost", GetRandomPort());
+ UNIT_ASSERT_C(resp->IsSuccess(), resp->GetErrorMessage());
+
+ Cerr << "Register node result " << resp->Record().ShortUtf8DebugString() << Endl;
+}
+
+Y_UNIT_TEST(TestServerWithCertVerificationClientWithoutCertCallsRegisterNodeFails) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey noCert;
+
+ NClient::TKikimr kikimr = GetKikimr(location, caCert, noCert);
+
+ Cerr << "Trying to register node" << Endl;
+
+ auto resp = TryToRegisterDynamicNode(kikimr, "Root", "localhost", "localhost", "localhost", GetRandomPort());
+ UNIT_ASSERT_C(!resp->IsSuccess(), resp->GetErrorMessage());
+ UNIT_ASSERT_STRINGS_EQUAL(resp->GetErrorMessage(), "Cannot authorize node. Node has not provided certificate");
+
+ Cerr << "Register node result " << resp->Record().ShortUtf8DebugString() << Endl;
+}
+
+Y_UNIT_TEST(TestServerWithoutCertVerificationClientWithCertCallsRegisterNode) {
+ TKikimrServerWithOutCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+
+ NClient::TKikimr kikimr = GetKikimr(location, caCert, clientServerCert);
+
+ Cerr << "Trying to register node" << Endl;
+
+ auto resp = TryToRegisterDynamicNode(kikimr, "Root", "localhost", "localhost", "localhost", GetRandomPort());
+ UNIT_ASSERT_C(resp->IsSuccess(), resp->GetErrorMessage());
+
+ Cerr << "Register node result " << resp->Record().ShortUtf8DebugString() << Endl;
+}
+
+Y_UNIT_TEST(TestServerWithoutCertVerificationClientWithoutCertCallsRegisterNode) {
+ TKikimrServerWithOutCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey noCert;
+
+ NClient::TKikimr kikimr = GetKikimr(location, caCert, noCert);
+
+ Cerr << "Trying to register node" << Endl;
+
+ auto resp = TryToRegisterDynamicNode(kikimr, "Root", "localhost", "localhost", "localhost", GetRandomPort());
+ UNIT_ASSERT_C(resp->IsSuccess(), resp->GetErrorMessage());
+
+ Cerr << "Register node result " << resp->Record().ShortUtf8DebugString() << Endl;
+}
+
+Y_UNIT_TEST(TestServerWithWrongIndentityClientWithCertCallsRegisterNodeFails) {
+ TKikimrServerWithCertVerificationAndWrongIndentity server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ const NTest::TCertAndKey& caCert = TKikimrTestWithServerCert::GetCACertAndKey();
+ NTest::TCertAndKey clientServerCert = NTest::GenerateSignedCert(caCert, NTest::TProps::AsClientServer());
+
+ NClient::TKikimr kikimr = GetKikimr(location, caCert, clientServerCert);
+
+ Cerr << "Trying to register node" << Endl;
+
+ auto resp = TryToRegisterDynamicNode(kikimr, "Root", "localhost", "localhost", "localhost", GetRandomPort());
+ UNIT_ASSERT_C(!resp->IsSuccess(), resp->GetErrorMessage());
+ UNIT_ASSERT_STRINGS_EQUAL(resp->GetErrorMessage(), "Cannot authorize node by certificate");
+
+ Cerr << "Register node result " << resp->Record().ShortUtf8DebugString() << Endl;
+}
+
+Y_UNIT_TEST(TestInsecureClient) {
+ TKikimrServerWithCertVerification server;
+ ui16 grpc = server.GetPort();
+ TString location = TStringBuilder() << "localhost:" << grpc;
+
+ auto connection = NYdb::TDriver(
+ TDriverConfig()
+ .SetAuthToken("test_user@builtin")
+ .SetEndpoint(location));
+
+ auto client = NYdb::NTable::TTableClient(connection);
+ std::function<void(const TAsyncCreateSessionResult& future)> createSessionHandler =
+ [client] (const TAsyncCreateSessionResult& future) mutable {
+ const auto& sessionValue = future.GetValue();
+ UNIT_ASSERT_C(sessionValue.IsTransportError(), sessionValue.GetIssues().ToString());
+ };
+
+ client.CreateSession().Apply(createSessionHandler).Wait();
+
+ connection.Stop(true);
+}
+
+}
+
+} // namespace NKikimr
diff --git a/ydb/services/ydb/ydb_common_ut.h b/ydb/services/ydb/ydb_common_ut.h
index 98dd10c49f7..e8b4fa75bdf 100644
--- a/ydb/services/ydb/ydb_common_ut.h
+++ b/ydb/services/ydb/ydb_common_ut.h
@@ -25,6 +25,12 @@ struct TKikimrTestSettings {
static constexpr bool AUTH = false;
static constexpr bool PrecreatePools = true;
static constexpr bool EnableSystemViews = true;
+
+ static TString GetCaCrt() { return NYdbSslTestData::CaCrt; }
+ static TString GetServerCrt() { return NYdbSslTestData::ServerCrt; }
+ static TString GetServerKey() { return NYdbSslTestData::ServerKey; }
+
+ static NKikimr::TDynamicNodeAuthorizationParams GetCertAuthParams() {return {}; }
};
struct TKikimrTestWithAuth : TKikimrTestSettings {
@@ -114,9 +120,12 @@ public:
}
grpcOption.SetPort(grpc);
if (TestSettings::SSL) {
- NGrpc::TSslData sslData{NYdbSslTestData::ServerCrt,
- NYdbSslTestData::ServerKey,
- NYdbSslTestData::CaCrt};
+ NGrpc::TSslData sslData;
+ sslData.Cert = TestSettings::GetServerCrt();
+ sslData.Key = TestSettings::GetServerKey();
+ sslData.Root =TestSettings::GetCaCrt();
+ sslData.DoRequestClientCertificate = appConfig.GetFeatureFlags().GetEnableDynamicNodeAuthorization() && appConfig.GetClientCertificateAuthorization().HasDynamicNodeAuthorization();
+
grpcOption.SetSslData(sslData);
}
Server_->EnableGRpc(grpcOption);