From 63b84367248be63a61066d3d764ac858b7fed1e8 Mon Sep 17 00:00:00 2001 From: Tao He Date: Fri, 24 Sep 2021 01:02:32 +0800 Subject: [PATCH] Add an optional `target_name_override` to support multiple-endpoints with SSL. Resolves #87. Signed-off-by: Tao He --- README.md | 33 +++++++++++++++++++++++++++++++++ etcd/Client.hpp | 5 +++++ src/Client.cpp | 15 ++++++++++----- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5cf79e4..24b281d 100644 --- a/README.md +++ b/README.md @@ -238,6 +238,39 @@ transport security using openssl. We also provide a tool [`setup-ca.sh`](./security-config/setup-ca.sh) as a helper for development and testing. +#### transport security & Multiple endpoints + +If you want to use multiple `https://` endpoints, and you are working with self-signed certificates, you +may encountered errors like + +``` +error: 14: connections to all backends failing +``` + +That means your DNS have some problems with your DNS resolver and SSL authority, you could put a domain +name (a host name) to the `SANS` field when self-signing your certificate, e.g, + +``` +"sans": [ + "etcd", + "127.0.0.1", + "127.0.0.2", + "127.0.0.3" +], +``` + +And pass a `target_name_override` arguments to `WithSSL`, + +```cpp + etcd::Client *etcd = etcd::Client::WithSSL( + "https://127.0.0.1:2379,https://127.0.0.2:2479", + "example.rootca.cert", "example.cert", "example.key", "etcd"); + +``` + +For more discussion about this feature, see also [#87](https://github.com/etcd-cpp-apiv3/etcd-cpp-apiv3/issues/87), +[grpc#20186](https://github.com/grpc/grpc/issues/20186) and [grpc#22119](https://github.com/grpc/grpc/issues/22119). + ### Reading a value You can read a value with the `get()` method of the client instance. The only parameter is the diff --git a/etcd/Client.hpp b/etcd/Client.hpp index c0d6f2a..8fe2548 100644 --- a/etcd/Client.hpp +++ b/etcd/Client.hpp @@ -98,6 +98,7 @@ namespace etcd std::string const & ca, std::string const & cert, std::string const & key, + std::string const & target_name_override, std::string const & load_balancer); /** @@ -108,12 +109,16 @@ namespace etcd * @param ca root CA file for SSL/TLS connection. * @param cert cert chain file for SSL/TLS authentication, could be empty string. * @param key private key file for SSL/TLS authentication, could be empty string. + * @param target_name_override Override the target host name if you want to pass multiple address + * for load balancing with SSL, and there's no DNS. The @target_name_override@ must exist in the + * SANS of your SSL certificate. * @param load_balancer is the load balance strategy, can be one of round_robin/pick_first/grpclb/xds. */ static etcd::Client *WithSSL(std::string const & etcd_url, std::string const & ca, std::string const & cert = "", std::string const & key = "", + std::string const & target_name_override = "", std::string const & load_balancer = "round_robin"); /** diff --git a/src/Client.cpp b/src/Client.cpp index deebb18..4bb042a 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -239,6 +239,7 @@ etcd::Client::Client(std::string const & address, std::string const & ca, std::string const & cert, std::string const & key, + std::string const & target_name_override, std::string const & load_balancer) { // create channels @@ -249,6 +250,9 @@ etcd::Client::Client(std::string const & address, std::shared_ptr creds = grpc::SslCredentials( etcd::detail::make_ssl_credentials(ca, cert, key)); grpc_args.SetLoadBalancingPolicyName(load_balancer); + if (!target_name_override.empty()) { + grpc_args.SetString(GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, target_name_override); + } this->channel = grpc::CreateCustomChannel(addresses, creds, grpc_args); // setup stubs @@ -261,11 +265,12 @@ etcd::Client::Client(std::string const & address, } etcd::Client *etcd::Client::WithSSL(std::string const & etcd_url, - std::string const & ca, - std::string const & cert, - std::string const & key, - std::string const & load_balancer) { - return new etcd::Client(etcd_url, ca, cert, key, load_balancer); + std::string const & ca, + std::string const & cert, + std::string const & key, + std::string const & target_name_override, + std::string const & load_balancer) { + return new etcd::Client(etcd_url, ca, cert, key, target_name_override, load_balancer); } pplx::task etcd::Client::head()