Add support for gRPC authenticated communications

Also, make a few namespace corrections and some minor refactoring.

Change-Id: Iedcaf6b43cb7576bc11dfefe980abd190c838831


[ROCm/rdc commit: 47fdfa4c7e]
Esse commit está contido em:
Chris Freehill
2020-03-02 15:06:01 -06:00
commit 2f59e7e1ab
28 arquivos alterados com 824 adições e 43 exclusões
+249 -19
Ver Arquivo
@@ -29,6 +29,7 @@ THE SOFTWARE.
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/capability.h>
#include <getopt.h>
#include <iostream>
#include <memory>
@@ -41,6 +42,17 @@ THE SOFTWARE.
#include "rdc/rdc_rsmi_service.h"
#include "rdc/rdc_api_service.h"
#include "rdc/rdc_server_utils.h"
#include "common/rdc_utils.h"
// TODO(cfreehil):
// The following need to be made configurable (e.g., from YAML):
// * location of ssl keys and certificates
// * which method of authentication to use (with root CA or not)
// * wether server accepts only unauthenticated connections or only
// authenticated
// * rsmi_init flags
// * which RDC grpc services to start
// * port on which to listen
static bool sShutDownServer = false;
static bool sRestartServer = false;
@@ -48,24 +60,143 @@ static const char *kDaemonName = "rdcd";
static const char *kRDCDHomeDir = "/";
static const char *kDaemonLockFile = "/var/run/rdcd.lock";
RDCServer::RDCServer() : server_address_("0.0.0.0:50051"),
rsmi_service_(nullptr), rdc_admin_service_(nullptr) {
// Pinned certificates
static const char * kDefaultRDCServerCertPinPath =
"/etc/rdc/server/rdc_server.crt";
static const char * kDefaultRDCServerKeyPinPath =
"/etc/rdc/server/private/rdc_server.key";
static const char * kDefaultRDCClientCertPinPath =
"/etc/rdc/client/rdc_client.crt";
// PKI certificates
static const char * kDefaultRDCServerCertKeyPkiPath =
"/etc/rdc/server/private/rdc_server_cert.key";
static const char * kDefaultRDCServerCertPemPkiPath =
"/etc/rdc/server/certs/rdc_server_cert.pem";
static const char * kDefaultRDCClientCACertPemPkiPath =
"/etc/rdc/client/certs/rdc_cacert.pem";
static const char *kDefaultListenPort = "50051";
RDCServer::RDCServer() : server_address_("0.0.0.0:"),
secure_creds_(false), rsmi_service_(nullptr), rdc_admin_service_(nullptr) {
}
RDCServer::~RDCServer() {
}
// TODO(cfreehil): resolve here command line options with
// (future) config file options
void
RDCServer::Initialize() {
RDCServer::Initialize(RdcdCmdLineOpts *cl) {
cmd_line_ = cl;
server_address_ += cmd_line_->listen_port;
secure_creds_ = !cmd_line_->no_authentication;
use_pinned_certs_ = cmd_line_->use_pinned_certs;
log_debug_ = cmd_line_->log_dbg;
}
static int ConstructSSLOptsPin(grpc::SslServerCredentialsOptions *ssl_opts) {
assert(ssl_opts != nullptr);
if (ssl_opts == nullptr) {
return -EINVAL;
}
// Ensure the required paths exists before going forward
if (!amd::rdc::FileExists(kDefaultRDCServerKeyPinPath) ||
!amd::rdc::FileExists(kDefaultRDCServerCertPinPath) ||
!amd::rdc::FileExists(kDefaultRDCClientCertPinPath)) {
return -ENOENT;
}
std::string ser_key;
std::string ser_crt;
std::string cli_crt;
int ret;
ret = amd::rdc::ReadFile(kDefaultRDCServerKeyPinPath, &ser_key);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCServerCertPinPath, &ser_crt);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCClientCertPinPath, &cli_crt);
if (ret) {
return ret;
}
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {ser_key, ser_crt};
ssl_opts->client_certificate_request =
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
ssl_opts->pem_root_certs = cli_crt;
ssl_opts->pem_key_cert_pairs.push_back(pkcp);
return 0;
}
static int ConstructSSLOptsPKI(grpc::SslServerCredentialsOptions *ssl_opts) {
assert(ssl_opts != nullptr);
if (ssl_opts == nullptr) {
return -EINVAL;
}
// Ensure the required paths exists before going forward
if (!amd::rdc::FileExists(kDefaultRDCServerCertKeyPkiPath) ||
!amd::rdc::FileExists(kDefaultRDCServerCertPemPkiPath) ||
!amd::rdc::FileExists(kDefaultRDCClientCACertPemPkiPath)) {
return -ENOENT;
}
std::string ser_key;
std::string ser_crt;
std::string cli_crt;
int ret;
ret = amd::rdc::ReadFile(kDefaultRDCServerCertKeyPkiPath, &ser_key);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCServerCertPemPkiPath, &ser_crt);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCClientCACertPemPkiPath, &cli_crt);
if (ret) {
return ret;
}
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {ser_key, ser_crt};
ssl_opts->client_certificate_request =
GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
ssl_opts->pem_root_certs = cli_crt;
ssl_opts->pem_key_cert_pairs.push_back(pkcp);
return 0;
}
// TODO(cfreehil): read server config from YAML file. Config can include things
// like server address, Secure/Insecure creds, rsmi_init flags, etc.
void
RDCServer::Run() {
::grpc::ServerBuilder builder;
// Listen on the given address without any authentication mechanism.
builder.AddListeningPort(server_address_, grpc::InsecureServerCredentials());
int ret;
if (secure_creds_) {
grpc::SslServerCredentialsOptions ssl_opts{};
if (use_pinned_certs_) {
ret = ConstructSSLOptsPin(&ssl_opts);
} else {
ret = ConstructSSLOptsPKI(&ssl_opts);
}
if (ret) {
std::cerr << "Failed to process OpenSSL keys and certificates. Errno: "
<< -ret << std::endl;
return;
}
builder.AddListeningPort(server_address_,
grpc::SslServerCredentials(ssl_opts));
} else {
builder.AddListeningPort(server_address_,
grpc::InsecureServerCredentials());
}
// Register services as the instances through which we'll communicate with
// clients. These are synchronous services.
@@ -78,11 +209,10 @@ RDCServer::Run() {
rsmi_service_ = new amd::rdc::RsmiServiceImpl();
builder.RegisterService(rsmi_service_);
// TODO(cfreehil): pass flags from cnfg file
rsmi_status_t ret = rsmi_service_->Initialize(0);
if (ret != RSMI_STATUS_SUCCESS) {
std::cerr << "Failed to start RSMI service" << std::endl;
std::cerr << "Failed to start RSMI service. ret = " << ret << std::endl;
return;
}
}
@@ -104,8 +234,10 @@ RDCServer::Run() {
// std::unique_ptr<::grpc::Server> server(builder.BuildAndStart());
server_ = builder.BuildAndStart();
std::cout << "Server listening on " << server_address_.c_str() << std::endl;
std::cout << "Server listening on " << server_address_.c_str() << std::endl;
std::cout << "Accepting " <<
(secure_creds_ ? "Authenticated" : "Unauthenticated") <<
" connections only." << std::endl;
server_->Wait();
}
@@ -263,20 +395,118 @@ MakeDaemon() {
InitializeSignalHandling();
}
// Group arguments by type, in this order:
// * required_argument
// * optional_argument
// * no_argument
static const struct option long_options[] = {
{"port", required_argument, nullptr, 'p'},
// Any options with optionals args would go here; e.g.,
// {"start_rdcd", optional_argument, nullptr, 'd'},
{"unauth_comm", no_argument, nullptr, 'u'},
{"pinned_cert", no_argument, nullptr, 'i'},
{"debug", no_argument, nullptr, 'd'},
{"help", no_argument, nullptr, 'h'},
{nullptr, 0, nullptr, 0}
};
static const char* short_options = "p:uidh";
static void PrintHelp(void) {
std::cout <<
"Optional rdctst Arguments:\n"
"--port, -p <port> specify port on which to listen; "
"default is to listen on port 50051\n"
"--unauth_comm, -u don't do authentication with communications"
" with client. When this flag is not specified, by default, "
"PKI authentication is used\n"
"--pinned_cert, -i used \"pinned\" certificates instead of PKI "
"authentication. This is for test purposes.\n"
"--debug, -d output debug messages\n"
"--help, -h print this message\n";
}
uint32_t ProcessCmdline(RdcdCmdLineOpts* cmdl_opts,
int arg_cnt, char** arg_list) {
int a;
int ind = -1;
assert(cmdl_opts != nullptr);
while (true) {
a = getopt_long(arg_cnt, arg_list, short_options, long_options, &ind);
if (a == -1) {
break;
}
switch (a) {
case 'p':
if (!amd::rdc::IsNumber(optarg)) {
std::cerr << "\"" << optarg <<
"\" is not a valid port number." << std::endl;
return -1;
}
cmdl_opts->listen_port = optarg;
break;
case 'u':
cmdl_opts->no_authentication = true;
break;
case 'i':
cmdl_opts->use_pinned_certs = true;
break;
case 'd':
cmdl_opts->log_dbg = true;
break;
case 'h':
PrintHelp();
exit(0);
default:
std::cout << "Unknown command line option: \"" << a <<
"\". Ignoring..." << std::endl;
PrintHelp();
return 0;
}
}
// Check for incompatibilities
if (cmdl_opts->use_pinned_certs && cmdl_opts->no_authentication) {
std::cerr << "--pinned_cert and --unauth_comm are incompatible options."
<< std::endl;
return -1;
}
return 0;
}
static void init_cmd_line_opts(RdcdCmdLineOpts *opts) {
assert(opts != nullptr);
opts->listen_port = kDefaultListenPort;
opts->no_authentication = false;
opts->use_pinned_certs = false;
opts->log_dbg = false;
}
int main(int argc, char** argv) {
RDCServer rdc_server;
RdcdCmdLineOpts cmd_line_opts;
int err;
(void)argc; // Ignore for now
(void)argv;
init_cmd_line_opts(&cmd_line_opts);
ProcessCmdline(&cmd_line_opts, argc, argv);
MakeDaemon();
rdc_server.Initialize();
rdc_server.Initialize(&cmd_line_opts);
bool cap_enabled;
err = GetCapability(CAP_DAC_OVERRIDE, CAP_EFFECTIVE, &cap_enabled);
err =
::amd::rdc::GetCapability(CAP_DAC_OVERRIDE, CAP_EFFECTIVE, &cap_enabled);
if (err) {
std::cerr << "Failed to get capability" << std::endl;
return 1;
@@ -288,7 +518,7 @@ int main(int argc, char** argv) {
return 1;
}
err = GetCapability(CAP_DAC_OVERRIDE, CAP_PERMITTED, &cap_enabled);
err = amd::rdc::GetCapability(CAP_DAC_OVERRIDE, CAP_PERMITTED, &cap_enabled);
if (err) {
std::cerr << "Failed to get capability" << std::endl;
return 1;
@@ -302,7 +532,7 @@ int main(int argc, char** argv) {
// Don't allow rwx access to all files to ever be inheritable. We may need
// relax this restriction if some new feature requires it.
err = ModifyCapability(CAP_DAC_OVERRIDE, CAP_INHERITABLE, false);
err = amd::rdc::ModifyCapability(CAP_DAC_OVERRIDE, CAP_INHERITABLE, false);
if (err) {
std::cerr << "Failed to disable CAP_DAC_OVERRIDE, CAP_INHERITABLE" <<
std::endl;
@@ -310,7 +540,7 @@ int main(int argc, char** argv) {
}
// By default, disable CAP_DAC_OVERRIDE. Turn on, when needed.
err = ModifyCapability(CAP_DAC_OVERRIDE, CAP_EFFECTIVE, false);
err = amd::rdc::ModifyCapability(CAP_DAC_OVERRIDE, CAP_EFFECTIVE, false);
if (err) {
std::cerr << "Failed to disable CAP_DAC_OVERRIDE, CAP_EFFECTIVE" <<
std::endl;
@@ -330,7 +560,7 @@ int main(int argc, char** argv) {
}
// TODO(cfreehil): Eventually, set these by reading a config file
rdc_server.set_start_rsmi_service(false);
rdc_server.set_start_rsmi_service(true);
rdc_server.set_start_rdc_admin_service(true);
rdc_server.set_start_api_service(true);
+6 -1
Ver Arquivo
@@ -24,6 +24,9 @@ THE SOFTWARE.
#include <errno.h>
#include <assert.h>
namespace amd {
namespace rdc {
int GetCapability(cap_value_t cap, cap_flag_t cap_type, bool *enabled) {
cap_t caps;
@@ -40,7 +43,6 @@ int GetCapability(cap_value_t cap, cap_flag_t cap_type, bool *enabled) {
}
cap_flag_value_t val;
if (cap_get_flag(caps, cap, cap_type, &val) == -1) {
int ret = errno;
cap_free(caps);
@@ -87,3 +89,6 @@ int ModifyCapability(cap_value_t cap, cap_flag_t cap_type, bool enable) {
}
return 0;
}
} // namespace rdc
} // namespace amd