summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/auth/TARGETS9
-rw-r--r--src/buildtool/auth/authentication.hpp128
-rw-r--r--src/buildtool/common/cli.hpp23
-rw-r--r--src/buildtool/execution_api/remote/TARGETS1
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp7
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp5
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp9
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp5
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp19
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp6
-rw-r--r--src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp5
-rw-r--r--src/buildtool/execution_api/remote/bazel/bytestream_client.hpp7
-rw-r--r--src/buildtool/main/TARGETS1
-rw-r--r--src/buildtool/main/main.cpp45
14 files changed, 228 insertions, 42 deletions
diff --git a/src/buildtool/auth/TARGETS b/src/buildtool/auth/TARGETS
new file mode 100644
index 00000000..6faf688c
--- /dev/null
+++ b/src/buildtool/auth/TARGETS
@@ -0,0 +1,9 @@
+{ "auth":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["auth"]
+ , "hdrs": ["authentication.hpp"]
+ , "deps":
+ [["@", "gsl-lite", "", "gsl-lite"], ["src/buildtool/logging", "logging"]]
+ , "stage": ["src", "buildtool", "auth"]
+ }
+}
diff --git a/src/buildtool/auth/authentication.hpp b/src/buildtool/auth/authentication.hpp
new file mode 100644
index 00000000..c3f6eb71
--- /dev/null
+++ b/src/buildtool/auth/authentication.hpp
@@ -0,0 +1,128 @@
+// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INCLUDED_SRC_BUILDTOOL_AUTH_AUTHENTICATION_HPP
+#define INCLUDED_SRC_BUILDTOOL_AUTH_AUTHENTICATION_HPP
+#include <cstdint>
+#include <filesystem>
+#include <fstream>
+#include <optional>
+#include <streambuf>
+#include <string>
+#include <utility>
+
+#include <gsl-lite/gsl-lite.hpp>
+
+#include "src/buildtool/logging/logger.hpp"
+enum class AuthMethod : std::uint8_t { kNONE, kTLS };
+
+class Auth {
+ public:
+ [[nodiscard]] static auto Instance() noexcept -> Auth& {
+ static Auth instance{};
+ return instance;
+ }
+
+ static void SetAuthMethod(AuthMethod x) { Instance().auth_ = x; }
+ [[nodiscard]] static auto GetAuthMethod() noexcept -> AuthMethod {
+ return Instance().auth_;
+ }
+
+ class TLS {
+ public:
+ [[nodiscard]] static auto Instance() noexcept -> TLS& {
+ static TLS instance{};
+ return instance;
+ }
+
+ [[nodiscard]] static auto CACert() noexcept -> const std::string& {
+ return Instance().ca_cert_;
+ }
+
+ [[nodiscard]] static auto ClientCert() noexcept -> const std::string& {
+ return Instance().client_cert_;
+ }
+
+ [[nodiscard]] static auto ClientKey() noexcept -> const std::string& {
+ return Instance().client_key_;
+ }
+
+ [[nodiscard]] static auto SetCACertificate(
+ std::filesystem::path const& cert_file) noexcept -> bool {
+ return set(cert_file, &Instance().ca_cert_);
+ }
+
+ [[nodiscard]] static auto SetClientCertificate(
+ std::filesystem::path const& cert_file) noexcept -> bool {
+ return set(cert_file, &Instance().client_cert_);
+ }
+
+ [[nodiscard]] static auto SetClientKey(
+ std::filesystem::path const& key_file) noexcept -> bool {
+ return set(key_file, &Instance().client_key_);
+ }
+
+ // 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]] static auto Validate() noexcept -> bool {
+ if (CACert().empty()) {
+ Logger::Log(LogLevel::Error, "Please provide tls-ca-cert");
+ return false;
+ }
+
+ // to enable mTLS, both tls_client_{ceritifcate,key} must be
+ // supplied
+ if (ClientCert().empty() && not(ClientKey().empty())) {
+ Logger::Log(LogLevel::Error,
+ "Please also provide tls-client-cert");
+ return false;
+ }
+ if (not(ClientCert().empty()) && ClientKey().empty()) {
+ Logger::Log(LogLevel::Error,
+ "Please also provide tls-client-key");
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ std::string ca_cert_;
+ std::string client_cert_;
+ std::string client_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::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;
+ }
+ };
+
+ private:
+ AuthMethod auth_{AuthMethod::kNONE};
+};
+#endif
diff --git a/src/buildtool/common/cli.hpp b/src/buildtool/common/cli.hpp
index 4650f749..b9c2feb9 100644
--- a/src/buildtool/common/cli.hpp
+++ b/src/buildtool/common/cli.hpp
@@ -125,6 +125,14 @@ struct GraphArguments {
std::optional<std::filesystem::path> git_cas{};
};
+/// \brief Arguments for authentication methods.
+struct AuthArguments {
+ // CA certificate used to verify server's identity
+ std::optional<std::filesystem::path> tls_ca_cert{std::nullopt};
+ std::optional<std::filesystem::path> tls_client_cert{std::nullopt};
+ std::optional<std::filesystem::path> tls_client_key{std::nullopt};
+};
+
static inline auto SetupCommonArguments(
gsl::not_null<CLI::App*> const& app,
gsl::not_null<CommonArguments*> const& clargs) {
@@ -457,4 +465,19 @@ static inline auto SetupCompatibilityArguments(
"remote build execution protocol. As the change affects identifiers, "
"the flag must be used consistently for all related invocations.");
}
+
+static inline auto SetupAuthArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<AuthArguments*> const& authargs) {
+ app->add_option("--tls-ca-cert",
+ authargs->tls_ca_cert,
+ "Path to a TLS CA certificate that is trusted to sign the "
+ "server certificate.");
+ app->add_option("--tls-client-cert",
+ authargs->tls_client_cert,
+ "Path to the TLS client certificate.");
+ app->add_option("--tls-client-key",
+ authargs->tls_client_key,
+ "Path to the TLS client key.");
+}
#endif // INCLUDED_SRC_BUILDTOOL_COMMON_CLI_HPP
diff --git a/src/buildtool/execution_api/remote/TARGETS b/src/buildtool/execution_api/remote/TARGETS
index 4bf96ea0..3f7961d5 100644
--- a/src/buildtool/execution_api/remote/TARGETS
+++ b/src/buildtool/execution_api/remote/TARGETS
@@ -27,6 +27,7 @@
, ["@", "gsl-lite", "", "gsl-lite"]
, ["src/buildtool/common", "bazel_types"]
, ["src/buildtool/execution_api/bazel_msg", "bazel_msg"]
+ , ["src/buildtool/auth", "auth"]
]
, "proto":
[ ["@", "bazel_remote_apis", "", "remote_execution_proto"]
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 d96db45a..6eac5adf 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.cpp
@@ -18,12 +18,9 @@
#include "src/buildtool/common/bazel_types.hpp"
#include "src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp"
-BazelAcClient::BazelAcClient(std::string const& server,
- Port port,
- std::string const& user,
- std::string const& pwd) noexcept {
+BazelAcClient::BazelAcClient(std::string const& server, Port port) noexcept {
stub_ = bazel_re::ActionCache::NewStub(
- CreateChannelWithCredentials(server, port, user, pwd));
+ CreateChannelWithCredentials(server, port));
}
auto BazelAcClient::GetActionResult(
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 8712beb8..c9914e77 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_ac_client.hpp
@@ -29,10 +29,7 @@
/// https://github.com/bazelbuild/bazel/blob/4b6ad34dbba15dacebfb6cbf76fa741649cdb007/third_party/remoteapis/build/bazel/remote/execution/v2/remote_execution.proto#L137
class BazelAcClient {
public:
- BazelAcClient(std::string const& server,
- Port port,
- std::string const& user = "",
- std::string const& pwd = "") noexcept;
+ BazelAcClient(std::string const& server, Port port) noexcept;
[[nodiscard]] auto GetActionResult(
std::string const& instance_name,
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 8158ee55..232c5c08 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.cpp
@@ -31,13 +31,10 @@ namespace {
} // namespace
-BazelCasClient::BazelCasClient(std::string const& server,
- Port port,
- std::string const& user,
- std::string const& pwd) noexcept
- : stream_{std::make_unique<ByteStreamClient>(server, port, user, pwd)} {
+BazelCasClient::BazelCasClient(std::string const& server, Port port) noexcept
+ : stream_{std::make_unique<ByteStreamClient>(server, port)} {
stub_ = bazel_re::ContentAddressableStorage::NewStub(
- CreateChannelWithCredentials(server, port, user, pwd));
+ CreateChannelWithCredentials(server, port));
}
auto BazelCasClient::FindMissingBlobs(
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 b40d84d2..bcf6df7e 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_cas_client.hpp
@@ -33,10 +33,7 @@
/// https://github.com/bazelbuild/bazel/blob/4b6ad34dbba15dacebfb6cbf76fa741649cdb007/third_party/remoteapis/build/bazel/remote/execution/v2/remote_execution.proto#L243
class BazelCasClient {
public:
- BazelCasClient(std::string const& server,
- Port port,
- std::string const& user = "",
- std::string const& pwd = "") noexcept;
+ BazelCasClient(std::string const& server, Port port) noexcept;
/// \brief Find missing blobs
/// \param[in] instance_name Name of the CAS instance
diff --git a/src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp b/src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp
index 9df99b97..60fb7860 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_client_common.hpp
@@ -22,6 +22,7 @@
#include <string>
#include "grpcpp/grpcpp.h"
+#include "src/buildtool/auth/authentication.hpp"
#include "src/buildtool/common/bazel_types.hpp"
#include "src/buildtool/execution_api/bazel_msg/bazel_common.hpp"
#include "src/buildtool/execution_api/remote/config.hpp"
@@ -29,18 +30,20 @@
[[maybe_unused]] [[nodiscard]] static inline auto CreateChannelWithCredentials(
std::string const& server,
- Port port,
- std::string const& user = "",
- [[maybe_unused]] std::string const& pwd = "") noexcept {
- std::shared_ptr<grpc::ChannelCredentials> cred;
+ Port port) noexcept {
+
+ std::shared_ptr<grpc::ChannelCredentials> creds;
std::string address = server + ':' + std::to_string(port);
- if (user.empty()) {
- cred = grpc::InsecureChannelCredentials();
+ if (Auth::GetAuthMethod() == AuthMethod::kTLS) {
+ auto tls_opts = grpc::SslCredentialsOptions{Auth::TLS::CACert(),
+ Auth::TLS::ClientKey(),
+ Auth::TLS::ClientCert()};
+ creds = grpc::SslCredentials(tls_opts);
}
else {
- // TODO(oreiche): set up authentication credentials
+ creds = grpc::InsecureChannelCredentials();
}
- return grpc::CreateChannel(address, cred);
+ return grpc::CreateChannel(address, creds);
}
[[maybe_unused]] static inline void LogStatus(Logger const* logger,
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 a1e031a8..b1244e0c 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.cpp
@@ -47,11 +47,9 @@ void LogExecutionStatus(gsl::not_null<Logger const*> const& logger,
} // namespace
BazelExecutionClient::BazelExecutionClient(std::string const& server,
- Port port,
- std::string const& user,
- std::string const& pwd) noexcept {
+ Port port) noexcept {
stub_ = bazel_re::Execution::NewStub(
- CreateChannelWithCredentials(server, port, user, pwd));
+ CreateChannelWithCredentials(server, port));
}
auto BazelExecutionClient::Execute(std::string const& instance_name,
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 06b3cfdc..480caf9c 100644
--- a/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp
+++ b/src/buildtool/execution_api/remote/bazel/bazel_execution_client.hpp
@@ -52,10 +52,7 @@ class BazelExecutionClient {
}
};
- BazelExecutionClient(std::string const& server,
- Port port,
- std::string const& user = "",
- std::string const& pwd = "") noexcept;
+ BazelExecutionClient(std::string const& server, Port port) noexcept;
[[nodiscard]] auto Execute(std::string const& instance_name,
bazel_re::Digest const& action_digest,
diff --git a/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp b/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp
index 85e26078..8edaef3e 100644
--- a/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp
+++ b/src/buildtool/execution_api/remote/bazel/bytestream_client.hpp
@@ -71,12 +71,9 @@ class ByteStreamClient {
}
};
- ByteStreamClient(std::string const& server,
- Port port,
- std::string const& user = "",
- std::string const& pwd = "") noexcept {
+ ByteStreamClient(std::string const& server, Port port) noexcept {
stub_ = google::bytestream::ByteStream::NewStub(
- CreateChannelWithCredentials(server, port, user, pwd));
+ CreateChannelWithCredentials(server, port));
}
[[nodiscard]] auto IncrementalRead(
diff --git a/src/buildtool/main/TARGETS b/src/buildtool/main/TARGETS
index 92a0b9a3..70e361a2 100644
--- a/src/buildtool/main/TARGETS
+++ b/src/buildtool/main/TARGETS
@@ -16,6 +16,7 @@
, ["src/buildtool/multithreading", "task_system"]
, ["src/utils/cpp", "concepts"]
, ["src/utils/cpp", "json"]
+ , ["src/buildtool/auth", "auth"]
, "common"
, "version"
, "analyse"
diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp
index 0c9f047a..cf98bcf3 100644
--- a/src/buildtool/main/main.cpp
+++ b/src/buildtool/main/main.cpp
@@ -36,6 +36,7 @@
#include "src/buildtool/main/exit_codes.hpp"
#include "src/buildtool/main/install_cas.hpp"
#ifndef BOOTSTRAP_BUILD_TOOL
+#include "src/buildtool/auth/authentication.hpp"
#include "src/buildtool/graph_traverser/graph_traverser.hpp"
#include "src/buildtool/progress_reporting/base_progress_reporter.hpp"
#endif
@@ -78,6 +79,7 @@ struct CommandLineArguments {
RebuildArguments rebuild;
FetchArguments fetch;
GraphArguments graph;
+ AuthArguments auth;
};
/// \brief Setup arguments for sub command "just describe".
@@ -110,6 +112,7 @@ auto SetupBuildCommandArguments(
SetupLogArguments(app, &clargs->log);
SetupAnalysisArguments(app, &clargs->analysis);
SetupEndpointArguments(app, &clargs->endpoint);
+ SetupAuthArguments(app, &clargs->auth);
SetupBuildArguments(app, &clargs->build);
SetupCompatibilityArguments(app);
}
@@ -136,6 +139,7 @@ auto SetupInstallCasCommandArguments(
gsl::not_null<CommandLineArguments*> const& clargs) {
SetupCompatibilityArguments(app);
SetupEndpointArguments(app, &clargs->endpoint);
+ SetupAuthArguments(app, &clargs->auth);
SetupFetchArguments(app, &clargs->fetch);
SetupLogArguments(app, &clargs->log);
}
@@ -147,6 +151,7 @@ auto SetupTraverseCommandArguments(
SetupCommonArguments(app, &clargs->common);
SetupLogArguments(app, &clargs->log);
SetupEndpointArguments(app, &clargs->endpoint);
+ SetupAuthArguments(app, &clargs->auth);
SetupGraphArguments(app, &clargs->graph); // instead of analysis
SetupBuildArguments(app, &clargs->build);
SetupStageArguments(app, &clargs->stage);
@@ -239,6 +244,7 @@ void SetupLogging(LogArguments const& clargs) {
#ifndef BOOTSTRAP_BUILD_TOOL
void SetupExecutionConfig(EndpointArguments const& eargs,
+ AuthArguments const& authargs,
BuildArguments const& bargs,
RebuildArguments const& rargs) {
using LocalConfig = LocalExecutionConfig;
@@ -276,6 +282,39 @@ void SetupExecutionConfig(EndpointArguments const& eargs,
std::exit(kExitFailure);
}
}
+ auto use_tls = false;
+ if (authargs.tls_ca_cert) {
+ use_tls = true;
+ if (not Auth::TLS::SetCACertificate(*authargs.tls_ca_cert)) {
+ Logger::Log(LogLevel::Error,
+ "Could not read '{}' certificate.",
+ authargs.tls_ca_cert->string());
+ std::exit(kExitFailure);
+ }
+ }
+ if (authargs.tls_client_cert) {
+ use_tls = true;
+ if (not Auth::TLS::SetClientCertificate(*authargs.tls_client_cert)) {
+ Logger::Log(LogLevel::Error,
+ "Could not read '{}' certificate.",
+ authargs.tls_client_cert->string());
+ std::exit(kExitFailure);
+ }
+ }
+ if (authargs.tls_client_key) {
+ use_tls = true;
+ if (not Auth::TLS::SetClientKey(*authargs.tls_client_key)) {
+ Logger::Log(LogLevel::Error,
+ "Could not read '{}' key.",
+ authargs.tls_client_key->string());
+ std::exit(kExitFailure);
+ }
+ }
+ if (use_tls) {
+ if (not Auth::TLS::Validate()) {
+ std::exit(kExitFailure);
+ }
+ }
}
void SetupHashFunction() {
@@ -1097,8 +1136,10 @@ auto main(int argc, char* argv[]) -> int {
}
#ifndef BOOTSTRAP_BUILD_TOOL
SetupHashFunction();
- SetupExecutionConfig(
- arguments.endpoint, arguments.build, arguments.rebuild);
+ SetupExecutionConfig(arguments.endpoint,
+ arguments.auth,
+ arguments.build,
+ arguments.rebuild);
#endif
auto jobs = arguments.build.build_jobs > 0 ? arguments.build.build_jobs