diff options
Diffstat (limited to 'src')
34 files changed, 301 insertions, 274 deletions
diff --git a/src/buildtool/auth/TARGETS b/src/buildtool/auth/TARGETS index 4d501a91..a66aae44 100644 --- a/src/buildtool/auth/TARGETS +++ b/src/buildtool/auth/TARGETS @@ -6,6 +6,7 @@ [ ["@", "gsl", "", "gsl"] , ["src/buildtool/logging", "log_level"] , ["src/buildtool/logging", "logging"] + , ["src/utils/cpp", "expected"] ] , "stage": ["src", "buildtool", "auth"] } diff --git a/src/buildtool/auth/authentication.hpp b/src/buildtool/auth/authentication.hpp index ae45561a..cd4ff86d 100644 --- a/src/buildtool/auth/authentication.hpp +++ b/src/buildtool/auth/authentication.hpp @@ -14,6 +14,7 @@ #ifndef INCLUDED_SRC_BUILDTOOL_AUTH_AUTHENTICATION_HPP #define INCLUDED_SRC_BUILDTOOL_AUTH_AUTHENTICATION_HPP + #include <cstdint> #include <filesystem> #include <fstream> @@ -25,135 +26,189 @@ #include "gsl/gsl" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" -enum class AuthMethod : std::uint8_t { kNONE, kTLS }; +#include "src/utils/cpp/expected.hpp" + +struct Auth final { + struct TLS final { + class Builder; + + // CA certificate bundle + std::string const ca_cert = {}; + // Client-side signed certificate + std::string const client_cert = {}; + // Client-side private key + std::string const client_key = {}; + // Server-side signed certificate + std::string const server_cert = {}; + // Server-side private key + std::string const server_key = {}; + }; -class Auth { + std::variant<std::monostate, TLS> method = {}; +}; + +class Auth::TLS::Builder final { public: - [[nodiscard]] static auto Instance() noexcept -> Auth& { - static Auth instance{}; - return instance; + auto SetCACertificate( + std::optional<std::filesystem::path> cert_file) noexcept -> Builder& { + ca_cert_file_ = std::move(cert_file); + return *this; } - void SetAuthMethod(AuthMethod x) { auth_ = x; } - [[nodiscard]] auto GetAuthMethod() const noexcept -> AuthMethod { - return auth_; + auto SetClientCertificate( + std::optional<std::filesystem::path> cert_file) noexcept -> Builder& { + client_cert_file_ = std::move(cert_file); + return *this; } - class TLS { - public: - [[nodiscard]] static auto Instance() noexcept -> TLS& { - static TLS instance{}; - return instance; - } - - [[nodiscard]] auto CACert() const noexcept -> const std::string& { - return ca_cert_; - } - - [[nodiscard]] auto ClientCert() const noexcept -> const std::string& { - return client_cert_; - } - - [[nodiscard]] auto ClientKey() const noexcept -> const std::string& { - return client_key_; - } - - [[nodiscard]] auto ServerCert() const noexcept -> const std::string& { - return server_cert_; - } + auto SetClientKey(std::optional<std::filesystem::path> key_file) noexcept + -> Builder& { + client_key_file_ = std::move(key_file); + return *this; + } - [[nodiscard]] auto ServerKey() const noexcept -> const std::string& { - return server_key_; - } + auto SetServerCertificate( + std::optional<std::filesystem::path> cert_file) noexcept -> Builder& { + server_cert_file_ = std::move(cert_file); + return *this; + } - [[nodiscard]] auto SetCACertificate( - std::filesystem::path const& cert_file) noexcept -> bool { - return set(cert_file, &ca_cert_); - } + auto SetServerKey(std::optional<std::filesystem::path> key_file) noexcept + -> Builder& { + server_key_file_ = std::move(key_file); + return *this; + } - [[nodiscard]] auto SetClientCertificate( - std::filesystem::path const& cert_file) noexcept -> bool { - return set(cert_file, &client_cert_); + /// \brief Finalize building, validate the entries, and create an Auth with + /// TLS as method. Validation ensures that either both tls_client_cert or + /// tls_client_key are set, or none of the two. + /// \return Auth on success, error string on failure, nullopt if no TLS + /// configuration fields were set. + [[nodiscard]] auto Build() noexcept + -> std::optional<expected<Auth, std::string>> { + // To not duplicate default arguments of Auth::TLS in builder, + // create a default config and copy default arguments from there. + Auth::TLS const default_auth_tls; + bool tls_args_exist = false; + + // Set and validate the CA certification. + // If provided, the CA certificate bundle should of course not be empty. + auto ca_cert = default_auth_tls.ca_cert; + if (ca_cert_file_.has_value()) { + if (auto content = read(*ca_cert_file_)) { + if (content->empty()) { + return unexpected( + std::string("Please provide tls-ca-cert")); + } + ca_cert = *std::move(content); + tls_args_exist = true; + } + else { + return unexpected( + fmt::format("Could not read '{}' CA certificate.", + ca_cert_file_->string())); + } } - [[nodiscard]] auto SetClientKey( - std::filesystem::path const& key_file) noexcept -> bool { - return set(key_file, &client_key_); + // Set and validate the client-side certification. + // To enable mTLS, both tls_client_{certificate,key} must be supplied. + auto client_cert = default_auth_tls.client_cert; + if (client_cert_file_.has_value()) { + if (auto content = read(*client_cert_file_)) { + client_cert = *std::move(content); + tls_args_exist = true; + } + else { + return unexpected( + fmt::format("Could not read '{}' client certificate.", + client_cert_file_->string())); + } } - - [[nodiscard]] auto SetServerCertificate( - std::filesystem::path const& cert_file) noexcept -> bool { - return set(cert_file, &server_cert_); + auto client_key = default_auth_tls.client_key; + if (client_key_file_.has_value()) { + if (auto content = read(*client_key_file_)) { + client_key = *std::move(content); + tls_args_exist = true; + } + else { + return unexpected(fmt::format("Could not read '{}' client key.", + client_key_file_->string())); + } } - - [[nodiscard]] auto SetServerKey( - std::filesystem::path const& key_file) noexcept -> bool { - return set(key_file, &server_key_); + if (client_cert.empty() != client_key.empty()) { + std::string error = client_cert.empty() + ? "Please also provide tls-client-cert" + : "Please also provide tls-client-key"; + return unexpected(std::move(error)); } - // must be called after the parsing of cmd line arguments - // we ensure that either both tls_client_cert or tls_client_key are set - // or none of the two. - [[nodiscard]] auto Validate() const noexcept -> bool { - if (CACert().empty()) { - Logger::Log(LogLevel::Error, "Please provide tls-ca-cert"); - return false; - } - // to enable mTLS, both tls_client_{certificate,key} must be - // supplied - if (ClientCert().empty() && not(ClientKey().empty())) { - Logger::Log(LogLevel::Error, - "Please also provide tls-client-cert"); - return false; + // Set and validate the server-side certification. + // To enable mTLS, both tls_server_{certificate,key} must be supplied. + auto server_cert = default_auth_tls.server_cert; + if (server_cert_file_.has_value()) { + if (auto content = read(*server_cert_file_)) { + server_cert = *std::move(content); + tls_args_exist = true; } - if (not(ClientCert().empty()) && ClientKey().empty()) { - Logger::Log(LogLevel::Error, - "Please also provide tls-client-key"); - return false; + else { + return unexpected( + fmt::format("Could not read '{}' server certificate.", + server_cert_file_->string())); } - - // to enable mTLS, both tls_server_{certificate,key} must be - // supplied - if (ServerCert().empty() && not(ServerKey().empty())) { - Logger::Log(LogLevel::Error, - "Please also provide tls-server-cert"); - return false; + } + auto server_key = default_auth_tls.server_key; + if (server_key_file_.has_value()) { + if (auto content = read(*server_key_file_)) { + server_key = *std::move(content); + tls_args_exist = true; } - if (not(ServerCert().empty()) && ServerKey().empty()) { - Logger::Log(LogLevel::Error, - "Please also provide tls-server-key"); - return false; + else { + return unexpected(fmt::format("Could not read '{}' server key.", + server_key_file_->string())); } - return true; + } + if (server_cert.empty() != server_key.empty()) { + std::string error = server_cert.empty() + ? "Please also provide tls-server-cert" + : "Please also provide tls-server-key"; + return unexpected(std::move(error)); } - private: - std::string ca_cert_; - std::string client_cert_; - std::string client_key_; - std::string server_cert_; - std::string server_key_; - // auxiliary function to set the content of the members of this class - [[nodiscard]] static auto set( - std::filesystem::path const& x, - gsl::not_null<std::string*> const& member) noexcept -> bool { - Auth::Instance().SetAuthMethod(AuthMethod::kTLS); - try { - // if the file does not exist, it will throw an exception - auto file = std::filesystem::canonical(x); - std::ifstream cert{file}; - std::string tmp((std::istreambuf_iterator<char>(cert)), - std::istreambuf_iterator<char>()); - *member = std::move(tmp); - } catch (std::exception const& e) { - Logger::Log(LogLevel::Error, e.what()); - return false; - } - return true; + // If no TLS arguments were ever set, there is nothing to build. + if (not tls_args_exist) { + return std::nullopt; } - }; + + // Return an authentication configuration with mTLS enabled. + return Auth{.method = Auth::TLS{.ca_cert = std::move(ca_cert), + .client_cert = std::move(client_cert), + .client_key = std::move(client_key), + .server_cert = std::move(server_cert), + .server_key = std::move(server_key)}}; + } private: - AuthMethod auth_{AuthMethod::kNONE}; + std::optional<std::filesystem::path> ca_cert_file_; + std::optional<std::filesystem::path> client_cert_file_; + std::optional<std::filesystem::path> client_key_file_; + std::optional<std::filesystem::path> server_cert_file_; + std::optional<std::filesystem::path> server_key_file_; + + /// \brief Auxiliary function to read the content of certification files. + [[nodiscard]] static auto read(std::filesystem::path const& x) noexcept + -> std::optional<std::string> { + try { + // if the file does not exist, it will throw an exception + auto file = std::filesystem::canonical(x); + std::ifstream cert{file}; + std::string tmp((std::istreambuf_iterator<char>(cert)), + std::istreambuf_iterator<char>()); + return tmp; + } catch (std::exception const& e) { + Logger::Log(LogLevel::Error, e.what()); + } + return std::nullopt; + } }; -#endif + +#endif // INCLUDED_SRC_BUILDTOOL_AUTH_AUTHENTICATION_HPP diff --git a/src/buildtool/common/remote/TARGETS b/src/buildtool/common/remote/TARGETS index 06604234..a5480e2b 100644 --- a/src/buildtool/common/remote/TARGETS +++ b/src/buildtool/common/remote/TARGETS @@ -5,6 +5,7 @@ , "deps": [ ["@", "fmt", "", "fmt"] , ["@", "grpc", "", "grpc++"] + , ["@", "gsl", "", "gsl"] , ["src/buildtool/auth", "auth"] , ["src/buildtool/common", "common"] , "port" diff --git a/src/buildtool/common/remote/client_common.hpp b/src/buildtool/common/remote/client_common.hpp index 4fd9e9a7..58c19458 100644 --- a/src/buildtool/common/remote/client_common.hpp +++ b/src/buildtool/common/remote/client_common.hpp @@ -21,9 +21,11 @@ #include <optional> #include <sstream> #include <string> +#include <variant> #include "fmt/core.h" #include "grpcpp/grpcpp.h" +#include "gsl/gsl" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/common/remote/port.hpp" @@ -33,16 +35,18 @@ [[maybe_unused]] [[nodiscard]] static inline auto CreateChannelWithCredentials( std::string const& server, Port port, - Auth::TLS const* auth) noexcept { + gsl::not_null<Auth const*> const& auth) noexcept { std::shared_ptr<grpc::ChannelCredentials> creds; std::string address = server + ':' + std::to_string(port); - if (auth != nullptr) { + if (const auto* tls_auth = std::get_if<Auth::TLS>(&auth->method); + tls_auth != nullptr) { auto tls_opts = grpc::SslCredentialsOptions{ - auth->CACert(), auth->ClientKey(), auth->ClientCert()}; + tls_auth->ca_cert, tls_auth->client_key, tls_auth->client_cert}; creds = grpc::SslCredentials(tls_opts); } else { + // currently only TLS/SSL is supported creds = grpc::InsecureChannelCredentials(); } return grpc::CreateChannel(address, creds); diff --git a/src/buildtool/execution_api/common/api_bundle.cpp b/src/buildtool/execution_api/common/api_bundle.cpp index 17e3d3af..41637eb4 100644 --- a/src/buildtool/execution_api/common/api_bundle.cpp +++ b/src/buildtool/execution_api/common/api_bundle.cpp @@ -19,10 +19,10 @@ #include "src/buildtool/execution_api/remote/bazel/bazel_api.hpp" ApiBundle::ApiBundle(RepositoryConfig const* repo_config, - Auth::TLS const* authentication, + gsl::not_null<Auth const*> const& authentication, std::optional<ServerAddress> const& remote_address) : local{std::make_shared<LocalApi>(repo_config)}, // needed by remote - auth{authentication}, // needed by remote + auth{*authentication}, // needed by remote remote{CreateRemote(remote_address)} {} auto ApiBundle::CreateRemote(std::optional<ServerAddress> const& address) const @@ -31,7 +31,7 @@ auto ApiBundle::CreateRemote(std::optional<ServerAddress> const& address) const ExecutionConfiguration config; config.skip_cache_lookup = false; return std::make_shared<BazelApi>( - "remote-execution", address->host, address->port, auth, config); + "remote-execution", address->host, address->port, &auth, config); } return local; } diff --git a/src/buildtool/execution_api/common/api_bundle.hpp b/src/buildtool/execution_api/common/api_bundle.hpp index 72fdb687..0148b6af 100644 --- a/src/buildtool/execution_api/common/api_bundle.hpp +++ b/src/buildtool/execution_api/common/api_bundle.hpp @@ -29,14 +29,14 @@ /// exactly the same instance that local api is (&*remote == & *local). struct ApiBundle final { explicit ApiBundle(RepositoryConfig const* repo_config, - Auth::TLS const* authentication, + gsl::not_null<Auth const*> const& authentication, std::optional<ServerAddress> const& remote_address); [[nodiscard]] auto CreateRemote(std::optional<ServerAddress> const& address) const -> gsl::not_null<IExecutionApi::Ptr>; gsl::not_null<IExecutionApi::Ptr> const local; // needed by remote - Auth::TLS const* auth; // needed by remote + Auth const& auth; // needed by remote gsl::not_null<IExecutionApi::Ptr> const remote; }; diff --git a/src/buildtool/execution_api/execution_service/server_implementation.cpp b/src/buildtool/execution_api/execution_service/server_implementation.cpp index 4a9f23cf..676bd0a7 100644 --- a/src/buildtool/execution_api/execution_service/server_implementation.cpp +++ b/src/buildtool/execution_api/execution_service/server_implementation.cpp @@ -70,13 +70,15 @@ auto ServerImpl::Run(ApiBundle const& apis) -> bool { .RegisterService(&cap) .RegisterService(&op); + // check authentication credentials; currently only TLS/SSL is supported std::shared_ptr<grpc::ServerCredentials> creds; - if (apis.auth != nullptr) { + if (const auto* tls_auth = std::get_if<Auth::TLS>(&apis.auth.method); + tls_auth != nullptr) { auto tls_opts = grpc::SslServerCredentialsOptions{}; - tls_opts.pem_root_certs = apis.auth->CACert(); + tls_opts.pem_root_certs = tls_auth->ca_cert; grpc::SslServerCredentialsOptions::PemKeyCertPair keycert = { - apis.auth->ServerKey(), apis.auth->ServerCert()}; + tls_auth->server_key, tls_auth->server_cert}; tls_opts.pem_key_cert_pairs.emplace_back(keycert); diff --git a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp index 65853702..4f93b62d 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp @@ -14,7 +14,6 @@ #include "src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp" -#include "gsl/gsl" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/common/remote/client_common.hpp" #include "src/buildtool/common/remote/retry.hpp" @@ -22,7 +21,7 @@ BazelAcClient::BazelAcClient(std::string const& server, Port port, - Auth::TLS const* auth) noexcept { + gsl::not_null<Auth const*> const& auth) noexcept { stub_ = bazel_re::ActionCache::NewStub( CreateChannelWithCredentials(server, port, auth)); } diff --git a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp index 4ac24bbc..36e83649 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp @@ -21,6 +21,7 @@ #include <vector> #include "build/bazel/remote/execution/v2/remote_execution.grpc.pb.h" +#include "gsl/gsl" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/common/remote/port.hpp" @@ -34,7 +35,7 @@ class BazelAcClient { public: explicit BazelAcClient(std::string const& server, Port port, - Auth::TLS const* auth) noexcept; + gsl::not_null<Auth const*> const& auth) noexcept; [[nodiscard]] auto GetActionResult( std::string const& instance_name, diff --git a/src/buildtool/execution_api/remote/bazel/bazel_api.cpp b/src/buildtool/execution_api/remote/bazel/bazel_api.cpp index f463ab3c..1ce65259 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_api.cpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_api.cpp @@ -190,7 +190,7 @@ namespace { BazelApi::BazelApi(std::string const& instance_name, std::string const& host, Port port, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, ExecutionConfiguration const& exec_config) noexcept { network_ = std::make_shared<BazelNetwork>( instance_name, host, port, auth, exec_config); diff --git a/src/buildtool/execution_api/remote/bazel/bazel_api.hpp b/src/buildtool/execution_api/remote/bazel/bazel_api.hpp index e87e6159..c9771ed7 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_api.hpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_api.hpp @@ -43,7 +43,7 @@ class BazelApi final : public IExecutionApi { BazelApi(std::string const& instance_name, std::string const& host, Port port, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, ExecutionConfiguration const& exec_config) noexcept; BazelApi(BazelApi const&) = delete; BazelApi(BazelApi&& other) noexcept; diff --git a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp index 3850ccff..af23e9b1 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp @@ -175,7 +175,7 @@ namespace { BazelCasClient::BazelCasClient(std::string const& server, Port port, - Auth::TLS const* auth) noexcept + gsl::not_null<Auth const*> const& auth) noexcept : stream_{std::make_unique<ByteStreamClient>(server, port, auth)} { stub_ = bazel_re::ContentAddressableStorage::NewStub( CreateChannelWithCredentials(server, port, auth)); diff --git a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp index d7aa5c05..90d9eb75 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp @@ -40,7 +40,7 @@ class BazelCasClient { public: explicit BazelCasClient(std::string const& server, Port port, - Auth::TLS const* auth) noexcept; + gsl::not_null<Auth const*> const& auth) noexcept; /// \brief Find missing blobs /// \param[in] instance_name Name of the CAS instance diff --git a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp index f4ad250c..51ee1869 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp @@ -17,7 +17,6 @@ #include <utility> // std::move #include "grpcpp/grpcpp.h" -#include "gsl/gsl" #include "src/buildtool/common/remote/client_common.hpp" #include "src/buildtool/common/remote/retry.hpp" #include "src/buildtool/logging/log_level.hpp" @@ -56,9 +55,10 @@ auto DebugString(grpc::Status const& status) -> std::string { } // namespace -BazelExecutionClient::BazelExecutionClient(std::string const& server, - Port port, - Auth::TLS const* auth) noexcept { +BazelExecutionClient::BazelExecutionClient( + std::string const& server, + Port port, + gsl::not_null<Auth const*> const& auth) noexcept { stub_ = bazel_re::Execution::NewStub( CreateChannelWithCredentials(server, port, auth)); } diff --git a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp index 74676d45..aa505121 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp @@ -22,6 +22,7 @@ #include "build/bazel/remote/execution/v2/remote_execution.grpc.pb.h" #include "google/longrunning/operations.pb.h" +#include "gsl/gsl" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/common/remote/port.hpp" @@ -55,9 +56,10 @@ class BazelExecutionClient { } }; - explicit BazelExecutionClient(std::string const& server, - Port port, - Auth::TLS const* auth) noexcept; + explicit BazelExecutionClient( + std::string const& server, + Port port, + gsl::not_null<Auth const*> const& auth) noexcept; [[nodiscard]] auto Execute(std::string const& instance_name, bazel_re::Digest const& action_digest, diff --git a/src/buildtool/execution_api/remote/bazel/bazel_network.cpp b/src/buildtool/execution_api/remote/bazel/bazel_network.cpp index 4d5509c9..6094888d 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_network.cpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_network.cpp @@ -24,7 +24,7 @@ BazelNetwork::BazelNetwork(std::string instance_name, std::string const& host, Port port, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, ExecutionConfiguration const& exec_config) noexcept : instance_name_{std::move(instance_name)}, exec_config_{exec_config}, diff --git a/src/buildtool/execution_api/remote/bazel/bazel_network.hpp b/src/buildtool/execution_api/remote/bazel/bazel_network.hpp index 4da302c9..ca0b0e2a 100644 --- a/src/buildtool/execution_api/remote/bazel/bazel_network.hpp +++ b/src/buildtool/execution_api/remote/bazel/bazel_network.hpp @@ -22,6 +22,7 @@ #include <utility> #include <vector> +#include "gsl/gsl" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/bazel_types.hpp" #include "src/buildtool/common/remote/port.hpp" @@ -39,7 +40,7 @@ class BazelNetwork { explicit BazelNetwork(std::string instance_name, std::string const& host, Port port, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, ExecutionConfiguration const& exec_config) noexcept; /// \brief Check if digest exists in CAS diff --git a/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp b/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp index 2879a90f..88abe6fd 100644 --- a/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp +++ b/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp @@ -83,7 +83,7 @@ class ByteStreamClient { explicit ByteStreamClient(std::string const& server, Port port, - Auth::TLS const* auth) noexcept { + gsl::not_null<Auth const*> const& auth) noexcept { stub_ = google::bytestream::ByteStream::NewStub( CreateChannelWithCredentials(server, port, auth)); } diff --git a/src/buildtool/execution_engine/executor/executor.hpp b/src/buildtool/execution_engine/executor/executor.hpp index 89a384b8..8b94a016 100644 --- a/src/buildtool/execution_engine/executor/executor.hpp +++ b/src/buildtool/execution_engine/executor/executor.hpp @@ -61,7 +61,7 @@ class ExecutorImpl { std::map<std::string, std::string> const& properties, std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>> const& dispatch_list, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, std::chrono::milliseconds const& timeout, IExecutionAction::CacheFlag cache_flag, gsl::not_null<Statistics*> const& stats, @@ -668,7 +668,7 @@ class ExecutorImpl { const std::map<std::string, std::string>& properties, const std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>>& dispatch_list, - const Auth::TLS* auth) -> std::unique_ptr<BazelApi> { + const gsl::not_null<Auth const*>& auth) -> std::unique_ptr<BazelApi> { for (auto const& [pred, endpoint] : dispatch_list) { bool match = true; for (auto const& [k, v] : pred) { @@ -708,7 +708,7 @@ class Executor { std::map<std::string, std::string> properties, std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>> dispatch_list, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, gsl::not_null<Statistics*> const& stats, gsl::not_null<Progress*> const& progress, Logger const* logger = nullptr, // log in caller logger, if given @@ -718,7 +718,7 @@ class Executor { remote_api_{*remote_api}, properties_{std::move(properties)}, dispatch_list_{std::move(dispatch_list)}, - auth_{auth}, + auth_{*auth}, stats_{stats}, progress_{progress}, logger_{logger}, @@ -741,7 +741,7 @@ class Executor { Impl::MergeProperties(properties_, action->ExecutionProperties()), dispatch_list_, - auth_, + &auth_, Impl::ScaleTime(timeout_, action->TimeoutScale()), action->NoCache() ? CF::DoNotCacheOutput : CF::CacheOutput, stats_, @@ -760,7 +760,7 @@ class Executor { remote_api_, Impl::MergeProperties(properties_, action->ExecutionProperties()), dispatch_list_, - auth_, + &auth_, Impl::ScaleTime(timeout_, action->TimeoutScale()), action->NoCache() ? CF::DoNotCacheOutput : CF::CacheOutput, stats_, @@ -798,7 +798,7 @@ class Executor { std::map<std::string, std::string> properties_; std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>> dispatch_list_; - Auth::TLS const* auth_; + Auth const& auth_; gsl::not_null<Statistics*> stats_; gsl::not_null<Progress*> progress_; Logger const* logger_; @@ -824,7 +824,7 @@ class Rebuilder { std::map<std::string, std::string> properties, std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>> dispatch_list, - Auth::TLS const* auth, + gsl::not_null<Auth const*> const& auth, gsl::not_null<Statistics*> const& stats, gsl::not_null<Progress*> const& progress, std::chrono::milliseconds timeout = IExecutionAction::kDefaultTimeout) @@ -834,7 +834,7 @@ class Rebuilder { api_cached_{*api_cached}, properties_{std::move(properties)}, dispatch_list_{std::move(dispatch_list)}, - auth_{auth}, + auth_{*auth}, stats_{stats}, progress_{progress}, timeout_{timeout} {} @@ -850,7 +850,7 @@ class Rebuilder { remote_api_, Impl::MergeProperties(properties_, action->ExecutionProperties()), dispatch_list_, - auth_, + &auth_, Impl::ScaleTime(timeout_, action->TimeoutScale()), CF::PretendCached, stats_, @@ -867,7 +867,7 @@ class Rebuilder { api_cached_, Impl::MergeProperties(properties_, action->ExecutionProperties()), dispatch_list_, - auth_, + &auth_, Impl::ScaleTime(timeout_, action->TimeoutScale()), CF::FromCacheOnly, stats_, @@ -916,7 +916,7 @@ class Rebuilder { std::map<std::string, std::string> properties_; std::vector<std::pair<std::map<std::string, std::string>, ServerAddress>> dispatch_list_; - Auth::TLS const* auth_; + Auth const& auth_; gsl::not_null<Statistics*> stats_; gsl::not_null<Progress*> progress_; std::chrono::milliseconds timeout_; diff --git a/src/buildtool/graph_traverser/graph_traverser.hpp b/src/buildtool/graph_traverser/graph_traverser.hpp index 40ca1ec3..5cc59d9b 100644 --- a/src/buildtool/graph_traverser/graph_traverser.hpp +++ b/src/buildtool/graph_traverser/graph_traverser.hpp @@ -364,7 +364,7 @@ class GraphTraverser { &*apis_.remote, platform_properties_, dispatch_list_, - apis_.auth, + &apis_.auth, stats_, progress_, logger_, @@ -398,7 +398,7 @@ class GraphTraverser { &*api_cached, platform_properties_, dispatch_list_, - apis_.auth, + &apis_.auth, stats_, progress_, clargs_.build.timeout}; diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp index cd073847..0e72890a 100644 --- a/src/buildtool/main/main.cpp +++ b/src/buildtool/main/main.cpp @@ -184,66 +184,32 @@ void SetupExecutionConfig(EndpointArguments const& eargs, return std::nullopt; } -void SetupAuthConfig(CommonAuthArguments const& authargs, - ClientAuthArguments const& client_authargs, - ServerAuthArguments const& server_authargs) { - auto use_tls = false; - if (authargs.tls_ca_cert) { - use_tls = true; - if (not Auth::TLS::Instance().SetCACertificate(*authargs.tls_ca_cert)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' certificate.", - authargs.tls_ca_cert->string()); - std::exit(kExitFailure); - } - } - if (client_authargs.tls_client_cert) { - use_tls = true; - if (not Auth::TLS::Instance().SetClientCertificate( - *client_authargs.tls_client_cert)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' certificate.", - client_authargs.tls_client_cert->string()); - std::exit(kExitFailure); - } - } - if (client_authargs.tls_client_key) { - use_tls = true; - if (not Auth::TLS::Instance().SetClientKey( - *client_authargs.tls_client_key)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' key.", - client_authargs.tls_client_key->string()); - std::exit(kExitFailure); +[[nodiscard]] auto CreateAuthConfig( + CommonAuthArguments const& authargs, + ClientAuthArguments const& client_authargs, + ServerAuthArguments const& server_authargs) noexcept + -> std::optional<Auth> { + Auth::TLS::Builder tls_builder; + tls_builder.SetCACertificate(authargs.tls_ca_cert) + .SetClientCertificate(client_authargs.tls_client_cert) + .SetClientKey(client_authargs.tls_client_key) + .SetServerCertificate(server_authargs.tls_server_cert) + .SetServerKey(server_authargs.tls_server_key); + + // create auth config (including validation) + auto result = tls_builder.Build(); + if (result) { + if (*result) { + // correctly configured TLS/SSL certification + return *std::move(*result); } + Logger::Log(LogLevel::Error, result->error()); + return std::nullopt; } - if (server_authargs.tls_server_cert) { - use_tls = true; - if (not Auth::TLS::Instance().SetServerCertificate( - *server_authargs.tls_server_cert)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' certificate.", - server_authargs.tls_server_cert->string()); - std::exit(kExitFailure); - } - } - if (server_authargs.tls_server_key) { - use_tls = true; - if (not Auth::TLS::Instance().SetServerKey( - *server_authargs.tls_server_key)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' key.", - server_authargs.tls_server_key->string()); - std::exit(kExitFailure); - } - } - - if (use_tls) { - if (not Auth::TLS::Instance().Validate()) { - std::exit(kExitFailure); - } - } + // no TLS/SSL configuration was given, and we currently support no other + // certification method, so return an empty config (no certification) + return Auth{}; } void SetupExecutionServiceConfig(ServiceArguments const& args) { @@ -812,10 +778,10 @@ auto main(int argc, char* argv[]) -> int { return kExitFailure; } - SetupAuthConfig(arguments.auth, arguments.cauth, arguments.sauth); - std::optional<Auth::TLS> auth = {}; - if (Auth::Instance().GetAuthMethod() == AuthMethod::kTLS) { - auth = Auth::TLS::Instance(); + auto auth_config = + CreateAuthConfig(arguments.auth, arguments.cauth, arguments.sauth); + if (not auth_config) { + return kExitFailure; } if (arguments.cmd == SubCommand::kGc) { @@ -829,7 +795,7 @@ auto main(int argc, char* argv[]) -> int { if (arguments.cmd == SubCommand::kExecute) { SetupExecutionServiceConfig(arguments.service); ApiBundle const exec_apis{/*repo_config=*/nullptr, - auth ? &*auth : nullptr, + &*auth_config, RemoteExecutionConfig::RemoteAddress()}; if (!ServerImpl::Instance().Run(exec_apis)) { return kExitFailure; @@ -846,7 +812,7 @@ auto main(int argc, char* argv[]) -> int { if (serve_server) { ApiBundle const serve_apis{ /*repo_config=*/nullptr, - auth ? &*auth : nullptr, + &*auth_config, RemoteExecutionConfig::RemoteAddress()}; auto serve = ServeApi::Create(*serve_config, &serve_apis); bool with_execute = not RemoteExecutionConfig::RemoteAddress(); @@ -899,7 +865,7 @@ auto main(int argc, char* argv[]) -> int { std::exit(kExitFailure); } ApiBundle const main_apis{&repo_config, - auth ? &*auth : nullptr, + &*auth_config, RemoteExecutionConfig::RemoteAddress()}; GraphTraverser const traverser{ {jobs, diff --git a/src/buildtool/serve_api/remote/TARGETS b/src/buildtool/serve_api/remote/TARGETS index e6f03424..4af6387f 100644 --- a/src/buildtool/serve_api/remote/TARGETS +++ b/src/buildtool/serve_api/remote/TARGETS @@ -16,7 +16,8 @@ , "hdrs": ["source_tree_client.hpp"] , "srcs": ["source_tree_client.cpp"] , "deps": - [ ["src/buildtool/auth", "auth"] + [ ["@", "gsl", "", "gsl"] + , ["src/buildtool/auth", "auth"] , ["src/buildtool/common/remote", "port"] , ["src/buildtool/file_system", "git_types"] , ["src/buildtool/file_system/symlinks_map", "pragma_special"] @@ -80,7 +81,8 @@ , "hdrs": ["configuration_client.hpp"] , "srcs": ["configuration_client.cpp"] , "deps": - [ ["src/buildtool/auth", "auth"] + [ ["@", "gsl", "", "gsl"] + , ["src/buildtool/auth", "auth"] , ["src/buildtool/common/remote", "port"] , ["src/buildtool/logging", "logging"] , ["src/buildtool/common/remote", "client_common"] diff --git a/src/buildtool/serve_api/remote/configuration_client.hpp b/src/buildtool/serve_api/remote/configuration_client.hpp index b7785315..3d0eb7ff 100644 --- a/src/buildtool/serve_api/remote/configuration_client.hpp +++ b/src/buildtool/serve_api/remote/configuration_client.hpp @@ -21,6 +21,7 @@ #include <utility> #include <vector> +#include "gsl/gsl" #include "justbuild/just_serve/just_serve.grpc.pb.h" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/remote/client_common.hpp" @@ -32,8 +33,9 @@ /// src/buildtool/serve_api/serve_service/just_serve.proto class ConfigurationClient { public: - explicit ConfigurationClient(ServerAddress address, - Auth::TLS const* auth) noexcept + explicit ConfigurationClient( + ServerAddress address, + gsl::not_null<Auth const*> const& auth) noexcept : client_serve_address_{std::move(address)}, stub_{justbuild::just_serve::Configuration::NewStub( CreateChannelWithCredentials(client_serve_address_.host, diff --git a/src/buildtool/serve_api/remote/serve_api.hpp b/src/buildtool/serve_api/remote/serve_api.hpp index 9e4a29bf..3374e6aa 100644 --- a/src/buildtool/serve_api/remote/serve_api.hpp +++ b/src/buildtool/serve_api/remote/serve_api.hpp @@ -42,9 +42,9 @@ class ServeApi final { public: explicit ServeApi(ServerAddress const& address, gsl::not_null<ApiBundle const*> const& apis) noexcept - : stc_{address, apis->auth}, + : stc_{address, &apis->auth}, tc_{address, apis}, - cc_{address, apis->auth} {} + cc_{address, &apis->auth} {} ~ServeApi() noexcept = default; ServeApi(ServeApi const&) = delete; diff --git a/src/buildtool/serve_api/remote/source_tree_client.cpp b/src/buildtool/serve_api/remote/source_tree_client.cpp index 3070a44f..7a922671 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.cpp +++ b/src/buildtool/serve_api/remote/source_tree_client.cpp @@ -59,8 +59,9 @@ auto PragmaSpecialToSymlinksResolve( } // namespace -SourceTreeClient::SourceTreeClient(ServerAddress const& address, - Auth::TLS const* auth) noexcept { +SourceTreeClient::SourceTreeClient( + ServerAddress const& address, + gsl::not_null<Auth const*> const& auth) noexcept { stub_ = justbuild::just_serve::SourceTree::NewStub( CreateChannelWithCredentials(address.host, address.port, auth)); } diff --git a/src/buildtool/serve_api/remote/source_tree_client.hpp b/src/buildtool/serve_api/remote/source_tree_client.hpp index 17eb0c57..e5001029 100644 --- a/src/buildtool/serve_api/remote/source_tree_client.hpp +++ b/src/buildtool/serve_api/remote/source_tree_client.hpp @@ -19,6 +19,7 @@ #include <string> #include <unordered_map> +#include "gsl/gsl" #include "justbuild/just_serve/just_serve.grpc.pb.h" #include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/common/remote/port.hpp" @@ -33,7 +34,7 @@ class SourceTreeClient { public: explicit SourceTreeClient(ServerAddress const& address, - Auth::TLS const* auth) noexcept; + gsl::not_null<Auth const*> const& auth) noexcept; // An error + data union type using result_t = expected<std::string, GitLookupError>; diff --git a/src/buildtool/serve_api/remote/target_client.cpp b/src/buildtool/serve_api/remote/target_client.cpp index d19ac26f..526121ab 100644 --- a/src/buildtool/serve_api/remote/target_client.cpp +++ b/src/buildtool/serve_api/remote/target_client.cpp @@ -31,7 +31,7 @@ TargetClient::TargetClient(ServerAddress const& address, gsl::not_null<ApiBundle const*> const& apis) noexcept : apis_{*apis} { stub_ = justbuild::just_serve::Target::NewStub( - CreateChannelWithCredentials(address.host, address.port, apis->auth)); + CreateChannelWithCredentials(address.host, address.port, &apis->auth)); } auto TargetClient::ServeTarget(const TargetCacheKey& key, diff --git a/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp index 1d81ebb0..906f331c 100644 --- a/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp +++ b/src/buildtool/serve_api/serve_service/serve_server_implementation.cpp @@ -18,6 +18,7 @@ #include <iostream> #include <memory> +#include <variant> #ifdef __unix__ #include <sys/types.h> @@ -132,13 +133,15 @@ auto ServeServerImpl::Run(RemoteServeConfig const& serve_config, .RegisterService(&op); } + // check authentication credentials; currently only TLS/SSL is supported std::shared_ptr<grpc::ServerCredentials> creds; - if (apis.auth != nullptr) { + if (const auto* tls_auth = std::get_if<Auth::TLS>(&apis.auth.method); + tls_auth != nullptr) { auto tls_opts = grpc::SslServerCredentialsOptions{}; - tls_opts.pem_root_certs = apis.auth->CACert(); + tls_opts.pem_root_certs = tls_auth->ca_cert; grpc::SslServerCredentialsOptions::PemKeyCertPair keycert = { - apis.auth->ServerKey(), apis.auth->ServerCert()}; + tls_auth->server_key, tls_auth->server_cert}; tls_opts.pem_key_cert_pairs.emplace_back(keycert); diff --git a/src/buildtool/serve_api/serve_service/target.cpp b/src/buildtool/serve_api/serve_service/target.cpp index fc09ee8c..44632590 100644 --- a/src/buildtool/serve_api/serve_service/target.cpp +++ b/src/buildtool/serve_api/serve_service/target.cpp @@ -499,7 +499,7 @@ auto TargetService::ServeTarget( // Use a new ApiBundle that knows about local repository config for // traversing. - ApiBundle const local_apis{&repository_config, apis_.auth, address}; + ApiBundle const local_apis{&repository_config, &apis_.auth, address}; GraphTraverser const traverser{ std::move(traverser_args), &repository_config, diff --git a/src/other_tools/just_mr/TARGETS b/src/other_tools/just_mr/TARGETS index b8afc631..a2878802 100644 --- a/src/other_tools/just_mr/TARGETS +++ b/src/other_tools/just_mr/TARGETS @@ -82,7 +82,8 @@ , "hdrs": ["setup_utils.hpp"] , "srcs": ["setup_utils.cpp"] , "deps": - [ ["src/buildtool/build_engine/expression", "expression_ptr_interface"] + [ ["src/buildtool/auth", "auth"] + , ["src/buildtool/build_engine/expression", "expression_ptr_interface"] , ["src/buildtool/build_engine/expression", "expression"] , ["src/buildtool/serve_api/remote", "config"] , "cli" @@ -94,7 +95,6 @@ , ["src/buildtool/logging", "log_level"] , ["src/buildtool/logging", "logging"] , "exit_codes" - , ["src/buildtool/auth", "auth"] ] } , "fetch": diff --git a/src/other_tools/just_mr/fetch.cpp b/src/other_tools/just_mr/fetch.cpp index 11ae3a01..07a03f3d 100644 --- a/src/other_tools/just_mr/fetch.cpp +++ b/src/other_tools/just_mr/fetch.cpp @@ -398,14 +398,13 @@ auto MultiRepoFetch(std::shared_ptr<Configuration> const& config, common_args.remote_serve_address); // setup authentication - JustMR::Utils::SetupAuthConfig(auth_args); - std::optional<Auth::TLS> auth = {}; - if (Auth::Instance().GetAuthMethod() == AuthMethod::kTLS) { - auth = Auth::TLS::Instance(); + auto auth_config = JustMR::Utils::CreateAuthConfig(auth_args); + if (not auth_config) { + return kExitConfigError; } ApiBundle const apis{/*repo_config=*/nullptr, - auth ? &*auth : nullptr, + &*auth_config, RemoteExecutionConfig::RemoteAddress()}; bool const has_remote_api = diff --git a/src/other_tools/just_mr/setup.cpp b/src/other_tools/just_mr/setup.cpp index 70c74eb0..6866bc26 100644 --- a/src/other_tools/just_mr/setup.cpp +++ b/src/other_tools/just_mr/setup.cpp @@ -117,14 +117,13 @@ auto MultiRepoSetup(std::shared_ptr<Configuration> const& config, common_args.remote_serve_address); // setup authentication - JustMR::Utils::SetupAuthConfig(auth_args); - std::optional<Auth::TLS> auth = {}; - if (Auth::Instance().GetAuthMethod() == AuthMethod::kTLS) { - auth = Auth::TLS::Instance(); + auto auth_config = JustMR::Utils::CreateAuthConfig(auth_args); + if (not auth_config) { + return std::nullopt; } ApiBundle const apis{/*repo_config=*/nullptr, - auth ? &*auth : nullptr, + &*auth_config, RemoteExecutionConfig::RemoteAddress()}; bool const has_remote_api = diff --git a/src/other_tools/just_mr/setup_utils.cpp b/src/other_tools/just_mr/setup_utils.cpp index 7ed61897..577fb1bf 100644 --- a/src/other_tools/just_mr/setup_utils.cpp +++ b/src/other_tools/just_mr/setup_utils.cpp @@ -19,7 +19,6 @@ #include <variant> #include "nlohmann/json.hpp" -#include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/build_engine/expression/expression.hpp" #include "src/buildtool/file_system/file_system_manager.hpp" #include "src/buildtool/logging/log_level.hpp" @@ -193,42 +192,28 @@ auto ReadConfiguration( } } -void SetupAuthConfig(MultiRepoRemoteAuthArguments const& authargs) noexcept { - bool use_tls{false}; - if (authargs.tls_ca_cert) { - use_tls = true; - if (not Auth::TLS::Instance().SetCACertificate(*authargs.tls_ca_cert)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' certificate.", - authargs.tls_ca_cert->string()); - std::exit(kExitConfigError); - } - } - if (authargs.tls_client_cert) { - use_tls = true; - if (not Auth::TLS::Instance().SetClientCertificate( - *authargs.tls_client_cert)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' certificate.", - authargs.tls_client_cert->string()); - std::exit(kExitConfigError); - } - } - if (authargs.tls_client_key) { - use_tls = true; - if (not Auth::TLS::Instance().SetClientKey(*authargs.tls_client_key)) { - Logger::Log(LogLevel::Error, - "Could not read '{}' key.", - authargs.tls_client_key->string()); - std::exit(kExitConfigError); - } - } +auto CreateAuthConfig(MultiRepoRemoteAuthArguments const& authargs) noexcept + -> std::optional<Auth> { - if (use_tls) { - if (not Auth::TLS::Instance().Validate()) { - std::exit(kExitConfigError); + Auth::TLS::Builder tls_builder; + tls_builder.SetCACertificate(authargs.tls_ca_cert) + .SetClientCertificate(authargs.tls_client_cert) + .SetClientKey(authargs.tls_client_key); + + // create auth config (including validation) + auto result = tls_builder.Build(); + if (result) { + if (*result) { + // correctly configured TLS/SSL certification + return *std::move(*result); } + Logger::Log(LogLevel::Error, result->error()); + return std::nullopt; } + + // no TLS/SSL configuration was given, and we currently support no other + // certification method, so return an empty config (no certification) + return Auth{}; } void SetupRemoteConfig( diff --git a/src/other_tools/just_mr/setup_utils.hpp b/src/other_tools/just_mr/setup_utils.hpp index 2ae08d41..3043855c 100644 --- a/src/other_tools/just_mr/setup_utils.hpp +++ b/src/other_tools/just_mr/setup_utils.hpp @@ -21,6 +21,7 @@ #include <string> #include <vector> +#include "src/buildtool/auth/authentication.hpp" #include "src/buildtool/build_engine/expression/configuration.hpp" #include "src/buildtool/build_engine/expression/expression_ptr.hpp" #include "src/buildtool/serve_api/remote/config.hpp" @@ -60,7 +61,9 @@ void DefaultReachableRepositories( std::optional<std::filesystem::path> const& absent_file_opt) noexcept -> std::shared_ptr<Configuration>; -void SetupAuthConfig(MultiRepoRemoteAuthArguments const& authargs) noexcept; +[[nodiscard]] auto CreateAuthConfig( + MultiRepoRemoteAuthArguments const& authargs) noexcept + -> std::optional<Auth>; void SetupRemoteConfig( std::optional<std::string> const& remote_exec_addr, |