From 197224ef72e503445dc85ad520f999f4bbc6ef42 Mon Sep 17 00:00:00 2001
From: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
Date: Mon, 28 Mar 2022 13:11:45 +0200
Subject: [PATCH] cta-dcache: add possibility to use gRPC over TLS

the new conf options to cta.conf file is added:

gRPC TlsCert /path/to/cert.pem
gRPC TlsKey /path/to/key.pem
gRPC TlsChain /path/to/chain.pem
---
 cta-dcache/FrontendGRpcSvc.h    |  1 +
 cta-dcache/Main.cpp             | 36 ++++++++++++++++++++++++++++++---
 cta-dcache/cta-dcache.1cta      |  5 +++++
 cta-dcache/cta-dcache.service   |  2 +-
 cta-dcache/cta-dcache.sysconfig |  5 ++++-
 5 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/cta-dcache/FrontendGRpcSvc.h b/cta-dcache/FrontendGRpcSvc.h
index 3fd112de6c..ee155e11a7 100644
--- a/cta-dcache/FrontendGRpcSvc.h
+++ b/cta-dcache/FrontendGRpcSvc.h
@@ -3,6 +3,7 @@
 
 #include "version.h"
 #include <grpcpp/grpcpp.h>
+#include <grpcpp/security/server_credentials.h>
 
 #include <scheduler/Scheduler.hpp>
 #include "common/log/Logger.hpp"
diff --git a/cta-dcache/Main.cpp b/cta-dcache/Main.cpp
index 8e43d8533c..d6c00febb9 100644
--- a/cta-dcache/Main.cpp
+++ b/cta-dcache/Main.cpp
@@ -40,7 +40,8 @@ std::string help =
         "\t--port <port>, -p <port>:\tTCP port number to use, defaults to 17017\n"
         "\t--log-header, -n         \tadd hostname and timestamp to log outputs, default\n"
         "\t--no-log-header, -s      \tdon't add hostname and timestamp to log outputs\n"
-        "\t--version, -v            \tprint version and exit.\n"
+        "\t--tls, -t                \tenable Transport Layer Security (TLS)\n"
+        "\t--version, -v            \tprint version and exit\n"
         "\t--help, -h               \tprint this help and exit\n";
 
 static struct option long_options[] =
@@ -49,7 +50,8 @@ static struct option long_options[] =
                 {"log-header", no_argument, 0, 'n'},
                 {"no-log-header", no_argument, 0, 's'},
                 {"help", no_argument, 0, 'h'},
-                { "version", no_argument, 0, 'v'},
+                {"version", no_argument, 0, 'v'},
+                {"tls", no_argument, 0, 't'},
                 {0, 0, 0, 0}
         };
 
@@ -63,6 +65,13 @@ void printVersionAndExit() {
     exit(0);
 }
 
+std::string file2string(std::string filename){
+    std::ifstream as_stream(filename);
+    std::ostringstream as_string;
+    as_string << as_stream.rdbuf();
+    return as_string.str();
+}
+
 int main(const int argc, char *const *const argv) {
 
     std::string port = "17017";
@@ -71,6 +80,7 @@ int main(const int argc, char *const *const argv) {
     bool shortHeader = false;
     int option_index = 0;
     const std::string shortHostName = utils::getShortHostname();
+    bool useTLS = false;
 
     while( (c = getopt_long(argc, argv, "p:nshv", long_options, &option_index)) != EOF) {
 
@@ -90,6 +100,9 @@ int main(const int argc, char *const *const argv) {
             case 'v':
                 printVersionAndExit();
                 break;
+            case 't':
+                useTLS = true;
+                break;
             default:
                 printHelpAndExit(1);
         }
@@ -137,8 +150,25 @@ int main(const int argc, char *const *const argv) {
     // start gRPC service
 
     ServerBuilder builder;
+
+    std::shared_ptr<grpc::ServerCredentials> creds;
+
+    if (useTLS) {
+        grpc::SslServerCredentialsOptions tls_options;
+        grpc::SslServerCredentialsOptions::PemKeyCertPair cert;
+
+        cert.private_key = file2string(config.getConfEntString("gRPC", "TlsKey"));
+        cert.cert_chain = file2string(config.getConfEntString("gRPC", "TlsCert"));
+        tls_options.pem_root_certs = file2string(config.getConfEntString("gRPC", "TlsChain"));
+        tls_options.pem_key_cert_pairs.emplace_back(std::move(cert));
+
+        creds = grpc::SslServerCredentials(tls_options);
+    } else {
+        creds = grpc::InsecureServerCredentials();
+    }
+
     // Listen on the given address without any authentication mechanism.
-    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+    builder.AddListeningPort(server_address, creds);
 
     // Register "service" as the instance through which we'll communicate with
     // clients. In this case it corresponds to an *synchronous* service.
diff --git a/cta-dcache/cta-dcache.1cta b/cta-dcache/cta-dcache.1cta
index 5648c8990f..5909032e9f 100644
--- a/cta-dcache/cta-dcache.1cta
+++ b/cta-dcache/cta-dcache.1cta
@@ -38,6 +38,11 @@ Include timestamp and host name into the log messages.
 \fB\-s, \-\-no\-log\-header
 Don't include timestamp and host name into the log messages, default behaviour.
 .TP
+\fB\-t, \-\-tls
+Enable TLS for communication. The paths to the TLS certificate, key and root-ca chan files in PEM
+format should be specified by '\fBgRPC TlsCert\fP', '\fBgRPC TlsKey\fP' and '\fBgRPC TlsChain\fP'
+in the cta.conf configuration file.
+.TP
 \fB\-v, \-\-version
 Print the version number and exit.
 
diff --git a/cta-dcache/cta-dcache.service b/cta-dcache/cta-dcache.service
index 3992409e17..8f1bb0bf0e 100644
--- a/cta-dcache/cta-dcache.service
+++ b/cta-dcache/cta-dcache.service
@@ -4,7 +4,7 @@ After=syslog.target network-online.target
 
 [Service]
 EnvironmentFile=/etc/sysconfig/cta-dcache
-ExecStart=/usr/bin/cta-dcache --no-log-header --port ${GRPC_PORT}
+ExecStart=/usr/bin/cta-dcache --no-log-header ${GRPC_USE_TLS} --port ${GRPC_PORT}
 Type=simple
 Restart=always
 User=cta
diff --git a/cta-dcache/cta-dcache.sysconfig b/cta-dcache/cta-dcache.sysconfig
index 0e963b5189..185b4e9630 100644
--- a/cta-dcache/cta-dcache.sysconfig
+++ b/cta-dcache/cta-dcache.sysconfig
@@ -3,4 +3,7 @@
 #
 
 # port number to accept TCP connections
-GRPC_PORT=17017
\ No newline at end of file
+GRPC_PORT=17017
+
+# change to '--tls' to enable
+GRPC_USE_TLS=""
\ No newline at end of file
-- 
GitLab