| #include <filesystem> |
| #include <memory> |
| #include <string> |
| #include <system_error> |
| #include <thread> |
| |
| #include <boost/asio.hpp> |
| #include "absl/flags/flag.h" |
| #include "absl/flags/parse.h" |
| #include "absl/log/log.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/string_view.h" |
| #include "grpc/grpc_security_constants.h" |
| #include "grpcpp/ext/proto_server_reflection_plugin.h" |
| #include "grpcpp/security/authorization_policy_provider.h" |
| #include "grpcpp/security/server_credentials.h" |
| #include "grpcpp/security/tls_certificate_provider.h" |
| #include "grpcpp/security/tls_credentials_options.h" |
| #include "grpcpp/server_builder.h" |
| #include "grpcpp/server_context.h" |
| #include "grpcpp/support/status.h" |
| #include "channel_server.hpp" |
| |
| using grpc::Server; |
| using grpc::ServerBuilder; |
| using ::grpc::experimental::AuthorizationPolicyProviderInterface; |
| using ::grpc::experimental::FileWatcherAuthorizationPolicyProvider; |
| using ::grpc::experimental::FileWatcherCertificateProvider; |
| using ::grpc::experimental::TlsServerCredentials; |
| using ::grpc::experimental::TlsServerCredentialsOptions; |
| |
| ABSL_FLAG(std::string, address_uri, "[::]:5124", |
| "Host address to listen to. Default to [::]:5124"); |
| ABSL_FLAG(bool, start_secure_server, true, |
| "Start secure server with Zatar credentials. Default to true"); |
| |
| constexpr absl::string_view kZatarCertFilePath = |
| "/var/volatile/prodid/server.pem"; |
| constexpr absl::string_view kTrustBundleFilePath = |
| "/var/google/trust_bundle/trust_bundle.pem"; |
| // Order matters in the array. If the policy file is not found in the |
| // first path, the second path will be checked, and so on. This is to |
| // give priority to the policy file provided by the merged view from |
| // the overlay filesystem. |
| constexpr absl::string_view kStrowgerdCertAuthZPolicyBasePath[] = {"/var/", |
| "/etc/"}; |
| constexpr absl::string_view kStrowgerdCertAuthZPolicy = |
| "google/authz_policies/strowgerd_authz_policy.json"; |
| |
| std::shared_ptr<grpc::ServerCredentials> GetCredsInfo() { |
| std::error_code file_error; |
| bool file_exist = std::filesystem::exists(kZatarCertFilePath, file_error); |
| if (file_error) { |
| LOG(ERROR) << "Zatar file error: " << file_error.message(); |
| return nullptr; |
| } |
| std::string keypair_path; |
| if (file_exist) { |
| keypair_path = std::string(kZatarCertFilePath); |
| } else { |
| // TODO(jorgecardona): Include self sign certificate implementation. |
| LOG(ERROR) << "Zatar Certificate file: " << kZatarCertFilePath |
| << " does not exist."; |
| return nullptr; |
| } |
| auto certificateProvider = std::make_shared<FileWatcherCertificateProvider>( |
| keypair_path, keypair_path, std::string(kTrustBundleFilePath), |
| /* refresh_interval_sec */ 30); |
| |
| TlsServerCredentialsOptions options(certificateProvider); |
| options.watch_root_certs(); |
| options.set_root_cert_name("Zatar"); |
| options.watch_identity_key_cert_pairs(); |
| options.set_cert_request_type( |
| GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY); |
| // TODO(jorgecardona): Investigate whether certificate verifier is needed. |
| std::shared_ptr<grpc::ServerCredentials> tlsServerCredentials = |
| TlsServerCredentials(options); |
| if (tlsServerCredentials == nullptr) { |
| LOG(ERROR) << "Error generating TLS Server credentials"; |
| return nullptr; |
| } |
| return tlsServerCredentials; |
| } |
| |
| std::shared_ptr<AuthorizationPolicyProviderInterface> GetAuthPolicy() { |
| grpc::Status policyStatus; |
| std::string policy_path; |
| for (const auto& prefix : kStrowgerdCertAuthZPolicyBasePath) { |
| std::string temp_policy_path = |
| absl::StrCat(prefix, kStrowgerdCertAuthZPolicy); |
| std::error_code file_error; |
| if (std::filesystem::exists(temp_policy_path, file_error)) { |
| policy_path = temp_policy_path; |
| LOG(INFO) << "Using policy path: " << policy_path; |
| break; |
| } |
| if (file_error) { |
| LOG(ERROR) << "Error checking policy file: " << file_error.message(); |
| } |
| } |
| if (policy_path.empty()) { |
| LOG(ERROR) << "Policy file not found."; |
| return nullptr; |
| } |
| |
| std::shared_ptr<AuthorizationPolicyProviderInterface> policy = |
| FileWatcherAuthorizationPolicyProvider::Create( |
| policy_path, |
| /* policy refresh_interval_sec = 5 minutes*/ 300, &policyStatus); |
| |
| if (!policyStatus.ok()) { |
| return nullptr; |
| } |
| return policy; |
| } |
| |
| std::shared_ptr<Server> CreateServer(RemoteDebugServiceImpl& service, |
| std::string address_uri, |
| bool start_secure_server) { |
| grpc::reflection::InitProtoReflectionServerBuilderPlugin(); |
| ServerBuilder builder; |
| std::shared_ptr<grpc::ServerCredentials> creds = |
| grpc::InsecureServerCredentials(); |
| |
| if (start_secure_server) { |
| if (auto secure_creds = GetCredsInfo()) { |
| creds = secure_creds; |
| if (auto policy = GetAuthPolicy()) { |
| builder.experimental().SetAuthorizationPolicyProvider(policy); |
| } else { |
| LOG(ERROR) << "Failed to get authorization policy."; |
| return nullptr; |
| } |
| } else { |
| LOG(WARNING) |
| << "Failed to get secure credentials. Using insecure server."; |
| } |
| } |
| |
| builder.AddListeningPort(address_uri, creds); |
| builder.RegisterService(&service); |
| return builder.BuildAndStart(); |
| } |
| |
| int main(int argc, char** argv) { |
| absl::ParseCommandLine(argc, argv); |
| std::string address_uri = absl::GetFlag(FLAGS_address_uri); |
| boost::asio::io_context io_context; |
| boost::asio::executor_work_guard<boost::asio::io_context::executor_type> |
| work_guard(io_context.get_executor()); |
| RemoteDebugServiceImpl service(io_context); |
| bool start_secure_server = absl::GetFlag(FLAGS_start_secure_server); |
| std::shared_ptr<Server> server = |
| CreateServer(service, address_uri, start_secure_server); |
| if (server == nullptr) { |
| return 1; |
| } |
| |
| std::thread thread{[&io_context]() { io_context.run(); }}; |
| |
| server->Wait(); |
| |
| return 0; |
| } |