-
Notifications
You must be signed in to change notification settings - Fork 592
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
security/a/s: Utils map http request to audit msg
- Loading branch information
1 parent
f16e929
commit f4554a3
Showing
3 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
/* | ||
* Copyright 2023 Redpanda Data, Inc. | ||
* | ||
* Use of this software is governed by the Business Source License | ||
* included in the file licenses/BSL.md | ||
* | ||
* As of the Change Date specified in that file, in accordance with | ||
* the Business Source License, use of this software will be governed | ||
* by the Apache License, Version 2.0 | ||
*/ | ||
|
||
#include "security/audit/schemas/utils.h" | ||
|
||
#include "security/audit/schemas/application_activity.h" | ||
#include "security/audit/schemas/types.h" | ||
#include "utils/request_auth.h" | ||
|
||
#include <boost/algorithm/string/predicate.hpp> | ||
|
||
namespace security::audit { | ||
|
||
namespace { | ||
|
||
api_activity::activity_id http_method_to_activity_id(std::string_view method) { | ||
return string_switch<api_activity::activity_id>(method) | ||
.match_all("POST", "post", api_activity::activity_id::create) | ||
.match_all("GET", "get", api_activity::activity_id::read) | ||
.match_all("PUT", "put", api_activity::activity_id::update) | ||
.match_all("DELETE", "delete", api_activity::activity_id::delete_id) | ||
.default_match(api_activity::activity_id::unknown); | ||
} | ||
|
||
uniform_resource_locator | ||
uri_from_ss_http_request(const ss::http::request& req) { | ||
return { | ||
.hostname = req.get_header("Host"), | ||
.path = req._url, | ||
.port = port_t{req.get_server_address().port()}, | ||
.scheme = req.get_protocol_name(), | ||
.url_string = req.get_url()}; | ||
} | ||
|
||
http_request from_ss_http_request(const ss::http::request& req) { | ||
using ss_http_headers_t = decltype(req._headers); | ||
using ss_http_headers_value_t = ss_http_headers_t::value_type; | ||
const auto get_headers = [](const ss_http_headers_t& headers) { | ||
const auto sanitize_header = | ||
[](const ss_http_headers_value_t& kv) -> ss::sstring { | ||
constexpr auto sensitive_headers = std::to_array<std::string_view>( | ||
{"Authorization", "Cookie"}); | ||
|
||
if ( | ||
std::find_if( | ||
sensitive_headers.begin(), | ||
sensitive_headers.end(), | ||
[&kv](std::string_view s) { | ||
return boost::iequals(s, kv.first); | ||
}) | ||
!= sensitive_headers.end()) { | ||
return "******"; | ||
} else { | ||
return kv.second; | ||
} | ||
}; | ||
std::vector<http_header> audit_headers; | ||
std::transform( | ||
headers.begin(), | ||
headers.end(), | ||
std::back_inserter(audit_headers), | ||
[sanitize_header = std::move(sanitize_header)](const auto& kv) { | ||
return http_header{ | ||
.name = kv.first, .value = sanitize_header(kv)}; | ||
}); | ||
return audit_headers; | ||
}; | ||
return http_request{ | ||
.http_headers = get_headers(req._headers), | ||
.http_method = req._method, | ||
.url = uri_from_ss_http_request(req), | ||
.user_agent = req.get_header("User-Agent"), | ||
.version = req._version}; | ||
} | ||
|
||
network_endpoint from_ss_endpoint(const ss::socket_address& sa) { | ||
return network_endpoint{ | ||
.addr = net::unresolved_address( | ||
fmt::format("{}", sa.addr()), sa.port(), sa.addr().in_family())}; | ||
} | ||
|
||
/// TODO: Via ACLs metadata return correct response | ||
api_activity_unmapped unmapped_data() { return api_activity_unmapped{}; } | ||
|
||
user user_from_request_auth_result(const request_auth_result& r) { | ||
auto& username = r.get_username(); | ||
|
||
return { | ||
.name = username.empty() ? "{{anonymous}}" : username, | ||
.type_id = r.is_authenticated() | ||
? (r.is_superuser() ? user::type::admin : user::type::user) | ||
: user::type::unknown, | ||
}; | ||
} | ||
|
||
actor actor_from_request_auth_result( | ||
const request_auth_result& r, | ||
bool authorized, | ||
const std::optional<std::string_view>& reason) { | ||
auto u = user_from_request_auth_result(r); | ||
std::vector<authorization_result> auths{ | ||
{.decision = authorized ? "authorized" : "denied", | ||
.policy = policy{ | ||
.desc = ss::sstring{reason.value_or( | ||
r.is_auth_required() ? "" : "Auth Disabled")}, | ||
.name = "Admin httpd authorizer"}}}; | ||
|
||
return {.authorizations = std::move(auths), .user = std::move(u)}; | ||
} | ||
|
||
template<typename Clock> | ||
timestamp_t create_timestamp_t(std::chrono::time_point<Clock> time_point) { | ||
return timestamp_t(std::chrono::duration_cast<std::chrono::milliseconds>( | ||
time_point.time_since_epoch()) | ||
.count()); | ||
} | ||
|
||
template<typename Clock> | ||
timestamp_t create_timestamp_t() { | ||
return create_timestamp_t(Clock::now()); | ||
} | ||
|
||
} // namespace | ||
|
||
api_activity make_api_activity_event( | ||
ss::httpd::const_req req, | ||
const request_auth_result& auth_result, | ||
bool authorized, | ||
const std::optional<std::string_view>& reason) { | ||
auto act = actor_from_request_auth_result(auth_result, authorized, reason); | ||
return { | ||
http_method_to_activity_id(req._method), | ||
std::move(act), | ||
api{.operation = req._method}, | ||
from_ss_endpoint(req.get_server_address()), | ||
from_ss_http_request(req), | ||
{}, | ||
severity_id::informational, | ||
from_ss_endpoint(req.get_client_address()), | ||
authorized ? api_activity::status_id::success | ||
: api_activity::status_id::failure, | ||
create_timestamp_t<std::chrono::system_clock>(), | ||
unmapped_data()}; | ||
} | ||
|
||
} // namespace security::audit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Copyright 2023 Redpanda Data, Inc. | ||
* | ||
* Use of this software is governed by the Business Source License | ||
* included in the file licenses/BSL.md | ||
* | ||
* As of the Change Date specified in that file, in accordance with | ||
* the Business Source License, use of this software will be governed | ||
* by the Apache License, Version 2.0 | ||
*/ | ||
|
||
#pragma once | ||
#include "net/unresolved_address.h" | ||
#include "security/audit/schemas/application_activity.h" | ||
#include "security/audit/schemas/types.h" | ||
#include "utils/request_auth.h" | ||
#include "utils/string_switch.h" | ||
|
||
#include <seastar/http/handlers.hh> | ||
#include <seastar/http/request.hh> | ||
|
||
namespace security::audit { | ||
|
||
api_activity make_api_activity_event( | ||
ss::httpd::const_req req, | ||
const request_auth_result& auth_result, | ||
bool authorized, | ||
const std::optional<std::string_view>& reason); | ||
|
||
} // namespace security::audit |