mirror of
https://github.com/openappsec/openappsec.git
synced 2025-09-29 19:24:26 +03:00
Apr 27th Update
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
add_subdirectory(layer_7_access_control)
|
||||
add_subdirectory(orchestration)
|
||||
add_subdirectory(waap)
|
||||
|
@@ -0,0 +1,3 @@
|
||||
add_library(l7_access_control layer_7_access_control.cc)
|
||||
|
||||
add_subdirectory(layer_7_access_control_ut)
|
@@ -0,0 +1,348 @@
|
||||
#include "layer_7_access_control.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
|
||||
#include "config.h"
|
||||
#include "cache.h"
|
||||
#include "http_inspection_events.h"
|
||||
#include "http_transaction_common.h"
|
||||
#include "nginx_attachment_common.h"
|
||||
#include "intelligence_comp_v2.h"
|
||||
#include "intelligence_is_v2/intelligence_query_v2.h"
|
||||
#include "intelligence_is_v2/query_request_v2.h"
|
||||
#include "log_generator.h"
|
||||
|
||||
USE_DEBUG_FLAG(D_L7_ACCESS_CONTROL);
|
||||
|
||||
using namespace std;
|
||||
using namespace Intelligence_IS_V2;
|
||||
|
||||
static const string crowdsec_enabled_value = "true";
|
||||
static const string crowdsec_asset_type = "data-cloud-ip-crowdSec";
|
||||
|
||||
class IntelligenceIpReputation
|
||||
{
|
||||
public:
|
||||
template <class Archive>
|
||||
void
|
||||
load(Archive &ar)
|
||||
{
|
||||
try {
|
||||
vector<string> ipv4_addresses;
|
||||
ar(cereal::make_nvp("type", type));
|
||||
ar(cereal::make_nvp("scenario", scenario));
|
||||
ar(cereal::make_nvp("origin", origin));
|
||||
ar(cereal::make_nvp("crowdsecId", crowdsec_event_id));
|
||||
ar(cereal::make_nvp("ipv4Addresses", ipv4_addresses));
|
||||
if (!ipv4_addresses.empty()) ipv4_address = ipv4_addresses.front();
|
||||
} catch (const cereal::Exception &e) {
|
||||
dbgWarning(D_L7_ACCESS_CONTROL) << "Failed to load IP reputation data JSON. Error: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<LogField>
|
||||
getType() const
|
||||
{
|
||||
if (type.empty()) return genError("Empty type");
|
||||
return LogField("externalVendorRecommendedAction", type);
|
||||
}
|
||||
|
||||
Maybe<LogField>
|
||||
getScenario() const
|
||||
{
|
||||
if (scenario.empty()) return genError("Empty scenario");
|
||||
return LogField("externalVendorRecommendationOriginDetails", scenario);
|
||||
}
|
||||
|
||||
Maybe<LogField>
|
||||
getOrigin() const
|
||||
{
|
||||
if (origin.empty()) return genError("Empty origin");
|
||||
return LogField("externalVendorRecommendationOrigin", origin);
|
||||
}
|
||||
|
||||
Maybe<LogField>
|
||||
getIpv4Address() const
|
||||
{
|
||||
if (ipv4_address.empty()) return genError("Empty ipv4 address");
|
||||
return LogField("externalVendorRecommendedAffectedScope", ipv4_address);
|
||||
}
|
||||
|
||||
Maybe<LogField>
|
||||
getCrowdsecEventId() const
|
||||
{
|
||||
if (!crowdsec_event_id) return genError("Empty ID");
|
||||
return LogField("externalVendorRecommendationId", crowdsec_event_id);
|
||||
}
|
||||
|
||||
bool isMalicious() const { return type == "ban"; }
|
||||
|
||||
void
|
||||
print(std::ostream &out) const
|
||||
{
|
||||
out
|
||||
<< "Crowdsec event ID: "
|
||||
<< crowdsec_event_id
|
||||
<< ", IPV4 address: "
|
||||
<< ipv4_address
|
||||
<< ", type: "
|
||||
<< type
|
||||
<< ", origin: "
|
||||
<< origin
|
||||
<< ", scenario: "
|
||||
<< scenario;
|
||||
}
|
||||
|
||||
private:
|
||||
string type;
|
||||
string scenario;
|
||||
string origin;
|
||||
string ipv4_address;
|
||||
unsigned int crowdsec_event_id;
|
||||
};
|
||||
|
||||
class Layer7AccessControl::Impl : public Listener<HttpRequestHeaderEvent>
|
||||
{
|
||||
public:
|
||||
void init();
|
||||
void fini();
|
||||
|
||||
string getListenerName() const override { return "Layer-7 Access Control app"; }
|
||||
|
||||
EventVerdict
|
||||
respond(const HttpRequestHeaderEvent &event) override
|
||||
{
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Handling a new layer-7 access control event: " << event;
|
||||
|
||||
if (!isAppEnabled()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Returning Accept verdict as the Layer-7 Access Control app is disabled";
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
|
||||
if (!event.isLastHeader()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Returning Inspect verdict";
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
}
|
||||
|
||||
auto source_identifier = i_env->get<string>(HttpTransactionData::source_identifier);
|
||||
if (source_identifier.ok() && IPAddr::createIPAddr(source_identifier.unpack()).ok()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Found a valid source identifier value: " << source_identifier.unpack();
|
||||
return checkReputation(source_identifier.unpack());
|
||||
}
|
||||
|
||||
auto orig_source_ip = i_env->get<IPAddr>(HttpTransactionData::client_ip_ctx);
|
||||
if (!orig_source_ip.ok()) {
|
||||
dbgWarning(D_L7_ACCESS_CONTROL) << "Could not extract the Client IP address from context";
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
|
||||
stringstream ss_client_ip;
|
||||
ss_client_ip << orig_source_ip.unpack();
|
||||
return checkReputation(ss_client_ip.str());
|
||||
}
|
||||
|
||||
private:
|
||||
Maybe<IntelligenceIpReputation> getIpReputation(const string &ip);
|
||||
ngx_http_cp_verdict_e checkReputation(const string &source_ip);
|
||||
void generateLog(const string &source_ip, const IntelligenceIpReputation &ip_reputation) const;
|
||||
|
||||
bool isAppEnabled() const;
|
||||
bool isPrevent() const;
|
||||
|
||||
Maybe<LogField, Context::Error> genLogField(const string &log_key, const string &env_key) const;
|
||||
Maybe<LogField, Context::Error> genLogIPField(const string &log_key, const string &env_key) const;
|
||||
|
||||
I_Environment *i_env = nullptr;
|
||||
I_Intelligence_IS_V2 *i_intelligence = nullptr;
|
||||
TemporaryCache<string, IntelligenceIpReputation> ip_reputation_cache;
|
||||
};
|
||||
|
||||
bool
|
||||
Layer7AccessControl::Impl::isAppEnabled() const
|
||||
{
|
||||
bool enabled = getenv("CROWDSEC_ENABLED") ? string(getenv("CROWDSEC_ENABLED")) == crowdsec_enabled_value : false;
|
||||
return getProfileAgentSettingWithDefault<bool>(enabled, "layer7AccessControl.crowdsec.enabled");
|
||||
}
|
||||
|
||||
bool
|
||||
Layer7AccessControl::Impl::isPrevent() const
|
||||
{
|
||||
string security_mode_env = getenv("CROWDSEC_MODE") ? getenv("CROWDSEC_MODE") : "prevent";
|
||||
string mode = getProfileAgentSettingWithDefault(security_mode_env, "layer7AccessControl.securityMode");
|
||||
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Selected security mode: " << mode;
|
||||
|
||||
return mode == "prevent";
|
||||
}
|
||||
|
||||
Maybe<IntelligenceIpReputation>
|
||||
Layer7AccessControl::Impl::getIpReputation(const string &ip)
|
||||
{
|
||||
dbgFlow(D_L7_ACCESS_CONTROL) << "Getting reputation of IP " << ip;
|
||||
|
||||
if (ip_reputation_cache.doesKeyExists(ip)) return ip_reputation_cache.getEntry(ip);
|
||||
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Not found in cache - about to query intelligence";
|
||||
|
||||
QueryRequest request = QueryRequest(
|
||||
Condition::EQUALS,
|
||||
"ipv4Addresses",
|
||||
ip,
|
||||
true,
|
||||
AttributeKeyType::REGULAR
|
||||
);
|
||||
|
||||
auto response = i_intelligence->queryIntelligence<IntelligenceIpReputation>(request);
|
||||
|
||||
if (!response.ok()) {
|
||||
dbgWarning(D_L7_ACCESS_CONTROL) << "Failed to query intelligence about reputation of IP: " << ip;
|
||||
return genError("Failed to query intelligence");
|
||||
}
|
||||
|
||||
auto &unpacked_response = response.unpack();
|
||||
if (unpacked_response.empty()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Intelligence reputation response collection is empty. IP is clean.";
|
||||
return IntelligenceIpReputation();
|
||||
}
|
||||
|
||||
for (const auto &intelligence_reply : unpacked_response) {
|
||||
if (intelligence_reply.getAssetType() == crowdsec_asset_type && !intelligence_reply.getData().empty()){
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << intelligence_reply.getData().front();
|
||||
return intelligence_reply.getData().front();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return IntelligenceIpReputation();
|
||||
}
|
||||
|
||||
ngx_http_cp_verdict_e
|
||||
Layer7AccessControl::Impl::checkReputation(const string &source_ip)
|
||||
{
|
||||
auto ip_reputation = getIpReputation(source_ip);
|
||||
if (!ip_reputation.ok()) {
|
||||
dbgWarning(D_L7_ACCESS_CONTROL) << "Could not query intelligence. Retruning default verdict";
|
||||
bool is_drop_by_default = getProfileAgentSettingWithDefault<bool>(false, "layer7AccessControl.dropByDefault");
|
||||
if (!(is_drop_by_default && isPrevent())) return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
generateLog(source_ip, IntelligenceIpReputation());
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
}
|
||||
|
||||
if (!ip_reputation.unpack().isMalicious()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Accepting IP: " << source_ip;
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
|
||||
ip_reputation_cache.emplaceEntry(source_ip, ip_reputation.unpack());
|
||||
|
||||
if (isPrevent()) {
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Dropping IP: " << source_ip;
|
||||
generateLog(source_ip, ip_reputation.unpack());
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
}
|
||||
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Detecting IP: " << source_ip;
|
||||
generateLog(source_ip, ip_reputation.unpack());
|
||||
return ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Layer7AccessControl::Impl::generateLog(const string &source_ip, const IntelligenceIpReputation &ip_reputation) const
|
||||
{
|
||||
dbgFlow(D_L7_ACCESS_CONTROL) << "About to generate Layer-7 Access Control log";
|
||||
|
||||
string security_action = isPrevent() ? "Prevent" : "Detect";
|
||||
|
||||
LogGen log(
|
||||
"Access Control External Vendor Reputation",
|
||||
ReportIS::Audience::SECURITY,
|
||||
ReportIS::Severity::CRITICAL,
|
||||
ReportIS::Priority::HIGH,
|
||||
ReportIS::Tags::LAYER_7_ACCESS_CONTROL
|
||||
);
|
||||
log
|
||||
<< genLogField("sourcePort", HttpTransactionData::client_port_ctx)
|
||||
<< genLogField("httpHostName", HttpTransactionData::host_name_ctx)
|
||||
<< genLogField("httpUriPath", HttpTransactionData::uri_ctx)
|
||||
<< genLogField("httpMethod", HttpTransactionData::method_ctx)
|
||||
<< genLogField("ipProtocol", HttpTransactionData::http_proto_ctx)
|
||||
<< genLogField("destinationPort", HttpTransactionData::listening_port_ctx)
|
||||
<< genLogField("proxyIP", HttpTransactionData::proxy_ip_ctx)
|
||||
<< genLogField("httpSourceId", HttpTransactionData::source_identifier)
|
||||
<< genLogField("httpUriPath", HttpTransactionData::uri_path_decoded)
|
||||
<< genLogField("httpUriQuery", HttpTransactionData::uri_query_decoded)
|
||||
<< genLogField("httpRequestHeaders", HttpTransactionData::req_headers)
|
||||
<< genLogIPField("destinationIP", HttpTransactionData::listening_ip_ctx)
|
||||
<< LogField("securityAction", security_action)
|
||||
<< LogField("sourceIP", source_ip)
|
||||
<< LogField("externalVendorName", "crowdsec")
|
||||
<< ip_reputation.getCrowdsecEventId()
|
||||
<< ip_reputation.getType()
|
||||
<< ip_reputation.getOrigin()
|
||||
<< ip_reputation.getIpv4Address()
|
||||
<< ip_reputation.getScenario();
|
||||
}
|
||||
|
||||
Maybe<LogField, Context::Error>
|
||||
Layer7AccessControl::Impl::genLogField(const string &log_key, const string &env_key) const
|
||||
{
|
||||
auto value = i_env->get<string>(env_key);
|
||||
if (value.ok()) return LogField(log_key, *value);
|
||||
return value.passErr();
|
||||
}
|
||||
|
||||
Maybe<LogField, Context::Error>
|
||||
Layer7AccessControl::Impl::genLogIPField(const string &log_key, const string &env_key) const
|
||||
{
|
||||
auto value = i_env->get<IPAddr>(env_key);
|
||||
if (value.ok()) {
|
||||
stringstream value_str;
|
||||
value_str << value.unpack();
|
||||
return LogField(log_key, value_str.str());
|
||||
}
|
||||
return value.passErr();
|
||||
}
|
||||
|
||||
void
|
||||
Layer7AccessControl::Impl::init()
|
||||
{
|
||||
registerListener();
|
||||
i_env = Singleton::Consume<I_Environment>::by<Layer7AccessControl>();
|
||||
i_intelligence = Singleton::Consume<I_Intelligence_IS_V2>::by<Layer7AccessControl>();
|
||||
|
||||
chrono::minutes expiration(
|
||||
getProfileAgentSettingWithDefault<uint>(60u, "layer7AccessControl.crowdsec.cacheExpiration")
|
||||
);
|
||||
|
||||
ip_reputation_cache.startExpiration(
|
||||
expiration,
|
||||
Singleton::Consume<I_MainLoop>::by<Layer7AccessControl>(),
|
||||
Singleton::Consume<I_TimeGet>::by<Layer7AccessControl>()
|
||||
);
|
||||
}
|
||||
|
||||
void
|
||||
Layer7AccessControl::Impl::fini()
|
||||
{
|
||||
unregisterListener();
|
||||
ip_reputation_cache.endExpiration();
|
||||
}
|
||||
|
||||
Layer7AccessControl::Layer7AccessControl() : Component("Layer-7 Access Control"), pimpl(make_unique<Impl>()) {}
|
||||
|
||||
Layer7AccessControl::~Layer7AccessControl() {}
|
||||
|
||||
void
|
||||
Layer7AccessControl::init()
|
||||
{
|
||||
pimpl->init();
|
||||
}
|
||||
|
||||
void
|
||||
Layer7AccessControl::fini()
|
||||
{
|
||||
pimpl->fini();
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
file(COPY data DESTINATION .)
|
||||
|
||||
add_unit_test(
|
||||
layer_7_access_control_ut
|
||||
"layer_7_access_control_ut.cc"
|
||||
"l7_access_control;logging;agent_details;table;singleton;time_proxy;metric;event_is;connkey;http_transaction_data;generic_rulebase;generic_rulebase_evaluators;ip_utilities;intelligence_is_v2"
|
||||
)
|
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"assetCollections": [
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"assetType": "not-crowdsec",
|
||||
"assetTypeSchemaVersion": 1,
|
||||
"permissionType": "allTenants",
|
||||
"name": "050 Plus",
|
||||
"objectType": "asset",
|
||||
"class": "appiApplication",
|
||||
"category": "cloud",
|
||||
"family": "applicationsAndCategories",
|
||||
"group": "appiObjects",
|
||||
"order": "application",
|
||||
"mainAttributes": {
|
||||
"appiObjUuid": "00FA9E4440350F65E05308241DC22DA2"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"tenantId": "27278218-0e7f-4cd8-bdfe-2a5897d68fd0",
|
||||
"sourceId": "434eabf4-651f-4a45-a9f7-159dc8183b78",
|
||||
"assetId": "2222222222222222222222222222222",
|
||||
"ttl": 86400,
|
||||
"expirationTime": "2023-03-29T15:16:11.367873254Z",
|
||||
"confidence": 900,
|
||||
"attributes": {
|
||||
"appType": "core",
|
||||
"blockOnAny": false,
|
||||
"categoryId": 40000060,
|
||||
"categoryName": "VoIP",
|
||||
"categoryUuid": "00FA9E44404E0F65E05308241DC22DA2",
|
||||
"cpId": 60517839,
|
||||
"dataType": false,
|
||||
"type": "appfw_application"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"assetType": "data-cloud-ip-crowdSec",
|
||||
"assetTypeSchemaVersion": 1,
|
||||
"permissionType": "tenant",
|
||||
"name": "1.2.3.4",
|
||||
"objectType": "asset",
|
||||
"class": "data",
|
||||
"category": "cloud",
|
||||
"family": "ip",
|
||||
"group": "crowdSec",
|
||||
"mainAttributes": {
|
||||
"ipv4Addresses": [
|
||||
"1.2.3.4"
|
||||
]
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"tenantId": "c6f606b1-e59b-4f94-b829-ce597bd03067",
|
||||
"sourceId": "529185bd-9c91-4853-9c26-3140950ecad7",
|
||||
"assetId": "YXNzZXQ7OztkYXRhOzs7Y2xvdWQ7OztpcDs7O2Nyb3dkU2VjOzs7Ozs7Ozs7eyJpcHY0QWRkcmVzc2VzIjpbIjEuMi4zLjQiXX0=",
|
||||
"ttl": 86400,
|
||||
"expirationTime": "2023-03-27T12:08:00.279Z",
|
||||
"confidence": 500,
|
||||
"attributes": {
|
||||
"crowdsecId": 2253734,
|
||||
"duration": "29m33.009472691s",
|
||||
"ipv4Addresses": [
|
||||
"1.2.3.4"
|
||||
],
|
||||
"ipv4AddressesRange": [
|
||||
{
|
||||
"max": "1.2.3.4",
|
||||
"min": "1.2.3.4"
|
||||
}
|
||||
],
|
||||
"origin": "cscli",
|
||||
"scenario": "manual 'ban' from 'localhost'",
|
||||
"scope": "Ip",
|
||||
"type": "ban"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "done",
|
||||
"totalNumAssets": 1,
|
||||
"cursor": ""
|
||||
}
|
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"assetCollections": [],
|
||||
"status": "done",
|
||||
"totalNumAssets": 0,
|
||||
"cursor": ""
|
||||
}
|
@@ -0,0 +1,413 @@
|
||||
#include "layer_7_access_control.h"
|
||||
|
||||
#include "cptest.h"
|
||||
#include "config_component.h"
|
||||
#include "mock/mock_mainloop.h"
|
||||
#include "mock/mock_time_get.h"
|
||||
#include "mock/mock_http_manager.h"
|
||||
#include "mock/mock_logging.h"
|
||||
#include "mock/mock_messaging.h"
|
||||
#include "intelligence_comp_v2.h"
|
||||
#include "agent_details.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
|
||||
USE_DEBUG_FLAG(D_L7_ACCESS_CONTROL);
|
||||
|
||||
class Layer7AccessControlTest : public Test
|
||||
{
|
||||
public:
|
||||
Layer7AccessControlTest()
|
||||
{
|
||||
Debug::setUnitTestFlag(D_L7_ACCESS_CONTROL, Debug::DebugLevel::TRACE);
|
||||
EXPECT_CALL(mock_logging, getCurrentLogId()).Times(AnyNumber());
|
||||
EXPECT_CALL(mock_time, getWalltimeStr(_)).WillRepeatedly(Return(string("2016-11-13T17:31:24.087")));
|
||||
EXPECT_CALL(mock_time, getWalltime()).WillRepeatedly(Return(chrono::seconds(0)));
|
||||
EXPECT_CALL(mock_time, getMonotonicTime()).WillRepeatedly(Return(chrono::seconds(60)));
|
||||
EXPECT_CALL(mock_ml, doesRoutineExist(_)).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(mock_ml, stop(_)).WillRepeatedly(Return());
|
||||
env.preload();
|
||||
env.init();
|
||||
config.preload();
|
||||
intelligence_comp.preload();
|
||||
intelligence_comp.init();
|
||||
l7_access_control.preload();
|
||||
l7_access_control.init();
|
||||
ctx.activate();
|
||||
}
|
||||
|
||||
~Layer7AccessControlTest()
|
||||
{
|
||||
ctx.deactivate();
|
||||
l7_access_control.fini();
|
||||
}
|
||||
|
||||
string loadIntelligenceResponse(const string &file_path);
|
||||
void registerTransactionData();
|
||||
void verifyReport(const Report &report, const string &source_identifier, const string &security_action);
|
||||
|
||||
const EventVerdict drop_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_DROP;
|
||||
const EventVerdict accept_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_ACCEPT;
|
||||
const EventVerdict inspect_verdict = ngx_http_cp_verdict_e::TRAFFIC_VERDICT_INSPECT;
|
||||
Layer7AccessControl l7_access_control;
|
||||
::Environment env;
|
||||
ConfigComponent config;
|
||||
StrictMock<MockLogging> mock_logging;
|
||||
StrictMock<MockTimeGet> mock_time;
|
||||
StrictMock<MockMainLoop> mock_ml;
|
||||
StrictMock<MockMessaging> messaging_mock;
|
||||
AgentDetails agent_details;
|
||||
IntelligenceComponentV2 intelligence_comp;
|
||||
Context ctx;
|
||||
};
|
||||
|
||||
string prevent_settings =
|
||||
"{\n"
|
||||
"\"agentSettings\": [\n"
|
||||
"{\n"
|
||||
"\"id\": \"aac36348-5826-17d4-de11-195dd4dfca4a\","
|
||||
"\"key\": \"agent.config.useLocalIntelligence\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"f6c386fb-e221-59af-dbf5-b9bed680ec6b\","
|
||||
"\"key\": \"layer7AccessControl.logOnDrop\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"5ac38ee8-8b3c-481b-b382-f1f0735c0468\","
|
||||
"\"key\": \"layer7AccessControl.securityMode\","
|
||||
"\"value\": \"prevent\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"54c38f89-8fe2-871e-b29a-31e088f1b1d3\","
|
||||
"\"key\": \"layer7AccessControl.crowdsec.enabled\","
|
||||
"\"value\": \"true\""
|
||||
"}"
|
||||
"],\n";
|
||||
|
||||
string detect_settings =
|
||||
"{\n"
|
||||
"\"agentSettings\": [\n"
|
||||
"{\n"
|
||||
"\"id\": \"aac36348-5826-17d4-de11-195dd4dfca4a\","
|
||||
"\"key\": \"agent.config.useLocalIntelligence\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"f6c386fb-e221-59af-dbf5-b9bed680ec6b\","
|
||||
"\"key\": \"layer7AccessControl.logOnDrop\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"5ac38ee8-8b3c-481b-b382-f1f0735c0468\","
|
||||
"\"key\": \"layer7AccessControl.securityMode\","
|
||||
"\"value\": \"detect\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"54c38f89-8fe2-871e-b29a-31e088f1b1d3\","
|
||||
"\"key\": \"layer7AccessControl.crowdsec.enabled\","
|
||||
"\"value\": \"true\""
|
||||
"}"
|
||||
"],\n";
|
||||
|
||||
string disabled_settings =
|
||||
"{"
|
||||
"\"agentSettings\": [\n"
|
||||
"{\n"
|
||||
"\"id\": \"aac36348-5826-17d4-de11-195dd4dfca4a\","
|
||||
"\"key\": \"agent.config.useLocalIntelligence\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"f6c386fb-e221-59af-dbf5-b9bed680ec6b\","
|
||||
"\"key\": \"layer7AccessControl.logOnDrop\","
|
||||
"\"value\": \"true\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"5ac38ee8-8b3c-481b-b382-f1f0735c0468\","
|
||||
"\"key\": \"layer7AccessControl.securityMode\","
|
||||
"\"value\": \"detect\""
|
||||
"},"
|
||||
"{"
|
||||
"\"id\": \"54c38f89-8fe2-871e-b29a-31e088f1b1d3\","
|
||||
"\"key\": \"layer7AccessControl.crowdsec.enabled\","
|
||||
"\"value\": \"false\""
|
||||
"}"
|
||||
"],\n";
|
||||
|
||||
string policy =
|
||||
"\"rulebase\": {"
|
||||
"\"usersIdentifiers\": ["
|
||||
"{"
|
||||
"\"context\": \"Any(All(Any(EqualHost(juice-shop.checkpoint.com)),EqualListeningPort(80)))\","
|
||||
"\"identifierValues\": [],"
|
||||
"\"sourceIdentifier\": \"\","
|
||||
"\"sourceIdentifiers\": ["
|
||||
"{"
|
||||
"\"identifierValues\": [],"
|
||||
"\"sourceIdentifier\": \"x-forwarded-for\""
|
||||
"}"
|
||||
"]"
|
||||
"}"
|
||||
"],\n"
|
||||
"\"rulesConfig\": ["
|
||||
"{"
|
||||
"\"assetId\": \"00c37544-047b-91d4-e5e5-31d90070bcfd\","
|
||||
"\"assetName\": \"juice\","
|
||||
"\"context\": \"Any(All(Any(EqualHost(juice-shop.checkpoint.com)),EqualListeningPort(80)))\","
|
||||
"\"isCleanup\": false,"
|
||||
"\"parameters\": [],"
|
||||
"\"practices\": ["
|
||||
"{"
|
||||
"\"practiceId\": \"36be58f5-2c99-1f16-f816-bf25118d9bc1\","
|
||||
"\"practiceName\": \"WEB APPLICATION BEST PRACTICE\","
|
||||
"\"practiceType\": \"WebApplication\""
|
||||
"}"
|
||||
"],"
|
||||
"\"priority\": 1,"
|
||||
"\"ruleId\": \"00c37544-047b-91d4-e5e5-31d90070bcfd\","
|
||||
"\"ruleName\": \"juice\","
|
||||
"\"triggers\": ["
|
||||
"{"
|
||||
"\"triggerId\": \"86be58f5-2b65-18ee-2bd7-b4429dab245d\","
|
||||
"\"triggerName\": \"Log Trigger\","
|
||||
"\"triggerType\": \"log\""
|
||||
"}"
|
||||
"],"
|
||||
"\"zoneId\": \"\","
|
||||
"\"zoneName\": \"\""
|
||||
"}"
|
||||
"]"
|
||||
"}\n"
|
||||
"}\n";
|
||||
|
||||
void
|
||||
Layer7AccessControlTest::registerTransactionData()
|
||||
{
|
||||
ctx.registerValue<IPAddr>(HttpTransactionData::client_ip_ctx, IPAddr::createIPAddr("4.4.4.4").unpack());
|
||||
ctx.registerValue<IPAddr>(HttpTransactionData::listening_ip_ctx, IPAddr::createIPAddr("5.6.7.8").unpack());
|
||||
ctx.registerValue<string>(HttpTransactionData::http_proto_ctx, "http");
|
||||
ctx.registerValue<string>(HttpTransactionData::method_ctx, "POST");
|
||||
ctx.registerValue<string>(HttpTransactionData::host_name_ctx, "juice-shop.checkpoint.com");
|
||||
ctx.registerValue<uint16_t>(HttpTransactionData::listening_port_ctx, 80);
|
||||
ctx.registerValue<uint16_t>(HttpTransactionData::client_port_ctx, 12345);
|
||||
ctx.registerValue<string>(HttpTransactionData::uri_ctx, "/");
|
||||
}
|
||||
|
||||
static bool
|
||||
operator==(const EventVerdict &first, const EventVerdict &second)
|
||||
{
|
||||
return first.getVerdict() == second.getVerdict();
|
||||
}
|
||||
|
||||
string
|
||||
Layer7AccessControlTest::loadIntelligenceResponse(const string &file_path)
|
||||
{
|
||||
stringstream ss;
|
||||
ifstream f(cptestFnameInExeDir(file_path), ios::in);
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Loading intelligence response from: " << file_path;
|
||||
ss << f.rdbuf();
|
||||
f.close();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
string
|
||||
reportToStr(const T &obj)
|
||||
{
|
||||
stringstream ss;
|
||||
{
|
||||
cereal::JSONOutputArchive ar(ss);
|
||||
obj.serialize(ar);
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void
|
||||
Layer7AccessControlTest::verifyReport(
|
||||
const Report &report,
|
||||
const string &source_identifier,
|
||||
const string &security_action
|
||||
)
|
||||
{
|
||||
string log = reportToStr(report);
|
||||
dbgTrace(D_L7_ACCESS_CONTROL) << "Report: " << log;
|
||||
|
||||
if (!source_identifier.empty()) EXPECT_THAT(log, HasSubstr("\"httpSourceId\": \"" + source_identifier + "\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"securityAction\": \"" + security_action + "\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"eventName\": \"Access Control External Vendor Reputation\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"httpHostName\": \"juice-shop.checkpoint.com\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"httpUriPath\": \"/\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"httpMethod\": \"POST\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"ipProtocol\": \"http\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"destinationIP\": \"5.6.7.8\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorName\": \"crowdsec\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationId\": 2253734"));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAction\": \"ban\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOrigin\": \"cscli\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendedAffectedScope\": \"1.2.3.4\""));
|
||||
EXPECT_THAT(log, HasSubstr("\"externalVendorRecommendationOriginDetails\": \"manual 'ban' from 'localhost'\""));
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnAcceptVerdict)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string intelligence_response_ok = loadIntelligenceResponse("data/ok_intelligence_response.json");
|
||||
|
||||
EXPECT_CALL(
|
||||
messaging_mock,
|
||||
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
|
||||
).WillOnce(Return(intelligence_response_ok));
|
||||
|
||||
registerTransactionData();
|
||||
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
|
||||
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
|
||||
|
||||
EXPECT_THAT(
|
||||
HttpRequestHeaderEvent(header1).performNamedQuery(),
|
||||
ElementsAre(Pair("Layer-7 Access Control app", inspect_verdict))
|
||||
);
|
||||
EXPECT_THAT(
|
||||
HttpRequestHeaderEvent(header2).performNamedQuery(),
|
||||
ElementsAre(Pair("Layer-7 Access Control app", inspect_verdict))
|
||||
);
|
||||
EXPECT_THAT(
|
||||
HttpRequestHeaderEvent(header3).performNamedQuery(),
|
||||
ElementsAre(Pair("Layer-7 Access Control app", accept_verdict))
|
||||
);
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnDropVerdictOnMaliciousReputation)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
|
||||
EXPECT_CALL(
|
||||
messaging_mock,
|
||||
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
|
||||
).WillOnce(Return(malicious_intelligence_response));
|
||||
|
||||
registerTransactionData();
|
||||
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
|
||||
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
|
||||
|
||||
Report report;
|
||||
EXPECT_CALL(mock_logging, sendLog(_)).WillOnce(SaveArg<0>(&report));
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(drop_verdict));
|
||||
|
||||
verifyReport(report, "1.2.3.4", "Prevent");
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, ReturnDropVerdictCacheBased)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
|
||||
EXPECT_CALL(
|
||||
messaging_mock,
|
||||
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
|
||||
).WillOnce(Return(malicious_intelligence_response));
|
||||
|
||||
registerTransactionData();
|
||||
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
|
||||
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
|
||||
|
||||
Report report;
|
||||
EXPECT_CALL(mock_logging, sendLog(_)).Times(2).WillRepeatedly(SaveArg<0>(&report));
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(drop_verdict));
|
||||
|
||||
verifyReport(report, "1.2.3.4", "Prevent");
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(drop_verdict));
|
||||
|
||||
verifyReport(report, "1.2.3.4", "Prevent");
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, AcceptOnDetect)
|
||||
{
|
||||
stringstream ss_conf(detect_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
|
||||
EXPECT_CALL(
|
||||
messaging_mock,
|
||||
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
|
||||
).WillOnce(Return(malicious_intelligence_response));
|
||||
|
||||
registerTransactionData();
|
||||
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
|
||||
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
|
||||
|
||||
Report report;
|
||||
EXPECT_CALL(mock_logging, sendLog(_)).WillOnce(SaveArg<0>(&report));
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header3).query(), ElementsAre(accept_verdict));
|
||||
|
||||
verifyReport(report, "1.2.3.4", "Detect");
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, FallbackToSourceIPAndDrop)
|
||||
{
|
||||
stringstream ss_conf(prevent_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
string malicious_intelligence_response = loadIntelligenceResponse("data/malicious_intelligence_response.json");
|
||||
|
||||
EXPECT_CALL(
|
||||
messaging_mock,
|
||||
sendMessage(true, _, _, _, _, _, _, MessageTypeTag::INTELLIGENCE)
|
||||
).WillOnce(Return(malicious_intelligence_response));
|
||||
|
||||
registerTransactionData();
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1, true };
|
||||
|
||||
Report report;
|
||||
EXPECT_CALL(mock_logging, sendLog(_)).WillOnce(SaveArg<0>(&report));
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(inspect_verdict));
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header2).query(), ElementsAre(drop_verdict));
|
||||
|
||||
verifyReport(report, "", "Prevent");
|
||||
}
|
||||
|
||||
TEST_F(Layer7AccessControlTest, AcceptOnDisabled)
|
||||
{
|
||||
stringstream ss_conf(disabled_settings + policy);
|
||||
Singleton::Consume<Config::I_Config>::from(config)->loadConfiguration(ss_conf);
|
||||
|
||||
registerTransactionData();
|
||||
ctx.registerValue<string>(HttpTransactionData::source_identifier, "1.2.3.4");
|
||||
const HttpHeader header1{ Buffer("Content-Type"), Buffer("application/json"), 0 };
|
||||
const HttpHeader header2{ Buffer("date"), Buffer("Sun, 26 Mar 2023 18:45:22 GMT"), 1 };
|
||||
const HttpHeader header3{ Buffer("x-forwarded-for"), Buffer("1.2.3.4"), 2, true};
|
||||
|
||||
EXPECT_THAT(HttpRequestHeaderEvent(header1).query(), ElementsAre(accept_verdict));
|
||||
}
|
@@ -201,6 +201,13 @@ DetailsResolver::Impl::isVersionEqualOrAboveR8110()
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
isNoResponse(const string &cmd)
|
||||
{
|
||||
auto res = DetailsResolvingHanlder::getCommandOutput(cmd);
|
||||
return !res.ok() || res.unpack().empty();
|
||||
}
|
||||
|
||||
Maybe<tuple<string, string, string>>
|
||||
DetailsResolver::Impl::parseNginxMetadata()
|
||||
{
|
||||
@@ -215,9 +222,8 @@ DetailsResolver::Impl::parseNginxMetadata()
|
||||
output_path;
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR) << "Details resolver, srcipt exe cmd: " << srcipt_exe_cmd;
|
||||
auto is_nginx_exist = DetailsResolvingHanlder::getCommandOutput("which nginx");
|
||||
if (!is_nginx_exist.ok() || is_nginx_exist.unpack().size() == 0) {
|
||||
return genError("Nginx isn't installed");
|
||||
if (isNoResponse("which nginx") && isNoResponse("which kong")) {
|
||||
return genError("Nginx or Kong isn't installed");
|
||||
}
|
||||
|
||||
auto script_output = DetailsResolvingHanlder::getCommandOutput(srcipt_exe_cmd);
|
||||
@@ -259,6 +265,7 @@ DetailsResolver::Impl::parseNginxMetadata()
|
||||
for(string &line : lines) {
|
||||
if (line.size() == 0) continue;
|
||||
if (line.find("RELEASE_VERSION") != string::npos) continue;
|
||||
if (line.find("KONG_VERSION") != string::npos) continue;
|
||||
if (line.find("--with-cc=") != string::npos) continue;
|
||||
if (line.find("NGINX_VERSION") != string::npos) {
|
||||
auto eq_index = line.find("=");
|
||||
|
@@ -15,6 +15,15 @@
|
||||
#error details_resolver_handlers/details_resolver_impl.h should not be included directly.
|
||||
#endif // __DETAILS_RESOLVER_HANDLER_CC__
|
||||
|
||||
// Retrieve artifacts by incorporating nano service names into additional metadata:
|
||||
// To include a required nano service in the additional metadata sent to the manifest generator,
|
||||
// add a handler in this file. The key to use is 'requiredNanoServices', and its value should be
|
||||
// a string representing an array of nano service prefix names, separated by semicolons.
|
||||
// For example: "httpTransactionHandler_linux;iotSnmp_gaia;"
|
||||
//
|
||||
// Handler example for reading the content of a configuration file:
|
||||
// FILE_CONTENT_HANDLER("requiredNanoServices", "/tmp/nano_services_list", getRequiredNanoServices)
|
||||
|
||||
// use SHELL_CMD_HANDLER(key as string, shell command as string, ptr to Maybe<string> handler(const string&))
|
||||
// to return a string value for an attribute key based on a logic executed in a handler that receives
|
||||
// shell command execution output as its input
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "i_env_details.h"
|
||||
#include "maybe_res.h"
|
||||
#include "event.h"
|
||||
#include "rest.h"
|
||||
|
||||
class ApplyPolicyEvent : public Event<ApplyPolicyEvent>
|
||||
{
|
||||
@@ -46,13 +47,15 @@ public:
|
||||
class ApplyPolicyRest : public ServerRest
|
||||
{
|
||||
public:
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
void
|
||||
doCall() override
|
||||
{
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->setPolicyPath(policy_path.get());
|
||||
ApplyPolicyEvent().notify();
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
private:
|
||||
C2S_PARAM(std::string, policy_path);
|
||||
};
|
||||
|
||||
void init();
|
||||
|
@@ -31,6 +31,13 @@ operator<<(std::ostream &os, const std::map<T, S> &)
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
std::ostream &
|
||||
operator<<(std::ostream &os, const Maybe<std::map<T, S>> &)
|
||||
{
|
||||
return os;
|
||||
}
|
||||
|
||||
class MockOrchestrationTools
|
||||
:
|
||||
public Singleton::Provide<I_OrchestrationTools>::From<MockProvider<I_OrchestrationTools>>
|
||||
|
@@ -26,6 +26,10 @@ class MockServiceController :
|
||||
public:
|
||||
MOCK_METHOD0(refreshPendingServices, void());
|
||||
|
||||
MOCK_METHOD0(doesFailedServicesExist, bool());
|
||||
|
||||
MOCK_METHOD0(clearFailedServices, void());
|
||||
|
||||
MOCK_CONST_METHOD0(getPolicyVersion, const std::string &());
|
||||
|
||||
MOCK_CONST_METHOD0(getUpdatePolicyVersion, const std::string &());
|
||||
|
@@ -91,6 +91,7 @@ private:
|
||||
SettingsWrapper settings;
|
||||
SecurityAppsWrapper security_apps;
|
||||
};
|
||||
|
||||
class PolicyMakerUtils
|
||||
:
|
||||
Singleton::Consume<I_Environment>,
|
||||
@@ -99,6 +100,19 @@ class PolicyMakerUtils
|
||||
Singleton::Consume<I_ShellCmd>
|
||||
{
|
||||
public:
|
||||
std::string proccesSingleAppsecPolicy(
|
||||
const std::string &policy_path,
|
||||
const std::string &policy_version,
|
||||
const std::string &local_appsec_policy_path
|
||||
);
|
||||
|
||||
std::string proccesMultipleAppsecPolicies(
|
||||
const std::map<std::string, AppsecLinuxPolicy> &appsec_policies,
|
||||
const std::string &policy_version,
|
||||
const std::string &local_appsec_policy_path
|
||||
);
|
||||
|
||||
private:
|
||||
std::string getPolicyName(const std::string &policy_path);
|
||||
|
||||
Maybe<AppsecLinuxPolicy> openPolicyAsJson(const std::string &policy_path);
|
||||
@@ -129,7 +143,8 @@ public:
|
||||
const std::string &policy_name
|
||||
);
|
||||
|
||||
private:
|
||||
void createAgentPolicyFromAppsecPolicy(const std::string &policy_name, const AppsecLinuxPolicy &appsec_policy);
|
||||
|
||||
std::map<std::string, LogTriggerSection> log_triggers;
|
||||
std::map<std::string, WebUserResponseTriggerSection> web_user_res_triggers;
|
||||
std::map<std::string, InnerException> inner_exceptions;
|
||||
|
@@ -22,6 +22,8 @@
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "local_policy_common.h"
|
||||
#include "i_agent_details.h"
|
||||
#include "i_env_details.h"
|
||||
|
||||
class LogTriggerSection
|
||||
{
|
||||
@@ -37,6 +39,7 @@ public:
|
||||
bool _logToAgent,
|
||||
bool _logToCef,
|
||||
bool _logToCloud,
|
||||
bool _logToK8sService,
|
||||
bool _logToSyslog,
|
||||
bool _responseBody,
|
||||
bool _tpDetect,
|
||||
@@ -68,6 +71,7 @@ private:
|
||||
bool logToAgent;
|
||||
bool logToCef;
|
||||
bool logToCloud;
|
||||
bool logToK8sService;
|
||||
bool logToSyslog;
|
||||
bool responseBody;
|
||||
bool tpDetect;
|
||||
@@ -233,7 +237,11 @@ private:
|
||||
std::string format;
|
||||
};
|
||||
|
||||
class AppsecTriggerLogDestination : public ClientRest
|
||||
class AppsecTriggerLogDestination
|
||||
:
|
||||
public ClientRest,
|
||||
Singleton::Consume<I_AgentDetails>,
|
||||
Singleton::Consume<I_EnvDetails>
|
||||
{
|
||||
public:
|
||||
void load(cereal::JSONInputArchive &archive_in);
|
||||
@@ -244,6 +252,7 @@ public:
|
||||
bool shouldBeautifyLogs() const;
|
||||
|
||||
bool getCloud() const;
|
||||
bool isK8SNeeded() const;
|
||||
bool isCefNeeded() const;
|
||||
bool isSyslogNeeded() const;
|
||||
const std::string & getSyslogServerIpv4Address() const;
|
||||
@@ -254,6 +263,7 @@ private:
|
||||
const LoggingService & getCefServiceData() const;
|
||||
|
||||
bool cloud = false;
|
||||
bool k8s_service = false;
|
||||
bool agent_local = true;
|
||||
bool beautify_logs = true;
|
||||
LoggingService syslog_service;
|
||||
|
@@ -50,14 +50,9 @@ using namespace std;
|
||||
|
||||
USE_DEBUG_FLAG(D_LOCAL_POLICY);
|
||||
|
||||
const static string local_appsec_policy_path = "/tmp/local_appsec.policy";
|
||||
const static string open_appsec_io = "openappsec.io/";
|
||||
const static string policy_key = "policy";
|
||||
const static string syslog_key = "syslog";
|
||||
const static string mode_key = "mode";
|
||||
const static string local_mgmt_policy_path = "/conf/local_policy.yaml";
|
||||
const static string default_local_appsec_policy_path = "/tmp/local_appsec.policy";
|
||||
const static string default_local_mgmt_policy_path = "/conf/local_policy.yaml";
|
||||
|
||||
// LCOV_EXCL_STOP
|
||||
class LocalPolicyMgmtGenerator::Impl
|
||||
:
|
||||
public Singleton::Provide<I_LocalPolicyMgmtGen>::From<LocalPolicyMgmtGenerator>,
|
||||
@@ -66,7 +61,6 @@ class LocalPolicyMgmtGenerator::Impl
|
||||
{
|
||||
|
||||
public:
|
||||
// LCOV_EXCL_START Reason: no test exist
|
||||
void
|
||||
init()
|
||||
{
|
||||
@@ -74,6 +68,7 @@ public:
|
||||
env_type = env_details->getEnvType();
|
||||
if (env_type == EnvType::LINUX) {
|
||||
dbgInfo(D_LOCAL_POLICY) << "Initializing Linux policy generator";
|
||||
local_policy_path = getFilesystemPathConfig() + default_local_mgmt_policy_path;
|
||||
return;
|
||||
}
|
||||
dbgInfo(D_LOCAL_POLICY) << "Initializing K8S policy generator";
|
||||
@@ -97,36 +92,10 @@ public:
|
||||
{
|
||||
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - embedded environment";
|
||||
|
||||
string policy_path = getConfigurationFlagWithDefault(
|
||||
getFilesystemPathConfig() + local_mgmt_policy_path,
|
||||
"local_mgmt_policy"
|
||||
);
|
||||
|
||||
Maybe<AppsecLinuxPolicy> maybe_policy = policy_maker_utils.openPolicyAsJson(policy_path);
|
||||
if (!maybe_policy.ok()){
|
||||
dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr();
|
||||
return "";
|
||||
}
|
||||
AppsecLinuxPolicy policy = maybe_policy.unpack();
|
||||
string policy_name = policy_maker_utils.getPolicyName(policy_path);
|
||||
dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name;
|
||||
|
||||
ParsedRule default_rule = policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
// add default rule to policy
|
||||
policy_maker_utils.createPolicyElementsByRule(default_rule, default_rule, policy, policy_name);
|
||||
|
||||
vector<ParsedRule> specific_rules = policy.getAppsecPolicySpec().getSpecificRules();
|
||||
policy_maker_utils.createPolicyElements(
|
||||
specific_rules,
|
||||
default_rule,
|
||||
policy,
|
||||
policy_name
|
||||
);
|
||||
PolicyWrapper policy_wrapper = policy_maker_utils.combineElementsToPolicy(policy_version);
|
||||
return policy_maker_utils.dumpPolicyToFile(
|
||||
policy_wrapper,
|
||||
local_appsec_policy_path
|
||||
return policy_maker_utils.proccesSingleAppsecPolicy(
|
||||
local_policy_path,
|
||||
policy_version,
|
||||
default_local_appsec_policy_path
|
||||
);
|
||||
}
|
||||
|
||||
@@ -136,30 +105,10 @@ public:
|
||||
dbgFlow(D_LOCAL_POLICY) << "Starting to parse policy - K8S environment";
|
||||
|
||||
map<string, AppsecLinuxPolicy> appsec_policies = k8s_policy_utils.createAppsecPoliciesFromIngresses();
|
||||
|
||||
for (const auto &appsec_policy : appsec_policies) {
|
||||
string policy_name = appsec_policy.first;
|
||||
dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name;
|
||||
AppsecLinuxPolicy policy = appsec_policy.second;
|
||||
|
||||
ParsedRule default_rule = policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
// add default rule to policy
|
||||
policy_maker_utils.createPolicyElementsByRule(default_rule, default_rule, policy, policy_name);
|
||||
|
||||
vector<ParsedRule> specific_rules = policy.getAppsecPolicySpec().getSpecificRules();
|
||||
policy_maker_utils.createPolicyElements(
|
||||
specific_rules,
|
||||
default_rule,
|
||||
policy,
|
||||
policy_name
|
||||
);
|
||||
}
|
||||
|
||||
PolicyWrapper policy_wrapper = policy_maker_utils.combineElementsToPolicy(policy_version);
|
||||
return policy_maker_utils.dumpPolicyToFile(
|
||||
policy_wrapper,
|
||||
local_appsec_policy_path
|
||||
return policy_maker_utils.proccesMultipleAppsecPolicies(
|
||||
appsec_policies,
|
||||
policy_version,
|
||||
default_local_appsec_policy_path
|
||||
);
|
||||
}
|
||||
|
||||
@@ -169,7 +118,9 @@ public:
|
||||
return isK8sEnv() ? parseK8sPolicy(policy_version) : parseLinuxPolicy(policy_version);
|
||||
}
|
||||
|
||||
const string & getPolicyPath(void) const override { return local_appsec_policy_path; }
|
||||
const string & getAgentPolicyPath(void) const override { return default_local_appsec_policy_path; }
|
||||
const string & getLocalPolicyPath(void) const override { return local_policy_path; }
|
||||
void setPolicyPath(const string &new_local_policy_path) override { local_policy_path = new_local_policy_path; }
|
||||
|
||||
private:
|
||||
bool
|
||||
@@ -182,6 +133,7 @@ private:
|
||||
EnvType env_type;
|
||||
PolicyMakerUtils policy_maker_utils;
|
||||
K8sPolicyUtils k8s_policy_utils;
|
||||
string local_policy_path;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -144,7 +144,6 @@ PolicyMakerUtils::dumpPolicyToFile(const PolicyWrapper &policy, const string &po
|
||||
policy.save(ar);
|
||||
}
|
||||
string policy_str = ss.str();
|
||||
dbgTrace(D_NGINX_POLICY) << "policy: " << policy_str;
|
||||
try {
|
||||
ofstream policy_file(policy_path);
|
||||
policy_file << policy_str;
|
||||
@@ -365,6 +364,7 @@ createLogTriggerSection(
|
||||
bool webHeaders = trigger_spec.getAppsecTriggerExtendedLogging().isHttpHeaders();
|
||||
bool webBody = trigger_spec.getAppsecTriggerExtendedLogging().isRequestBody();
|
||||
bool logToCloud = trigger_spec.getAppsecTriggerLogDestination().getCloud();
|
||||
bool logToK8sService = trigger_spec.getAppsecTriggerLogDestination().isK8SNeeded();
|
||||
bool logToAgent = trigger_spec.getAppsecTriggerLogDestination().isAgentLocal();
|
||||
bool beautify_logs = trigger_spec.getAppsecTriggerLogDestination().shouldBeautifyLogs();
|
||||
bool logToCef = trigger_spec.getAppsecTriggerLogDestination().isCefNeeded();
|
||||
@@ -391,6 +391,7 @@ createLogTriggerSection(
|
||||
logToAgent,
|
||||
logToCef,
|
||||
logToCloud,
|
||||
logToK8sService,
|
||||
logToSyslog,
|
||||
responseBody,
|
||||
tpDetect,
|
||||
@@ -758,3 +759,54 @@ PolicyMakerUtils::createPolicyElements(
|
||||
createPolicyElementsByRule(rule, default_rule, policy, policy_name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PolicyMakerUtils::createAgentPolicyFromAppsecPolicy(const string &policy_name, const AppsecLinuxPolicy &appsec_policy)
|
||||
{
|
||||
dbgTrace(D_LOCAL_POLICY) << "Proccesing policy, name: " << policy_name;
|
||||
|
||||
ParsedRule default_rule = appsec_policy.getAppsecPolicySpec().getDefaultRule();
|
||||
|
||||
// add default rule to policy
|
||||
createPolicyElementsByRule(default_rule, default_rule, appsec_policy, policy_name);
|
||||
|
||||
vector<ParsedRule> specific_rules = appsec_policy.getAppsecPolicySpec().getSpecificRules();
|
||||
createPolicyElements(specific_rules, default_rule, appsec_policy, policy_name);
|
||||
}
|
||||
|
||||
string
|
||||
PolicyMakerUtils::proccesSingleAppsecPolicy(
|
||||
const string &policy_path,
|
||||
const string &policy_version,
|
||||
const string &local_appsec_policy_path)
|
||||
{
|
||||
Maybe<AppsecLinuxPolicy> maybe_policy = openPolicyAsJson(policy_path);
|
||||
if (!maybe_policy.ok()){
|
||||
dbgWarning(D_LOCAL_POLICY) << maybe_policy.getErr();
|
||||
return "";
|
||||
}
|
||||
createAgentPolicyFromAppsecPolicy(getPolicyName(policy_path), maybe_policy.unpack());
|
||||
|
||||
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
|
||||
return dumpPolicyToFile(
|
||||
policy_wrapper,
|
||||
local_appsec_policy_path
|
||||
);
|
||||
}
|
||||
|
||||
string
|
||||
PolicyMakerUtils::proccesMultipleAppsecPolicies(
|
||||
const map<string, AppsecLinuxPolicy> &appsec_policies,
|
||||
const string &policy_version,
|
||||
const string &local_appsec_policy_path)
|
||||
{
|
||||
for (const auto &appsec_policy : appsec_policies) {
|
||||
createAgentPolicyFromAppsecPolicy(appsec_policy.first, appsec_policy.second);
|
||||
}
|
||||
|
||||
PolicyWrapper policy_wrapper = combineElementsToPolicy(policy_version);
|
||||
return dumpPolicyToFile(
|
||||
policy_wrapper,
|
||||
local_appsec_policy_path
|
||||
);
|
||||
}
|
||||
|
@@ -30,6 +30,7 @@ LogTriggerSection::LogTriggerSection(
|
||||
bool _logToAgent,
|
||||
bool _logToCef,
|
||||
bool _logToCloud,
|
||||
bool _logToK8sService,
|
||||
bool _logToSyslog,
|
||||
bool _responseBody,
|
||||
bool _tpDetect,
|
||||
@@ -52,6 +53,7 @@ LogTriggerSection::LogTriggerSection(
|
||||
logToAgent(_logToAgent),
|
||||
logToCef(_logToCef),
|
||||
logToCloud(_logToCloud),
|
||||
logToK8sService(_logToK8sService),
|
||||
logToSyslog(_logToSyslog),
|
||||
responseBody(_responseBody),
|
||||
tpDetect(_tpDetect),
|
||||
@@ -95,6 +97,7 @@ LogTriggerSection::save(cereal::JSONOutputArchive &out_ar) const
|
||||
cereal::make_nvp("logToAgent", logToAgent),
|
||||
cereal::make_nvp("logToCef", logToCef),
|
||||
cereal::make_nvp("logToCloud", logToCloud),
|
||||
cereal::make_nvp("logToK8sService", logToK8sService),
|
||||
cereal::make_nvp("logToSyslog", logToSyslog),
|
||||
cereal::make_nvp("responseBody", responseBody),
|
||||
cereal::make_nvp("responseCode", false),
|
||||
@@ -382,6 +385,10 @@ AppsecTriggerLogDestination::load(cereal::JSONInputArchive &archive_in)
|
||||
dbgTrace(D_LOCAL_POLICY) << "Loading AppSec Trigger LogDestination";
|
||||
// TBD: support "file"
|
||||
parseAppsecJSONKey<bool>("cloud", cloud, archive_in, false);
|
||||
auto mode = Singleton::Consume<I_AgentDetails>::by<AppsecTriggerLogDestination>()->getOrchestrationMode();
|
||||
auto env_type = Singleton::Consume<I_EnvDetails>::by<AppsecTriggerLogDestination>()->getEnvType();
|
||||
bool k8s_service_default = (mode == OrchestrationMode::HYBRID && env_type == EnvType::K8S);
|
||||
parseAppsecJSONKey<bool>("k8s-service", k8s_service, archive_in, k8s_service_default);
|
||||
|
||||
StdoutLogging stdout_log;
|
||||
parseAppsecJSONKey<StdoutLogging>("stdout", stdout_log, archive_in);
|
||||
@@ -421,6 +428,12 @@ AppsecTriggerLogDestination::getCloud() const
|
||||
return cloud;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::isK8SNeeded() const
|
||||
{
|
||||
return k8s_service;
|
||||
}
|
||||
|
||||
bool
|
||||
AppsecTriggerLogDestination::isCefNeeded() const
|
||||
{
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "orchestration_comp.h"
|
||||
|
||||
#include <cereal/archives/json.hpp>
|
||||
#include <unordered_map>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
@@ -157,7 +158,7 @@ private:
|
||||
class OrchestrationComp::Impl
|
||||
{
|
||||
public:
|
||||
explicit Impl() {}
|
||||
explicit Impl() : curr_agent_data_report(false) {}
|
||||
|
||||
void
|
||||
init()
|
||||
@@ -171,6 +172,7 @@ public:
|
||||
doEncrypt();
|
||||
health_check_status_listener.registerListener();
|
||||
|
||||
curr_agent_data_report.disableReportSending();
|
||||
auto rest = Singleton::Consume<I_RestApi>::by<OrchestrationComp>();
|
||||
rest->addRestCall<getStatusRest>(RestAction::SHOW, "orchestration-status");
|
||||
rest->addRestCall<AddProxyRest>(RestAction::ADD, "proxy");
|
||||
@@ -197,6 +199,7 @@ public:
|
||||
fini()
|
||||
{
|
||||
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->writeStatusToFile();
|
||||
curr_agent_data_report.disableReportSending();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -514,6 +517,81 @@ private:
|
||||
return Maybe<void>();
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START Reason: future changes will be done
|
||||
bool
|
||||
updateServiceConfigurationFromBackup()
|
||||
{
|
||||
auto policy_file_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/policy.json",
|
||||
"orchestration",
|
||||
"Policy file path"
|
||||
);
|
||||
|
||||
auto orchestration_policy_file = getPolicyConfigPath("orchestration", Config::ConfigFileType::Policy);
|
||||
|
||||
auto settings_file_path = getConfigurationWithDefault<string>(
|
||||
filesystem_prefix + "/conf/settings.json",
|
||||
"orchestration",
|
||||
"Settings file path"
|
||||
);
|
||||
|
||||
dbgInfo(D_ORCHESTRATOR)
|
||||
<< "Enforcing new configuration. Policy file: "
|
||||
<< policy_file_path
|
||||
<< ", Settings file: "
|
||||
<< settings_file_path;
|
||||
|
||||
string backup_ext = getConfigurationWithDefault<string>(
|
||||
".bk",
|
||||
"orchestration",
|
||||
"Backup file extension"
|
||||
);
|
||||
|
||||
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
|
||||
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
|
||||
|
||||
// Try to use the backup policy.json file and re-write the services's policies.
|
||||
dbgInfo(D_ORCHESTRATOR) << "Updating services with the new policy.";
|
||||
if (service_controller->updateServiceConfiguration(policy_file_path + backup_ext, settings_file_path)) {
|
||||
dbgInfo(D_ORCHESTRATOR) << "Recovering the policy file from backup.";
|
||||
if (!orchestration_tools->copyFile(policy_file_path + backup_ext, policy_file_path)) {
|
||||
dbgWarning (D_ORCHESTRATOR)
|
||||
<< "Failed to recover policy file from backup. File: "
|
||||
<< policy_file_path + backup_ext;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
dbgWarning (D_ORCHESTRATOR) << "Failed to load Orchestration policy.";
|
||||
return false;
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
string
|
||||
updatePolicyAndFogAddress(const OrchestrationPolicy &orchestration_policy)
|
||||
{
|
||||
if (!updateFogAddress(orchestration_policy.getFogAddress())) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to update the new Fog address.";
|
||||
if (!updateFogAddress(policy.getFogAddress())) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to restore the old Fog address.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
policy = orchestration_policy;
|
||||
|
||||
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
|
||||
string new_policy_version = service_controller->getPolicyVersion();
|
||||
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(new_policy_version);
|
||||
auto update_communication = Singleton::Consume<I_UpdateCommunication>::by<OrchestrationComp>();
|
||||
auto path_policy_version = update_communication->sendPolicyVersion(new_policy_version);
|
||||
if (!path_policy_version.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << path_policy_version.getErr();
|
||||
}
|
||||
|
||||
return new_policy_version;
|
||||
}
|
||||
|
||||
Maybe<void>
|
||||
handlePolicyUpdate(const OrchPolicy &new_policy, const string &settings_path, const vector<string> &data_updates)
|
||||
{
|
||||
@@ -531,6 +609,17 @@ private:
|
||||
return genError("Failed to download the new policy file. Error: " + new_policy_file.getErr());
|
||||
}
|
||||
|
||||
auto orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<OrchestrationComp>();
|
||||
auto conf_path = filesystem_prefix + "/conf/policy.json";
|
||||
string last_ext = getConfigurationWithDefault<string>(
|
||||
".last",
|
||||
"orchestration",
|
||||
"last fog policy file extension"
|
||||
);
|
||||
if (!orchestration_tools->copyFile(new_policy_file.unpack(), conf_path + last_ext)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to copy a new policy file to " << conf_path + last_ext;
|
||||
}
|
||||
|
||||
// Calculate the changes between the existing policy to the new one.
|
||||
auto service_controller = Singleton::Consume<I_ServiceController>::by<OrchestrationComp>();
|
||||
string old_policy_version = service_controller->getPolicyVersion();
|
||||
@@ -579,27 +668,29 @@ private:
|
||||
return genError("Failed to load new Orchestration policy file.");
|
||||
}
|
||||
|
||||
if (!updateFogAddress(orchestration_policy.unpack().getFogAddress())) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to update the new Fog address.";
|
||||
if (!updateFogAddress(policy.getFogAddress())) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to restore the old Fog address.";
|
||||
}
|
||||
return genError("Failed to load Orchestration new policy file, fog update failed.");
|
||||
}
|
||||
|
||||
policy = orchestration_policy.unpack();
|
||||
|
||||
string new_policy_version = service_controller->getPolicyVersion();
|
||||
Singleton::Consume<I_OrchestrationStatus>::by<OrchestrationComp>()->setPolicyVersion(new_policy_version);
|
||||
auto update_communication = Singleton::Consume<I_UpdateCommunication>::by<OrchestrationComp>();
|
||||
auto path_policy_version = update_communication->sendPolicyVersion(new_policy_version);
|
||||
if (!path_policy_version.ok()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << path_policy_version.getErr();
|
||||
string new_policy_version = updatePolicyAndFogAddress(orchestration_policy.unpack());
|
||||
if (new_policy_version.empty()) {
|
||||
return genError("Failed to load Orchestration new policy file.");
|
||||
}
|
||||
|
||||
reloadConfiguration();
|
||||
if (getProfileAgentSettingWithDefault<bool>(false, "agent.config.orchestration.reportAgentDetail")) {
|
||||
service_controller->clearFailedServices();
|
||||
reportAgentDetailsMetaData();
|
||||
if(service_controller->doesFailedServicesExist()) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to enforce Orchestration policy.";
|
||||
updateServiceConfigurationFromBackup();
|
||||
// Reload the orchestration policy, in case of the policy updated
|
||||
orchestration_policy = loadDefaultOrchestrationPolicy();
|
||||
if (!orchestration_policy.ok()) {
|
||||
return genError("Failed to load new Orchestration policy file.");
|
||||
}
|
||||
|
||||
new_policy_version = updatePolicyAndFogAddress(orchestration_policy.unpack());
|
||||
if (new_policy_version.empty()) {
|
||||
return genError("Failed to load Orchestration new policy file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbgTrace(D_ORCHESTRATOR)
|
||||
@@ -1230,6 +1321,8 @@ private:
|
||||
reportAgentDetailsMetaData()
|
||||
{
|
||||
I_DetailsResolver *i_details_resolver = Singleton::Consume<I_DetailsResolver>::by<OrchestrationComp>();
|
||||
i_details_resolver->getResolvedDetails();
|
||||
|
||||
AgentDataReport agent_data_report;
|
||||
agent_data_report << AgentReportFieldWithLabel("agent_version", i_details_resolver->getAgentVersion());
|
||||
|
||||
@@ -1280,6 +1373,13 @@ private:
|
||||
agent_data_report << AgentReportFieldWithLabel("isCheckpointVersionGER81", "true");
|
||||
}
|
||||
#endif // gaia || smb
|
||||
|
||||
if (agent_data_report == curr_agent_data_report) {
|
||||
agent_data_report.disableReportSending();
|
||||
} else {
|
||||
curr_agent_data_report = agent_data_report;
|
||||
curr_agent_data_report.disableReportSending();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1371,6 +1471,7 @@ private:
|
||||
while (true) {
|
||||
static int failure_count = 0;
|
||||
Singleton::Consume<I_Environment>::by<OrchestrationComp>()->startNewTrace(false);
|
||||
reportAgentDetailsMetaData();
|
||||
auto check_update_result = checkUpdate();
|
||||
if (!check_update_result.ok()) {
|
||||
failure_count++;
|
||||
@@ -1477,7 +1578,7 @@ private:
|
||||
getAttribute(const string &setting, const string &env)
|
||||
{
|
||||
auto res = getSetting<string>(setting);
|
||||
if (res.ok()) return res.unpack();
|
||||
if (res.ok() && *res != "") return res.unpack();
|
||||
auto env_res = getenv(env.c_str());
|
||||
if (env_res != nullptr) return env_res;
|
||||
return "";
|
||||
@@ -1705,6 +1806,7 @@ private:
|
||||
EnvDetails env_details;
|
||||
|
||||
string filesystem_prefix = "";
|
||||
AgentDataReport curr_agent_data_report;
|
||||
};
|
||||
|
||||
OrchestrationComp::OrchestrationComp()
|
||||
|
@@ -104,19 +104,17 @@ public:
|
||||
expectDetailsResolver()
|
||||
{
|
||||
Maybe<tuple<string, string, string>> no_nginx(genError("No nginx"));
|
||||
EXPECT_CALL(mock_details_resolver, getPlatform()).WillOnce(Return(string("linux")));
|
||||
EXPECT_CALL(mock_details_resolver, getArch()).WillOnce(Return(string("x86_64")));
|
||||
EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isKernelVersion3OrHigher()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isGwNotVsx()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isVersionEqualOrAboveR8110()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, parseNginxMetadata()).WillOnce(Return(no_nginx));
|
||||
EXPECT_CALL(mock_details_resolver, getAgentVersion())
|
||||
.WillOnce(Return("1.1.1"))
|
||||
.WillOnce(Return("1.1.1"));
|
||||
EXPECT_CALL(mock_details_resolver, getPlatform()).WillRepeatedly(Return(string("linux")));
|
||||
EXPECT_CALL(mock_details_resolver, getArch()).WillRepeatedly(Return(string("x86_64")));
|
||||
EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isKernelVersion3OrHigher()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isGwNotVsx()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isVersionEqualOrAboveR8110()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, parseNginxMetadata()).WillRepeatedly(Return(no_nginx));
|
||||
EXPECT_CALL(mock_details_resolver, getAgentVersion()).WillRepeatedly(Return("1.1.1"));
|
||||
|
||||
map<string, string> resolved_mgmt_details({{"kernel_version", "4.4.0-87-generic"}});
|
||||
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillOnce(Return(resolved_mgmt_details));
|
||||
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_mgmt_details));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -156,7 +154,6 @@ public:
|
||||
}
|
||||
|
||||
::Environment env;
|
||||
OrchestrationComp orchestration_comp;
|
||||
AgentDetails agent_details;
|
||||
ConfigComponent config_comp;
|
||||
Config::I_Config *config;
|
||||
@@ -185,6 +182,7 @@ public:
|
||||
NiceMock<MockAgenetDetailsReporter> mock_agent_reporter;
|
||||
NiceMock<MockLogging> mock_log;
|
||||
|
||||
OrchestrationComp orchestration_comp;
|
||||
|
||||
private:
|
||||
bool
|
||||
@@ -215,6 +213,7 @@ TEST_F(OrchestrationMultitenancyTest, handle_virtual_resource)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
|
@@ -130,19 +130,17 @@ public:
|
||||
expectDetailsResolver()
|
||||
{
|
||||
Maybe<tuple<string, string, string>> no_nginx(genError("No nginx"));
|
||||
EXPECT_CALL(mock_details_resolver, getPlatform()).WillOnce(Return(string("linux")));
|
||||
EXPECT_CALL(mock_details_resolver, getArch()).WillOnce(Return(string("x86_64")));
|
||||
EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isKernelVersion3OrHigher()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isGwNotVsx()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isVersionEqualOrAboveR8110()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, parseNginxMetadata()).WillOnce(Return(no_nginx));
|
||||
EXPECT_CALL(mock_details_resolver, getAgentVersion())
|
||||
.WillOnce(Return("1.1.1"))
|
||||
.WillOnce(Return("1.1.1"));
|
||||
EXPECT_CALL(mock_details_resolver, getPlatform()).WillRepeatedly(Return(string("linux")));
|
||||
EXPECT_CALL(mock_details_resolver, getArch()).WillRepeatedly(Return(string("x86_64")));
|
||||
EXPECT_CALL(mock_details_resolver, isReverseProxy()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isKernelVersion3OrHigher()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isGwNotVsx()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, isVersionEqualOrAboveR8110()).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(mock_details_resolver, parseNginxMetadata()).WillRepeatedly(Return(no_nginx));
|
||||
EXPECT_CALL(mock_details_resolver, getAgentVersion()).WillRepeatedly(Return("1.1.1"));
|
||||
|
||||
map<string, string> resolved_mgmt_details({{"kernel_version", "4.4.0-87-generic"}});
|
||||
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillOnce(Return(resolved_mgmt_details));
|
||||
EXPECT_CALL(mock_details_resolver, getResolvedDetails()).WillRepeatedly(Return(resolved_mgmt_details));
|
||||
}
|
||||
|
||||
string
|
||||
@@ -561,6 +559,7 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
string host_address = "1.2.3.5";
|
||||
string new_host_address = "6.2.3.5";
|
||||
@@ -603,6 +602,8 @@ TEST_F(OrchestrationTest, orchestrationPolicyUpdate)
|
||||
EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path))
|
||||
.WillOnce(Return(policy_response))
|
||||
.WillOnce(Return(new_policy_response));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_path, policy_file_path + ".last"))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_update_communication, setAddressExtenesion(""));
|
||||
EXPECT_CALL(mock_update_communication, authenticateAgent()).WillOnce(Return(Maybe<void>()));
|
||||
@@ -727,6 +728,7 @@ TEST_F(OrchestrationTest, startOrchestrationPoliceWithFailures)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
@@ -853,6 +855,7 @@ TEST_F(OrchestrationTest, loadOrchestrationPolicyFromBackup)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
@@ -987,6 +990,7 @@ TEST_F(OrchestrationTest, manifestUpdate)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
@@ -1139,7 +1143,9 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
string new_policy_path = "policy path";
|
||||
|
||||
string manifest_checksum = "manifest";
|
||||
string policy_checksum = "policy";
|
||||
@@ -1166,6 +1172,8 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(orchestration_policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, readFile(orchestration_policy_file_path)).WillOnce(Return(response));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_path, policy_file_path + ".last"))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_message, setActiveFog(host_address, 443, true, MessageTypeTag::GENERIC)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_update_communication, setAddressExtenesion(""));
|
||||
|
||||
@@ -1194,7 +1202,7 @@ TEST_F(OrchestrationTest, getBadPolicyUpdate)
|
||||
Package::ChecksumTypes::SHA256,
|
||||
policy_file
|
||||
)
|
||||
).WillOnce(Return(Maybe<std::string>(string("policy path"))));
|
||||
).WillOnce(Return(Maybe<std::string>(string(new_policy_path))));
|
||||
string manifest = "";
|
||||
string policy = "111111";
|
||||
string setting = "";
|
||||
@@ -1284,6 +1292,7 @@ TEST_F(OrchestrationTest, failedDownloadSettings)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
@@ -1445,6 +1454,7 @@ TEST_P(OrchestrationTest, orchestrationFirstRun)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
@@ -1665,6 +1675,7 @@ TEST_F(OrchestrationTest, dataUpdate)
|
||||
string manifest_file_path = "/etc/cp/conf/manifest.json";
|
||||
string setting_file_path = "/etc/cp/conf/settings.json";
|
||||
string policy_file_path = "/etc/cp/conf/policy.json";
|
||||
string last_policy_file_path = "/etc/cp/conf/policy.json.last";
|
||||
string data_file_path = "/etc/cp/conf/data.json";
|
||||
|
||||
string host_address = "1.2.3.5";
|
||||
|
@@ -296,6 +296,10 @@ public:
|
||||
const string &service_id
|
||||
) override;
|
||||
|
||||
bool doesFailedServicesExist() override;
|
||||
|
||||
void clearFailedServices() override;
|
||||
|
||||
private:
|
||||
void cleanUpVirtualFiles();
|
||||
|
||||
@@ -323,6 +327,7 @@ private:
|
||||
string update_policy_version;
|
||||
string settings_path;
|
||||
map<int, ReconfStatus> services_reconf_status;
|
||||
map<int, ReconfStatus> failed_services;
|
||||
map<int, string> services_reconf_names;
|
||||
map<int, string> services_reconf_ids;
|
||||
string filesystem_prefix;
|
||||
@@ -387,9 +392,24 @@ ServiceController::Impl::getUpdatedReconfStatus()
|
||||
|
||||
if (res < service_and_reconf_status.second) res = service_and_reconf_status.second;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// LCOV_EXCL_START Reason: future fix will be done
|
||||
void
|
||||
ServiceController::Impl::clearFailedServices()
|
||||
{
|
||||
failed_services.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
ServiceController::Impl::doesFailedServicesExist()
|
||||
{
|
||||
return (failed_services.size() > 0);
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
void
|
||||
ServiceController::Impl::init()
|
||||
{
|
||||
@@ -775,18 +795,11 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
if (new_policy_path.compare(config_file_path) == 0) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "Enforcing the default policy file";
|
||||
policy_version = version_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string backup_ext = getConfigurationWithDefault<string>(".bk", "orchestration", "Backup file extension");
|
||||
|
||||
// Save the new configuration file.
|
||||
if (!orchestration_tools->copyFile(new_policy_path, config_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to save the policy file.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Backup the current configuration file.
|
||||
uint max_backup_attempts = 3;
|
||||
bool is_backup_succeed = false;
|
||||
@@ -794,7 +807,7 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
I_MainLoop *mainloop = Singleton::Consume<I_MainLoop>::by<ServiceController>();
|
||||
|
||||
for (size_t i = 0; i < max_backup_attempts; i++) {
|
||||
if (orchestration_tools->copyFile(new_policy_path, backup_file)) {
|
||||
if (orchestration_tools->copyFile(config_file_path, backup_file)) {
|
||||
is_backup_succeed = true;
|
||||
break;
|
||||
}
|
||||
@@ -807,6 +820,12 @@ ServiceController::Impl::updateServiceConfiguration(
|
||||
}
|
||||
|
||||
policy_version = version_value;
|
||||
|
||||
// Save the new configuration file.
|
||||
if (!orchestration_tools->copyFile(new_policy_path, config_file_path)) {
|
||||
dbgWarning(D_ORCHESTRATOR) << "Failed to save the policy file.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return was_policy_updated;
|
||||
@@ -835,7 +854,7 @@ ServiceController::Impl::sendSignalForServices(
|
||||
}
|
||||
|
||||
if (reconf_status == ReconfStatus::FAILED) {
|
||||
dbgDebug(D_ORCHESTRATOR) << "The reconfiguration failed for serivce " << service_id;
|
||||
dbgDebug(D_ORCHESTRATOR) << "The reconfiguration failed for serivce: " << service_id;
|
||||
services_reconf_status.clear();
|
||||
services_reconf_names.clear();
|
||||
return false;
|
||||
@@ -972,6 +991,10 @@ ServiceController::Impl::getUpdatePolicyVersion() const
|
||||
void
|
||||
ServiceController::Impl::updateReconfStatus(int id, ReconfStatus status)
|
||||
{
|
||||
if (status == ReconfStatus::FAILED) {
|
||||
failed_services.emplace(id, status);
|
||||
}
|
||||
|
||||
if (services_reconf_status.find(id) == services_reconf_status.end()) {
|
||||
dbgError(D_ORCHESTRATOR) << "Service reconfiguration monitor received illegal id :" << id;
|
||||
return;
|
||||
|
@@ -254,7 +254,7 @@ TEST_F(ServiceControllerTest, UpdateConfiguration)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -346,7 +346,7 @@ TEST_F(ServiceControllerTest, TimeOutUpdateConfiguration)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -465,7 +465,7 @@ TEST_F(ServiceControllerTest, writeRegisteredServicesFromFile)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -606,7 +606,7 @@ TEST_F(ServiceControllerTest, noPolicyUpdate)
|
||||
.WillOnce(Return(json_parser_return));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, readFile(l4_firewall_policy_path)).WillOnce(Return(l4_firewall));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
@@ -697,7 +697,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
|
||||
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -743,7 +743,7 @@ TEST_F(ServiceControllerTest, SettingsAndPolicyUpdateCombinations)
|
||||
.WillOnce(Return(json_parser_return));
|
||||
EXPECT_CALL(mock_orchestration_tools, doesFileExist(l4_firewall_policy_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, readFile(l4_firewall_policy_path)).WillOnce(Return(l4_firewall));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
@@ -849,7 +849,7 @@ TEST_F(ServiceControllerTest, backup)
|
||||
mock_orchestration_tools,
|
||||
writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)
|
||||
);
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -963,7 +963,7 @@ TEST_F(ServiceControllerTest, backupAttempts)
|
||||
writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true)
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true));
|
||||
@@ -1078,7 +1078,7 @@ TEST_F(ServiceControllerTest, MultiUpdateConfiguration)
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, writeFile(l4_firewall, l4_firewall_policy_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, writeFile(orchestration, orchestration_policy_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -1136,7 +1136,7 @@ TEST_F(ServiceControllerTest, emptyServices)
|
||||
Return(json_parser_return)
|
||||
);
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -1355,19 +1355,17 @@ TEST_F(ServiceControllerTest, ErrorUpdateConfigurationRest)
|
||||
_
|
||||
)
|
||||
).WillRepeatedly(Return(string("not-registered")));
|
||||
EXPECT_CALL(
|
||||
mock_orchestration_tools,
|
||||
copyFile(file_name, policy_file_path)
|
||||
).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
EXPECT_FALSE(i_service_controller->updateServiceConfiguration(file_name, ""));
|
||||
EXPECT_TRUE(i_service_controller->updateServiceConfiguration(file_name, ""));
|
||||
EXPECT_THAT(
|
||||
capture_debug.str(),
|
||||
HasSubstr("Service mock access control is inactive")
|
||||
);
|
||||
EXPECT_FALSE(i_service_controller->isServiceInstalled("family1_id2"));
|
||||
EXPECT_NE(i_service_controller->getPolicyVersion(), version_value);
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), "");
|
||||
EXPECT_EQ(i_service_controller->getPolicyVersion(), version_value);
|
||||
EXPECT_EQ(i_service_controller->getUpdatePolicyVersion(), version_value);
|
||||
}
|
||||
|
||||
@@ -1567,7 +1565,7 @@ TEST_F(ServiceControllerTest, testMultitenantConfFiles)
|
||||
);
|
||||
|
||||
string new_policy_file_path = "/etc/cp/conf/tenant_" + tenant + "_profile_" + profile + "/" + "policy.json";
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(conf_file_name, new_policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(new_policy_file_path, new_policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(conf_file_name, new_policy_file_path)).WillOnce(Return(true));
|
||||
|
||||
@@ -1664,7 +1662,7 @@ TEST_F(ServiceControllerTest, test_delayed_reconf)
|
||||
EXPECT_CALL(mock_orchestration_status,
|
||||
setServiceConfiguration("l4_firewall", l4_firewall_policy_path, OrchestrationStatusConfigType::POLICY));
|
||||
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path + backup_extension))
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(policy_file_path, policy_file_path + backup_extension))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_orchestration_tools, copyFile(file_name, policy_file_path)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_ml, yield(false)).Times(AnyNumber());
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include "declarative_policy_utils.h"
|
||||
#include "rest.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "log_generator.h"
|
||||
#include "agent_details.h"
|
||||
@@ -54,10 +54,7 @@ DeclarativePolicyUtils::getLocalPolicyChecksum()
|
||||
return orchestration_tools->readFile("/etc/cp/conf/k8s-policy-check.trigger");
|
||||
}
|
||||
|
||||
string policy_path = getConfigurationFlagWithDefault(
|
||||
getFilesystemPathConfig() + "/conf/local_policy.yaml",
|
||||
"local_mgmt_policy"
|
||||
);
|
||||
string policy_path = Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->getLocalPolicyPath();
|
||||
|
||||
Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
|
||||
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
|
||||
@@ -97,7 +94,7 @@ DeclarativePolicyUtils::getPolicyChecksum()
|
||||
I_OrchestrationTools *orchestration_tools = Singleton::Consume<I_OrchestrationTools>::by<DeclarativePolicyUtils>();
|
||||
Maybe<string> file_checksum = orchestration_tools->calculateChecksum(
|
||||
I_OrchestrationTools::SELECTED_CHECKSUM_TYPE,
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->getPolicyPath()
|
||||
Singleton::Consume<I_LocalPolicyMgmtGen>::by<DeclarativePolicyUtils>()->getAgentPolicyPath()
|
||||
);
|
||||
|
||||
if (!file_checksum.ok()) {
|
||||
|
@@ -68,6 +68,11 @@ public:
|
||||
void
|
||||
init()
|
||||
{
|
||||
I_AgentDetails *agentDetails = Singleton::Consume<I_AgentDetails>::by<ReputationFeaturesAgg>();
|
||||
|
||||
if (agentDetails->getOrchestrationMode() != OrchestrationMode::ONLINE) {
|
||||
return;
|
||||
}
|
||||
registerListener();
|
||||
I_MainLoop* i_mainLoop = Singleton::Consume<I_MainLoop>::by<ReputationFeaturesAgg>();
|
||||
I_MainLoop::Routine routine = [this]() { reportReputationFeatures(); };
|
||||
@@ -77,6 +82,11 @@ public:
|
||||
void
|
||||
fini()
|
||||
{
|
||||
I_AgentDetails *agentDetails = Singleton::Consume<I_AgentDetails>::by<ReputationFeaturesAgg>();
|
||||
|
||||
if (agentDetails->getOrchestrationMode() != OrchestrationMode::ONLINE) {
|
||||
return;
|
||||
}
|
||||
unregisterListener();
|
||||
}
|
||||
|
||||
|
@@ -118,15 +118,13 @@ void TuningDecision::updateDecisions()
|
||||
{
|
||||
TuningEvents tuningEvents;
|
||||
RemoteFilesList tuningDecisionFiles;
|
||||
if (m_baseUri == "") {
|
||||
I_AgentDetails *agentDetails = Singleton::Consume<I_AgentDetails>::by<WaapComponent>();
|
||||
if (agentDetails->getOrchestrationMode() != OrchestrationMode::ONLINE) {
|
||||
m_baseUri = "/api/";
|
||||
} else {
|
||||
m_baseUri = "/storage/waap/";
|
||||
}
|
||||
dbgTrace(D_WAAP) << "URI prefix: " << m_baseUri;
|
||||
I_AgentDetails *agentDetails = Singleton::Consume<I_AgentDetails>::by<WaapComponent>();
|
||||
if (agentDetails->getOrchestrationMode() != OrchestrationMode::ONLINE) {
|
||||
m_baseUri = "/api/";
|
||||
} else {
|
||||
m_baseUri = "/storage/waap/";
|
||||
}
|
||||
dbgTrace(D_WAAP) << "URI prefix: " << m_baseUri;
|
||||
bool isSuccessful = sendObject(tuningDecisionFiles,
|
||||
I_Messaging::Method::GET,
|
||||
m_baseUri + "?list-type=2&prefix=" + m_remotePath);
|
||||
|
@@ -42,35 +42,6 @@ namespace Waap {
|
||||
|
||||
auto preconditions = jsObj.at("preconditions").get<picojson::value::object>();
|
||||
|
||||
// Build full list of words to load into aho-corasick pattern matcher
|
||||
dbgTrace(D_WAAP_REGEX) << "Loading regex precondition_keys into Aho-Corasick pattern matcher...";
|
||||
|
||||
auto preconditionKeys = jsObj.at("precondition_keys").get<picojson::value::array>();
|
||||
std::set<PMPattern> pmPatterns;
|
||||
|
||||
for (const auto &preconditionKey : preconditionKeys) {
|
||||
std::string wordStr(preconditionKey.get<std::string>());
|
||||
|
||||
// Do not load the "empty" word into Aho-Corasick. It's meaningless and Aho prepare() call would fail.
|
||||
if (wordStr.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WordIndex wordIndex = registerWord(wordStr);
|
||||
pmPatterns.insert(PMPattern(wordStr, false, false, wordIndex));
|
||||
}
|
||||
|
||||
// Initialize the aho-corasick pattern matcher with the patterns
|
||||
Maybe<void> pmHookStatus = m_pmHook.prepare(pmPatterns);
|
||||
|
||||
if (!pmHookStatus.ok()) {
|
||||
dbgError(D_WAAP_REGEX) << "Aho-Corasick engine failed to load!";
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
dbgTrace(D_WAAP_REGEX) << "Aho-Corasick engine loaded.";
|
||||
|
||||
// Loop over pre-conditions (rules) and load them
|
||||
dbgTrace(D_WAAP_REGEX) << "Loading regex preconditions...";
|
||||
|
||||
@@ -140,6 +111,7 @@ namespace Waap {
|
||||
if (flags == "_noregex") {
|
||||
// Add regex pattern to set of "noRegex" patterns
|
||||
m_noRegexPatterns.insert(regexPattern);
|
||||
m_pmWordInfo[wordIndex].noRegex = true;
|
||||
}
|
||||
|
||||
m_regexToWordMap[regexPattern] = wordIndex;
|
||||
@@ -167,6 +139,43 @@ namespace Waap {
|
||||
}
|
||||
}
|
||||
|
||||
// Build full list of words to load into aho-corasick pattern matcher
|
||||
dbgTrace(D_WAAP_REGEX) << "Loading regex precondition_keys into Aho-Corasick pattern matcher...";
|
||||
|
||||
auto preconditionKeys = jsObj.at("precondition_keys").get<picojson::value::array>();
|
||||
std::set<PMPattern> pmPatterns;
|
||||
|
||||
for (const auto &preconditionKey : preconditionKeys) {
|
||||
std::string wordStr(preconditionKey.get<std::string>());
|
||||
|
||||
// Do not load the "empty" word into Aho-Corasick. It's meaningless and Aho prepare() call would fail.
|
||||
if (wordStr.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WordIndex wordIndex = registerWord(wordStr);
|
||||
WordIndex napreWordIndex = m_pmWordInfo[wordIndex].napreWordIndex;
|
||||
WordIndex napostWordIndex = m_pmWordInfo[wordIndex].napostWordIndex;
|
||||
WordIndex napostNapreWordIndex = m_pmWordInfo[wordIndex].napostNapreWordIndex;
|
||||
|
||||
bool noRegex = ((napreWordIndex != emptyWordIndex) && m_pmWordInfo[napreWordIndex].noRegex) ||
|
||||
((napostWordIndex != emptyWordIndex) && m_pmWordInfo[napostWordIndex].noRegex) ||
|
||||
((napostNapreWordIndex != emptyWordIndex) && m_pmWordInfo[napostNapreWordIndex].noRegex);
|
||||
|
||||
pmPatterns.insert(PMPattern(wordStr, false, false, wordIndex, noRegex));
|
||||
}
|
||||
|
||||
// Initialize the aho-corasick pattern matcher with the patterns
|
||||
Maybe<void> pmHookStatus = m_pmHook.prepare(pmPatterns);
|
||||
|
||||
if (!pmHookStatus.ok()) {
|
||||
dbgError(D_WAAP_REGEX) << "Aho-Corasick engine failed to load!";
|
||||
error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
dbgTrace(D_WAAP_REGEX) << "Aho-Corasick engine loaded.";
|
||||
|
||||
dbgTrace(D_WAAP_REGEX) << "Aho-corasick pattern matching engine initialized!";
|
||||
}
|
||||
|
||||
@@ -225,17 +234,17 @@ namespace Waap {
|
||||
dbgTrace(D_WAAP_REGEX) << "Rules pass #1: collect OR sets";
|
||||
|
||||
m_pmHook.scanBufWithOffsetLambda(buffer, [this, &wordsSet, &buffer]
|
||||
(u_int endMatchOffset, const PMPattern &pmPattern)
|
||||
(u_int endMatchOffset, const PMPattern &pmPattern, bool matchAll)
|
||||
{
|
||||
uint offset = endMatchOffset + 1 - pmPattern.size(); // reported offset points to last character of a match
|
||||
|
||||
// Extract the word index from the PMPattern object (we do not need the string part of it)
|
||||
WordIndex wordIndex = pmPattern.getIndex();
|
||||
|
||||
bool regexWordBefore = (offset != 0) &&
|
||||
(isRegexWordChar(buffer.data()[offset - 1]));
|
||||
bool regexWordAfter = (offset + pmPattern.size() < buffer.size()) &&
|
||||
(isRegexWordChar(buffer.data()[offset + pmPattern.size()]));
|
||||
bool regexWordBefore = !matchAll && (offset != 0) &&
|
||||
(isRegexWordChar(buffer.data()[offset - 1]));
|
||||
bool regexWordAfter = !matchAll && (offset + pmPattern.size() < buffer.size()) &&
|
||||
(isRegexWordChar(buffer.data()[offset + pmPattern.size()]));
|
||||
|
||||
processWord(wordsSet, wordIndex);
|
||||
|
||||
|
@@ -67,6 +67,7 @@ namespace Waap {
|
||||
WordIndex napreWordIndex;
|
||||
WordIndex baseWordIndex;
|
||||
std::string wordStr;
|
||||
bool noRegex;
|
||||
|
||||
WordInfo()
|
||||
:
|
||||
@@ -74,7 +75,8 @@ namespace Waap {
|
||||
napostWordIndex(emptyWordIndex),
|
||||
napreWordIndex(emptyWordIndex),
|
||||
baseWordIndex(0),
|
||||
wordStr()
|
||||
wordStr(),
|
||||
noRegex(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@@ -2205,6 +2205,9 @@ Waf2Transaction::shouldIgnoreOverride(const Waf2ScanResult &res) {
|
||||
for (auto &keyword : res.keyword_matches) {
|
||||
exceptions_dict["indicator"].insert(keyword);
|
||||
}
|
||||
for (auto &it : res.found_patterns) {
|
||||
exceptions_dict["indicator"].insert(it.first);
|
||||
}
|
||||
|
||||
// calling behavior and check if there is a behavior that match to this specific param name.
|
||||
auto behaviors = exceptions.unpack().getBehavior(exceptions_dict,
|
||||
|
@@ -1186,7 +1186,7 @@ static const SingleRegex base64_key_value_detector_re(
|
||||
err,
|
||||
"base64_key_value");
|
||||
static const SingleRegex json_key_value_detector_re(
|
||||
"^[^<>{};,&\\?|=\\s]+={.+:.+}\\z",
|
||||
"^[^<>{};,&\\?|=\\s]+={.+(?s):.+(?s)}\\z",
|
||||
err,
|
||||
"json_key_value");
|
||||
static const SingleRegex base64_key_detector_re(
|
||||
|
Reference in New Issue
Block a user