Skip to content

Commit

Permalink
cloud_roles: Redact fields when printing request
Browse files Browse the repository at this point in the history
When printing a request the fields inside the string can leak secrets. A
replacement is done inside the string for sensitive headers.
  • Loading branch information
abhijat committed Oct 19, 2023
1 parent 2d7dcf4 commit 2c570d8
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
39 changes: 38 additions & 1 deletion src/v/cloud_roles/signature.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -20,6 +21,8 @@
#include <seastar/core/lowres_clock.hh>
#include <seastar/core/sstring.hh>

#include <absl/strings/str_join.h>
#include <absl/strings/str_split.h>
#include <boost/algorithm/string/compare.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
Expand Down Expand Up @@ -372,6 +375,37 @@ 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<ss::sstring> redacted{};
for (const auto& rf : http::redacted_fields()) {
redacted.insert(ss::visit(
rf,
[](const boost::beast::http::field& f) {
const auto view = to_string(f);
return ss::sstring{view.data(), view.size()};
},
[](const std::string& s) { return ss::sstring{s}; }));
}

const auto lines = absl::StrSplit(original, "\n");
std::vector<ss::sstring> 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();
Expand All @@ -392,7 +426,10 @@ 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());
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);
Expand Down
2 changes: 2 additions & 0 deletions src/v/cloud_roles/signature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
26 changes: 26 additions & 0 deletions src/v/cloud_roles/tests/signature_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include <seastar/core/temporary_buffer.hh>
#include <seastar/testing/thread_test_case.hh>

#include <absl/strings/str_join.h>
#include <absl/strings/str_split.h>
#include <boost/test/unit_test.hpp>

#include <chrono>
Expand Down Expand Up @@ -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<ss::sstring> 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]");
}

0 comments on commit 2c570d8

Please sign in to comment.