From 4dadc372003effa49e7161b7e54fbe9918e0eec3 Mon Sep 17 00:00:00 2001 From: Abhijat Malviya Date: Thu, 19 Oct 2023 14:28:16 +0530 Subject: [PATCH] cloud_roles: Redact fields when printing request When printing a request the fields inside the string can leak secrets. A replacement is done inside the string for sensitive headers. --- src/v/cloud_roles/signature.cc | 41 ++++++++++++++++++++++- src/v/cloud_roles/signature.h | 2 ++ src/v/cloud_roles/tests/signature_test.cc | 26 ++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/src/v/cloud_roles/signature.cc b/src/v/cloud_roles/signature.cc index b4b2084acc590..59dfde6a41252 100644 --- a/src/v/cloud_roles/signature.cc +++ b/src/v/cloud_roles/signature.cc @@ -12,6 +12,7 @@ #include "bytes/bytes.h" #include "cloud_roles/logger.h" +#include "config/base_property.h" #include "hashing/secure.h" #include "ssx/sformat.h" #include "utils/base64.h" @@ -20,6 +21,8 @@ #include #include +#include +#include #include #include #include @@ -372,6 +375,35 @@ ss::sstring signature_v4::sha256_hexdigest(std::string_view payload) { return sha_256(payload); } +ss::sstring redact_headers_from_string(const std::string_view original) { + std::set redacted{}; + const auto redacted_fields = http::redacted_fields(); + for (const auto& rf : redacted_fields) { + redacted.insert(ss::visit( + rf, + [](const boost::beast::http::field& f) { return to_string(f); }, + [](const std::string& s) { return boost::core::string_view{s}; })); + } + + const auto lines = absl::StrSplit(original, "\n"); + std::vector result{}; + for (const auto& line : lines) { + if (line.find(':') != std::string_view::npos) { + const auto tokens = absl::StrSplit(line, ":"); + const auto key = *tokens.begin(); + if ( + std::find(redacted.cbegin(), redacted.cend(), key) + != redacted.cend()) { + result.emplace_back(fmt::format( + "{}:{}", *tokens.begin(), config::secret_placeholder)); + continue; + } + } + result.emplace_back(line.data(), line.size()); + } + return absl::StrJoin(result, "\n"); +} + std::error_code signature_v4::sign_header( http::client::request_header& header, std::string_view sha256) const { ss::sstring date_str = _sig_time.format_date(); @@ -392,7 +424,14 @@ std::error_code signature_v4::sign_header( if (!canonical_req) { return canonical_req.error(); } - vlog(clrl_log.trace, "\n[canonical-request]\n{}\n", canonical_req.value()); + + if (clrl_log.is_enabled(seastar::log_level::trace)) { + vlog( + clrl_log.trace, + "\n[canonical-request]\n{}\n", + redact_headers_from_string(canonical_req.value())); + } + auto str_to_sign = get_string_to_sign( amz_date, cred_scope, canonical_req.value()); auto digest = hmac(sign_key, str_to_sign); diff --git a/src/v/cloud_roles/signature.h b/src/v/cloud_roles/signature.h index c41d8a77c89e9..d9591d5fcceb0 100644 --- a/src/v/cloud_roles/signature.h +++ b/src/v/cloud_roles/signature.h @@ -180,4 +180,6 @@ time_source::time_source(Fn&& fn, int) ss::sstring uri_encode(const ss::sstring& input, bool encode_slash); +ss::sstring redact_headers_from_string(const std::string_view original); + } // namespace cloud_roles diff --git a/src/v/cloud_roles/tests/signature_test.cc b/src/v/cloud_roles/tests/signature_test.cc index 95ccd81e1d1f5..03f835d4f215e 100644 --- a/src/v/cloud_roles/tests/signature_test.cc +++ b/src/v/cloud_roles/tests/signature_test.cc @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -237,3 +239,27 @@ SEASTAR_THREAD_TEST_CASE(test_gnutls) { to_hex(bytes_view{result.data(), 32}), "c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9"); } + +SEASTAR_THREAD_TEST_CASE(test_redact_headers_from_string) { + std::vector lines{}; + lines.emplace_back(fmt::format("{}:{}", "x-amz-security-token", "abcd")); + lines.emplace_back(fmt::format("{}:{}", "x-amz-content-sha256", "secret")); + lines.emplace_back( + fmt::format("{}:{}", "x-amz-security-token111", "abcd111")); + lines.emplace_back( + fmt::format("{}:{}", "x-amz-security-token222", "abcd222")); + lines.emplace_back( + fmt::format("{}:{}", "x-amz-security-token", "abcdabcd")); + + const std::string redacted = cloud_roles::redact_headers_from_string( + absl::StrJoin(lines, "\n")); + + const auto redacted_lines = absl::StrSplit(redacted, "\n"); + auto it = redacted_lines.begin(); + + BOOST_REQUIRE_EQUAL(*(it++), "x-amz-security-token:[secret]"); + BOOST_REQUIRE_EQUAL(*(it++), "x-amz-content-sha256:[secret]"); + BOOST_REQUIRE_EQUAL(*(it++), "x-amz-security-token111:abcd111"); + BOOST_REQUIRE_EQUAL(*(it++), "x-amz-security-token222:abcd222"); + BOOST_REQUIRE_EQUAL(*(it++), "x-amz-security-token:[secret]"); +}