Add support for gRPC authenticated communications

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

Change-Id: Iedcaf6b43cb7576bc11dfefe980abd190c838831
Этот коммит содержится в:
Chris Freehill
2020-03-02 15:06:01 -06:00
родитель 020f6939f7
Коммит 47fdfa4c7e
28 изменённых файлов: 824 добавлений и 43 удалений
+2
Просмотреть файл
@@ -73,6 +73,8 @@ set(CPACK_GENERATOR "DEB;RPM" CACHE STRING "Default packaging generators.")
project(${RDC})
set(RDC_SRC_ROOT "${PROJECT_SOURCE_DIR}")
# Create a configure file to get version info from within library
configure_file(
"${PROJECT_SOURCE_DIR}/src/${RDC}64Config.in"
Исполняемый файл
+30
Просмотреть файл
@@ -0,0 +1,30 @@
#!/bin/bash
# This script should be called only once to generate a root
# certificate
mkdir -p CA
pushd CA
mkdir private newcerts
chmod 700 private newcerts
# Our next step is to create a database for the certificates we will sign:
echo '01' >serial
touch index.txt
# openssl_part1.cnf
# Create the Root Certificate
# This call of openssl encrypts the keys
# openssl req -new -x509 extensions v3_ca -keyout private/rdc_cakey.pem \
# -out rdc_cacert.pem -days 3650 -config ../openssl.cnf
# This call of openssl does not encrypt the keys
openssl req -new -x509 -nodes -extensions v3_ca -keyout private/rdc_cakey.pem \
-out rdc_cacert.pem -days 3650 -config ../openssl.cnf
# This generates:
# A private key in private/rdc_cakey.pem
# A root CA certificate in rdc_cacert.pem (distribute to clients)
popd
Исполняемый файл
+42
Просмотреть файл
@@ -0,0 +1,42 @@
#!/bin/bash
# This script generates ssl keys and self-signed certificates
INSTALL_RT="artifacts"
generate_artifacts() {
HOST=$1
echo "**********************************"
echo "*** Generating $HOST artifacts ***"
echo "**********************************"
mkdir -p ${INSTALL_RT}/${HOST}/private
mkdir -p ${INSTALL_RT}/${HOST}/certs
echo "Generate CSR..."
openssl req -new -nodes -out rdc_csr.pem -config ../openssl.cnf
echo "Sign Certificate..."
openssl ca -out rdc_${HOST}_cert.pem -config ../openssl.cnf -infiles rdc_csr.pem
mv rdc_${HOST}_cert.pem ${INSTALL_RT}/${HOST}/certs/
mv key.pem ${INSTALL_RT}/${HOST}/private/rdc_${HOST}_cert.key
cp rdc_cacert.pem ${INSTALL_RT}/${HOST}/certs/
}
pushd CA
echo
echo "**********************"
echo "IMPORTANT:"
echo " * Make sure to use the same hostname (wildcards accepted) each"
echo " time when prompted for \"Common Name\""
echo " * Make sure to select \"y\" when you are asked whether you want"
echo " to sign the certificates"
echo "**********************"
echo
generate_artifacts "server"
generate_artifacts "client"
rm rdc_cacert.pem
cp ../install_client.sh ../install_server.sh $INSTALL_RT
popd
Исполняемый файл
+15
Просмотреть файл
@@ -0,0 +1,15 @@
#!/bin/bash
# Note:
# * This script should reside in the artifacts directory
# when executed.
# * This script may require root privilege
if [ $# -lt 1 ]; then
echo "Need to specify a installation root directory (e.g., /etc/rdc)"
exit 1
fi
INSTALL_DIR=$1
cp -R client $INSTALL_DIR
Исполняемый файл
+18
Просмотреть файл
@@ -0,0 +1,18 @@
#!/bin/bash
# Note:
# * This script should reside in the artifacts directory
# when executed.
# * This script may require root privilege
if [ $# -lt 1 ]; then
echo "Need to specify a installation root directory (e.g., /etc/rdc)"
exit 1
fi
INSTALL_DIR=$1
cp -R server $INSTALL_DIR
mkdir -p $INSTALL_DIR/client/certs
cp client/certs/rdc_cacert.pem $INSTALL_DIR/client/certs
chmod 700 $INSTALL_DIR/server/private
Исполняемый файл
+88
Просмотреть файл
@@ -0,0 +1,88 @@
#
# OpenSSL configuration file.
#
# Establish working directory.
dir = .
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = $dir/serial
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/rdc_cacert.pem
private_key = $dir/private/rdc_cakey.pem
default_days = 365
default_md = sha512
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
unique_subject = no
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 4096 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = sha512 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
# Variable name Prompt string
#---------------------- ----------------------------------
0.organizationName = Organization Name (company)
organizationalUnitName = Organizational Unit Name (department, division)
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name (city, district)
stateOrProvinceName = State or Province Name (full name)
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name (hostname, IP, or your name)
commonName_max = 64
#-------------------------------------------------------------------------------
# Specify default values below for the fields above. This speeds things up if
# and is more consistent if you have to run the openssl commands repeatedly.
#-------------------------------------------------------------------------------
# < ** REPLACE VALUES IN THIS SECTION WITH APPROPRIATE VALUES FOR YOUR ORG. **>
0.organizationName_default = MyCompany
organizationalUnitName_default = MyCompanyUnit
emailAddress_default = MyEmailAddress
localityName_default = MyCity
stateOrProvinceName_default = MyStateProvince
countryName_default = MC
# wildcards are acceptable for domain; e.g., *.amd.com
commonName_default = Mydomain
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
# < ** MODIFY BELOW TO YOUR NEEDS. WILDCARDS ARE ACCEPTED. **>
DNS.1 = localhost
DNS.2 = another-website.dev
+1
Просмотреть файл
@@ -121,6 +121,7 @@ file(GLOB PROTOBUF_GENERATED_SRCS "${PROTOB_OUT_DIR}/*.cc")
set(CLIENT_LIB_SRC_LIST "${SRC_DIR}/rdc_client.cc")
set(CLIENT_LIB_SRC_LIST ${CLIENT_LIB_SRC_LIST} "${SRC_DIR}/rdc_client_main.cc")
set(CLIENT_LIB_SRC_LIST ${CLIENT_LIB_SRC_LIST} "${SRC_DIR}/rdc_client_utils.cc")
set(CLIENT_LIB_SRC_LIST ${CLIENT_LIB_SRC_LIST} "${PROTOBUF_GENERATED_SRCS}")
set(CLIENT_LIB_SRC_LIST ${CLIENT_LIB_SRC_LIST}
"${PROJECT_SOURCE_DIR}/common/rdc_utils.cc")
+5
Просмотреть файл
@@ -182,6 +182,11 @@ typedef enum {
/// Unrecoverable data loss or corruption.
RDC_STATUS_GRPC_DATA_LOSS,
RDC_STATUS_CLIENT_ERR_FIRST = 2000,
/// SSL authentication error occurred.
RDC_STATUS_CLIENT_ERR_SSL = RDC_STATUS_CLIENT_ERR_FIRST,
RDC_STATUS_UNKNOWN_ERROR = 0xFFFFFFFF, //!< An unknown error occurred
} rdc_status_t;
+3
Просмотреть файл
@@ -24,6 +24,8 @@ THE SOFTWARE.
#ifndef CLIENT_INCLUDE_RDC_RDC_CLIENT_MAIN_H_
#define CLIENT_INCLUDE_RDC_RDC_CLIENT_MAIN_H_
#include <grpcpp/grpcpp.h>
#include <string>
#include <memory>
@@ -60,6 +62,7 @@ class RDCChannel {
std::shared_ptr<::rdc::Rsmi::Stub> rsmi_stub_;
std::shared_ptr<::rdc::RdcAdmin::Stub> rdc_admin_stub_;
std::shared_ptr<grpc::Channel> channel_;
std::shared_ptr<grpc::ChannelCredentials> channel_creds_;
};
} // namespace rdc
Исполняемый файл
+33
Просмотреть файл
@@ -0,0 +1,33 @@
/*
Copyright (c) 2020 - present Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef CLIENT_INCLUDE_RDC_RDC_CLIENT_UTILS_H_
#define CLIENT_INCLUDE_RDC_RDC_CLIENT_UTILS_H_
namespace amd {
namespace rdc {
rdc_status_t GrpcErrorToRdcError(::grpc::StatusCode grpc_err);
} // namespace rdc
} // namespace amd
#endif // CLIENT_INCLUDE_RDC_RDC_CLIENT_UTILS_H_
+6
Просмотреть файл
@@ -28,6 +28,7 @@ THE SOFTWARE.
#include "rdc/rdc_client_main.h"
#include "rdc/rdc_client.h"
#include "rdc/rdc_client_utils.h"
#include "common/rdc_utils.h"
#include "rdc/rdc_exception.h"
#include "rdc.grpc.pb.h" // NOLINT
@@ -552,6 +553,11 @@ rdc_status_string(rdc_status_t status, const char **status_string) {
"RDC_STATUS_UNKNOWN_ERROR An unknown RDC error occurred.";
break;
case RDC_STATUS_CLIENT_ERR_SSL:
*status_string =
"An error occurred when executing SSL authentication operations.";
break;
default:
*status_string = "RDC_RSMI_STATUS_UNKNOWN_ERROR An "
"unknown error occurred";
+115 -2
Просмотреть файл
@@ -29,10 +29,29 @@ THE SOFTWARE.
#include "rdc.grpc.pb.h" // NOLINT
#include "rdc/rdc_client_main.h"
#include "rdc/rdc_client.h"
#include "common/rdc_utils.h"
namespace amd {
namespace rdc {
#ifdef USE_PINNED_CERTS
// Pinned certificates
static const char *kDefaultRDCServerCertPinPath =
"/etc/rdc/server/rdc_server.crt";
static const char *kDefaultRDCClientKeyPinPath =
"/etc/rdc/client/private/rdc_client.key";
static const char *kDefaultRDCClientCertPinPath =
"/etc/rdc/client/rdc_client.crt";
#endif // USE_PINNED_CERTS
// PKI certificates
static const char * kDefaultRDCClientCertKeyPkiPath =
"/etc/rdc/client/private/rdc_client_cert.key";
static const char * kDefaultRDCClientCertPemPkiPath =
"/etc/rdc/client/certs/rdc_client_cert.pem";
static const char * kDefaultRDCClientCACertPemPkiPath =
"/etc/rdc/client/certs/rdc_cacert.pem";
RDCChannel::RDCChannel(std::string server_ip, std::string server_port,
bool secure) : server_ip_(server_ip), server_port_(server_port),
secure_channel_(secure) {}
@@ -40,17 +59,111 @@ RDCChannel::RDCChannel(std::string server_ip, std::string server_port,
RDCChannel::~RDCChannel() {
}
#ifdef USE_PINNED_CERTS
static int ConstructSSLOptsPin(grpc::SslCredentialsOptions *ssl_opts) {
assert(ssl_opts != nullptr);
if (ssl_opts == nullptr) {
return -EINVAL;
}
// Ensure the required paths exists before going forward
// TODO(cfreehil): override these defaults with values read from config
// file
if (!amd::rdc::FileExists(kDefaultRDCClientKeyPinPath) ||
!amd::rdc::FileExists(kDefaultRDCServerCertPinPath) ||
!amd::rdc::FileExists(kDefaultRDCClientCertPinPath)) {
return -ENOENT;
}
std::string cli_key;
std::string ser_crt;
std::string cli_crt;
int ret;
ret = amd::rdc::ReadFile(kDefaultRDCClientKeyPinPath, &cli_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;
}
ssl_opts->pem_root_certs = ser_crt;
ssl_opts->pem_private_key = cli_key;
ssl_opts->pem_cert_chain = cli_crt;
return 0;
}
#endif // USE_PINNED_CERTS
static int ConstructSSLOptsPKI(grpc::SslCredentialsOptions *ssl_opts) {
assert(ssl_opts != nullptr);
if (ssl_opts == nullptr) {
return -EINVAL;
}
// Ensure the required paths exists before going forward
// TODO(cfreehil): override these defaults with values read from config
// file
if (!amd::rdc::FileExists(kDefaultRDCClientCertKeyPkiPath) ||
!amd::rdc::FileExists(kDefaultRDCClientCertPemPkiPath) ||
!amd::rdc::FileExists(kDefaultRDCClientCACertPemPkiPath)) {
return -ENOENT;
}
std::string pem_root_certs;
std::string pem_private_key;
std::string pem_cert_chain;
int ret;
ret = amd::rdc::ReadFile(kDefaultRDCClientCACertPemPkiPath, &pem_root_certs);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCClientCertKeyPkiPath, &pem_private_key);
if (ret) {
return ret;
}
ret = amd::rdc::ReadFile(kDefaultRDCClientCertPemPkiPath, &pem_cert_chain);
if (ret) {
return ret;
}
ssl_opts->pem_root_certs = pem_root_certs;
ssl_opts->pem_private_key = pem_private_key;
ssl_opts->pem_cert_chain = pem_cert_chain;
return 0;
}
rdc_status_t
RDCChannel::Initialize(void) {
assert(!server_port_.empty());
assert(!server_ip_.empty());
int ret;
std::string addr_str = server_ip() + ":";
addr_str += server_port();
if (secure_channel_) {
// Not yet supported
return RDC_STATUS_GRPC_UNIMPLEMENTED;
grpc::SslCredentialsOptions ssl_opts;
#ifdef USE_PINNED_CERTS
ret = ConstructSSLOptsPin(&ssl_opts);
#else
ret = ConstructSSLOptsPKI(&ssl_opts);
#endif
if (ret) {
std::cerr << "Failed to process OpenSSL keys and certificates." <<
std::endl;
return RDC_STATUS_CLIENT_ERR_SSL;
}
channel_creds_ = grpc::SslCredentials(ssl_opts);
channel_ = grpc::CreateChannel(addr_str, channel_creds_);
} else {
channel_ = ::grpc::CreateChannel(addr_str,
grpc::InsecureChannelCredentials());
Исполняемый файл
+40
Просмотреть файл
@@ -0,0 +1,40 @@
/*
Copyright (c) 2020 - present Advanced Micro Devices, Inc. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "rdc/rdc_client.h"
#include "rdc.grpc.pb.h" // NOLINT
#include "rdc/rdc_client_utils.h"
namespace amd {
namespace rdc {
rdc_status_t GrpcErrorToRdcError(grpc::StatusCode grpc_err) {
uint32_t grpc_err_int = static_cast<uint32_t>(grpc_err);
uint32_t rdc_grpc_base_int =
static_cast<uint32_t>(RDC_STATUS_GRPC_ERR_FIRST);
uint32_t rdc_err_int = grpc_err_int + rdc_grpc_base_int;
return static_cast<rdc_status_t>(rdc_err_int);
}
} // namespace rdc
} // namespace amd
+45 -8
Просмотреть файл
@@ -20,22 +20,59 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <sys/stat.h>
#include "rdc/rdc_client.h"
#include "rdc.grpc.pb.h" // NOLINT
#include <string>
#include <fstream>
#include <sstream>
#include "common/rdc_utils.h"
namespace amd {
namespace rdc {
rdc_status_t GrpcErrorToRdcError(grpc::StatusCode grpc_err) {
uint32_t grpc_err_int = static_cast<uint32_t>(grpc_err);
uint32_t rdc_grpc_base_int =
static_cast<uint32_t>(RDC_STATUS_GRPC_ERR_FIRST);
uint32_t rdc_err_int = grpc_err_int + rdc_grpc_base_int;
bool FileExists(char const *filename) {
struct stat buf;
return (stat(filename, &buf) == 0);
}
return static_cast<rdc_status_t>(rdc_err_int);
int ReadFile(std::string path, std::string *retStr, bool chop_newline) {
std::stringstream ss;
int ret = 0;
assert(retStr != nullptr);
std::ifstream fs;
fs.open(path);
if (!fs.is_open()) {
ret = errno;
errno = 0;
return ret;
}
ss << fs.rdbuf();
fs.close();
*retStr = ss.str();
if (chop_newline) {
retStr->erase(std::remove(retStr->begin(), retStr->end(), '\n'),
retStr->end());
}
return ret;
}
int ReadFile(const char *path, std::string *retStr, bool chop_newline) {
assert(path != nullptr);
assert(retStr != nullptr);
std::string file_path(path);
return amd::rdc::ReadFile(file_path, retStr, chop_newline);
}
bool IsNumber(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
} // namespace rdc
+13 -1
Просмотреть файл
@@ -24,6 +24,10 @@ THE SOFTWARE.
#ifndef COMMON_RDC_UTILS_H_
#define COMMON_RDC_UTILS_H_
#include <grpcpp/grpcpp.h>
#include <string>
namespace amd {
namespace rdc {
@@ -38,7 +42,15 @@ namespace rdc {
} while (false)
#endif
rdc_status_t GrpcErrorToRdcError(::grpc::StatusCode grpc_err);
bool
FileExists(char const *filename);
int
ReadFile(std::string path, std::string *retStr, bool chop_newline = false);
int
ReadFile(const char *path, std::string *retStr, bool chop_newline = false);
bool IsNumber(const std::string &s);
} // namespace rdc
} // namespace amd
+67
Просмотреть файл
@@ -59,3 +59,70 @@ To run the test, execute the program `rsmitst` that is built from the steps abov
# Hello RDC
### Authentication
RDC supports encrypted communications between clients and servers. The communication can be configured to be authenticated or not authenticated.
##### Unauthenticated Communications
By default, authentication is enabled. To disable authentication, when starting the server use the "--unauth_comm" flag (or "-u" for short). On the client side, when calling rdc_channel_create(), the "secure" argument should be set to false.
##### Public Key Infrastructure (PKI) Authentication
A number of SSL keys and certificates must be generated and installed on the clients and servers for authentication to work properly. By default, the RDC server will look under /etc/rdc for the following keys and certificates:
- Servers
```sh
$ sudo tree /etc/rdc
/etc/rdc
└── server
├── certs
│   ├── rdc_cacert.pem
│   └── rdc_server_cert.pem
└── private
└── rdc_server_cert.key
```
- Clients
```sh
$ sudo tree /etc/rdc
/etc/rdc
└── client
   ├── certs
   │   ├── rdc_cacert.pem
   │   └── rdc_client_cert.pem
   └── private
   └── rdc_client_cert.key
```
Machines that are both clients and servers will have both directory structures.
RDC users would normally generate their own keys and certificates. However, there are scripts that will generate self-signed certficates in RDC source tree, under the "authentication" directory. The scripts call the openssl command to generate the required keys and certificates. The openssl command will query the caller for different identifying information. The calls to openssl will refer to the openssl.cnf file for configuration information. Included in this file is a section where default responses to the openssl questions can be specified. Look for the comment line
```sh
# < ** REPLACE VALUES IN THIS SECTION WITH APPROPRIATE VALUES FOR YOUR ORG. **>
```
to find this section. It is helpful to modify this section with values appropriate for your organization if this script will be called many times.
Additionally, the alt_names section needs to be updated for your environment (instead of the dummy values that there initially).
To generate the keys and certficates using these scripts, make the following calls:
```sh
$ 01gen_root_cert.sh
# provide answers to posed questions
$ 02gen_ssl_artifacts.sh
# provide answers to posed questions
```
At this point, the keys and certficates will be in the newly created "CA/artifacts" directory. This directory should be deleted if you need to rerun the scripts.
To install the scripts cd into the artifacts directory and run the install.sh script as root, specifying the install location. By default, RDC will expect this to be in /etc/rdc:
```sh
$ cd CA/artifacts
$ sudo install_<client|server>.sh /etc/rdc
```
These files should be copied to and and installed on all client and server machines that are expected to communicate with one another.
##### Current Limitations
There are a few limitations on the authentication capabilities. These limitations are temporary and will be eliminated when the server has a configuration file where user preferences can be specified.
* The client and server are hard-coded to look for openssl certificate and key files in /etc/rdc.
+2 -1
Просмотреть файл
@@ -69,7 +69,7 @@ file(GLOB PROTOBUF_GENERATED_SRCS "${PROTOB_OUT_DIR}/*.cc")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include
"${PROJECT_SOURCE_DIR}/include"
"${PROTOB_OUT_DIR}" "${RSMI_INC_DIR}")
"${PROTOB_OUT_DIR}" "${RSMI_INC_DIR}" "${RDC_SRC_ROOT}")
set(SERVER_SRC_LIST "${SRC_DIR}/rdc_rsmi_service.cc")
set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${SRC_DIR}/rdc_admin_service.cc")
@@ -77,6 +77,7 @@ set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${SRC_DIR}/rdc_api_service.cc")
set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${SRC_DIR}/rdc_server_main.cc")
set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${SRC_DIR}/rdc_server_utils.cc")
set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${PROTOBUF_GENERATED_SRCS}")
set(SERVER_SRC_LIST ${SERVER_SRC_LIST} "${RDC_SRC_ROOT}/common/rdc_utils.cc")
message("SERVER_SRC_LIST=${SERVER_SRC_LIST}")
set(SERVER_DAEMON_EXE "rdcd")
+2 -2
Просмотреть файл
@@ -39,7 +39,7 @@ class RDCAdminServiceImpl final : public ::rdc::RdcAdmin::Service {
private:
};
} // namespace rdc
} // namespace amd
} // namespace rdc
} // namespace amd
#endif // SERVER_INCLUDE_RDC_RDC_ADMIN_SERVICE_H_
+15 -3
Просмотреть файл
@@ -31,14 +31,22 @@ THE SOFTWARE.
#include "rdc/rdc_admin_service.h"
#include "rdc/rdc_api_service.h"
typedef struct {
std::string listen_port;
bool no_authentication;
bool use_pinned_certs;
bool log_dbg;
} RdcdCmdLineOpts;
class RDCServer {
public:
RDCServer();
~RDCServer();
void Initialize();
void Initialize(RdcdCmdLineOpts *cl);
void Run(void);
void ShutDown(void);
bool start_rsmi_service(void) const {return start_rsmi_service_;}
void set_start_rsmi_service(bool s) {start_rsmi_service_ = s;}
@@ -49,15 +57,19 @@ class RDCServer {
bool start_api_service(void) const {return start_api_service_;}
void set_start_api_service(bool s) {start_api_service_ = s;}
void ShutDown(void);
bool secure_creds(void) const {return secure_creds_;}
void set_secure_creds(bool s) {secure_creds_ = s;}
private:
void HandleSignal(int sig);
std::string server_address_;
std::unique_ptr<::grpc::Server> server_;
bool secure_creds_;
bool use_pinned_certs_;
bool log_debug_;
bool start_rsmi_service_;
amd::rdc::RsmiServiceImpl *rsmi_service_;
RdcdCmdLineOpts *cmd_line_;
bool start_rdc_admin_service_;
amd::rdc::RDCAdminServiceImpl *rdc_admin_service_;
+6 -1
Просмотреть файл
@@ -24,7 +24,12 @@ THE SOFTWARE.
#include <sys/capability.h>
namespace amd {
namespace rdc {
int GetCapability(cap_value_t cap, cap_flag_t cap_type, bool *enabled);
int ModifyCapability(cap_value_t cap, cap_flag_t cap_type, bool enable);
} // namespace rdc
} // namespace amd
#endif // SERVER_INCLUDE_RDC_RDC_SERVER_UTILS_H_
#endif // SERVER_INCLUDE_RDC_RDC_SERVER_UTILS_H_
+249 -19
Просмотреть файл
@@ -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
Просмотреть файл
@@ -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
+1 -1
Просмотреть файл
@@ -124,7 +124,7 @@ endif()
set(RDCTST_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set(RDCTST "rdctst")
set(RDCTST_LIBS "rdc_client")
set(RDCTST_LIBS "rdc_client_smi")
# Set Name for Google Test Framework and build it as a
# static library to be linked with user test programs
+2
Просмотреть файл
@@ -48,6 +48,7 @@ static void SetFlags(TestBase *test) {
test->set_init_options(sRDCGlvalues->init_options);
test->set_monitor_server_ip(sRDCGlvalues->monitor_server_ip);
test->set_monitor_server_port(sRDCGlvalues->monitor_server_port);
test->set_secure(sRDCGlvalues->secure);
}
static void RunCustomTestProlog(TestBase *test) {
@@ -201,6 +202,7 @@ int main(int argc, char** argv) {
settings.rdcd_path = "";
settings.monitor_server_ip = "";
settings.monitor_server_port = "";
settings.secure = true;
if (ProcessCmdline(&settings, argc, argv)) {
return 1;
+1 -1
Просмотреть файл
@@ -114,7 +114,7 @@ TestBase::AllocateRDCChannel(void) {
err = rdc_channel_create(&c,
monitor_server_ip() == "" ? nullptr : monitor_server_ip().c_str(),
monitor_server_port() == "" ? nullptr : monitor_server_port().c_str(),
false);
secure());
if (err != RDC_STATUS_SUCCESS) {
std::cout << "rdc_channel_create() failed" << std::endl;
+7 -1
Просмотреть файл
@@ -101,7 +101,12 @@ class TestBase {
std::string monitor_server_port(void) const {
return monitor_server_port_;
}
void set_secure(bool sec) {
secure_ = sec;
}
bool secure(void) const {
return secure_;
}
protected:
void PrintDeviceHeader(uint32_t dv_ind);
@@ -117,6 +122,7 @@ class TestBase {
std::string monitor_server_ip_;
std::string monitor_server_port_;
rdc_channel_t rdc_channel_;
bool secure_; // Use authenticated comms. (SSL/TSL)
};
#define IF_VERB(VB) if (verbosity() && verbosity() >= (TestBase::VERBOSE_##VB))
+9 -2
Просмотреть файл
@@ -106,11 +106,12 @@ static const struct option long_options[] = {
{"remote_server_port", required_argument, nullptr, 'p'},
{"start_rdcd", optional_argument, nullptr, 'd'},
{"dont_fail", no_argument, nullptr, 'f'},
{"unauth_comm", no_argument, nullptr, 'u'},
{"rdctst_help", no_argument, nullptr, 'r'},
{nullptr, 0, nullptr, 0}
};
static const char* short_options = "i:v:m:s:p:d:fr";
static const char* short_options = "i:v:m:s:p:d:fur";
static void PrintHelp(void) {
std::cout <<
@@ -130,7 +131,9 @@ static void PrintHelp(void) {
"--remote_server_ip <ip address>; connect to already running "
"rdcd on specified IP\n"
"--remote_server_port <remote port>; connect to already running "
"rdcd on specified IP at this port\n";
"rdcd on specified IP at this port\n"
"--unauth_comm; don't use TSL/SSL authentication; "
"default is with authentication\n";
}
uint32_t ProcessCmdline(RDCTstGlobals* test, int arg_cnt, char** arg_list) {
@@ -183,6 +186,10 @@ uint32_t ProcessCmdline(RDCTstGlobals* test, int arg_cnt, char** arg_list) {
test->dont_fail = true;
break;
case 'u':
test->secure = false;
break;
default:
std::cout << "Unknown command line option: \"" << a <<
"\". Ignoring..." << std::endl;
+1
Просмотреть файл
@@ -38,6 +38,7 @@ struct RDCTstGlobals {
uint32_t num_iterations;
uint64_t init_options;
bool dont_fail;
bool secure;
};
uint32_t ProcessCmdline(RDCTstGlobals* test, int arg_cnt, char** arg_list);