Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added grpc ssl config #628

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmake/GrpcTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ function(userver_generate_grpc_files)
"--plugin=protoc-gen-grpc=${PROTO_GRPC_CPP_PLUGIN}"
"--plugin=protoc-gen-usrv=${PROTO_GRPC_USRV_PLUGIN}"
"--plugin=protoc-gen-grpc_python=${PROTO_GRPC_PYTHON_PLUGIN}"
"--experimental_allow_proto3_optional"
)

set(proto_abs_paths)
Expand Down
3 changes: 3 additions & 0 deletions grpc/include/userver/ugrpc/server/impl/service_worker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ struct ServiceSettings final {
Middlewares middlewares;
logging::LoggerPtr access_tskv_logger;
const dynamic_config::Source config_source;
std::optional<std::string> end_point;
};

/// @brief Listens to requests for a gRPC service, forwarding them to a
Expand All @@ -49,6 +50,8 @@ class ServiceWorker {
/// Get the static per-gRPC-service metadata provided by codegen
virtual const ugrpc::impl::StaticServiceMetadata& GetMetadata() const = 0;

virtual const std::optional<std::string> EndPoint() const = 0;

/// Start serving requests. Should be called after the grpcpp server starts.
virtual void Start() = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ class ServiceWorkerImpl final : public ServiceWorker {
return service_data_.metadata;
}

const std::optional<std::string> EndPoint() const override {
return service_data_.settings.end_point;
}

void Start() override { start_(); }

private:
Expand Down
29 changes: 29 additions & 0 deletions grpc/include/userver/ugrpc/server/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,46 @@
#include <userver/ugrpc/server/middlewares/fwd.hpp>
#include <userver/ugrpc/server/service_base.hpp>

#include <userver/formats/parse/common_containers.hpp>
#include <userver/dynamic_config/storage/component.hpp>
#include <userver/dynamic_config/value.hpp>
#include <userver/yaml_config/merge_schemas.hpp>
#include <userver/yaml_config/yaml_config.hpp>

USERVER_NAMESPACE_BEGIN

namespace ugrpc::server {

struct SslConf
{
int port;
std::string server_cert;
std::string server_private_key;
std::string client_root_cert;
bool need_verify_client_cert;
};

inline SslConf Parse(const userver::yaml_config::YamlConfig& cfg, userver::formats::parse::To<SslConf>)
{
return SslConf
{
cfg["port"].As<int>(),
cfg["server_cert"].As<std::string>(),
cfg["server_private_key"].As<std::string>(),
cfg["client_root_cert"].As<std::string>(""),
cfg["verify_client_cert"].As<bool>(false)
};
}

/// Settings relating to the whole gRPC server
struct ServerConfig final {
/// The port to listen to. If `0`, a free port will be picked automatically.
/// If none, the ports have to be configured programmatically using
/// Server::WithServerBuilder.
std::optional<int> port{0};

std::optional<SslConf> sslConf;

/// Absolute path to the unix socket to listen to.
/// A server can listen to both port and unix socket simultaneously.
std::optional<std::string> unix_socket_path{std::nullopt};
Expand Down
1 change: 1 addition & 0 deletions grpc/include/userver/ugrpc/server/service_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct ServiceConfig final {

/// Server middlewares to use for the gRPC service.
Middlewares middlewares;
std::optional<std::string> end_point;
};

/// @brief The type-erased base class for all gRPC service implementations
Expand Down
2 changes: 2 additions & 0 deletions grpc/src/ugrpc/server/impl/parse_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ server::ServiceConfig ParseServiceConfig(
MergeField(value[kMiddlewaresKey], defaults.middleware_names, context,
ParseMiddlewares),
context),
value["end-point"].As<std::optional<std::string>>()
};
}

Expand All @@ -97,6 +98,7 @@ ServerConfig ParseServerConfig(const yaml_config::YamlConfig& value,
config.unix_socket_path =
value["unix-socket-path"].As<std::optional<std::string>>();
config.port = value["port"].As<std::optional<int>>();
config.sslConf = value["ssl-conf"].As<std::optional<SslConf>>();
config.completion_queue_num = value["completion-queue-count"].As<int>(2);
config.channel_args =
value["channel-args"].As<decltype(config.channel_args)>({});
Expand Down
70 changes: 69 additions & 1 deletion grpc/src/ugrpc/server/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
#include <userver/ugrpc/server/impl/queue_holder.hpp>
#include <userver/ugrpc/server/impl/service_worker.hpp>


#include <grpcpp/impl/server_builder_option.h>
#include <grpcpp/impl/server_builder_plugin.h>
#include <grpcpp/security/authorization_policy_provider.h>
#include <grpcpp/server.h>
#include <grpcpp/support/config.h>
#include <userver/fs/blocking/read.hpp>

USERVER_NAMESPACE_BEGIN

namespace ugrpc::server {
Expand Down Expand Up @@ -106,13 +114,16 @@ class Server::Impl final {

void AddListeningPort(int port);

void AddSslConfiguration(const SslConf& conf);

void AddListeningUnixSocket(std::string_view path);

void DoStart();

State state_{State::kConfiguration};
std::optional<grpc::ServerBuilder> server_builder_;
std::optional<int> port_;
std::optional<int> ssl_port_;
std::vector<std::unique_ptr<impl::ServiceWorker>> service_workers_;
std::optional<impl::QueueHolder> queue_;
std::unique_ptr<grpc::Server> server_;
Expand Down Expand Up @@ -148,6 +159,11 @@ Server::Impl::Impl(ServerConfig&& config,
if (config.unix_socket_path) AddListeningUnixSocket(*config.unix_socket_path);

if (config.port) AddListeningPort(*config.port);

if (config.sslConf)
{
AddSslConfiguration(*config.sslConf);
}
}

Server::Impl::~Impl() {
Expand All @@ -159,6 +175,47 @@ Server::Impl::~Impl() {
}
}

void Server::Impl::AddSslConfiguration(const SslConf& config)
{
LOG_INFO() << "Configuring the gRPC server with ssl config";
UINVARIANT(config.port >= 0 && config.port <= 65535, "Invalid gRPC listening ssl port");
UASSERT_MSG(!ssl_port_,
"As of now, AddSslConfiguration can be called no more than once");
ssl_port_ = config.port;
grpc::SslServerCredentialsOptions ssl_opts;
try {
auto server_key =
userver::fs::blocking::ReadFileContents(config.server_private_key);
auto server_cert =
userver::fs::blocking::ReadFileContents(config.server_cert);
if (config.need_verify_client_cert) {
ssl_opts.client_certificate_request =
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY;
if (!config.client_root_cert.empty()) {
ssl_opts.pem_root_certs =
userver::fs::blocking::ReadFileContents(config.client_root_cert);
} else {
LOG_INFO() << "Client root cert is not provided, try to find it in system certs";
}
} else {
ssl_opts.client_certificate_request =
GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY;
}
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {server_key,
server_cert};
ssl_opts.pem_key_cert_pairs.push_back(pkcp);
}
catch (const std::exception& ex) {
LOG_ERROR() << "The gRPC server failed to add ssl configuration. " << ex;
throw;
}
auto server_creds = SslServerCredentials(ssl_opts);
const auto uri = fmt::format("[::]:{}", ssl_port_.value());
LOG_INFO() << "Add ssl listening port "<<ssl_port_.value();
server_builder_->AddListeningPort(ugrpc::impl::ToGrpcString(uri),
server_creds, &*ssl_port_);
}

void Server::Impl::AddListeningPort(int port) {
std::lock_guard lock(configuration_mutex_);
UASSERT(state_ == State::kConfiguration);
Expand Down Expand Up @@ -200,6 +257,7 @@ void Server::Impl::AddService(ServiceBase& service, ServiceConfig&& config) {
std::move(config.middlewares),
access_tskv_logger_,
config_source_,
config.end_point
}));
}

Expand Down Expand Up @@ -290,7 +348,17 @@ void Server::Impl::DoStart() {
"Multiple services have been registered "
"for the same gRPC method");
for (auto& worker : service_workers_) {
server_builder_->RegisterService(&worker->GetService());
auto end_point = worker->EndPoint();
if(end_point)
{
LOG_INFO() << "Register service to endpoint "<<end_point.value();
server_builder_->RegisterService(end_point.value(), &worker->GetService());
}
else
{
LOG_INFO() << "Register service wo endpoint ";
server_builder_->RegisterService(&worker->GetService());
}
}

server_ = server_builder_->BuildAndStart();
Expand Down
20 changes: 20 additions & 0 deletions grpc/src/ugrpc/server/server_component.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,26 @@ additionalProperties: false
port:
type: integer
description: the port to use for all gRPC services, or 0 to pick any available
ssl-conf:
type: object
description: ssl conf for grpc server
properties:
port:
type: integer
description: the port to use for all gRPC services, or 0 to pick any available
server_cert:
type: string
description: server ssl cert
server_private_key:
type: string
description: server ssl private key
client_root_cert:
type: string
description: client ssl root cert
verify_client_cert:
type: boolean
description: verify client cert
additionalProperties: false
unix-socket-path:
type: string
description: unix socket absolute path
Expand Down
3 changes: 3 additions & 0 deletions grpc/src/ugrpc/server/service_component_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ additionalProperties: false
items:
type: string
description: middleware component name
end-point:
type: string
description: service endpoint
)");
}

Expand Down
Loading